diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index d52c954df5..41935d39d5 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -347,8 +347,6 @@ typedef struct InputStream { AVRational framerate_guessed; - int64_t nb_samples; /* number of samples in the last decoded audio frame before looping */ - AVDictionary *decoder_opts; AVRational framerate; /* framerate forced with -r */ #if FFMPEG_OPT_TOP @@ -391,11 +389,6 @@ typedef struct InputStream { uint64_t decode_errors; } InputStream; -typedef struct LastFrameDuration { - int stream_idx; - int64_t duration; -} LastFrameDuration; - typedef struct InputFile { const AVClass *class; @@ -427,9 +420,9 @@ typedef struct InputFile { int accurate_seek; /* when looping the input file, this queue is used by decoders to report - * the last frame duration back to the demuxer thread */ - AVThreadMessageQueue *audio_duration_queue; - int audio_duration_queue_size; + * the last frame timestamp back to the demuxer thread */ + AVThreadMessageQueue *audio_ts_queue; + int audio_ts_queue_size; } InputFile; enum forced_keyframes_const { diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c index 8795a94c1a..517d6b3ced 100644 --- a/fftools/ffmpeg_dec.c +++ b/fftools/ffmpeg_dec.c @@ -632,7 +632,6 @@ static int packet_decode(InputStream *ist, AVPacket *pkt, AVFrame *frame) if (dec->codec_type == AVMEDIA_TYPE_AUDIO) { ist->samples_decoded += frame->nb_samples; - ist->nb_samples = frame->nb_samples; audio_ts_process(ist, ist->decoder, frame); } else { @@ -724,14 +723,9 @@ static void *decoder_thread(void *arg) /* report last frame duration to the demuxer thread */ if (ist->dec->type == AVMEDIA_TYPE_AUDIO) { - LastFrameDuration dur; - - dur.stream_idx = ist->index; - dur.duration = av_rescale_q(ist->nb_samples, - (AVRational){ 1, ist->dec_ctx->sample_rate}, - ist->st->time_base); - - av_thread_message_queue_send(ifile->audio_duration_queue, &dur, 0); + Timestamp ts = { .ts = d->last_frame_pts + d->last_frame_duration_est, + .tb = d->last_frame_tb }; + av_thread_message_queue_send(ifile->audio_ts_queue, &ts, 0); } avcodec_flush_buffers(ist->dec_ctx); @@ -760,8 +754,8 @@ finish: // make sure the demuxer does not get stuck waiting for audio durations // that will never arrive - if (ifile->audio_duration_queue && ist->dec->type == AVMEDIA_TYPE_AUDIO) - av_thread_message_queue_set_err_recv(ifile->audio_duration_queue, AVERROR_EOF); + if (ifile->audio_ts_queue && ist->dec->type == AVMEDIA_TYPE_AUDIO) + av_thread_message_queue_set_err_recv(ifile->audio_ts_queue, AVERROR_EOF); dec_thread_uninit(&dt); diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c index ec96daf26b..791952f120 100644 --- a/fftools/ffmpeg_demux.c +++ b/fftools/ffmpeg_demux.c @@ -74,9 +74,6 @@ typedef struct DemuxStream { ///< dts of the last packet read for this stream (in AV_TIME_BASE units) int64_t dts; - int64_t min_pts; /* pts with the smallest value in a current stream */ - int64_t max_pts; /* pts with the higher value in a current stream */ - /* number of packets successfully read for this stream */ uint64_t nb_packets; // combined size of all the packets read @@ -99,11 +96,11 @@ typedef struct Demuxer { /* number of times input stream should be looped */ int loop; - /* actual duration of the longest stream in a file at the moment when - * looping happens */ - int64_t duration; - /* time base of the duration */ - AVRational time_base; + /* duration of the looped segment of the input file */ + Timestamp duration; + /* pts with the smallest/largest values ever seen */ + Timestamp min_pts; + Timestamp max_pts; /* number of streams that the user was warned of */ int nb_streams_warn; @@ -156,23 +153,6 @@ static void report_new_stream(Demuxer *d, const AVPacket *pkt) d->nb_streams_warn = pkt->stream_index + 1; } -static void ifile_duration_update(Demuxer *d, DemuxStream *ds, - int64_t last_duration) -{ - /* the total duration of the stream, max_pts - min_pts is - * the duration of the stream without the last frame */ - if (ds->max_pts > ds->min_pts && - ds->max_pts - (uint64_t)ds->min_pts < INT64_MAX - last_duration) - last_duration += ds->max_pts - ds->min_pts; - - if (!d->duration || - av_compare_ts(d->duration, d->time_base, - last_duration, ds->ist.st->time_base) < 0) { - d->duration = last_duration; - d->time_base = ds->ist.st->time_base; - } -} - static int seek_to_start(Demuxer *d) { InputFile *ifile = &d->f; @@ -183,41 +163,28 @@ static int seek_to_start(Demuxer *d) if (ret < 0) return ret; - if (ifile->audio_duration_queue_size) { - /* duration is the length of the last frame in a stream - * when audio stream is present we don't care about - * last video frame length because it's not defined exactly */ - int got_durations = 0; + if (ifile->audio_ts_queue_size) { + int got_ts = 0; - while (got_durations < ifile->audio_duration_queue_size) { - DemuxStream *ds; - LastFrameDuration dur; - ret = av_thread_message_queue_recv(ifile->audio_duration_queue, &dur, 0); + while (got_ts < ifile->audio_ts_queue_size) { + Timestamp ts; + ret = av_thread_message_queue_recv(ifile->audio_ts_queue, &ts, 0); if (ret < 0) return ret; - got_durations++; + got_ts++; - ds = ds_from_ist(ifile->streams[dur.stream_idx]); - ifile_duration_update(d, ds, dur.duration); - } - } else { - for (int i = 0; i < ifile->nb_streams; i++) { - int64_t duration = 0; - InputStream *ist = ifile->streams[i]; - DemuxStream *ds = ds_from_ist(ist); - - if (ist->framerate.num) { - duration = av_rescale_q(1, av_inv_q(ist->framerate), ist->st->time_base); - } else if (ist->st->avg_frame_rate.num) { - duration = av_rescale_q(1, av_inv_q(ist->st->avg_frame_rate), ist->st->time_base); - } else { - duration = 1; - } - - ifile_duration_update(d, ds, duration); + if (d->max_pts.ts == AV_NOPTS_VALUE || + av_compare_ts(d->max_pts.ts, d->max_pts.tb, ts.ts, ts.tb) < 0) + d->max_pts = ts; } } + if (d->max_pts.ts != AV_NOPTS_VALUE) { + int64_t min_pts = d->min_pts.ts == AV_NOPTS_VALUE ? 0 : d->min_pts.ts; + d->duration.ts = d->max_pts.ts - av_rescale_q(min_pts, d->min_pts.tb, d->max_pts.tb); + } + d->duration.tb = d->max_pts.tb; + if (d->loop > 0) d->loop--; @@ -434,11 +401,27 @@ static int ts_fixup(Demuxer *d, AVPacket *pkt) if (pkt->dts != AV_NOPTS_VALUE) pkt->dts *= ds->ts_scale; - duration = av_rescale_q(d->duration, d->time_base, pkt->time_base); + duration = av_rescale_q(d->duration.ts, d->duration.tb, pkt->time_base); if (pkt->pts != AV_NOPTS_VALUE) { + // audio decoders take precedence for estimating total file duration + int64_t pkt_duration = ifile->audio_ts_queue_size ? 0 : pkt->duration; + pkt->pts += duration; - ds->max_pts = FFMAX(pkt->pts, ds->max_pts); - ds->min_pts = FFMIN(pkt->pts, ds->min_pts); + + // update max/min pts that will be used to compute total file duration + // when using -stream_loop + if (d->max_pts.ts == AV_NOPTS_VALUE || + av_compare_ts(d->max_pts.ts, d->max_pts.tb, + pkt->pts + pkt_duration, pkt->time_base) < 0) { + d->max_pts = (Timestamp){ .ts = pkt->pts + pkt_duration, + .tb = pkt->time_base }; + } + if (d->min_pts.ts == AV_NOPTS_VALUE || + av_compare_ts(d->min_pts.ts, d->min_pts.tb, + pkt->pts, pkt->time_base) > 0) { + d->min_pts = (Timestamp){ .ts = pkt->pts, + .tb = pkt->time_base }; + } } if (pkt->dts != AV_NOPTS_VALUE) @@ -669,7 +652,7 @@ static void thread_stop(Demuxer *d) pthread_join(d->thread, NULL); av_thread_message_queue_free(&d->in_thread_queue); - av_thread_message_queue_free(&f->audio_duration_queue); + av_thread_message_queue_free(&f->audio_ts_queue); } static int thread_start(Demuxer *d) @@ -699,11 +682,11 @@ static int thread_start(Demuxer *d) } if (nb_audio_dec) { - ret = av_thread_message_queue_alloc(&f->audio_duration_queue, - nb_audio_dec, sizeof(LastFrameDuration)); + ret = av_thread_message_queue_alloc(&f->audio_ts_queue, + nb_audio_dec, sizeof(Timestamp)); if (ret < 0) goto fail; - f->audio_duration_queue_size = nb_audio_dec; + f->audio_ts_queue_size = nb_audio_dec; } } @@ -1053,13 +1036,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) ist->discard = 1; st->discard = AVDISCARD_ALL; - ist->nb_samples = 0; ds->first_dts = AV_NOPTS_VALUE; ds->next_dts = AV_NOPTS_VALUE; - ds->min_pts = INT64_MAX; - ds->max_pts = INT64_MIN; - ds->ts_scale = 1.0; MATCH_PER_STREAM_OPT(ts_scale, dbl, ds->ts_scale, ic, st); @@ -1591,10 +1570,12 @@ int ifile_open(const OptionsContext *o, const char *filename) f->ts_offset = o->input_ts_offset - (copy_ts ? (start_at_zero && ic->start_time != AV_NOPTS_VALUE ? ic->start_time : 0) : timestamp); f->accurate_seek = o->accurate_seek; d->loop = o->loop; - d->duration = 0; - d->time_base = (AVRational){ 1, 1 }; d->nb_streams_warn = ic->nb_streams; + d->duration = (Timestamp){ .ts = 0, .tb = (AVRational){ 1, 1 } }; + d->min_pts = (Timestamp){ .ts = AV_NOPTS_VALUE, .tb = (AVRational){ 1, 1 } }; + d->max_pts = (Timestamp){ .ts = AV_NOPTS_VALUE, .tb = (AVRational){ 1, 1 } }; + f->format_nots = !!(ic->iformat->flags & AVFMT_NOTIMESTAMPS); f->readrate = o->readrate ? o->readrate : 0.0; diff --git a/fftools/ffmpeg_utils.h b/fftools/ffmpeg_utils.h index 20cde94969..bd225abc38 100644 --- a/fftools/ffmpeg_utils.h +++ b/fftools/ffmpeg_utils.h @@ -23,9 +23,15 @@ #include "libavutil/common.h" #include "libavutil/frame.h" +#include "libavutil/rational.h" #include "libavcodec/packet.h" +typedef struct Timestamp { + int64_t ts; + AVRational tb; +} Timestamp; + /** * Merge two return codes - return one of the error codes if at least one of * them was negative, 0 otherwise. diff --git a/tests/ref/fate/ffmpeg-streamloop-transcode-av b/tests/ref/fate/ffmpeg-streamloop-transcode-av index 6934e39d41..202fc9e53e 100644 --- a/tests/ref/fate/ffmpeg-streamloop-transcode-av +++ b/tests/ref/fate/ffmpeg-streamloop-transcode-av @@ -44,108 +44,108 @@ 1, 22488, 22488, 1024, 8192, 0x00000000 1, 23496, 23496, 1024, 8192, 0x00000000 0, 12, 12, 1, 1378560, 0x9c598000 -1, 25488, 25488, 1024, 8192, 0x00000000 +1, 25536, 25536, 1024, 8192, 0x00000000 0, 13, 13, 1, 1378560, 0xbaf121ba -1, 26512, 26512, 1024, 8192, 0x00000000 -1, 27528, 27528, 1024, 8192, 0x00000000 +1, 26560, 26560, 1024, 8192, 0x00000000 +1, 27576, 27576, 1024, 8192, 0x00000000 0, 14, 14, 1, 1378560, 0xbaf121ba -1, 28552, 28552, 1024, 8192, 0x00000000 -1, 29576, 29576, 1024, 8192, 0x00000000 +1, 28600, 28600, 1024, 8192, 0x00000000 +1, 29624, 29624, 1024, 8192, 0x00000000 0, 15, 15, 1, 1378560, 0x6579d31a -1, 30600, 30600, 1024, 8192, 0x00000000 -1, 31608, 31608, 1024, 8192, 0x00000000 +1, 30648, 30648, 1024, 8192, 0x00000000 +1, 31656, 31656, 1024, 8192, 0x00000000 0, 16, 16, 1, 1378560, 0xca1deba8 -1, 32688, 32688, 1024, 8192, 0x00000000 -1, 33712, 33712, 1024, 8192, 0x00000000 +1, 32736, 32736, 1024, 8192, 0x00000000 +1, 33760, 33760, 1024, 8192, 0x00000000 0, 17, 17, 1, 1378560, 0xd4eed467 -1, 34728, 34728, 1024, 8192, 0x00000000 -1, 35736, 35736, 1024, 8192, 0x00000000 +1, 34776, 34776, 1024, 8192, 0x00000000 +1, 35784, 35784, 1024, 8192, 0x00000000 0, 18, 18, 1, 1378560, 0xd6e1d5b7 -1, 36760, 36760, 1024, 8192, 0x00000000 -1, 37784, 37784, 1024, 8192, 0x00000000 +1, 36808, 36808, 1024, 8192, 0x00000000 +1, 37832, 37832, 1024, 8192, 0x00000000 0, 19, 19, 1, 1378560, 0x0b574d39 -1, 38808, 38808, 1024, 8192, 0x00000000 -1, 39816, 39816, 1024, 8192, 0x00000000 +1, 38856, 38856, 1024, 8192, 0x00000000 +1, 39864, 39864, 1024, 8192, 0x00000000 0, 20, 20, 1, 1378560, 0x1bdd4d61 -1, 40840, 40840, 1024, 8192, 0x00000000 -1, 41864, 41864, 1024, 8192, 0x00000000 +1, 40888, 40888, 1024, 8192, 0x00000000 +1, 41912, 41912, 1024, 8192, 0x00000000 0, 21, 21, 1, 1378560, 0x3b28f549 -1, 42888, 42888, 1024, 8192, 0x00000000 -1, 43896, 43896, 1024, 8192, 0x00000000 +1, 42936, 42936, 1024, 8192, 0x00000000 +1, 43944, 43944, 1024, 8192, 0x00000000 0, 22, 22, 1, 1378560, 0x45b2f57b -1, 44920, 44920, 1024, 8192, 0x00000000 -1, 45944, 45944, 1024, 8192, 0x00000000 +1, 44968, 44968, 1024, 8192, 0x00000000 +1, 45992, 45992, 1024, 8192, 0x00000000 0, 23, 23, 1, 1378560, 0x8955570e -1, 46968, 46968, 1024, 8192, 0x00000000 -1, 47976, 47976, 1024, 8192, 0x00000000 +1, 47016, 47016, 1024, 8192, 0x00000000 +1, 48024, 48024, 1024, 8192, 0x00000000 0, 24, 24, 1, 1378560, 0x9c598000 -1, 49968, 49968, 1024, 8192, 0x00000000 0, 25, 25, 1, 1378560, 0xbaf121ba -1, 50992, 50992, 1024, 8192, 0x00000000 -1, 52008, 52008, 1024, 8192, 0x00000000 +1, 50064, 50064, 1024, 8192, 0x00000000 +1, 51088, 51088, 1024, 8192, 0x00000000 0, 26, 26, 1, 1378560, 0xbaf121ba -1, 53032, 53032, 1024, 8192, 0x00000000 +1, 52104, 52104, 1024, 8192, 0x00000000 +1, 53128, 53128, 1024, 8192, 0x00000000 0, 27, 27, 1, 1378560, 0x6579d31a -1, 54056, 54056, 1024, 8192, 0x00000000 -1, 55080, 55080, 1024, 8192, 0x00000000 +1, 54152, 54152, 1024, 8192, 0x00000000 +1, 55176, 55176, 1024, 8192, 0x00000000 0, 28, 28, 1, 1378560, 0xca1deba8 -1, 56088, 56088, 1024, 8192, 0x00000000 -1, 57168, 57168, 1024, 8192, 0x00000000 +1, 56184, 56184, 1024, 8192, 0x00000000 +1, 57264, 57264, 1024, 8192, 0x00000000 0, 29, 29, 1, 1378560, 0xd4eed467 -1, 58192, 58192, 1024, 8192, 0x00000000 -1, 59208, 59208, 1024, 8192, 0x00000000 +1, 58288, 58288, 1024, 8192, 0x00000000 +1, 59304, 59304, 1024, 8192, 0x00000000 0, 30, 30, 1, 1378560, 0xd6e1d5b7 -1, 60216, 60216, 1024, 8192, 0x00000000 -1, 61240, 61240, 1024, 8192, 0x00000000 +1, 60312, 60312, 1024, 8192, 0x00000000 +1, 61336, 61336, 1024, 8192, 0x00000000 0, 31, 31, 1, 1378560, 0x0b574d39 -1, 62264, 62264, 1024, 8192, 0x00000000 -1, 63288, 63288, 1024, 8192, 0x00000000 +1, 62360, 62360, 1024, 8192, 0x00000000 +1, 63384, 63384, 1024, 8192, 0x00000000 0, 32, 32, 1, 1378560, 0x1bdd4d61 -1, 64296, 64296, 1024, 8192, 0x00000000 -1, 65320, 65320, 1024, 8192, 0x00000000 +1, 64392, 64392, 1024, 8192, 0x00000000 +1, 65416, 65416, 1024, 8192, 0x00000000 0, 33, 33, 1, 1378560, 0x3b28f549 -1, 66344, 66344, 1024, 8192, 0x00000000 -1, 67368, 67368, 1024, 8192, 0x00000000 +1, 66440, 66440, 1024, 8192, 0x00000000 +1, 67464, 67464, 1024, 8192, 0x00000000 0, 34, 34, 1, 1378560, 0x45b2f57b -1, 68376, 68376, 1024, 8192, 0x00000000 -1, 69400, 69400, 1024, 8192, 0x00000000 +1, 68472, 68472, 1024, 8192, 0x00000000 +1, 69496, 69496, 1024, 8192, 0x00000000 0, 35, 35, 1, 1378560, 0x8955570e -1, 70424, 70424, 1024, 8192, 0x00000000 -1, 71448, 71448, 1024, 8192, 0x00000000 -0, 36, 36, 1, 1378560, 0x9c598000 -1, 72456, 72456, 1024, 8192, 0x00000000 -0, 37, 37, 1, 1378560, 0xbaf121ba -1, 74448, 74448, 1024, 8192, 0x00000000 -1, 75472, 75472, 1024, 8192, 0x00000000 +1, 70520, 70520, 1024, 8192, 0x00000000 +1, 71544, 71544, 1024, 8192, 0x00000000 +1, 72552, 72552, 1024, 8192, 0x00000000 +0, 37, 37, 1, 1378560, 0x9c598000 +1, 74592, 74592, 1024, 8192, 0x00000000 +1, 75616, 75616, 1024, 8192, 0x00000000 0, 38, 38, 1, 1378560, 0xbaf121ba -1, 76488, 76488, 1024, 8192, 0x00000000 -1, 77512, 77512, 1024, 8192, 0x00000000 -0, 39, 39, 1, 1378560, 0x6579d31a -1, 78536, 78536, 1024, 8192, 0x00000000 -1, 79560, 79560, 1024, 8192, 0x00000000 -0, 40, 40, 1, 1378560, 0xca1deba8 -1, 80568, 80568, 1024, 8192, 0x00000000 -1, 81648, 81648, 1024, 8192, 0x00000000 -0, 41, 41, 1, 1378560, 0xd4eed467 -1, 82672, 82672, 1024, 8192, 0x00000000 -1, 83688, 83688, 1024, 8192, 0x00000000 -0, 42, 42, 1, 1378560, 0xd6e1d5b7 -1, 84696, 84696, 1024, 8192, 0x00000000 -1, 85720, 85720, 1024, 8192, 0x00000000 -0, 43, 43, 1, 1378560, 0x0b574d39 -1, 86744, 86744, 1024, 8192, 0x00000000 -1, 87768, 87768, 1024, 8192, 0x00000000 -0, 44, 44, 1, 1378560, 0x1bdd4d61 -1, 88776, 88776, 1024, 8192, 0x00000000 -1, 89800, 89800, 1024, 8192, 0x00000000 -0, 45, 45, 1, 1378560, 0x3b28f549 -1, 90824, 90824, 1024, 8192, 0x00000000 -1, 91848, 91848, 1024, 8192, 0x00000000 -0, 46, 46, 1, 1378560, 0x45b2f57b -1, 92856, 92856, 1024, 8192, 0x00000000 -1, 93880, 93880, 1024, 8192, 0x00000000 -0, 47, 47, 1, 1378560, 0x8955570e -1, 94904, 94904, 1024, 8192, 0x00000000 -1, 95928, 95928, 1024, 8192, 0x00000000 -1, 96936, 96936, 1024, 8192, 0x00000000 +1, 76632, 76632, 1024, 8192, 0x00000000 +1, 77656, 77656, 1024, 8192, 0x00000000 +0, 39, 39, 1, 1378560, 0xbaf121ba +1, 78680, 78680, 1024, 8192, 0x00000000 +1, 79704, 79704, 1024, 8192, 0x00000000 +0, 40, 40, 1, 1378560, 0x6579d31a +1, 80712, 80712, 1024, 8192, 0x00000000 +1, 81792, 81792, 1024, 8192, 0x00000000 +0, 41, 41, 1, 1378560, 0xca1deba8 +1, 82816, 82816, 1024, 8192, 0x00000000 +1, 83832, 83832, 1024, 8192, 0x00000000 +0, 42, 42, 1, 1378560, 0xd4eed467 +1, 84840, 84840, 1024, 8192, 0x00000000 +1, 85864, 85864, 1024, 8192, 0x00000000 +0, 43, 43, 1, 1378560, 0xd6e1d5b7 +1, 86888, 86888, 1024, 8192, 0x00000000 +1, 87912, 87912, 1024, 8192, 0x00000000 +0, 44, 44, 1, 1378560, 0x0b574d39 +1, 88920, 88920, 1024, 8192, 0x00000000 +1, 89944, 89944, 1024, 8192, 0x00000000 +0, 45, 45, 1, 1378560, 0x1bdd4d61 +1, 90968, 90968, 1024, 8192, 0x00000000 +1, 91992, 91992, 1024, 8192, 0x00000000 +0, 46, 46, 1, 1378560, 0x3b28f549 +1, 93000, 93000, 1024, 8192, 0x00000000 +1, 94024, 94024, 1024, 8192, 0x00000000 +0, 47, 47, 1, 1378560, 0x45b2f57b +1, 95048, 95048, 1024, 8192, 0x00000000 +1, 96072, 96072, 1024, 8192, 0x00000000 +0, 48, 48, 1, 1378560, 0x8955570e +1, 97080, 97080, 1024, 8192, 0x00000000 0, 49, 49, 1, 1378560, 0x9c598000