From: Anton Khirnov <anton@khirnov.net>
To: ffmpeg-devel@ffmpeg.org
Subject: [FFmpeg-devel] [PATCH 11/15] fftools/ffmpeg_dec: move timestamp estimation state to Decoder
Date: Tue, 23 May 2023 15:58:38 +0200
Message-ID: <20230523135842.20388-11-anton@khirnov.net> (raw)
In-Reply-To: <20230523135842.20388-1-anton@khirnov.net>
It is purely internal to decoding.
---
fftools/ffmpeg.h | 10 -----
fftools/ffmpeg_dec.c | 87 +++++++++++++++++++++++++-----------------
fftools/ffmpeg_demux.c | 5 ---
3 files changed, 52 insertions(+), 50 deletions(-)
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index b377871980..d9cac95710 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -352,16 +352,6 @@ typedef struct InputStream {
AVRational framerate_guessed;
- // pts/estimated duration of the last decoded frame
- // * in decoder timebase for video,
- // * in last_frame_tb (may change during decoding) for audio
- int64_t last_frame_pts;
- int64_t last_frame_duration_est;
- AVRational last_frame_tb;
- int last_frame_sample_rate;
-
- int64_t filter_in_rescale_delta_last;
-
int64_t nb_samples; /* number of samples in the last decoded audio frame before looping */
AVDictionary *decoder_opts;
diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index 23c50cc272..c952473c16 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -34,6 +34,15 @@
struct Decoder {
AVFrame *frame;
AVPacket *pkt;
+
+ // pts/estimated duration of the last decoded frame
+ // * in decoder timebase for video,
+ // * in last_frame_tb (may change during decoding) for audio
+ int64_t last_frame_pts;
+ int64_t last_frame_duration_est;
+ AVRational last_frame_tb;
+ int64_t last_filter_in_rescale_delta;
+ int last_frame_sample_rate;
};
void dec_free(Decoder **pdec)
@@ -67,6 +76,9 @@ static int dec_alloc(Decoder **pdec)
if (!dec->pkt)
goto fail;
+ dec->last_filter_in_rescale_delta = AV_NOPTS_VALUE;
+ dec->last_frame_pts = AV_NOPTS_VALUE;
+ dec->last_frame_tb = (AVRational){ 1, 1 };
*pdec = dec;
@@ -94,21 +106,22 @@ static int send_frame_to_filters(InputStream *ist, AVFrame *decoded_frame)
return ret;
}
-static AVRational audio_samplerate_update(InputStream *ist, const AVFrame *frame)
+static AVRational audio_samplerate_update(void *logctx, Decoder *d,
+ const AVFrame *frame)
{
- const int prev = ist->last_frame_tb.den;
+ const int prev = d->last_frame_tb.den;
const int sr = frame->sample_rate;
AVRational tb_new;
int64_t gcd;
- if (frame->sample_rate == ist->last_frame_sample_rate)
+ if (frame->sample_rate == d->last_frame_sample_rate)
goto finish;
gcd = av_gcd(prev, sr);
if (prev / gcd >= INT_MAX / sr) {
- av_log(ist, AV_LOG_WARNING,
+ av_log(logctx, AV_LOG_WARNING,
"Audio timestamps cannot be represented exactly after "
"sample rate change: %d -> %d\n", prev, sr);
@@ -123,20 +136,20 @@ static AVRational audio_samplerate_update(InputStream *ist, const AVFrame *frame
!(frame->time_base.den % tb_new.den))
tb_new = frame->time_base;
- if (ist->last_frame_pts != AV_NOPTS_VALUE)
- ist->last_frame_pts = av_rescale_q(ist->last_frame_pts,
- ist->last_frame_tb, tb_new);
- ist->last_frame_duration_est = av_rescale_q(ist->last_frame_duration_est,
- ist->last_frame_tb, tb_new);
+ if (d->last_frame_pts != AV_NOPTS_VALUE)
+ d->last_frame_pts = av_rescale_q(d->last_frame_pts,
+ d->last_frame_tb, tb_new);
+ d->last_frame_duration_est = av_rescale_q(d->last_frame_duration_est,
+ d->last_frame_tb, tb_new);
- ist->last_frame_tb = tb_new;
- ist->last_frame_sample_rate = frame->sample_rate;
+ d->last_frame_tb = tb_new;
+ d->last_frame_sample_rate = frame->sample_rate;
finish:
- return ist->last_frame_tb;
+ return d->last_frame_tb;
}
-static void audio_ts_process(InputStream *ist, AVFrame *frame)
+static void audio_ts_process(void *logctx, Decoder *d, AVFrame *frame)
{
AVRational tb_filter = (AVRational){1, frame->sample_rate};
AVRational tb;
@@ -145,27 +158,27 @@ static void audio_ts_process(InputStream *ist, AVFrame *frame)
// on samplerate change, choose a new internal timebase for timestamp
// generation that can represent timestamps from all the samplerates
// seen so far
- tb = audio_samplerate_update(ist, frame);
- pts_pred = ist->last_frame_pts == AV_NOPTS_VALUE ? 0 :
- ist->last_frame_pts + ist->last_frame_duration_est;
+ tb = audio_samplerate_update(logctx, d, frame);
+ pts_pred = d->last_frame_pts == AV_NOPTS_VALUE ? 0 :
+ d->last_frame_pts + d->last_frame_duration_est;
if (frame->pts == AV_NOPTS_VALUE) {
frame->pts = pts_pred;
frame->time_base = tb;
- } else if (ist->last_frame_pts != AV_NOPTS_VALUE &&
+ } else if (d->last_frame_pts != AV_NOPTS_VALUE &&
frame->pts > av_rescale_q_rnd(pts_pred, tb, frame->time_base,
AV_ROUND_UP)) {
// there was a gap in timestamps, reset conversion state
- ist->filter_in_rescale_delta_last = AV_NOPTS_VALUE;
+ d->last_filter_in_rescale_delta = AV_NOPTS_VALUE;
}
frame->pts = av_rescale_delta(frame->time_base, frame->pts,
tb, frame->nb_samples,
- &ist->filter_in_rescale_delta_last, tb);
+ &d->last_filter_in_rescale_delta, tb);
- ist->last_frame_pts = frame->pts;
- ist->last_frame_duration_est = av_rescale_q(frame->nb_samples,
- tb_filter, tb);
+ d->last_frame_pts = frame->pts;
+ d->last_frame_duration_est = av_rescale_q(frame->nb_samples,
+ tb_filter, tb);
// finally convert to filtering timebase
frame->pts = av_rescale_q(frame->pts, tb, tb_filter);
@@ -175,6 +188,7 @@ static void audio_ts_process(InputStream *ist, AVFrame *frame)
static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *frame)
{
+ const Decoder *d = ist->decoder;
const InputFile *ifile = input_files[ist->file_index];
int64_t codec_duration = 0;
@@ -202,9 +216,9 @@ static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *fr
// when timestamps are available, repeat last frame's actual duration
// (i.e. pts difference between this and last frame)
- if (frame->pts != AV_NOPTS_VALUE && ist->last_frame_pts != AV_NOPTS_VALUE &&
- frame->pts > ist->last_frame_pts)
- return frame->pts - ist->last_frame_pts;
+ if (frame->pts != AV_NOPTS_VALUE && d->last_frame_pts != AV_NOPTS_VALUE &&
+ frame->pts > d->last_frame_pts)
+ return frame->pts - d->last_frame_pts;
// try frame/codec duration
if (frame->duration > 0)
@@ -221,11 +235,13 @@ static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *fr
}
// last resort is last frame's estimated duration, and 1
- return FFMAX(ist->last_frame_duration_est, 1);
+ return FFMAX(d->last_frame_duration_est, 1);
}
static int video_frame_process(InputStream *ist, AVFrame *frame)
{
+ Decoder *d = ist->decoder;
+
// The following line may be required in some cases where there is no parser
// or the parser does not has_b_frames correctly
if (ist->par->video_delay < ist->dec_ctx->has_b_frames) {
@@ -273,13 +289,13 @@ static int video_frame_process(InputStream *ist, AVFrame *frame)
// no timestamp available - extrapolate from previous frame duration
if (frame->pts == AV_NOPTS_VALUE)
- frame->pts = ist->last_frame_pts == AV_NOPTS_VALUE ? 0 :
- ist->last_frame_pts + ist->last_frame_duration_est;
+ frame->pts = d->last_frame_pts == AV_NOPTS_VALUE ? 0 :
+ d->last_frame_pts + d->last_frame_duration_est;
// update timestamp history
- ist->last_frame_duration_est = video_duration_estimate(ist, frame);
- ist->last_frame_pts = frame->pts;
- ist->last_frame_tb = frame->time_base;
+ d->last_frame_duration_est = video_duration_estimate(ist, frame);
+ d->last_frame_pts = frame->pts;
+ d->last_frame_tb = frame->time_base;
if (debug_ts) {
av_log(ist, AV_LOG_INFO,
@@ -404,12 +420,13 @@ static int transcode_subtitles(InputStream *ist, const AVPacket *pkt)
static int send_filter_eof(InputStream *ist)
{
+ Decoder *d = ist->decoder;
int i, ret;
for (i = 0; i < ist->nb_filters; i++) {
- int64_t end_pts = ist->last_frame_pts == AV_NOPTS_VALUE ? AV_NOPTS_VALUE :
- ist->last_frame_pts + ist->last_frame_duration_est;
- ret = ifilter_send_eof(ist->filters[i], end_pts, ist->last_frame_tb);
+ int64_t end_pts = d->last_frame_pts == AV_NOPTS_VALUE ? AV_NOPTS_VALUE :
+ d->last_frame_pts + d->last_frame_duration_est;
+ ret = ifilter_send_eof(ist->filters[i], end_pts, d->last_frame_tb);
if (ret < 0)
return ret;
}
@@ -506,7 +523,7 @@ int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
ist->samples_decoded += frame->nb_samples;
ist->nb_samples = frame->nb_samples;
- audio_ts_process(ist, frame);
+ audio_ts_process(ist, ist->decoder, frame);
} else {
ret = video_frame_process(ist, frame);
if (ret < 0) {
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index c65c72f556..e02bdc3b96 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -1181,11 +1181,6 @@ static void add_input_streams(const OptionsContext *o, Demuxer *d)
exit_program(1);
}
- ist->filter_in_rescale_delta_last = AV_NOPTS_VALUE;
-
- ist->last_frame_pts = AV_NOPTS_VALUE;
- ist->last_frame_tb = (AVRational){ 1, 1 };
-
ist->dec_ctx = avcodec_alloc_context3(ist->dec);
if (!ist->dec_ctx)
report_and_exit(AVERROR(ENOMEM));
--
2.39.2
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2023-05-23 14:00 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-05-23 13:58 [FFmpeg-devel] [PATCH 01/15] fftools/ffmpeg_hw: move hw_device_setup_for_decode() to ffmpeg_dec Anton Khirnov
2023-05-23 13:58 ` [FFmpeg-devel] [PATCH 02/15] fftools/ffmpeg_hw: move hw_device_setup_for_encode() to ffmpeg_enc Anton Khirnov
2023-05-23 13:58 ` [FFmpeg-devel] [PATCH 03/15] fftools/ffmpeg_enc: use AVFrame.hw_frames_ctx for encoder hw setup Anton Khirnov
2023-05-23 13:58 ` [FFmpeg-devel] [PATCH 04/15] fftools/ffmpeg: fail earlier on text/bitmap subtitles mismatch Anton Khirnov
2023-05-23 13:58 ` [FFmpeg-devel] [PATCH 05/15] fftools/ffmpeg: drop outdated comments Anton Khirnov
2023-05-23 13:58 ` [FFmpeg-devel] [PATCH 06/15] fftools/ffmpeg_demux: only print demuxing stats if demuxing actually started Anton Khirnov
2023-05-23 13:58 ` [FFmpeg-devel] [PATCH 07/15] fftools/ffmpeg_demux: initialize nb_streams_warn Anton Khirnov
2023-05-23 13:58 ` [FFmpeg-devel] [PATCH 08/15] fftools/ffmpeg_demux: skip unused/attachment streams in final stats Anton Khirnov
2023-05-23 13:58 ` [FFmpeg-devel] [PATCH 09/15] fftools/ffmpeg_dec: add decoder private data Anton Khirnov
2023-05-23 13:58 ` [FFmpeg-devel] [PATCH 10/15] fftools/ffmpeg_dec: move InputStream.pkt to Decoder Anton Khirnov
2023-05-23 13:58 ` Anton Khirnov [this message]
2023-05-23 13:58 ` [FFmpeg-devel] [PATCH 12/15] fftools/ffmpeg: add InputStream.index Anton Khirnov
2023-05-23 13:58 ` [FFmpeg-devel] [PATCH 13/15] fftools/ffmpeg_demux: log discontinuity warnings to stream context Anton Khirnov
2023-05-23 13:58 ` [FFmpeg-devel] [PATCH 14/15] fftools/sync_queue: add debug logging Anton Khirnov
2023-05-23 13:58 ` [FFmpeg-devel] [PATCH 15/15] fftools/sync_queue: make sure non-limiting streams are not used as queue head Anton Khirnov
2023-05-24 12:01 ` James Almer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230523135842.20388-11-anton@khirnov.net \
--to=anton@khirnov.net \
--cc=ffmpeg-devel@ffmpeg.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git