1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-23 12:43:46 +02:00

fftools/ffmpeg: rework keeping track of file duration for -stream_loop

Current code tracks min/max pts for each stream separately; then when
the file ends it combines them with last frame's duration to compute the
total duration of each stream; finally it selects the longest of those
durations as the file duration.

This is incorrect - the total file duration is the largest timestamp
difference between any frames, regardless of the stream.

Also change the way the last frame information is reported from decoders
to the muxer - previously it would be just the last frame's duration,
now the end timestamp is sent, which is simpler.

Changes the result of the fate-ffmpeg-streamloop-transcode-av test,
where the timestamps are shifted slightly forward. Note that the
matroska demuxer does not return the first audio packet after seeking
(due to buggy interaction betwen the generic code and the demuxer), so
there is a gap in audio.
This commit is contained in:
Anton Khirnov 2023-10-11 17:43:51 +02:00
parent 87016e031f
commit 889a022cce
5 changed files with 141 additions and 167 deletions

View File

@ -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 {

View File

@ -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);

View File

@ -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;

View File

@ -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.

View File

@ -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