filter_dust.yml: apply description fix patch from Mads Dydensborg.
[melted] / src / modules / avformat / producer_avformat.c
index 8d4c591..e182229 100644 (file)
@@ -74,11 +74,17 @@ mlt_producer producer_avformat_init( mlt_profile profile, char *file )
                                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 );
+                       else
+                       {
+                               // 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 );
+
+                               // Default the user-selectable indices from the auto-detected indices
+                               mlt_properties_set_int( properties, "audio_index",  mlt_properties_get_int( properties, "_audio_index" ) );
+                               mlt_properties_set_int( properties, "video_index",  mlt_properties_get_int( properties, "_video_index" ) );
+                       }
                }
        }
 
@@ -154,6 +160,88 @@ static void producer_codec_close( void *codec )
        }
 }
 
+static inline int dv_is_pal( AVPacket *pkt )
+{
+       return pkt->data[3] & 0x80;
+}
+
+static int dv_is_wide( AVPacket *pkt )
+{
+       int i = 80 /* block size */ *3 /* VAUX starts at block 3 */ +3 /* skip block header */;
+
+       for ( ; i < pkt->size; i += 5 /* packet size */ )
+       {
+               if ( pkt->data[ i ] == 0x61 )
+               {
+                       uint8_t x = pkt->data[ i + 2 ] & 0x7;
+                       return ( x == 2 ) || ( x == 7 );
+               }
+       }
+       return 0;
+}
+
+static double get_aspect_ratio( AVStream *stream, AVCodecContext *codec_context, AVPacket *pkt )
+{
+       double aspect_ratio = 1.0;
+
+       if ( codec_context->codec_id == CODEC_ID_DVVIDEO )
+       {
+               if ( pkt )
+               {
+                       if ( dv_is_pal( pkt ) )
+                       {
+                               aspect_ratio = dv_is_wide( pkt )
+                                       ? 64.0/45.0 // 16:9 PAL
+                                       : 16.0/15.0; // 4:3 PAL
+                       }
+                       else
+                       {
+                               aspect_ratio = dv_is_wide( pkt )
+                                       ? 32.0/27.0 // 16:9 NTSC
+                                       : 8.0/9.0; // 4:3 NTSC
+                       }
+               }
+               else
+               {
+                       AVRational ar =
+#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(21<<8)+0)
+                               stream->sample_aspect_ratio;
+#else
+                               codec_context->sample_aspect_ratio;
+#endif
+                       // 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 ( ar.num == 10 && ar.den == 11 )
+                               aspect_ratio = 8.0/9.0; // 4:3 NTSC
+                       else if ( ar.num == 59 && ar.den == 54 )
+                               aspect_ratio = 16.0/15.0; // 4:3 PAL
+                       else if ( ar.num == 40 && ar.den == 33 )
+                               aspect_ratio = 32.0/27.0; // 16:9 NTSC
+                       else if ( ar.num == 118 && ar.den == 81 )
+                               aspect_ratio = 64.0/45.0; // 16:9 PAL
+               }
+       }
+       else
+       {
+               AVRational codec_sar = codec_context->sample_aspect_ratio;
+               AVRational stream_sar =
+#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(21<<8)+0)
+                       stream->sample_aspect_ratio;
+#else
+                       { 0, 1 };
+#endif
+               if ( codec_sar.num > 0 )
+                       aspect_ratio = av_q2d( codec_sar );
+               else if ( stream_sar.num > 0 )
+                       aspect_ratio = av_q2d( stream_sar );
+       }
+       return aspect_ratio;
+}
+
 /** Open the file.
 */
 
@@ -290,7 +378,7 @@ static int producer_open( mlt_producer this, mlt_profile profile, char *file )
                                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 ) )
+                       if ( strcmp( file, "pipe:" ) && strncmp( file, "http://", 6 )  && strncmp( file, "udp:", 4 )  && strncmp( file, "tcp:", 4 ) && strncmp( file, "rtsp:", 5 )  && strncmp( file, "rtp:", 4 ) )
                        {
                                mlt_properties_set_int( properties, "seekable", av_seek_frame( context, -1, mlt_properties_get_double( properties, "_start_time" ), AVSEEK_FLAG_BACKWARD ) >= 0 );
                                mlt_properties_set_data( properties, "dummy_context", context, 0, producer_file_close, NULL );
@@ -301,8 +389,8 @@ static int producer_open( mlt_producer this, mlt_profile profile, char *file )
                                av_bypass = 1;
 
                        // Store selected audio and video indexes on properties
-                       mlt_properties_set_int( properties, "audio_index", audio_index );
-                       mlt_properties_set_int( properties, "video_index", video_index );
+                       mlt_properties_set_int( properties, "_audio_index", audio_index );
+                       mlt_properties_set_int( properties, "_video_index", video_index );
                        mlt_properties_set_int( properties, "_last_position", -1 );
 
                        // Fetch the width, height and aspect ratio
@@ -311,7 +399,28 @@ static int producer_open( mlt_producer this, mlt_profile profile, char *file )
                                AVCodecContext *codec_context = context->streams[ video_index ]->codec;
                                mlt_properties_set_int( properties, "width", codec_context->width );
                                mlt_properties_set_int( properties, "height", codec_context->height );
-                               mlt_properties_set_double( properties, "aspect_ratio", av_q2d( codec_context->sample_aspect_ratio ) );
+
+                               if ( codec_context->codec_id == CODEC_ID_DVVIDEO )
+                               {
+                                       // Fetch the first frame of DV so we can read it directly
+                                       AVPacket pkt;
+                                       int ret = 0;
+                                       while ( ret >= 0 )
+                                       {
+                                               ret = av_read_frame( context, &pkt );
+                                               if ( ret >= 0 && pkt.stream_index == video_index && pkt.size > 0 )
+                                               {
+                                                       mlt_properties_set_double( properties, "aspect_ratio",
+                                                               get_aspect_ratio( context->streams[ video_index ], codec_context, &pkt ) );
+                                                       break;
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       mlt_properties_set_double( properties, "aspect_ratio",
+                                               get_aspect_ratio( context->streams[ video_index ], codec_context, NULL ) );
+                               }
                        }
 
                        // Read Metadata
@@ -331,7 +440,7 @@ static int producer_open( mlt_producer this, mlt_profile profile, char *file )
                                mlt_properties_set_int(properties, "meta.attr.track.markup", context->track );
                        
                        // We're going to cheat here - for a/v files, we will have two contexts (reasoning will be clear later)
-                       if ( av == 0 && !av_bypass && audio_index != -1 && video_index != -1 )
+                       if ( av == 0 && audio_index != -1 && video_index != -1 )
                        {
                                // We'll use the open one as our video_context
                                mlt_properties_set_data( properties, "video_context", context, 0, producer_file_close, NULL );
@@ -685,21 +794,34 @@ static void producer_set_up_video( mlt_producer this, mlt_frame frame )
        int index = mlt_properties_get_int( properties, "video_index" );
 
        // Reopen the file if necessary
-       if ( !context && index != -1 )
+       if ( !context && index > -1 )
        {
                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 );
-               index = mlt_properties_get_int( properties, "video_index" );
                mlt_properties_set_data( properties, "dummy_context", NULL, 0, NULL, NULL );
                mlt_events_unblock( properties, this );
        }
 
+       // Exception handling for video_index
+       if ( context && index >= (int) context->nb_streams )
+       {
+               // Get the last video stream
+               for ( index = context->nb_streams - 1; index >= 0 && context->streams[ index ]->codec->codec_type != CODEC_TYPE_VIDEO; --index );
+               mlt_properties_set_int( properties, "video_index", index );
+       }
+       if ( context && index > -1 && context->streams[ index ]->codec->codec_type != CODEC_TYPE_VIDEO )
+       {
+               // Invalidate the video stream
+               index = -1;
+               mlt_properties_set_int( properties, "video_index", index );
+       }
+
        // Get the frame properties
        mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );
 
-       if ( context != NULL && index != -1 )
+       if ( context && index > -1 )
        {
                // Get the video stream
                AVStream *stream = context->streams[ index ];
@@ -710,6 +832,20 @@ static void producer_set_up_video( mlt_producer this, mlt_frame frame )
                // Get the codec
                AVCodec *codec = mlt_properties_get_data( properties, "video_codec", NULL );
 
+               // Update the video properties if the index changed
+               if ( index != mlt_properties_get_int( properties, "_video_index" ) )
+               {
+                       // Reset the video properties if the index changed
+                       mlt_properties_set_int( properties, "_video_index", index );
+                       mlt_properties_set_data( properties, "video_codec", NULL, 0, NULL, NULL );
+                       mlt_properties_set_int( properties, "width", codec_context->width );
+                       mlt_properties_set_int( properties, "height", codec_context->height );
+                       // TODO: get the first usable AVPacket and reset the stream position
+                       mlt_properties_set_double( properties, "aspect_ratio",
+                               get_aspect_ratio( context->streams[ index ], codec_context, NULL ) );
+                       codec = NULL;
+               }
+       
                // Initialise the codec if necessary
                if ( codec == NULL )
                {
@@ -745,47 +881,9 @@ static void producer_set_up_video( mlt_producer this, mlt_frame frame )
                if ( codec != NULL )
                {
                        double source_fps = 0;
-                       int norm_aspect_ratio = mlt_properties_get_int( properties, "norm_aspect_ratio" );
                        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
-                       if ( force_aspect_ratio > 0.0 )
-                       {
-                               aspect_ratio = force_aspect_ratio;
-                       }
-                       else if ( !norm_aspect_ratio && codec_context->sample_aspect_ratio.num > 0 )
-                       {
-                               aspect_ratio = av_q2d( codec_context->sample_aspect_ratio );
-                       }
-                       else
-                       {
-                               aspect_ratio = 1.0;
-                       }
+                       double aspect_ratio = ( force_aspect_ratio > 0.0 ) ?
+                               force_aspect_ratio : mlt_properties_get_double( properties, "aspect_ratio" );
 
                        // Determine the fps
                        source_fps = ( double )codec_context->time_base.den / ( codec_context->time_base.num == 0 ? 1 : codec_context->time_base.num );
@@ -987,9 +1085,12 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form
                                }
 
                                // If we're behind, ignore this packet
-                               float current_pts = av_q2d( stream->time_base ) * pkt.pts;
-                               if ( seekable && ( !ignore && current_pts <= ( real_timecode - 0.02 ) ) )
-                                       ignore = 1;
+                               if ( pkt.pts >= 0 )
+                               {
+                                       float current_pts = av_q2d( stream->time_base ) * pkt.pts;
+                                       if ( seekable && ( !ignore && current_pts <= ( real_timecode - 0.02 ) ) )
+                                               ignore = 1;
+                               }
                        }
 
                        // We're finished with this packet regardless
@@ -1045,19 +1146,36 @@ static void producer_set_up_audio( mlt_producer this, mlt_frame frame )
        int index = mlt_properties_get_int( properties, "audio_index" );
 
        // Reopen the file if necessary
-       if ( !context && index != -1 )
+       if ( !context && index > -1 )
        {
                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, "audio_context", NULL );
-               index = mlt_properties_get_int( properties, "audio_index" );
                mlt_properties_set_data( properties, "dummy_context", NULL, 0, NULL, NULL );
                mlt_events_unblock( properties, this );
        }
 
+       // Exception handling for audio_index
+       if ( context && index >= (int) context->nb_streams )
+       {
+               for ( index = context->nb_streams - 1; index >= 0 && context->streams[ index ]->codec->codec_type != CODEC_TYPE_AUDIO; --index );
+               mlt_properties_set_int( properties, "audio_index", index );
+       }
+       if ( context && index > -1 && context->streams[ index ]->codec->codec_type != CODEC_TYPE_AUDIO )
+       {
+               index = -1;
+               mlt_properties_set_int( properties, "audio_index", index );
+       }
+
+       // Update the audio properties if the index changed
+       if ( index > -1 && index != mlt_properties_get_int( properties, "_audio_index" ) ) {
+               mlt_properties_set_int( properties, "_audio_index", index );
+               mlt_properties_set_data( properties, "audio_codec", NULL, 0, NULL, NULL );
+       }
+
        // Deal with audio context
-       if ( context != NULL && index != -1 )
+       if ( context != NULL && index > -1 )
        {
                // Get the frame properties
                mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );