producer_avformat.c: fix to previous commit to still allow compilation on version...
[melted] / src / modules / avformat / producer_avformat.c
index e182229..1dfb5a9 100644 (file)
 // ffmpeg Header files
 #include <avformat.h>
 #ifdef SWSCALE
-#include <swscale.h>
+#  include <swscale.h>
+#endif
+#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0))
+#  include "audioconvert.h"
 #endif
 
 // System header files
@@ -551,6 +554,45 @@ static inline void convert_image( AVFrame *frame, uint8_t *buffer, int pix_fmt,
 #endif
 }
 
+/** Allocate the image buffer and set it on the frame.
+*/
+
+static int allocate_buffer( mlt_properties frame_properties, AVCodecContext *codec_context, uint8_t **buffer, mlt_image_format *format, int *width, int *height )
+{
+       int size = 0;
+
+       if ( codec_context->width == 0 || codec_context->height == 0 )
+               return size;
+
+       *width = codec_context->width;
+       *height = codec_context->height;
+       mlt_properties_set_int( frame_properties, "width", *width );
+       mlt_properties_set_int( frame_properties, "height", *height );
+
+       switch ( *format )
+       {
+               case mlt_image_yuv420p:
+                       size = *width * 3 * ( *height + 1 ) / 2;
+                       break;
+               case mlt_image_rgb24:
+                       size = *width * ( *height + 1 ) * 3;
+                       break;
+               default:
+                       *format = mlt_image_yuv422;
+                       size = *width * ( *height + 1 ) * 2;
+                       break;
+       }
+
+       // Construct the output image
+       *buffer = mlt_pool_alloc( size );
+       if ( *buffer )
+               mlt_properties_set_data( frame_properties, "image", *buffer, size, (mlt_destructor)mlt_pool_release, NULL );
+       else
+               size = 0;
+
+       return size;
+}
+
 /** Get an image from a frame.
 */
 
@@ -605,40 +647,12 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
        // Get the seekable status
        int seekable = mlt_properties_get_int( properties, "seekable" );
 
-       // Generate the size in bytes
-       int size = 0; 
-
        // Hopefully provide better support for streams...
        int av_bypass = mlt_properties_get_int( properties, "av_bypass" );
 
        // Determines if we have to decode all frames in a sequence
        int must_decode = 1;
 
-       // Set the result arguments that we know here (only *buffer is now required)
-       *width = codec_context->width;
-       *height = codec_context->height;
-
-       switch ( *format )
-       {
-               case mlt_image_yuv420p:
-                       size = *width * 3 * ( *height + 1 ) / 2;
-                       break;
-               case mlt_image_rgb24:
-                       size = *width * ( *height + 1 ) * 3;
-                       break;
-               default:
-                       *format = mlt_image_yuv422;
-                       size = *width * ( *height + 1 ) * 2;
-                       break;
-       }
-
-       // Set this on the frame properties
-       mlt_properties_set_int( frame_properties, "width", *width );
-       mlt_properties_set_int( frame_properties, "height", *height );
-
-       // Construct the output image
-       *buffer = mlt_pool_alloc( size );
-
        // Temporary hack to improve intra frame only
        must_decode = strcmp( codec_context->codec->name, "mjpeg" ) &&
                                  strcmp( codec_context->codec->name, "rawvideo" ) &&
@@ -685,10 +699,10 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
        if ( av_frame != NULL && got_picture && ( paused || current_position >= req_position ) && av_bypass == 0 )
        {
                // Duplicate it
-               convert_image( av_frame, *buffer, codec_context->pix_fmt, *format, *width, *height );
-
-               // Set this on the frame properties
-               mlt_properties_set_data( frame_properties, "image", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL );
+               if ( allocate_buffer( frame_properties, codec_context, buffer, format, width, height ) )
+                       convert_image( av_frame, *buffer, codec_context->pix_fmt, *format, *width, *height );
+               else
+                       mlt_frame_get_image( frame, buffer, format, width, height, writable );
        }
        else
        {
@@ -753,12 +767,18 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
                        // 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( 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 );
+                               if ( allocate_buffer( frame_properties, codec_context, buffer, format, width, height ) )
+                               {
+                                       convert_image( av_frame, *buffer, codec_context->pix_fmt, *format, *width, *height );
+                                       mlt_properties_set_int( frame_properties, "progressive", !av_frame->interlaced_frame );
+                                       mlt_properties_set_int( properties, "top_field_first", av_frame->top_field_first );
+                                       mlt_properties_set_int( properties, "_current_position", int_position );
+                                       mlt_properties_set_int( properties, "_got_picture", 1 );
+                               }
+                               else
+                               {
+                                       got_picture = 0;
+                               }
                        }
                }
                if ( !got_picture )
@@ -873,12 +893,13 @@ static void producer_set_up_video( mlt_producer this, mlt_frame frame )
                        {
                                // Remember that we can't use this later
                                mlt_properties_set_int( properties, "video_index", -1 );
+                               index = -1;
                        }
                        avformat_unlock( );
                }
 
                // No codec, no show...
-               if ( codec != NULL )
+               if ( codec && index > -1 )
                {
                        double source_fps = 0;
                        double force_aspect_ratio = mlt_properties_get_double( properties, "force_aspect_ratio" );
@@ -946,8 +967,15 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form
        // Obtain the resample context if it exists (not always needed)
        ReSampleContext *resample = mlt_properties_get_data( properties, "audio_resample", NULL );
 
-       // Obtain the audio buffer
+#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0))
+       // Get the format converter context if it exists
+       AVAudioConvert *convert = mlt_properties_get_data( properties, "audio_convert", NULL );
+#endif
+
+       // Obtain the audio buffers
        int16_t *audio_buffer = mlt_properties_get_data( properties, "audio_buffer", NULL );
+       int16_t *decode_buffer = mlt_properties_get_data( properties, "decode_buffer", NULL );
+       int16_t *convert_buffer = mlt_properties_get_data( properties, "convert_buffer", NULL );
 
        // Get amount of audio used
        int audio_used =  mlt_properties_get_int( properties, "_audio_used" );
@@ -971,7 +999,7 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form
        int paused = 0;
 
        // Check for resample and create if necessary
-       if ( resample == NULL && codec_context->channels <= 2 )
+       if ( resample == NULL && ( *frequency != codec_context->sample_rate || codec_context->channels <= 2 ) )
        {
                // Create the resampler
                resample = audio_resample_init( *channels, codec_context->channels, *frequency, codec_context->sample_rate );
@@ -985,6 +1013,17 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form
                *frequency = codec_context->sample_rate;
        }
 
+#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0))
+       // Check for audio format converter and create if necessary
+       // TODO: support higher resolutions than 16-bit.
+       if ( convert == NULL && codec_context->sample_fmt != SAMPLE_FMT_S16 )
+       {
+               // Create single channel converter for interleaved with no mixing matrix
+               convert = av_audio_convert_alloc( SAMPLE_FMT_S16, 1, codec_context->sample_fmt, 1, NULL, 0 );
+               mlt_properties_set_data( properties, "audio_convert", convert, 0, ( mlt_destructor )av_audio_convert_free, NULL );
+       }
+#endif
+
        // Check for audio buffer and create if necessary
        if ( audio_buffer == NULL )
        {
@@ -995,6 +1034,28 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form
                mlt_properties_set_data( properties, "audio_buffer", audio_buffer, 0, ( mlt_destructor )mlt_pool_release, NULL );
        }
 
+       // Check for decoder buffer and create if necessary
+       if ( decode_buffer == NULL )
+       {
+               // Allocate the audio buffer
+               decode_buffer = mlt_pool_alloc( AVCODEC_MAX_AUDIO_FRAME_SIZE * sizeof( int16_t ) );
+
+               // And store it on properties for reuse
+               mlt_properties_set_data( properties, "decode_buffer", decode_buffer, 0, ( mlt_destructor )mlt_pool_release, NULL );
+       }
+
+#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0))
+       // Check for format converter buffer and create if necessary
+       if ( resample && convert && convert_buffer == NULL )
+       {
+               // Allocate the audio buffer
+               convert_buffer = mlt_pool_alloc( AVCODEC_MAX_AUDIO_FRAME_SIZE * sizeof( int16_t ) );
+
+               // And store it on properties for reuse
+               mlt_properties_set_data( properties, "convert_buffer", convert_buffer, 0, ( mlt_destructor )mlt_pool_release, NULL );
+       }
+#endif
+
        // Seek if necessary
        if ( position != expected )
        {
@@ -1024,7 +1085,6 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form
        {
                int ret = 0;
                int got_audio = 0;
-               int16_t *temp = av_malloc( sizeof( int16_t ) * AVCODEC_MAX_AUDIO_FRAME_SIZE );
 
                av_init_packet( &pkt );
 
@@ -1050,9 +1110,9 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form
 
                                // Decode the audio
 #if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(29<<8)+0))
-                               ret = avcodec_decode_audio2( codec_context, temp, &data_size, ptr, len );
+                               ret = avcodec_decode_audio2( codec_context, decode_buffer, &data_size, ptr, len );
 #else
-                               ret = avcodec_decode_audio( codec_context, temp, &data_size, ptr, len );
+                               ret = avcodec_decode_audio( codec_context, decode_buffer, &data_size, ptr, len );
 #endif
                                if ( ret < 0 )
                                {
@@ -1065,14 +1125,41 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form
 
                                if ( data_size > 0 )
                                {
-                                       if ( resample != NULL )
+                                       int src_stride[6]= { av_get_bits_per_sample_format( codec_context->sample_fmt ) / 8 };
+                                       int dst_stride[6]= { av_get_bits_per_sample_format( SAMPLE_FMT_S16 ) / 8 };
+
+                                       if ( resample )
                                        {
-                                               audio_used += audio_resample( resample, &audio_buffer[ audio_used * *channels ], temp, data_size / ( codec_context->channels * sizeof( int16_t ) ) );
+                                               int16_t *source = decode_buffer;
+                                               int16_t *dest = &audio_buffer[ audio_used * *channels ];
+                                               int convert_samples = data_size / src_stride[0];
+
+#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0))
+                                               if ( convert )
+                                               {
+                                                       const void *src_buf[6] = { decode_buffer };
+                                                       void *dst_buf[6] = { convert_buffer };
+                                                       av_audio_convert( convert, dst_buf, dst_stride, src_buf, src_stride, convert_samples );
+                                                       source = convert_buffer;
+                                               }
+#endif
+                                               audio_used += audio_resample( resample, dest, source, convert_samples / codec_context->channels );
                                        }
                                        else
                                        {
-                                               memcpy( &audio_buffer[ audio_used * *channels ], temp, data_size );
-                                               audio_used += data_size / ( codec_context->channels * sizeof( int16_t ) );
+#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0))
+                                               if ( convert )
+                                               {
+                                                       const void *src_buf[6] = { decode_buffer };
+                                                       void *dst_buf[6] = { &audio_buffer[ audio_used * *channels ] };
+                                                       av_audio_convert( convert, dst_buf, dst_stride, src_buf, src_stride, data_size / src_stride[0] );
+                                               }
+                                               else
+#endif
+                                               {
+                                                       memcpy( &audio_buffer[ audio_used * *channels ], decode_buffer, data_size );
+                                               }
+                                               audio_used += data_size / *channels / src_stride[0];
                                        }
 
                                        // Handle ignore
@@ -1114,9 +1201,6 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_form
                
                // Store the number of audio samples still available
                mlt_properties_set_int( properties, "_audio_used", audio_used );
-
-               // Release the temporary audio
-               av_free( temp );
        }
        else
        {
@@ -1169,7 +1253,8 @@ static void producer_set_up_audio( mlt_producer this, mlt_frame frame )
        }
 
        // Update the audio properties if the index changed
-       if ( index > -1 && index != mlt_properties_get_int( properties, "_audio_index" ) ) {
+       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 );
        }
@@ -1207,12 +1292,13 @@ static void producer_set_up_audio( mlt_producer this, mlt_frame frame )
                        {
                                // Remember that we can't use this later
                                mlt_properties_set_int( properties, "audio_index", -1 );
+                               index = -1;
                        }
                        avformat_unlock( );
                }
 
                // No codec, no show...
-               if ( codec != NULL )
+               if ( codec && index > -1 )
                {
                        mlt_frame_push_audio( frame, producer_get_audio );
                        mlt_properties_set_data( frame_properties, "avformat_producer", this, 0, NULL, NULL );