]> git.sesse.net Git - mlt/blobdiff - src/modules/avformat/producer_avformat.c
Use int64_t for req_position and int_position.
[mlt] / src / modules / avformat / producer_avformat.c
index b3ecf7b95391e7cfee5d89ceb287e8ba8b5c8ee6..b96bf10d56e58e5aa037ef138e1b855e7ab90e46 100644 (file)
@@ -91,9 +91,10 @@ struct producer_avformat_s
        int video_index;
        double start_time;
        int first_pts;
-       int last_position;
+       int64_t last_position;
        int seekable;
-       int current_position;
+       int64_t current_position;
+       mlt_position nonseek_position;
        int got_picture;
        int top_field_first;
        uint8_t *audio_buffer[ MAX_AUDIO_STREAMS ];
@@ -571,7 +572,8 @@ static char* parse_url( mlt_profile profile, const char* URL, AVInputFormat **fo
                        // These are required by video4linux2 (defaults)
                        params->width = profile->width;
                        params->height = profile->height;
-                       params->time_base= (AVRational){ profile->frame_rate_den, profile->frame_rate_num };
+                       if ( !strstr( URL, "&frame_rate" ) )
+                               params->time_base = (AVRational){ profile->frame_rate_den, profile->frame_rate_num };
                        params->channels = 2;
                        params->sample_rate = 48000;
 
@@ -615,8 +617,9 @@ static char* parse_url( mlt_profile profile, const char* URL, AVInputFormat **fo
                        }
                }
        }
+       result = strdup( result );
        free( protocol );
-       return strdup( result );
+       return result;
 }
 
 static int get_basic_info( producer_avformat self, mlt_profile profile, const char *filename )
@@ -768,13 +771,13 @@ static int producer_open( producer_avformat self, mlt_profile profile, const cha
                free( (void*) params.standard );
 
        // If successful, then try to get additional info
-       if ( !error )
+       if ( !error && self->video_format )
        {
                // Get the stream info
                error = av_find_stream_info( self->video_format ) < 0;
 
                // Continue if no error
-               if ( !error )
+               if ( !error && self->video_format )
                {
                        // Find default audio and video streams
                        find_default_streams( self );
@@ -884,7 +887,7 @@ static void reopen_video( producer_avformat self, mlt_producer producer )
 }
 
 static int seek_video( producer_avformat self, mlt_position position,
-       int req_position, int must_decode, int use_new_seek, int *ignore )
+       int64_t req_position, int must_decode, int use_new_seek, int *ignore )
 {
        mlt_producer producer = self->parent;
        int paused = 0;
@@ -947,7 +950,7 @@ static int seek_video( producer_avformat self, mlt_position position,
                        {
                                timestamp = ( req_position - 0.1 / source_fps ) /
                                        ( av_q2d( stream->time_base ) * source_fps );
-                               mlt_log_verbose( MLT_PRODUCER_SERVICE(producer), "pos %d pts %"PRId64" ", req_position, timestamp );
+                               mlt_log_verbose( MLT_PRODUCER_SERVICE(producer), "pos %"PRId64" pts %"PRId64" ", req_position, timestamp );
                                if ( self->first_pts > 0 )
                                        timestamp += self->first_pts;
                                else if ( context->start_time != AV_NOPTS_VALUE )
@@ -963,7 +966,7 @@ static int seek_video( producer_avformat self, mlt_position position,
                                timestamp -= AV_TIME_BASE;
                        if ( timestamp < 0 )
                                timestamp = 0;
-                       mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "seeking timestamp %"PRId64" position %d expected %d last_pos %d\n",
+                       mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "seeking timestamp %"PRId64" position %d expected %d last_pos %"PRId64"\n",
                                timestamp, position, self->video_expected, self->last_position );
 
                        // Seek to the timestamp
@@ -1301,7 +1304,7 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
                mlt_properties_get_double( properties, "meta.media.frame_rate_den" );
 
        // This is the physical frame position in the source
-       int req_position = ( int )( position / mlt_producer_get_fps( producer ) * source_fps + 0.5 );
+       int64_t req_position = ( int64_t )( position / mlt_producer_get_fps( producer ) * source_fps + 0.5 );
 
        // Determines if we have to decode all frames in a sequence
        // Temporary hack to improve intra frame only
@@ -1326,7 +1329,7 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
        codec_context = stream->codec;
 
        // Duplicate the last image if necessary
-       if ( self->av_frame && self->av_frame->linesize[0] && self->got_picture && self->seekable
+       if ( self->av_frame && self->av_frame->linesize[0] && self->got_picture
                 && ( paused
                          || self->current_position == req_position
                          || ( !use_new_seek && self->current_position > req_position ) ) )
@@ -1361,7 +1364,7 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
        else
        {
                int ret = 0;
-               int int_position = 0;
+               int64_t int_position = 0;
                int decode_errors = 0;
                int got_picture = 0;
 
@@ -1407,7 +1410,7 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
                                                pts -= self->first_pts;
                                        else if ( context->start_time != AV_NOPTS_VALUE )
                                                pts -= context->start_time;
-                                       int_position = ( int )( av_q2d( stream->time_base ) * pts * source_fps + 0.1 );
+                                       int_position = ( int64_t )( av_q2d( stream->time_base ) * pts * source_fps + 0.1 );
                                        if ( pkt.pts == AV_NOPTS_VALUE )
                                        {
                                                self->invalid_pts_counter++;
@@ -1423,24 +1426,21 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
                                        {
                                                self->invalid_pts_counter = 0;
                                        }
-                                       mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "pkt.pts %"PRId64" req_pos %d cur_pos %d pkt_pos %d\n",
+                                       mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "pkt.pts %"PRId64" req_pos %"PRId64" cur_pos %"PRId64" pkt_pos %"PRId64"\n",
                                                pkt.pts, req_position, self->current_position, int_position );
                                }
                                else
                                {
-                                       if ( self->seekable && pkt.dts != AV_NOPTS_VALUE )
+                                       if ( pkt.dts != AV_NOPTS_VALUE )
                                        {
-                                               int_position = ( int )( av_q2d( stream->time_base ) * pkt.dts * source_fps + 0.5 );
+                                               double delay = mlt_properties_get_double( properties, "video_delay" );
+                                               int_position = ( int64_t )( ( av_q2d( stream->time_base ) * pkt.dts + delay ) * source_fps + 0.5 );
                                                if ( context->start_time != AV_NOPTS_VALUE )
-                                                       int_position -= ( int )( context->start_time * source_fps / AV_TIME_BASE + 0.5 );
+                                                       int_position -= ( int64_t )( context->start_time * source_fps / AV_TIME_BASE + 0.5 );
                                                if ( int_position == self->last_position )
                                                        int_position = self->last_position + 1;
                                        }
-                                       else
-                                       {
-                                               int_position = req_position;
-                                       }
-                                       mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "pkt.dts %"PRId64" req_pos %d cur_pos %d pkt_pos %d\n",
+                                       mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "pkt.dts %"PRId64" req_pos %"PRId64" cur_pos %"PRId64" pkt_pos %"PRId64"\n",
                                                pkt.dts, req_position, self->current_position, int_position );
                                        // Make a dumb assumption on streams that contain wild timestamps
                                        if ( abs( req_position - int_position ) > 999 )
@@ -1496,8 +1496,8 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
                                                        pts -= self->first_pts;
                                                else if ( context->start_time != AV_NOPTS_VALUE )
                                                        pts -= context->start_time;
-                                               int_position = ( int )( av_q2d( stream->time_base) * pts * source_fps + 0.1 );
-                                               mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "got frame %d, key %d\n", int_position, self->av_frame->key_frame );
+                                               int_position = ( int64_t )( av_q2d( stream->time_base) * pts * source_fps + 0.1 );
+                                               mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "got frame %"PRId64", key %d\n", int_position, self->av_frame->key_frame );
                                        }
                                        // Handle ignore
                                        if ( int_position < req_position )
@@ -2061,17 +2061,21 @@ static int decode_audio( producer_avformat self, int *ignore, AVPacket pkt, int
        if ( pkt.pts >= 0 )
        {
                double current_pts = av_q2d( context->streams[ index ]->time_base ) * pkt.pts;
-               int req_position = ( int )( timecode * fps + 0.5 );
-               int int_position = ( int )( current_pts * fps + 0.5 );
+               int64_t req_position = ( int64_t )( timecode * fps + 0.5 );
+               int64_t int_position = ( int64_t )( current_pts * fps + 0.5 );
                if ( context->start_time != AV_NOPTS_VALUE )
-                       int_position -= ( int )( fps * context->start_time / AV_TIME_BASE + 0.5 );
+                       int_position -= ( int64_t )( fps * context->start_time / AV_TIME_BASE + 0.5 );
 
-               if ( self->seekable && *ignore == 0 )
+               if ( *ignore == 0 )
                {
                        if ( int_position < req_position )
                                // We are behind, so skip some
                                *ignore = 1;
-                       else if ( int_position > req_position + 2 )
+
+                       // We use nb_streams in this test because the tolerance is dependent
+                       // on the interleaving of all streams esp. when there is more than
+                       // one audio stream.
+                       else if ( int_position > req_position + context->nb_streams )
                                // We are ahead, so seek backwards some more
                                seek_audio( self, req_position, timecode - 1.0, ignore );
                }
@@ -2101,10 +2105,15 @@ static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format
        double fps = mlt_producer_get_fps( self->parent );
 
        // Number of frames to ignore (for ffwd)
-       int ignore = 0;
+       int ignore[ MAX_AUDIO_STREAMS ] = { 0 };
 
        // Flag for paused (silence)
-       int paused = seek_audio( self, position, real_timecode, &ignore );
+       int paused = seek_audio( self, position, real_timecode, &ignore[0] );
+
+       // Initialize ignore for all streams from the seek return value
+       int i = MAX_AUDIO_STREAMS;
+       while ( i-- )
+               ignore[i] = ignore[0];
 
        // Fetch the audio_format
        AVFormatContext *context = self->audio_format;
@@ -2185,11 +2194,23 @@ static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format
                while ( ret >= 0 && !got_audio )
                {
                        // Check if the buffer already contains the samples required
-                       if ( self->audio_index != INT_MAX && self->audio_used[ self->audio_index ] >= *samples && ignore == 0 )
+                       if ( self->audio_index != INT_MAX &&
+                                self->audio_used[ self->audio_index ] >= *samples &&
+                                ignore[ self->audio_index ] == 0 )
                        {
                                got_audio = 1;
                                break;
                        }
+                       else if ( self->audio_index == INT_MAX )
+                       {
+                               // Check if there is enough audio for all streams
+                               got_audio = 1;
+                               for ( index = 0; got_audio && index < context->nb_streams; index++ )
+                                       if ( ( self->audio_codec[ index ] && self->audio_used[ index ] < *samples ) || ignore[ index ] )
+                                               got_audio = 0;
+                               if ( got_audio )
+                                       break;
+                       }
 
                        // Read a packet
                        pthread_mutex_lock( &self->packets_mutex );
@@ -2221,22 +2242,12 @@ static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format
                        {
                                int channels2 = ( self->audio_index == INT_MAX || !self->audio_resample[index] ) ?
                                        self->audio_codec[index]->channels : *channels;
-                               ret = decode_audio( self, &ignore, pkt, channels2, *samples, real_timecode, fps );
+                               ret = decode_audio( self, &ignore[index], pkt, channels2, *samples, real_timecode, fps );
                        }
 
                        if ( self->seekable || index != self->video_index )
                                av_free_packet( &pkt );
 
-                       if ( self->audio_index == INT_MAX && ret >= 0 )
-                       {
-                               // Determine if there is enough audio for all streams
-                               got_audio = 1;
-                               for ( index = 0; index < context->nb_streams; index++ )
-                               {
-                                       if ( self->audio_codec[ index ] && self->audio_used[ index ] < *samples )
-                                               got_audio = 0;
-                               }
-                       }
                }
 
                // Set some additional return values
@@ -2505,7 +2516,8 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i
        mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
 
        // Set the position of this producer
-       mlt_properties_set_position( MLT_FRAME_PROPERTIES( *frame ), "avformat_position", mlt_producer_frame( producer ) );
+       mlt_position position = self->seekable ? mlt_producer_frame( producer ) : self->nonseek_position++;
+       mlt_properties_set_position( MLT_FRAME_PROPERTIES( *frame ), "avformat_position", position );
        
        // Set up the video
        producer_set_up_video( self, *frame );