X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmodules%2Favformat%2Fproducer_avformat.c;h=89d59b7ea39434b72f30eed0301d461a13db2034;hb=7601aa4468f96fb8e3395266b194e7e7bd095453;hp=de9b44fbe9090fd0b30a39b76c7ee764454bd532;hpb=7d5e839ba53328b1dfb36ba10d72136df24dad6e;p=mlt diff --git a/src/modules/avformat/producer_avformat.c b/src/modules/avformat/producer_avformat.c index de9b44fb..89d59b7e 100644 --- a/src/modules/avformat/producer_avformat.c +++ b/src/modules/avformat/producer_avformat.c @@ -816,46 +816,66 @@ static int producer_open( producer_avformat self, mlt_profile profile, const cha return error; } -static void reopen_video( producer_avformat self, mlt_producer producer ) +static void prepare_reopen( producer_avformat self ) { - mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); - mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); + mlt_service_lock( MLT_PRODUCER_SERVICE( self->parent ) ); pthread_mutex_lock( &self->audio_mutex ); pthread_mutex_lock( &self->open_mutex ); + int i; + for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) + { + mlt_pool_release( self->audio_buffer[i] ); + self->audio_buffer[i] = NULL; + av_free( self->decode_buffer[i] ); + self->decode_buffer[i] = NULL; + if ( self->audio_codec[i] ) + avcodec_close( self->audio_codec[i] ); + self->audio_codec[i] = NULL; + } if ( self->video_codec ) avcodec_close( self->video_codec ); self->video_codec = NULL; + #if LIBAVFORMAT_VERSION_INT >= ((53<<16)+(17<<8)+0) - if ( self->dummy_context ) - avformat_close_input( &self->dummy_context ); + if ( self->seekable && self->audio_format ) + avformat_close_input( &self->audio_format ); if ( self->video_format ) avformat_close_input( &self->video_format ); #else - if ( self->dummy_context ) - av_close_input_file( self->dummy_context ); + if ( self->seekable && self->audio_format ) + av_close_input_file( self->audio_format ); if ( self->video_format ) av_close_input_file( self->video_format ); #endif - self->dummy_context = NULL; + self->audio_format = NULL; self->video_format = NULL; pthread_mutex_unlock( &self->open_mutex ); - int audio_index = self->audio_index; - int video_index = self->video_index; - - producer_open( self, mlt_service_profile( MLT_PRODUCER_SERVICE(producer) ), - mlt_properties_get( properties, "resource" ), 0 ); - - self->audio_index = audio_index; - if ( self->video_format && video_index > -1 ) + // Cleanup the packet queues + AVPacket *pkt; + if ( self->apackets ) { - self->video_index = video_index; - video_codec_init( self, video_index, properties ); + while ( ( pkt = mlt_deque_pop_back( self->apackets ) ) ) + { + av_free_packet( pkt ); + free( pkt ); + } + mlt_deque_close( self->apackets ); + self->apackets = NULL; + } + if ( self->vpackets ) + { + while ( ( pkt = mlt_deque_pop_back( self->vpackets ) ) ) + { + av_free_packet( pkt ); + free( pkt ); + } + mlt_deque_close( self->vpackets ); + self->vpackets = NULL; } - pthread_mutex_unlock( &self->audio_mutex ); - mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); + mlt_service_unlock( MLT_PRODUCER_SERVICE( self->parent ) ); } static int64_t best_pts( producer_avformat self, int64_t pts, int64_t dts ) @@ -939,26 +959,15 @@ static int seek_video( producer_avformat self, mlt_position position, timestamp -= 2 / av_q2d( self->video_time_base ); if ( timestamp < 0 ) timestamp = 0; - mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "seeking timestamp %"PRId64" position %d expected %d last_pos %"PRId64"\n", + mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "seeking timestamp %"PRId64" position " MLT_POSITION_FMT " expected "MLT_POSITION_FMT" last_pos %"PRId64"\n", timestamp, position, self->video_expected, self->last_position ); // Seek to the timestamp - // NOTE: reopen_video is disabled at this time because it is causing trouble with A/V sync. - if ( 1 || req_position > 0 || self->last_position <= 0 ) - { - codec_context->skip_loop_filter = AVDISCARD_NONREF; - av_seek_frame( context, self->video_index, timestamp, AVSEEK_FLAG_BACKWARD ); + codec_context->skip_loop_filter = AVDISCARD_NONREF; + av_seek_frame( context, self->video_index, timestamp, AVSEEK_FLAG_BACKWARD ); - // flush any pictures still in decode buffer - avcodec_flush_buffers( codec_context ); - } - else - { - // Re-open video stream when rewinding to beginning from somewhere else. - // This is rather ugly, and I prefer not to do it this way, but ffmpeg is - // not reliably seeking to the first frame across formats. - reopen_video( self, producer ); - } + // flush any pictures still in decode buffer + avcodec_flush_buffers( codec_context ); // Remove the cached info relating to the previous position self->current_position = POSITION_INVALID; @@ -1236,8 +1245,14 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form pthread_mutex_lock( &self->video_mutex ); + uint8_t *alpha = NULL; + int got_picture = 0; + int image_size = 0; + // Fetch the video format context AVFormatContext *context = self->video_format; + if ( !context ) + goto exit_get_image; // Get the video stream AVStream *stream = context->streams[ self->video_index ]; @@ -1245,10 +1260,6 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form // Get codec context AVCodecContext *codec_context = stream->codec; - uint8_t *alpha = NULL; - int got_picture = 0; - int image_size = 0; - // Get the image cache if ( ! self->image_cache ) { @@ -1404,6 +1415,23 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form mlt_deque_push_back( self->apackets, tmp ); } } + else if ( ret < 0 ) + { + mlt_log_verbose( MLT_PRODUCER_SERVICE(producer), "av_read_frame returned error %d inside get_image\n", ret ); + if ( !self->seekable && mlt_properties_get_int( properties, "reconnect" ) ) + { + // Try to reconnect to live sources by closing context and codecs, + // and letting next call to get_frame() reopen. + prepare_reopen( self ); + pthread_mutex_unlock( &self->packets_mutex ); + goto exit_get_image; + } + if ( !self->seekable && mlt_properties_get_int( properties, "exit_on_disconnect" ) ) + { + mlt_log_fatal( MLT_PRODUCER_SERVICE(producer), "Exiting with error due to disconnected source.\n" ); + exit( EXIT_FAILURE ); + } + } } pthread_mutex_unlock( &self->packets_mutex ); @@ -1461,6 +1489,8 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form { if ( ++decode_errors <= 10 ) ret = 0; + else + mlt_log_warning( MLT_PRODUCER_SERVICE(producer), "video decoding error %d\n", ret ); } else { @@ -1786,8 +1816,7 @@ static int video_codec_init( producer_avformat self, int index, mlt_properties p if ( mlt_properties_get( properties, "force_fps" ) ) { AVRational force_fps = av_d2q( mlt_properties_get_double( properties, "force_fps" ), 1024 ); - self->video_time_base.num *= frame_rate.num * force_fps.den; - self->video_time_base.den *= frame_rate.den * force_fps.num; + self->video_time_base = av_mul_q( stream->time_base, av_div_q( frame_rate, force_fps ) ); frame_rate = force_fps; } mlt_properties_set_int( properties, "meta.media.frame_rate_num", frame_rate.num ); @@ -1849,11 +1878,15 @@ static void producer_set_up_video( producer_avformat self, mlt_frame frame ) // Get the video_index int index = mlt_properties_get_int( properties, "video_index" ); + int unlock_needed = 0; + // Reopen the file if necessary if ( !context && index > -1 ) { + unlock_needed = 1; + pthread_mutex_lock( &self->video_mutex ); producer_open( self, mlt_service_profile( MLT_PRODUCER_SERVICE(producer) ), - mlt_properties_get( properties, "resource" ), 1 ); + mlt_properties_get( properties, "resource" ), 0 ); context = self->video_format; } @@ -1919,6 +1952,8 @@ static void producer_set_up_video( producer_avformat self, mlt_frame frame ) // If something failed, use test card image mlt_properties_set_int( frame_properties, "test_image", 1 ); } + if ( unlock_needed ) + pthread_mutex_unlock( &self->video_mutex ); } static int seek_audio( producer_avformat self, mlt_position position, double timecode ) @@ -2161,6 +2196,8 @@ static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format // Fetch the audio_format AVFormatContext *context = self->audio_format; + if ( !context ) + goto exit_get_audio; int sizeof_sample = sizeof( int16_t ); @@ -2250,6 +2287,25 @@ static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format mlt_deque_push_back( self->vpackets, tmp ); } } + else if ( ret < 0 ) + { + mlt_producer producer = self->parent; + mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); + mlt_log_verbose( MLT_PRODUCER_SERVICE(producer), "av_read_frame returned error %d inside get_audio\n", ret ); + if ( !self->seekable && mlt_properties_get_int( properties, "reconnect" ) ) + { + // Try to reconnect to live sources by closing context and codecs, + // and letting next call to get_frame() reopen. + prepare_reopen( self ); + pthread_mutex_unlock( &self->packets_mutex ); + goto exit_get_audio; + } + if ( !self->seekable && mlt_properties_get_int( properties, "exit_on_disconnect" ) ) + { + mlt_log_fatal( MLT_PRODUCER_SERVICE(producer), "Exiting with error due to disconnected source.\n" ); + exit( EXIT_FAILURE ); + } + } } pthread_mutex_unlock( &self->packets_mutex ); @@ -2347,6 +2403,7 @@ static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format } else { +exit_get_audio: // Get silence and don't touch the context mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); }