[Jahshaka-cvs] SF.net SVN: openlibraries:[1476] trunk/src/openmedialib/plugins/avformat/ avformat_p
Status: Beta
Brought to you by:
jahshaka
From: <tim...@us...> - 2009-07-06 11:14:31
|
Revision: 1476 http://openlibraries.svn.sourceforge.net/openlibraries/?rev=1476&view=rev Author: timdewhirst Date: 2009-07-06 11:14:29 +0000 (Mon, 06 Jul 2009) Log Message: ----------- OML * various fixed to avoid short playback in certain cases e.g. mp3 audio * fixes to ensure all audio data is correctly written Modified Paths: -------------- trunk/src/openmedialib/plugins/avformat/avformat_plugin.cpp Modified: trunk/src/openmedialib/plugins/avformat/avformat_plugin.cpp =================================================================== --- trunk/src/openmedialib/plugins/avformat/avformat_plugin.cpp 2009-06-11 15:18:49 UTC (rev 1475) +++ trunk/src/openmedialib/plugins/avformat/avformat_plugin.cpp 2009-07-06 11:14:29 UTC (rev 1476) @@ -516,23 +516,37 @@ video_pts = 0.0; // Write interleaved audio and video frames + bool did_audio = false; + bool did_video = false; if ( !video_stream_ || ( video_stream_ && audio_stream_ && audio_pts < video_pts ) ) { - if ( !audio_queue_.size( ) ) - break; - if ( !process_audio( ) ) - return false; + if ( audio_queue_.size( ) ) + { + did_audio = true; + + if ( !process_audio( ) ) + { + return false; + } + } } - else if ( video_stream_ ) + + if ( !did_audio && video_stream_ ) { - if ( !video_queue_.size( ) ) - break; - if ( !process_video( ) ) - return false; + if ( video_queue_.size( ) ) + { + did_video = true; + + if ( !process_video( ) ) + { + return false; + } + } } - else + + if ( !did_audio && !did_video ) { - return false; + break; } } @@ -559,7 +573,9 @@ // Playout all queued frames and return when done. The default // implementation applies when the store doesn't queue frames. virtual void complete( ) - { + { + flush_audio(); + if ( prop_show_stats_.value< int >( ) ) { double audio_pts = audio_stream_ != 0 ? double( audio_stream_->pts.val ) * audio_stream_->time_base.num / audio_stream_->time_base.den : 0.0; @@ -914,7 +930,7 @@ int available = current->allocsize( ); int offset = 0; - while ( bytes > 0 && audio_block_used_ + available > bytes ) + while ( bytes > 0 && audio_block_used_ + available >= bytes ) { memcpy( audio_block_->data( ) + audio_block_used_, current->data( ) + offset, bytes - audio_block_used_ ); audio_queue_.push_back( audio_block_ ); @@ -1036,18 +1052,60 @@ // Precondition: the audio queue is not empty bool process_audio( ) { - bool ret = true; - audio_type_ptr audio = *( audio_queue_.begin( ) ); audio_queue_.pop_front( ); + int size = avcodec_encode_audio( audio_stream_->codec, audio_outbuf_, audio_outbuf_size_, ( short * )audio->data( ) ); + + if ( size < 0 ) return false; + + if ( size == 0 ) return true; + + return write_audio_packet( size ); + } + + void flush_audio() + { + // The libmp3lame codec (and maybe others) doesn't produce + // all its data immediately - it needs to be flushed after + // all the input data has been passed to it. To get the + // whole output we call avcodec_encode_audio with no data + // until we don't get anything back. + + if ( !audio_stream_ ) return; + + for (;;) + { + int size = avcodec_encode_audio( audio_stream_->codec, + audio_outbuf_, + audio_outbuf_size_, + NULL ); // means flush + + if ( size < 0 ) + { + WARNING_LOG << "error in avcodec_encode_audio while flushing audio" << size; + break; + } + + if ( size == 0 ) break; // all flushed + + // we write audio packets in the same way as in process_audio above + if ( !write_audio_packet( size ) ) + WARNING_LOG << "failed to write frame while flushing audio"; + } + } + + bool write_audio_packet( int size ) + { + assert( audio_stream_ != NULL ); + assert( size > 0 ); + AVCodecContext *c = audio_stream_->codec; AVPacket pkt; av_init_packet( &pkt ); + pkt.size = size; - pkt.size = avcodec_encode_audio( c, audio_outbuf_, audio_outbuf_size_, ( short * )audio->data( ) ); - // Write the compressed frame in the media file if ( c->coded_frame && uint64_t( c->coded_frame->pts ) != AV_NOPTS_VALUE ) pkt.pts = av_rescale_q( c->coded_frame->pts, c->time_base, audio_stream_->time_base ); @@ -1055,12 +1113,12 @@ pkt.flags |= PKT_FLAG_KEY; pkt.stream_index = audio_stream_->index; pkt.data = audio_outbuf_; - + if ( pkt.size ) if ( av_interleaved_write_frame( oc_, &pkt ) != 0 ) - ret = false; + return false; - return ret; + return true; } // The output file or device @@ -1325,7 +1383,15 @@ start_time_ = context_->start_time; // Set the duration - if ( uint64_t( context_->duration ) != AV_NOPTS_VALUE ) + + // We prefer to get this from the video stream if + // possible. Previously we didn't do this and if the + // audio stream was longer than the video, we would get a + // frame count from the audio but actually fetching a + // frame past the end of the video would fail. + if ( get_video_stream() && get_video_stream()->duration != AV_NOPTS_VALUE ) + frames_ = get_video_stream()->duration; + else if ( uint64_t( context_->duration ) != AV_NOPTS_VALUE ) frames_ = int( ( avformat_input::fps( ) * ( context_->duration - start_time_ ) ) / ( double )AV_TIME_BASE ); else frames_ = 1 << 29; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |