X-Git-Url: http://research.m1stereo.tv/gitweb?a=blobdiff_plain;f=src%2Fmodules%2Favformat%2Fproducer_avformat.c;h=c188b27cc481e184c2ddfc2bd3b63a7ca2281f82;hb=29bc1b715ce20f8202c60740707c39fd723c1c50;hp=bc7971243fb7e041062502a86327e54f9b463ac4;hpb=642d69d110cb683b43857bb8385de38c58f5695d;p=melted diff --git a/src/modules/avformat/producer_avformat.c b/src/modules/avformat/producer_avformat.c index bc79712..c188b27 100644 --- a/src/modules/avformat/producer_avformat.c +++ b/src/modules/avformat/producer_avformat.c @@ -2,6 +2,7 @@ * producer_avformat.c -- avformat producer * Copyright (C) 2003-2004 Ushodaya Enterprises Limited * Author: Charles Yates + * Much code borrowed from ffmpeg.c: Copyright (c) 2000-2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,10 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -// Local header files -#include "producer_avformat.h" - // MLT Header files +#include #include // ffmpeg Header files @@ -40,13 +39,13 @@ void avformat_lock( ); void avformat_unlock( ); // Forward references. -static int producer_open( mlt_producer this, char *file ); +static int producer_open( mlt_producer this, mlt_profile profile, char *file ); static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int index ); /** Constructor for libavformat. */ -mlt_producer producer_avformat_init( char *file ) +mlt_producer producer_avformat_init( mlt_profile profile, char *file ) { mlt_producer this = NULL; @@ -69,12 +68,17 @@ mlt_producer producer_avformat_init( char *file ) this->get_frame = producer_get_frame; // Open the file - if ( producer_open( this, file ) != 0 ) + if ( producer_open( this, profile, file ) != 0 ) { // Clean up mlt_producer_close( this ); this = NULL; } + + // Close the file to release resources for large playlists - reopen later as needed + mlt_properties_set_data( properties, "dummy_context", NULL, 0, NULL, NULL ); + mlt_properties_set_data( properties, "audio_context", NULL, 0, NULL, NULL ); + mlt_properties_set_data( properties, "video_context", NULL, 0, NULL, NULL ); } } @@ -92,13 +96,13 @@ static void find_default_streams( AVFormatContext *context, int *audio_index, in for( i = 0; i < context->nb_streams; i++ ) { // Get the codec context - AVCodecContext *codec_context = context->streams[ i ]->codec; + AVCodecContext *codec_context = context->streams[ i ]->codec; if ( avcodec_find_decoder( codec_context->codec_id ) == NULL ) continue; // Determine the type and obtain the first index of each type - switch( codec_context->codec_type ) + switch( codec_context->codec_type ) { case CODEC_TYPE_VIDEO: if ( *video_index < 0 ) @@ -107,9 +111,9 @@ static void find_default_streams( AVFormatContext *context, int *audio_index, in case CODEC_TYPE_AUDIO: if ( *audio_index < 0 ) *audio_index = i; - break; + break; default: - break; + break; } } } @@ -153,7 +157,7 @@ static void producer_codec_close( void *codec ) /** Open the file. */ -static int producer_open( mlt_producer this, char *file ) +static int producer_open( mlt_producer this, mlt_profile profile, char *file ) { // Return an error code (0 == no error) int error = 0; @@ -165,7 +169,7 @@ static int producer_open( mlt_producer this, char *file ) mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); // We will treat everything with the producer fps - double fps = mlt_properties_get_double( properties, "fps" ); + double fps = mlt_profile_fps( profile ); // Lock the mutex now avformat_lock( ); @@ -203,11 +207,13 @@ static int producer_open( mlt_producer this, char *file ) params->width = 640; params->height = 480; params->time_base= (AVRational){1,25}; - params->device = file; + // params->device = file; params->channels = 2; params->sample_rate = 48000; } + // XXX: this does not work anymore since avdevice + // TODO: make producer_avddevice? // Parse out params mrl = strchr( file, '?' ); while ( mrl ) @@ -272,16 +278,16 @@ static int producer_open( mlt_producer this, char *file ) if ( context->duration != AV_NOPTS_VALUE ) { // This isn't going to be accurate for all formats - mlt_position frames = ( mlt_position )( ( ( double )context->duration / ( double )AV_TIME_BASE ) * fps ); - mlt_properties_set_position( properties, "out", frames - 2 ); - mlt_properties_set_position( properties, "length", frames - 1 ); + mlt_position frames = ( mlt_position )( ( ( double )context->duration / ( double )AV_TIME_BASE ) * fps + 0.5 ); + mlt_properties_set_position( properties, "out", frames - 1 ); + mlt_properties_set_position( properties, "length", frames ); } // Find default audio and video streams find_default_streams( context, &audio_index, &video_index ); - if ( context->start_time != AV_NOPTS_VALUE ) - mlt_properties_set_double( properties, "_start_time", context->start_time ); + if ( context->start_time != AV_NOPTS_VALUE ) + mlt_properties_set_double( properties, "_start_time", context->start_time ); // Check if we're seekable (something funny about mpeg here :-/) if ( strcmp( file, "pipe:" ) && strncmp( file, "http://", 6 ) ) @@ -368,14 +374,7 @@ static int producer_open( mlt_producer this, char *file ) static double producer_time_of_frame( mlt_producer this, mlt_position position ) { - // Get the properties - mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); - - // Obtain the fps - double fps = mlt_properties_get_double( properties, "fps" ); - - // Do the calc - return ( double )position / fps; + return ( double )position / mlt_producer_get_fps( this ); } static inline void convert_image( AVFrame *frame, uint8_t *buffer, int pix_fmt, mlt_image_format format, int width, int height ) @@ -489,10 +488,10 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form // We may want to use the source fps if available double source_fps = mlt_properties_get_double( properties, "source_fps" ); - double fps = mlt_properties_get_double( properties, "fps" ); + double fps = mlt_producer_get_fps( this ); // This is the physical frame position in the source - int req_position = ( int )( position / fps * source_fps ); + int req_position = ( int )( position / fps * source_fps + 0.5 ); // Get the seekable status int seekable = mlt_properties_get_int( properties, "seekable" ); @@ -552,7 +551,7 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form else if ( seekable && ( position < expected || position - expected >= 12 ) ) { // Calculate the timestamp for the requested frame - int64_t timestamp = ( int64_t )( ( double )req_position / source_fps * AV_TIME_BASE ); + int64_t timestamp = ( int64_t )( ( double )req_position / source_fps * AV_TIME_BASE + 0.5 ); if ( ( uint64_t )context->start_time != AV_NOPTS_VALUE ) timestamp += context->start_time; if ( must_decode ) @@ -606,10 +605,9 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form if ( ret >= 0 && pkt.stream_index == index && pkt.size > 0 ) { // Determine time code of the packet - int_position = ( int )( av_q2d( stream->time_base ) * pkt.dts * source_fps ); + int_position = ( int )( av_q2d( stream->time_base ) * pkt.dts * source_fps + 0.5 ); if ( context->start_time != AV_NOPTS_VALUE ) - int_position -= ( int )( context->start_time * source_fps / AV_TIME_BASE ); - + int_position -= ( int )( context->start_time * source_fps / AV_TIME_BASE + 0.5 ); int last_position = mlt_properties_get_int( properties, "_last_position" ); if ( int_position == last_position ) int_position = last_position + 1; @@ -636,21 +634,23 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form got_picture = 0; } } + av_free_packet( &pkt ); + } + else if ( ret >= 0 ) + { + av_free_packet( &pkt ); } // Now handle the picture if we have one if ( got_picture ) { mlt_properties_set_int( frame_properties, "progressive", !av_frame->interlaced_frame ); - mlt_properties_set_int( frame_properties, "top_field_first", av_frame->top_field_first ); + mlt_properties_set_int( properties, "top_field_first", av_frame->top_field_first ); convert_image( av_frame, *buffer, codec_context->pix_fmt, *format, *width, *height ); mlt_properties_set_data( frame_properties, "image", *buffer, size, (mlt_destructor)mlt_pool_release, NULL ); mlt_properties_set_int( properties, "_current_position", int_position ); mlt_properties_set_int( properties, "_got_picture", 1 ); } - - // We're finished with this packet regardless - av_free_packet( &pkt ); } } @@ -678,6 +678,16 @@ static void producer_set_up_video( mlt_producer this, mlt_frame frame ) // Fetch the video_context AVFormatContext *context = mlt_properties_get_data( properties, "video_context", NULL ); + if ( !context ) + { + // Reopen the file + mlt_events_block( properties, this ); + producer_open( this, mlt_service_profile( MLT_PRODUCER_SERVICE(this) ), + mlt_properties_get( properties, "resource" ) ); + context = mlt_properties_get_data( properties, "video_context", NULL ); + mlt_properties_set_data( properties, "dummy_context", NULL, 0, NULL, NULL ); + mlt_events_unblock( properties, this ); + } // Get the video_index int index = mlt_properties_get_int( properties, "video_index" ); @@ -699,6 +709,16 @@ static void producer_set_up_video( mlt_producer this, mlt_frame frame ) // Initialise the codec if necessary if ( codec == NULL ) { + // Initialise multi-threading + int thread_count = mlt_properties_get_int( properties, "threads" ); + if ( thread_count == 0 && getenv( "MLT_AVFORMAT_THREADS" ) ) + thread_count = atoi( getenv( "MLT_AVFORMAT_THREADS" ) ); + if ( thread_count > 1 ) + { + avcodec_thread_init( codec_context, thread_count ); + codec_context->thread_count = thread_count; + } + // Find the codec codec = avcodec_find_decoder( codec_context->codec_id ); @@ -723,6 +743,28 @@ static void producer_set_up_video( mlt_producer this, mlt_frame frame ) double force_aspect_ratio = mlt_properties_get_double( properties, "force_aspect_ratio" ); double aspect_ratio; + if ( strcmp( codec_context->codec->name, "dvvideo" ) == 0 ) + { + // Override FFmpeg's notion of DV aspect ratios, which are + // based upon a width of 704. Since we do not have a normaliser + // that crops (nor is cropping 720 wide ITU-R 601 video always desirable) + // we just coerce the values to facilitate a passive behaviour through + // the rescale normaliser when using equivalent producers and consumers. + // = display_aspect / (width * height) + if ( codec_context->sample_aspect_ratio.num == 10 && + codec_context->sample_aspect_ratio.den == 11 ) + force_aspect_ratio = 8.0/9.0; // 4:3 NTSC + else if ( codec_context->sample_aspect_ratio.num == 59 && + codec_context->sample_aspect_ratio.den == 54 ) + force_aspect_ratio = 16.0/15.0; // 4:3 PAL + else if ( codec_context->sample_aspect_ratio.num == 40 && + codec_context->sample_aspect_ratio.den == 33 ) + force_aspect_ratio = 32.0/27.0; // 16:9 NTSC + else if ( codec_context->sample_aspect_ratio.num == 118 && + codec_context->sample_aspect_ratio.den == 81 ) + force_aspect_ratio = 64.0/45.0; // 16:9 PAL + } + // XXX: We won't know the real aspect ratio until an image is decoded // but we do need it now (to satisfy filter_resize) - take a guess based // on pal/ntsc @@ -736,18 +778,17 @@ static void producer_set_up_video( mlt_producer this, mlt_frame frame ) } else { - int is_pal = mlt_properties_get_double( properties, "fps" ) == 25.0; - aspect_ratio = is_pal ? 59.0/54.0 : 10.0/11.0; + aspect_ratio = 1.0; } // Determine the fps source_fps = ( double )codec_context->time_base.den / ( codec_context->time_base.num == 0 ? 1 : codec_context->time_base.num ); // We'll use fps if it's available - if ( source_fps > 0 && source_fps < 30 ) + if ( source_fps > 0 ) mlt_properties_set_double( properties, "source_fps", source_fps ); else - mlt_properties_set_double( properties, "source_fps", mlt_properties_get_double( properties, "fps" ) ); + mlt_properties_set_double( properties, "source_fps", mlt_producer_get_fps( this ) ); mlt_properties_set_double( properties, "aspect_ratio", aspect_ratio ); // Set the width and height @@ -1049,7 +1090,7 @@ static void producer_set_up_audio( mlt_producer this, mlt_frame frame ) static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int index ) { // Create an empty frame - *frame = mlt_frame_init( ); + *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( this ) ); // Update timecode on the frame we're creating mlt_frame_set_position( *frame, mlt_producer_position( this ) );