Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name
@ 2023-05-17 10:19 Anton Khirnov
  2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 02/36] fftools/ffmpeg: drop a useless local variable Anton Khirnov
                   ` (34 more replies)
  0 siblings, 35 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:19 UTC (permalink / raw)
  To: ffmpeg-devel

There is only one frame used in decode_video() -- the one output by the
decoder. So there is no point in explicitly calling it the _decoded_
frame.
---
 fftools/ffmpeg.c | 52 ++++++++++++++++++++++++------------------------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index ebd793a98c..084192f270 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1027,7 +1027,7 @@ static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *fr
 static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
                         int eof, int *decode_failed)
 {
-    AVFrame *decoded_frame = ist->decoded_frame;
+    AVFrame *frame = ist->decoded_frame;
     int ret = 0, err = 0;
     int64_t best_effort_timestamp;
 
@@ -1038,7 +1038,7 @@ static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
         return 0;
 
     update_benchmark(NULL);
-    ret = decode(ist, ist->dec_ctx, decoded_frame, got_output, pkt);
+    ret = decode(ist, ist->dec_ctx, frame, got_output, pkt);
     update_benchmark("decode_video %d.%d", ist->file_index, ist->st->index);
     if (ret < 0)
         *decode_failed = 1;
@@ -1062,13 +1062,13 @@ static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
         check_decode_result(ist, got_output, ret);
 
     if (*got_output && ret >= 0) {
-        if (ist->dec_ctx->width  != decoded_frame->width ||
-            ist->dec_ctx->height != decoded_frame->height ||
-            ist->dec_ctx->pix_fmt != decoded_frame->format) {
+        if (ist->dec_ctx->width  != frame->width ||
+            ist->dec_ctx->height != frame->height ||
+            ist->dec_ctx->pix_fmt != frame->format) {
             av_log(NULL, AV_LOG_DEBUG, "Frame parameters mismatch context %d,%d,%d != %d,%d,%d\n",
-                decoded_frame->width,
-                decoded_frame->height,
-                decoded_frame->format,
+                frame->width,
+                frame->height,
+                frame->format,
                 ist->dec_ctx->width,
                 ist->dec_ctx->height,
                 ist->dec_ctx->pix_fmt);
@@ -1079,17 +1079,17 @@ static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
         return ret;
 
     if(ist->top_field_first>=0)
-        decoded_frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
+        frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
 
     ist->frames_decoded++;
 
-    if (ist->hwaccel_retrieve_data && decoded_frame->format == ist->hwaccel_pix_fmt) {
-        err = ist->hwaccel_retrieve_data(ist->dec_ctx, decoded_frame);
+    if (ist->hwaccel_retrieve_data && frame->format == ist->hwaccel_pix_fmt) {
+        err = ist->hwaccel_retrieve_data(ist->dec_ctx, frame);
         if (err < 0)
             goto fail;
     }
 
-    best_effort_timestamp= decoded_frame->best_effort_timestamp;
+    best_effort_timestamp = frame->best_effort_timestamp;
 
     if (ist->framerate.num)
         best_effort_timestamp = ist->cfr_next_pts++;
@@ -1100,13 +1100,13 @@ static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
                                 ist->last_frame_pts + ist->last_frame_duration_est;
 
     if(best_effort_timestamp != AV_NOPTS_VALUE) {
-        decoded_frame->pts = best_effort_timestamp;
+        frame->pts = best_effort_timestamp;
     }
 
     // update timestamp history
-    ist->last_frame_duration_est = video_duration_estimate(ist, decoded_frame);
-    ist->last_frame_pts          = decoded_frame->pts;
-    ist->last_frame_tb           = decoded_frame->time_base;
+    ist->last_frame_duration_est = video_duration_estimate(ist, frame);
+    ist->last_frame_pts          = frame->pts;
+    ist->last_frame_tb           = frame->time_base;
 
     if (debug_ts) {
         av_log(ist, AV_LOG_INFO,
@@ -1115,25 +1115,25 @@ static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
                "best_effort_ts:%"PRId64" best_effort_ts_time:%s "
                "duration:%s duration_time:%s "
                "keyframe:%d frame_type:%d time_base:%d/%d\n",
-               av_ts2str(decoded_frame->pts),
-               av_ts2timestr(decoded_frame->pts, &ist->st->time_base),
-               av_ts2str(decoded_frame->pkt_dts),
-               av_ts2timestr(decoded_frame->pkt_dts, &ist->st->time_base),
+               av_ts2str(frame->pts),
+               av_ts2timestr(frame->pts, &ist->st->time_base),
+               av_ts2str(frame->pkt_dts),
+               av_ts2timestr(frame->pkt_dts, &ist->st->time_base),
                best_effort_timestamp,
                av_ts2timestr(best_effort_timestamp, &ist->st->time_base),
-               av_ts2str(decoded_frame->duration),
-               av_ts2timestr(decoded_frame->duration, &ist->st->time_base),
-               !!(decoded_frame->flags & AV_FRAME_FLAG_KEY), decoded_frame->pict_type,
+               av_ts2str(frame->duration),
+               av_ts2timestr(frame->duration, &ist->st->time_base),
+               !!(frame->flags & AV_FRAME_FLAG_KEY), frame->pict_type,
                ist->st->time_base.num, ist->st->time_base.den);
     }
 
     if (ist->st->sample_aspect_ratio.num)
-        decoded_frame->sample_aspect_ratio = ist->st->sample_aspect_ratio;
+        frame->sample_aspect_ratio = ist->st->sample_aspect_ratio;
 
-    err = send_frame_to_filters(ist, decoded_frame);
+    err = send_frame_to_filters(ist, frame);
 
 fail:
-    av_frame_unref(decoded_frame);
+    av_frame_unref(frame);
     return err < 0 ? err : ret;
 }
 
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 02/36] fftools/ffmpeg: drop a useless local variable
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
@ 2023-05-17 10:19 ` Anton Khirnov
  2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 03/36] fftools/ffmpeg: replace stream timebase with decoded frame one Anton Khirnov
                   ` (33 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:19 UTC (permalink / raw)
  To: ffmpeg-devel

Store decoded frame timestamp directly in AVFrame.pts, there is no
advantage to using a separate local variable for it.
---
 fftools/ffmpeg.c | 18 +++++-------------
 1 file changed, 5 insertions(+), 13 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 084192f270..60f0ff3b12 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1029,7 +1029,6 @@ static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
 {
     AVFrame *frame = ist->decoded_frame;
     int ret = 0, err = 0;
-    int64_t best_effort_timestamp;
 
     // With fate-indeo3-2, we're getting 0-sized packets before EOF for some
     // reason. This seems like a semi-critical bug. Don't trigger EOF, and
@@ -1089,19 +1088,15 @@ static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
             goto fail;
     }
 
-    best_effort_timestamp = frame->best_effort_timestamp;
+    frame->pts = frame->best_effort_timestamp;
 
     if (ist->framerate.num)
-        best_effort_timestamp = ist->cfr_next_pts++;
+        frame->pts = ist->cfr_next_pts++;
 
     // no timestamp available - extrapolate from previous frame duration
-    if (best_effort_timestamp == AV_NOPTS_VALUE)
-        best_effort_timestamp = ist->last_frame_pts == AV_NOPTS_VALUE ? 0 :
-                                ist->last_frame_pts + ist->last_frame_duration_est;
-
-    if(best_effort_timestamp != AV_NOPTS_VALUE) {
-        frame->pts = best_effort_timestamp;
-    }
+    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;
 
     // update timestamp history
     ist->last_frame_duration_est = video_duration_estimate(ist, frame);
@@ -1112,15 +1107,12 @@ static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
         av_log(ist, AV_LOG_INFO,
                "decoder -> pts:%s pts_time:%s "
                "pkt_dts:%s pkt_dts_time:%s "
-               "best_effort_ts:%"PRId64" best_effort_ts_time:%s "
                "duration:%s duration_time:%s "
                "keyframe:%d frame_type:%d time_base:%d/%d\n",
                av_ts2str(frame->pts),
                av_ts2timestr(frame->pts, &ist->st->time_base),
                av_ts2str(frame->pkt_dts),
                av_ts2timestr(frame->pkt_dts, &ist->st->time_base),
-               best_effort_timestamp,
-               av_ts2timestr(best_effort_timestamp, &ist->st->time_base),
                av_ts2str(frame->duration),
                av_ts2timestr(frame->duration, &ist->st->time_base),
                !!(frame->flags & AV_FRAME_FLAG_KEY), frame->pict_type,
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 03/36] fftools/ffmpeg: replace stream timebase with decoded frame one
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
  2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 02/36] fftools/ffmpeg: drop a useless local variable Anton Khirnov
@ 2023-05-17 10:19 ` Anton Khirnov
  2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 04/36] fftools/ffmpeg_filter: convert input frame timestamps Anton Khirnov
                   ` (32 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:19 UTC (permalink / raw)
  To: ffmpeg-devel

They are the same for now, but this may change in the future.
---
 fftools/ffmpeg.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 60f0ff3b12..9e5e56e9e7 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -993,7 +993,7 @@ static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *fr
         AVRational field_rate = av_mul_q(ist->dec_ctx->framerate,
                                          (AVRational){ 2, 1 });
         codec_duration = av_rescale_q(fields, av_inv_q(field_rate),
-                                      ist->st->time_base);
+                                      frame->time_base);
     }
 
     // prefer codec-layer duration for containers without timestamps
@@ -1015,7 +1015,7 @@ static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *fr
     // try average framerate
     if (ist->st->avg_frame_rate.num && ist->st->avg_frame_rate.den) {
         int64_t d = av_rescale_q(1, av_inv_q(ist->st->avg_frame_rate),
-                                 ist->st->time_base);
+                                 frame->time_base);
         if (d > 0)
             return d;
     }
@@ -1110,13 +1110,13 @@ static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
                "duration:%s duration_time:%s "
                "keyframe:%d frame_type:%d time_base:%d/%d\n",
                av_ts2str(frame->pts),
-               av_ts2timestr(frame->pts, &ist->st->time_base),
+               av_ts2timestr(frame->pts, &frame->time_base),
                av_ts2str(frame->pkt_dts),
-               av_ts2timestr(frame->pkt_dts, &ist->st->time_base),
+               av_ts2timestr(frame->pkt_dts, &frame->time_base),
                av_ts2str(frame->duration),
-               av_ts2timestr(frame->duration, &ist->st->time_base),
+               av_ts2timestr(frame->duration, &frame->time_base),
                !!(frame->flags & AV_FRAME_FLAG_KEY), frame->pict_type,
-               ist->st->time_base.num, ist->st->time_base.den);
+               frame->time_base.num, frame->time_base.den);
     }
 
     if (ist->st->sample_aspect_ratio.num)
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 04/36] fftools/ffmpeg_filter: convert input frame timestamps
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
  2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 02/36] fftools/ffmpeg: drop a useless local variable Anton Khirnov
  2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 03/36] fftools/ffmpeg: replace stream timebase with decoded frame one Anton Khirnov
@ 2023-05-17 10:19 ` Anton Khirnov
  2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 05/36] fftools/ffmpeg_filter: make sure pkt_duration matches duration Anton Khirnov
                   ` (31 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:19 UTC (permalink / raw)
  To: ffmpeg-devel

Decoder timebase does not always have to match filter timebase.
---
 fftools/ffmpeg_filter.c | 29 ++++++++++++++++++++++++-----
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index aea951a2da..95ffa0f087 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -55,6 +55,9 @@ static FilterGraphPriv *fgp_from_fg(FilterGraph *fg)
 typedef struct InputFilterPriv {
     InputFilter ifilter;
 
+    // used to hold submitted input
+    AVFrame *frame;
+
     int eof;
 
     AVRational time_base;
@@ -244,6 +247,10 @@ static InputFilter *ifilter_alloc(FilterGraph *fg)
     ifilter->graph  = fg;
     ifilter->format = -1;
 
+    ifp->frame = av_frame_alloc();
+    if (!ifp->frame)
+        report_and_exit(AVERROR(ENOMEM));
+
     ifp->fallback.format = -1;
 
     ifp->frame_queue = av_fifo_alloc2(8, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW);
@@ -284,6 +291,8 @@ void fg_free(FilterGraph **pfg)
 
         av_channel_layout_uninit(&ifp->fallback.ch_layout);
 
+        av_frame_free(&ifp->frame);
+
         av_buffer_unref(&ifp->hw_frames_ctx);
         av_freep(&ifilter->name);
         av_freep(&fg->inputs[j]);
@@ -1541,10 +1550,6 @@ int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_reference)
     FilterGraph *fg = ifilter->graph;
     AVFrameSideData *sd;
     int need_reinit, ret;
-    int buffersrc_flags = AV_BUFFERSRC_FLAG_PUSH;
-
-    if (keep_reference)
-        buffersrc_flags |= AV_BUFFERSRC_FLAG_KEEP_REF;
 
     /* determine if the parameters for this input changed */
     need_reinit = ifilter->format != frame->format;
@@ -1606,8 +1611,22 @@ int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_reference)
         }
     }
 
-    ret = av_buffersrc_add_frame_flags(ifilter->filter, frame, buffersrc_flags);
+    if (keep_reference) {
+        ret = av_frame_ref(ifp->frame, frame);
+        if (ret < 0)
+            return ret;
+    } else
+        av_frame_move_ref(ifp->frame, frame);
+    frame = ifp->frame;
+
+    frame->pts       = av_rescale_q(frame->pts,      frame->time_base, ifp->time_base);
+    frame->duration  = av_rescale_q(frame->duration, frame->time_base, ifp->time_base);
+    frame->time_base = ifp->time_base;
+
+    ret = av_buffersrc_add_frame_flags(ifilter->filter, frame,
+                                       AV_BUFFERSRC_FLAG_PUSH);
     if (ret < 0) {
+        av_frame_unref(frame);
         if (ret != AVERROR_EOF)
             av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", av_err2str(ret));
         return ret;
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 05/36] fftools/ffmpeg_filter: make sure pkt_duration matches duration
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (2 preceding siblings ...)
  2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 04/36] fftools/ffmpeg_filter: convert input frame timestamps Anton Khirnov
@ 2023-05-17 10:19 ` Anton Khirnov
  2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 06/36] fftools/ffmpeg: rework applying input -r Anton Khirnov
                   ` (30 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:19 UTC (permalink / raw)
  To: ffmpeg-devel

Otherwise the two values might get desynchronized and lavfi can prefer
the wrong one.
---
 fftools/ffmpeg_filter.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 95ffa0f087..274eefe11c 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -1622,6 +1622,11 @@ int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_reference)
     frame->pts       = av_rescale_q(frame->pts,      frame->time_base, ifp->time_base);
     frame->duration  = av_rescale_q(frame->duration, frame->time_base, ifp->time_base);
     frame->time_base = ifp->time_base;
+#if LIBAVUTIL_VERSION_MAJOR < 59
+    AV_NOWARN_DEPRECATED(
+    frame->pkt_duration = frame->duration;
+    )
+#endif
 
     ret = av_buffersrc_add_frame_flags(ifilter->filter, frame,
                                        AV_BUFFERSRC_FLAG_PUSH);
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 06/36] fftools/ffmpeg: rework applying input -r
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (3 preceding siblings ...)
  2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 05/36] fftools/ffmpeg_filter: make sure pkt_duration matches duration Anton Khirnov
@ 2023-05-17 10:19 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 07/36] tests/fate/ffmpeg: move a misplaced line Anton Khirnov
                   ` (29 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:19 UTC (permalink / raw)
  To: ffmpeg-devel

Do not use a separate counter for CFR timestamps forced with -r used as
an input option. Set durations properly and let estimation code do the
rest.
---
 fftools/ffmpeg.c | 10 +++++++---
 fftools/ffmpeg.h |  4 ----
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 9e5e56e9e7..e368f5a148 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -985,7 +985,7 @@ static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *fr
     // durations, then this should be simplified.
 
     // prefer frame duration for containers with timestamps
-    if (frame->duration > 0 && !ifile->format_nots)
+    if (frame->duration > 0 && (!ifile->format_nots || ist->framerate.num))
         return frame->duration;
 
     if (ist->dec_ctx->framerate.den && ist->dec_ctx->framerate.num) {
@@ -1090,8 +1090,12 @@ static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
 
     frame->pts = frame->best_effort_timestamp;
 
-    if (ist->framerate.num)
-        frame->pts = ist->cfr_next_pts++;
+    // forced fixed framerate
+    if (ist->framerate.num) {
+        frame->pts       = AV_NOPTS_VALUE;
+        frame->duration  = 1;
+        frame->time_base = av_inv_q(ist->framerate);
+    }
 
     // no timestamp available - extrapolate from previous frame duration
     if (frame->pts == AV_NOPTS_VALUE)
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index f88792d7eb..3c7991c73a 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -372,10 +372,6 @@ typedef struct InputStream {
 
     int64_t filter_in_rescale_delta_last;
 
-    // when forcing constant input framerate through -r,
-    // this contains the pts that will be given to the next decoded frame
-    int64_t cfr_next_pts;
-
     int64_t nb_samples; /* number of samples in the last decoded audio frame before looping */
 
     AVDictionary *decoder_opts;
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 07/36] tests/fate/ffmpeg: move a misplaced line
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (4 preceding siblings ...)
  2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 06/36] fftools/ffmpeg: rework applying input -r Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 08/36] tests/fate/ffmpeg: add a test for input -r option Anton Khirnov
                   ` (28 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

---
 tests/fate/ffmpeg.mak | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak
index 0f33c2a0ed..892624e523 100644
--- a/tests/fate/ffmpeg.mak
+++ b/tests/fate/ffmpeg.mak
@@ -190,6 +190,7 @@ fate-copy-shortest1: CMD = framemd5 -auto_conversion_filters -fflags +bitexact -
 fate-copy-shortest2: CMD = framemd5 -auto_conversion_filters -fflags +bitexact -flags +bitexact -f lavfi -i "sine=3000:d=10" -i $(TARGET_PATH)/tests/data/audio_shorter_than_video.nut -filter_complex "[0:a:0][1:a:0]amix=inputs=2[audio]" -map 1:v:0 -map "[audio]" -fflags +bitexact -flags +bitexact -c:v copy -c:a ac3_fixed -shortest
 
 fate-streamcopy: $(FATE_STREAMCOPY-yes)
+FATE_SAMPLES_FFMPEG-yes += $(FATE_STREAMCOPY-yes)
 
 FATE_SAMPLES_FFMPEG-$(call TRANSCODE, RAWVIDEO, MATROSKA, MOV_DEMUXER QTRLE_DECODER) += fate-rgb24-mkv
 fate-rgb24-mkv: CMD = transcode "mov" $(TARGET_SAMPLES)/qtrle/aletrek-rle.mov\
@@ -218,8 +219,6 @@ fate-ffmpeg-bsf-remove-e: CMD = transcode "mpeg" $(TARGET_SAMPLES)/mpeg2/matrixb
 FATE_SAMPLES_FFMPEG-$(call DEMMUX, APNG, FRAMECRC, SETTS_BSF PIPE_PROTOCOL) += fate-ffmpeg-setts-bsf
 fate-ffmpeg-setts-bsf: CMD = framecrc -i $(TARGET_SAMPLES)/apng/clock.png -c:v copy -bsf:v "setts=duration=if(eq(NEXT_PTS\,NOPTS)\,PREV_OUTDURATION\,(NEXT_PTS-PTS)/2):ts=PTS/2" -fflags +bitexact
 
-FATE_SAMPLES_FFMPEG-yes += $(FATE_STREAMCOPY-yes)
-
 FATE_TIME_BASE-$(call PARSERDEMDEC, MPEGVIDEO, MPEGPS, MPEG2VIDEO, MPEGVIDEO_DEMUXER MXF_MUXER) += fate-time_base
 fate-time_base: CMD = md5 -i $(TARGET_SAMPLES)/mpeg2/dvd_single_frame.vob -an -sn -c:v copy -r 25 -time_base 1001:30000 -fflags +bitexact -f mxf
 
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 08/36] tests/fate/ffmpeg: add a test for input -r option
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (5 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 07/36] tests/fate/ffmpeg: move a misplaced line Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 09/36] fftools/ffmpeg_filter: split finding an unused stream into a function Anton Khirnov
                   ` (27 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

---
 tests/fate/ffmpeg.mak         |  4 ++++
 tests/ref/fate/ffmpeg-input-r | 12 ++++++++++++
 2 files changed, 16 insertions(+)
 create mode 100644 tests/ref/fate/ffmpeg-input-r

diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak
index 892624e523..aca949176a 100644
--- a/tests/fate/ffmpeg.mak
+++ b/tests/fate/ffmpeg.mak
@@ -223,3 +223,7 @@ FATE_TIME_BASE-$(call PARSERDEMDEC, MPEGVIDEO, MPEGPS, MPEG2VIDEO, MPEGVIDEO_DEM
 fate-time_base: CMD = md5 -i $(TARGET_SAMPLES)/mpeg2/dvd_single_frame.vob -an -sn -c:v copy -r 25 -time_base 1001:30000 -fflags +bitexact -f mxf
 
 FATE_SAMPLES_FFMPEG-yes += $(FATE_TIME_BASE-yes)
+
+# test -r used as an input option
+fate-ffmpeg-input-r: CMD = framecrc -r 27 -i $(TARGET_SAMPLES)/mpeg2/sony-ct3.bs
+FATE_SAMPLES_FFMPEG-$(call FRAMECRC, MPEGVIDEO, MPEG2VIDEO) += fate-ffmpeg-input-r
diff --git a/tests/ref/fate/ffmpeg-input-r b/tests/ref/fate/ffmpeg-input-r
new file mode 100644
index 0000000000..d11f870b10
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-input-r
@@ -0,0 +1,12 @@
+#tb 0: 1/27
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 720x480
+#sar 0: 8/9
+0,          0,          0,        1,   518400, 0xc1866f5f
+0,          1,          1,        1,   518400, 0x9ba32764
+0,          2,          2,        1,   518400, 0xa9031bb8
+0,          3,          3,        1,   518400, 0x5e2c3502
+0,          4,          4,        1,   518400, 0xe860027a
+0,          5,          5,        1,   518400, 0xa9152430
+0,          6,          6,        1,   518400, 0xb98dd9f7
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 09/36] fftools/ffmpeg_filter: split finding an unused stream into a function
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (6 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 08/36] tests/fate/ffmpeg: add a test for input -r option Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 10/36] fftools/ffmpeg: return error codes from ist_*_add() Anton Khirnov
                   ` (26 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

Avoids filtering code from digging in demuxer internals.
---
 fftools/ffmpeg.h        |  5 +++++
 fftools/ffmpeg_demux.c  | 10 ++++++++++
 fftools/ffmpeg_filter.c |  8 +-------
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 3c7991c73a..9cb7198dfd 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -882,6 +882,11 @@ int ifile_get_packet(InputFile *f, AVPacket **pkt);
 void ist_output_add(InputStream *ist, OutputStream *ost);
 void ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple);
 
+/**
+ * Find an unused input stream of given type.
+ */
+InputStream *ist_find_unused(enum AVMediaType type);
+
 /* iterate over all input streams in all input files;
  * pass NULL to start iteration */
 InputStream *ist_iter(InputStream *prev);
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index 0a37cc7c25..b93e171037 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -130,6 +130,16 @@ static Demuxer *demuxer_from_ifile(InputFile *f)
     return (Demuxer*)f;
 }
 
+InputStream *ist_find_unused(enum AVMediaType type)
+{
+    for (InputStream *ist = ist_iter(NULL); ist; ist = ist_iter(ist)) {
+        if (ist->par->codec_type == type && ist->discard &&
+            ist->user_set_discard != AVDISCARD_ALL)
+            return ist;
+    }
+    return NULL;
+}
+
 static void report_new_stream(Demuxer *d, const AVPacket *pkt)
 {
     AVStream *st = d->f.ctx->streams[pkt->stream_index];
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 274eefe11c..8cc76209d0 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -420,13 +420,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
             exit_program(1);
         }
     } else {
-        /* find the first unused stream of corresponding type */
-        for (ist = ist_iter(NULL); ist; ist = ist_iter(ist)) {
-            if (ist->user_set_discard == AVDISCARD_ALL)
-                continue;
-            if (ist->dec_ctx->codec_type == type && ist->discard)
-                break;
-        }
+        ist = ist_find_unused(type);
         if (!ist) {
             av_log(NULL, AV_LOG_FATAL, "Cannot find a matching stream for "
                    "unlabeled input pad %d on filter %s\n", in->pad_idx,
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 10/36] fftools/ffmpeg: return error codes from ist_*_add()
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (7 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 09/36] fftools/ffmpeg_filter: split finding an unused stream into a function Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 11/36] fftools/ffmpeg_demux: disallow using disabled input streams Anton Khirnov
                   ` (25 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

Will be useful in future commits.
---
 fftools/ffmpeg.h          |  4 ++--
 fftools/ffmpeg_demux.c    | 26 +++++++++++++++++++-------
 fftools/ffmpeg_filter.c   | 15 ++++++++++++---
 fftools/ffmpeg_mux_init.c | 10 ++++++++--
 4 files changed, 41 insertions(+), 14 deletions(-)

diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 9cb7198dfd..189454d629 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -879,8 +879,8 @@ void ifile_close(InputFile **f);
  */
 int ifile_get_packet(InputFile *f, AVPacket **pkt);
 
-void ist_output_add(InputStream *ist, OutputStream *ost);
-void ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple);
+int ist_output_add(InputStream *ist, OutputStream *ost);
+int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple);
 
 /**
  * Find an unused input stream of given type.
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index b93e171037..ae2133bdbf 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -844,7 +844,7 @@ void ifile_close(InputFile **pf)
     av_freep(pf);
 }
 
-static void ist_use(InputStream *ist, int decoding_needed)
+static int ist_use(InputStream *ist, int decoding_needed)
 {
     DemuxStream *ds = ds_from_ist(ist);
 
@@ -856,23 +856,33 @@ static void ist_use(InputStream *ist, int decoding_needed)
     if (decoding_needed && !avcodec_is_open(ist->dec_ctx)) {
         int ret = dec_open(ist);
         if (ret < 0)
-            report_and_exit(ret);
+            return ret;
     }
+
+    return 0;
 }
 
-void ist_output_add(InputStream *ist, OutputStream *ost)
+int ist_output_add(InputStream *ist, OutputStream *ost)
 {
-    ist_use(ist, ost->enc ? DECODING_FOR_OST : 0);
+    int ret;
+
+    ret = ist_use(ist, ost->enc ? DECODING_FOR_OST : 0);
+    if (ret < 0)
+        return ret;
 
     GROW_ARRAY(ist->outputs, ist->nb_outputs);
     ist->outputs[ist->nb_outputs - 1] = ost;
+
+    return 0;
 }
 
-void ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple)
+int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple)
 {
     int ret;
 
-    ist_use(ist, is_simple ? DECODING_FOR_OST : DECODING_FOR_FILTER);
+    ret = ist_use(ist, is_simple ? DECODING_FOR_OST : DECODING_FOR_FILTER);
+    if (ret < 0)
+        return ret;
 
     GROW_ARRAY(ist->filters, ist->nb_filters);
     ist->filters[ist->nb_filters - 1] = ifilter;
@@ -880,7 +890,9 @@ void ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple)
     // initialize fallback parameters for filtering
     ret = ifilter_parameters_from_dec(ifilter, ist->dec_ctx);
     if (ret < 0)
-        report_and_exit(ret);
+        return ret;
+
+    return 0;
 }
 
 static const AVCodec *choose_decoder(const OptionsContext *o, AVFormatContext *s, AVStream *st,
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 8cc76209d0..ca43b4803a 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -334,6 +334,7 @@ int init_simple_filtergraph(InputStream *ist, OutputStream *ost)
     FilterGraph *fg;
     OutputFilter *ofilter;
     InputFilter  *ifilter;
+    int ret;
 
     fg = fg_create(NULL);
     if (!fg)
@@ -347,7 +348,9 @@ int init_simple_filtergraph(InputStream *ist, OutputStream *ost)
     ifilter         = ifilter_alloc(fg);
     ifilter->ist    = ist;
 
-    ist_filter_add(ist, ifilter, 1);
+    ret = ist_filter_add(ist, ifilter, 1);
+    if (ret < 0)
+        return ret;
 
     return 0;
 }
@@ -375,7 +378,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
     InputStream *ist = NULL;
     enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);
     InputFilter *ifilter;
-    int i;
+    int i, ret;
 
     // TODO: support other filter types
     if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
@@ -435,7 +438,13 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
     ifilter->type   = ist->st->codecpar->codec_type;
     ifilter->name   = describe_filter_link(fg, in, 1);
 
-    ist_filter_add(ist, ifilter, 0);
+    ret = ist_filter_add(ist, ifilter, 0);
+    if (ret < 0) {
+        av_log(NULL, AV_LOG_ERROR,
+               "Error binding an input stream to complex filtergraph input %s.\n",
+               in->name ? in->name : "");
+        exit_program(1);
+    }
 }
 
 static int read_binary(const char *path, uint8_t **data, int *len)
diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index 2c0e2faf4a..b73791acee 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -1225,8 +1225,14 @@ static OutputStream *ost_add(Muxer *mux, const OptionsContext *o,
                        "Error initializing a simple filtergraph\n");
                 exit_program(1);
             }
-        } else
-            ist_output_add(ost->ist, ost);
+        } else {
+            ret = ist_output_add(ost->ist, ost);
+            if (ret < 0) {
+                av_log(ost, AV_LOG_ERROR,
+                       "Error binding an input stream\n");
+                exit_program(1);
+            }
+        }
     }
 
     if (ost->ist && !ost->enc) {
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 11/36] fftools/ffmpeg_demux: disallow using disabled input streams
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (8 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 10/36] fftools/ffmpeg: return error codes from ist_*_add() Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 12/36] fftools/ffmpeg_filter: only use fallback parameters when necessary Anton Khirnov
                   ` (24 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

This is less ad-hoc than checking explicitly in every place that binds
an input stream to a filter or output.
---
 fftools/ffmpeg_demux.c  | 6 ++++++
 fftools/ffmpeg_filter.c | 5 -----
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index ae2133bdbf..df87e0f30a 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -848,6 +848,12 @@ static int ist_use(InputStream *ist, int decoding_needed)
 {
     DemuxStream *ds = ds_from_ist(ist);
 
+    if (ist->user_set_discard == AVDISCARD_ALL) {
+        av_log(ist, AV_LOG_ERROR, "Cannot %s a disabled input stream\n",
+               decoding_needed ? "decode" : "streamcopy");
+        return AVERROR(EINVAL);
+    }
+
     ist->discard          = 0;
     ist->st->discard      = ist->user_set_discard;
     ist->decoding_needed |= decoding_needed;
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index ca43b4803a..2c3e2a96f7 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -417,11 +417,6 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
             exit_program(1);
         }
         ist = input_files[file_idx]->streams[st->index];
-        if (ist->user_set_discard == AVDISCARD_ALL) {
-            av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s "
-                   "matches a disabled input stream.\n", p, fgp->graph_desc);
-            exit_program(1);
-        }
     } else {
         ist = ist_find_unused(type);
         if (!ist) {
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 12/36] fftools/ffmpeg_filter: only use fallback parameters when necessary
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (9 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 11/36] fftools/ffmpeg_demux: disallow using disabled input streams Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 13/36] fftools/ffmpeg_filter: try configuring graphs from input EOF Anton Khirnov
                   ` (23 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

With complex filtergraphs it can happen that the filtergraph is
unconfigured because some other filter than the one we just got EOF on
is missing parameters.

Make sure that the fallback parametes for a given input are only used
when that input is unconfigured.
---
 fftools/ffmpeg_filter.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 2c3e2a96f7..8eca0f2cae 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -1521,17 +1521,19 @@ int ifilter_send_eof(InputFilter *ifilter, int64_t pts, AVRational tb)
         if (ret < 0)
             return ret;
     } else {
-        // the filtergraph was never configured, use the fallback parameters
-        ifilter->format                 = ifp->fallback.format;
-        ifilter->sample_rate            = ifp->fallback.sample_rate;
-        ifilter->width                  = ifp->fallback.width;
-        ifilter->height                 = ifp->fallback.height;
-        ifilter->sample_aspect_ratio    = ifp->fallback.sample_aspect_ratio;
-
-        ret = av_channel_layout_copy(&ifilter->ch_layout,
-                                     &ifp->fallback.ch_layout);
-        if (ret < 0)
-            return ret;
+        if (ifilter->format < 0) {
+            // the filtergraph was never configured, use the fallback parameters
+            ifilter->format                 = ifp->fallback.format;
+            ifilter->sample_rate            = ifp->fallback.sample_rate;
+            ifilter->width                  = ifp->fallback.width;
+            ifilter->height                 = ifp->fallback.height;
+            ifilter->sample_aspect_ratio    = ifp->fallback.sample_aspect_ratio;
+
+            ret = av_channel_layout_copy(&ifilter->ch_layout,
+                                         &ifp->fallback.ch_layout);
+            if (ret < 0)
+                return ret;
+        }
 
         if (ifilter->format < 0 && (ifilter->type == AVMEDIA_TYPE_AUDIO || ifilter->type == AVMEDIA_TYPE_VIDEO)) {
             av_log(NULL, AV_LOG_ERROR, "Cannot determine format of input stream %d:%d after EOF\n", ifilter->ist->file_index, ifilter->ist->st->index);
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 13/36] fftools/ffmpeg_filter: try configuring graphs from input EOF
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (10 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 12/36] fftools/ffmpeg_filter: only use fallback parameters when necessary Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 14/36] fftools/ffmpeg: move ifilter_has_all_input_formats() to ffmpeg_filter Anton Khirnov
                   ` (22 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

When a filtergraph input receives EOF but never saw any input frames, we
use the fallback parameters. Currently an attempt to actually configure
the filtergraph will happen elsewhere, but there is no reason to
postpone this.
---
 fftools/ffmpeg_filter.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 8eca0f2cae..6323278d15 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -1533,6 +1533,14 @@ int ifilter_send_eof(InputFilter *ifilter, int64_t pts, AVRational tb)
                                          &ifp->fallback.ch_layout);
             if (ret < 0)
                 return ret;
+
+            if (ifilter_has_all_input_formats(ifilter->graph)) {
+                ret = configure_filtergraph(ifilter->graph);
+                if (ret < 0) {
+                    av_log(NULL, AV_LOG_ERROR, "Error initializing filters!\n");
+                    return ret;
+                }
+            }
         }
 
         if (ifilter->format < 0 && (ifilter->type == AVMEDIA_TYPE_AUDIO || ifilter->type == AVMEDIA_TYPE_VIDEO)) {
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 14/36] fftools/ffmpeg: move ifilter_has_all_input_formats() to ffmpeg_filter
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (11 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 13/36] fftools/ffmpeg_filter: try configuring graphs from input EOF Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 15/36] fftools/ffmpeg_filter: make input filter configured parameters private Anton Khirnov
                   ` (21 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

That is a more appropriate place for that function.
---
 fftools/ffmpeg.c        | 12 ------------
 fftools/ffmpeg_filter.c | 12 ++++++++++++
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index e368f5a148..9d554e2fb0 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -787,18 +787,6 @@ static void check_decode_result(InputStream *ist, int *got_output, int ret)
     }
 }
 
-// Filters can be configured only if the formats of all inputs are known.
-int ifilter_has_all_input_formats(FilterGraph *fg)
-{
-    int i;
-    for (i = 0; i < fg->nb_inputs; i++) {
-        if (fg->inputs[i]->format < 0 && (fg->inputs[i]->type == AVMEDIA_TYPE_AUDIO ||
-                                          fg->inputs[i]->type == AVMEDIA_TYPE_VIDEO))
-            return 0;
-    }
-    return 1;
-}
-
 // This does not quite work like avcodec_decode_audio4/avcodec_decode_video2.
 // There is the following difference: if you got a frame, you must call
 // it again with pkt=NULL. pkt==NULL is treated differently from pkt->size==0
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 6323278d15..d85d9e2c67 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -1445,6 +1445,18 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr
     return 0;
 }
 
+// Filters can be configured only if the formats of all inputs are known.
+int ifilter_has_all_input_formats(FilterGraph *fg)
+{
+    int i;
+    for (i = 0; i < fg->nb_inputs; i++) {
+        if (fg->inputs[i]->format < 0 && (fg->inputs[i]->type == AVMEDIA_TYPE_AUDIO ||
+                                          fg->inputs[i]->type == AVMEDIA_TYPE_VIDEO))
+            return 0;
+    }
+    return 1;
+}
+
 int filtergraph_is_simple(FilterGraph *fg)
 {
     FilterGraphPriv *fgp = fgp_from_fg(fg);
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 15/36] fftools/ffmpeg_filter: make input filter configured parameters private
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (12 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 14/36] fftools/ffmpeg: move ifilter_has_all_input_formats() to ffmpeg_filter Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 16/36] fftools/ffmpeg_filter: drop a redundant error message Anton Khirnov
                   ` (20 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

They are not used outside of ffmpeg_filter.
---
 fftools/ffmpeg.h        |  9 -----
 fftools/ffmpeg_filter.c | 89 +++++++++++++++++++++++------------------
 2 files changed, 50 insertions(+), 48 deletions(-)

diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 189454d629..9cb9f35bc2 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -283,15 +283,6 @@ typedef struct InputFilter {
     struct FilterGraph *graph;
     uint8_t            *name;
     enum AVMediaType    type;   // AVMEDIA_TYPE_SUBTITLE for sub2video
-
-    // parameters configured for this input
-    int format;
-
-    int width, height;
-    AVRational sample_aspect_ratio;
-
-    int sample_rate;
-    AVChannelLayout ch_layout;
 } InputFilter;
 
 typedef struct OutputFilter {
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index d85d9e2c67..12e756e489 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -60,6 +60,15 @@ typedef struct InputFilterPriv {
 
     int eof;
 
+    // parameters configured for this input
+    int format;
+
+    int width, height;
+    AVRational sample_aspect_ratio;
+
+    int sample_rate;
+    AVChannelLayout ch_layout;
+
     AVRational time_base;
 
     AVFifo *frame_queue;
@@ -245,12 +254,12 @@ static InputFilter *ifilter_alloc(FilterGraph *fg)
     InputFilter *ifilter = &ifp->ifilter;
 
     ifilter->graph  = fg;
-    ifilter->format = -1;
 
     ifp->frame = av_frame_alloc();
     if (!ifp->frame)
         report_and_exit(AVERROR(ENOMEM));
 
+    ifp->format          = -1;
     ifp->fallback.format = -1;
 
     ifp->frame_queue = av_fifo_alloc2(8, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW);
@@ -956,14 +965,15 @@ void check_filter_outputs(void)
 
 static int sub2video_prepare(InputStream *ist, InputFilter *ifilter)
 {
+    InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
     AVFormatContext *avf = input_files[ist->file_index]->ctx;
     int i, w, h;
 
     /* Compute the size of the canvas for the subtitles stream.
        If the subtitles codecpar has set a size, use it. Otherwise use the
        maximum dimensions of the video streams in the same file. */
-    w = ifilter->width;
-    h = ifilter->height;
+    w = ifp->width;
+    h = ifp->height;
     if (!(w && h)) {
         for (i = 0; i < avf->nb_streams; i++) {
             if (avf->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
@@ -977,15 +987,15 @@ static int sub2video_prepare(InputStream *ist, InputFilter *ifilter)
         }
         av_log(avf, AV_LOG_INFO, "sub2video: using %dx%d canvas\n", w, h);
     }
-    ist->sub2video.w = ifilter->width  = w;
-    ist->sub2video.h = ifilter->height = h;
+    ist->sub2video.w = ifp->width  = w;
+    ist->sub2video.h = ifp->height = h;
 
-    ifilter->width  = ist->dec_ctx->width  ? ist->dec_ctx->width  : ist->sub2video.w;
-    ifilter->height = ist->dec_ctx->height ? ist->dec_ctx->height : ist->sub2video.h;
+    ifp->width  = ist->dec_ctx->width  ? ist->dec_ctx->width  : ist->sub2video.w;
+    ifp->height = ist->dec_ctx->height ? ist->dec_ctx->height : ist->sub2video.h;
 
     /* rectangles are AV_PIX_FMT_PAL8, but we have no guarantee that the
        palettes for all rectangles are identical or compatible */
-    ifilter->format = AV_PIX_FMT_RGB32;
+    ifp->format = AV_PIX_FMT_RGB32;
 
     ist->sub2video.frame = av_frame_alloc();
     if (!ist->sub2video.frame)
@@ -1042,14 +1052,14 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
     ifp->time_base =  ist->framerate.num ? av_inv_q(ist->framerate) :
                                            ist->st->time_base;
 
-    sar = ifilter->sample_aspect_ratio;
+    sar = ifp->sample_aspect_ratio;
     if(!sar.den)
         sar = (AVRational){0,1};
     av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);
     av_bprintf(&args,
              "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:"
              "pixel_aspect=%d/%d",
-             ifilter->width, ifilter->height, ifilter->format,
+             ifp->width, ifp->height, ifp->format,
              ifp->time_base.num, ifp->time_base.den, sar.num, sar.den);
     if (fr.num && fr.den)
         av_bprintf(&args, ":frame_rate=%d/%d", fr.num, fr.den);
@@ -1067,7 +1077,7 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
     av_freep(&par);
     last_filter = ifilter->filter;
 
-    desc = av_pix_fmt_desc_get(ifilter->format);
+    desc = av_pix_fmt_desc_get(ifp->format);
     av_assert0(desc);
 
     // TODO: insert hwaccel enabled filters like transpose_vaapi into the graph
@@ -1147,19 +1157,19 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
         return AVERROR(EINVAL);
     }
 
-    ifp->time_base = (AVRational){ 1, ifilter->sample_rate };
+    ifp->time_base = (AVRational){ 1, ifp->sample_rate };
 
     av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);
     av_bprintf(&args, "time_base=%d/%d:sample_rate=%d:sample_fmt=%s",
                ifp->time_base.num, ifp->time_base.den,
-             ifilter->sample_rate,
-             av_get_sample_fmt_name(ifilter->format));
-    if (av_channel_layout_check(&ifilter->ch_layout) &&
-        ifilter->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {
+               ifp->sample_rate,
+               av_get_sample_fmt_name(ifp->format));
+    if (av_channel_layout_check(&ifp->ch_layout) &&
+        ifp->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {
         av_bprintf(&args, ":channel_layout=");
-        av_channel_layout_describe_bprint(&ifilter->ch_layout, &args);
+        av_channel_layout_describe_bprint(&ifp->ch_layout, &args);
     } else
-        av_bprintf(&args, ":channels=%d", ifilter->ch_layout.nb_channels);
+        av_bprintf(&args, ":channels=%d", ifp->ch_layout.nb_channels);
     snprintf(name, sizeof(name), "graph_%d_in_%d_%d", fg->index,
              ist->file_index, ist->st->index);
 
@@ -1426,14 +1436,14 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr
     if (ret < 0)
         return ret;
 
-    ifilter->format = frame->format;
+    ifp->format              = frame->format;
 
-    ifilter->width               = frame->width;
-    ifilter->height              = frame->height;
-    ifilter->sample_aspect_ratio = frame->sample_aspect_ratio;
+    ifp->width               = frame->width;
+    ifp->height              = frame->height;
+    ifp->sample_aspect_ratio = frame->sample_aspect_ratio;
 
-    ifilter->sample_rate         = frame->sample_rate;
-    ret = av_channel_layout_copy(&ifilter->ch_layout, &frame->ch_layout);
+    ifp->sample_rate         = frame->sample_rate;
+    ret = av_channel_layout_copy(&ifp->ch_layout, &frame->ch_layout);
     if (ret < 0)
         return ret;
 
@@ -1450,8 +1460,9 @@ int ifilter_has_all_input_formats(FilterGraph *fg)
 {
     int i;
     for (i = 0; i < fg->nb_inputs; i++) {
-        if (fg->inputs[i]->format < 0 && (fg->inputs[i]->type == AVMEDIA_TYPE_AUDIO ||
-                                          fg->inputs[i]->type == AVMEDIA_TYPE_VIDEO))
+        InputFilterPriv *ifp = ifp_from_ifilter(fg->inputs[i]);
+        if (ifp->format < 0 && (fg->inputs[i]->type == AVMEDIA_TYPE_AUDIO ||
+                                fg->inputs[i]->type == AVMEDIA_TYPE_VIDEO))
             return 0;
     }
     return 1;
@@ -1533,15 +1544,15 @@ int ifilter_send_eof(InputFilter *ifilter, int64_t pts, AVRational tb)
         if (ret < 0)
             return ret;
     } else {
-        if (ifilter->format < 0) {
+        if (ifp->format < 0) {
             // the filtergraph was never configured, use the fallback parameters
-            ifilter->format                 = ifp->fallback.format;
-            ifilter->sample_rate            = ifp->fallback.sample_rate;
-            ifilter->width                  = ifp->fallback.width;
-            ifilter->height                 = ifp->fallback.height;
-            ifilter->sample_aspect_ratio    = ifp->fallback.sample_aspect_ratio;
+            ifp->format                 = ifp->fallback.format;
+            ifp->sample_rate            = ifp->fallback.sample_rate;
+            ifp->width                  = ifp->fallback.width;
+            ifp->height                 = ifp->fallback.height;
+            ifp->sample_aspect_ratio    = ifp->fallback.sample_aspect_ratio;
 
-            ret = av_channel_layout_copy(&ifilter->ch_layout,
+            ret = av_channel_layout_copy(&ifp->ch_layout,
                                          &ifp->fallback.ch_layout);
             if (ret < 0)
                 return ret;
@@ -1555,7 +1566,7 @@ int ifilter_send_eof(InputFilter *ifilter, int64_t pts, AVRational tb)
             }
         }
 
-        if (ifilter->format < 0 && (ifilter->type == AVMEDIA_TYPE_AUDIO || ifilter->type == AVMEDIA_TYPE_VIDEO)) {
+        if (ifp->format < 0 && (ifilter->type == AVMEDIA_TYPE_AUDIO || ifilter->type == AVMEDIA_TYPE_VIDEO)) {
             av_log(NULL, AV_LOG_ERROR, "Cannot determine format of input stream %d:%d after EOF\n", ifilter->ist->file_index, ifilter->ist->st->index);
             return AVERROR_INVALIDDATA;
         }
@@ -1572,16 +1583,16 @@ int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_reference)
     int need_reinit, ret;
 
     /* determine if the parameters for this input changed */
-    need_reinit = ifilter->format != frame->format;
+    need_reinit = ifp->format != frame->format;
 
     switch (ifilter->ist->par->codec_type) {
     case AVMEDIA_TYPE_AUDIO:
-        need_reinit |= ifilter->sample_rate    != frame->sample_rate ||
-                       av_channel_layout_compare(&ifilter->ch_layout, &frame->ch_layout);
+        need_reinit |= ifp->sample_rate    != frame->sample_rate ||
+                       av_channel_layout_compare(&ifp->ch_layout, &frame->ch_layout);
         break;
     case AVMEDIA_TYPE_VIDEO:
-        need_reinit |= ifilter->width  != frame->width ||
-                       ifilter->height != frame->height;
+        need_reinit |= ifp->width  != frame->width ||
+                       ifp->height != frame->height;
         break;
     }
 
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 16/36] fftools/ffmpeg_filter: drop a redundant error message
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (13 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 15/36] fftools/ffmpeg_filter: make input filter configured parameters private Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 17/36] fftools/ffmpeg_filter: move InputFilter.ist to private data Anton Khirnov
                   ` (19 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

In case no decoder is available, dec_open() called from ist_use() will
fail with 'Decoding requested, but no decoder found', so this check is
redundant.
---
 fftools/ffmpeg_filter.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 12e756e489..16f29a313f 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -1201,12 +1201,6 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
 static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
                                   AVFilterInOut *in)
 {
-    if (!ifilter->ist->dec) {
-        av_log(NULL, AV_LOG_ERROR,
-               "No decoder for stream #%d:%d, filtering impossible\n",
-               ifilter->ist->file_index, ifilter->ist->st->index);
-        return AVERROR_DECODER_NOT_FOUND;
-    }
     switch (avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx)) {
     case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, ifilter, in);
     case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, ifilter, in);
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 17/36] fftools/ffmpeg_filter: move InputFilter.ist to private data
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (14 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 16/36] fftools/ffmpeg_filter: drop a redundant error message Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 18/36] fftools/ffmpeg_filter: move InputFilter.type " Anton Khirnov
                   ` (18 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

It is not accessed outside of ffmpeg_filter.
---
 fftools/ffmpeg.h        |  1 -
 fftools/ffmpeg_filter.c | 34 +++++++++++++++++++---------------
 2 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 9cb9f35bc2..c33e537faa 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -279,7 +279,6 @@ typedef struct OptionsContext {
 
 typedef struct InputFilter {
     AVFilterContext    *filter;
-    struct InputStream *ist;
     struct FilterGraph *graph;
     uint8_t            *name;
     enum AVMediaType    type;   // AVMEDIA_TYPE_SUBTITLE for sub2video
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 16f29a313f..e6e9e00985 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -55,6 +55,8 @@ static FilterGraphPriv *fgp_from_fg(FilterGraph *fg)
 typedef struct InputFilterPriv {
     InputFilter ifilter;
 
+    InputStream *ist;
+
     // used to hold submitted input
     AVFrame *frame;
 
@@ -247,7 +249,7 @@ static OutputFilter *ofilter_alloc(FilterGraph *fg)
     return ofilter;
 }
 
-static InputFilter *ifilter_alloc(FilterGraph *fg)
+static InputFilter *ifilter_alloc(FilterGraph *fg, InputStream *ist)
 {
     InputFilterPriv *ifp = allocate_array_elem(&fg->inputs, sizeof(*ifp),
                                                &fg->nb_inputs);
@@ -261,6 +263,7 @@ static InputFilter *ifilter_alloc(FilterGraph *fg)
 
     ifp->format          = -1;
     ifp->fallback.format = -1;
+    ifp->ist             = ist;
 
     ifp->frame_queue = av_fifo_alloc2(8, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW);
     if (!ifp->frame_queue)
@@ -282,7 +285,7 @@ void fg_free(FilterGraph **pfg)
     for (int j = 0; j < fg->nb_inputs; j++) {
         InputFilter *ifilter = fg->inputs[j];
         InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
-        struct InputStream *ist = ifilter->ist;
+        InputStream     *ist = ifp->ist;
 
         if (ifp->frame_queue) {
             AVFrame *frame;
@@ -354,8 +357,7 @@ int init_simple_filtergraph(InputStream *ist, OutputStream *ost)
 
     ost->filter = ofilter;
 
-    ifilter         = ifilter_alloc(fg);
-    ifilter->ist    = ist;
+    ifilter = ifilter_alloc(fg, ist);
 
     ret = ist_filter_add(ist, ifilter, 1);
     if (ret < 0)
@@ -437,8 +439,8 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
     }
     av_assert0(ist);
 
-    ifilter = ifilter_alloc(fg);
-    ifilter->ist    = ist;
+    ifilter         = ifilter_alloc(fg, ist);
+
     ifilter->type   = ist->st->codecpar->codec_type;
     ifilter->name   = describe_filter_link(fg, in, 1);
 
@@ -1019,7 +1021,7 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
     AVFilterContext *last_filter;
     const AVFilter *buffer_filt = avfilter_get_by_name("buffer");
     const AVPixFmtDescriptor *desc;
-    InputStream *ist = ifilter->ist;
+    InputStream *ist = ifp->ist;
     InputFile     *f = input_files[ist->file_index];
     AVRational fr = ist->framerate;
     AVRational sar;
@@ -1145,7 +1147,7 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
     InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
     AVFilterContext *last_filter;
     const AVFilter *abuffer_filt = avfilter_get_by_name("abuffer");
-    InputStream *ist = ifilter->ist;
+    InputStream *ist = ifp->ist;
     InputFile     *f = input_files[ist->file_index];
     AVBPrint args;
     char name[255];
@@ -1380,7 +1382,7 @@ int configure_filtergraph(FilterGraph *fg)
 
     /* process queued up subtitle packets */
     for (i = 0; i < fg->nb_inputs; i++) {
-        InputStream *ist = fg->inputs[i]->ist;
+        InputStream *ist = ifp_from_ifilter(fg->inputs[i])->ist;
         if (ist->sub2video.sub_queue && ist->sub2video.frame) {
             AVSubtitle tmp;
             while (av_fifo_read(ist->sub2video.sub_queue, &tmp, 1) >= 0) {
@@ -1561,7 +1563,9 @@ int ifilter_send_eof(InputFilter *ifilter, int64_t pts, AVRational tb)
         }
 
         if (ifp->format < 0 && (ifilter->type == AVMEDIA_TYPE_AUDIO || ifilter->type == AVMEDIA_TYPE_VIDEO)) {
-            av_log(NULL, AV_LOG_ERROR, "Cannot determine format of input stream %d:%d after EOF\n", ifilter->ist->file_index, ifilter->ist->st->index);
+            av_log(NULL, AV_LOG_ERROR,
+                   "Cannot determine format of input stream %d:%d after EOF\n",
+                   ifp->ist->file_index, ifp->ist->st->index);
             return AVERROR_INVALIDDATA;
         }
     }
@@ -1579,7 +1583,7 @@ int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_reference)
     /* determine if the parameters for this input changed */
     need_reinit = ifp->format != frame->format;
 
-    switch (ifilter->ist->par->codec_type) {
+    switch (ifp->ist->par->codec_type) {
     case AVMEDIA_TYPE_AUDIO:
         need_reinit |= ifp->sample_rate    != frame->sample_rate ||
                        av_channel_layout_compare(&ifp->ch_layout, &frame->ch_layout);
@@ -1590,7 +1594,7 @@ int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_reference)
         break;
     }
 
-    if (!ifilter->ist->reinit_filters && fg->graph)
+    if (!ifp->ist->reinit_filters && fg->graph)
         need_reinit = 0;
 
     if (!!ifp->hw_frames_ctx != !!frame->hw_frames_ctx ||
@@ -1686,8 +1690,8 @@ int fg_transcode_step(FilterGraph *graph, InputStream **best_ist)
         for (int i = 0; i < graph->nb_inputs; i++) {
             InputFilter *ifilter = graph->inputs[i];
             InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
-            if (!ifilter->ist->got_output && !ifp->eof) {
-                *best_ist = ifilter->ist;
+            if (!ifp->ist->got_output && !ifp->eof) {
+                *best_ist = ifp->ist;
                 return 0;
             }
         }
@@ -1717,7 +1721,7 @@ int fg_transcode_step(FilterGraph *graph, InputStream **best_ist)
         InputFilter *ifilter = graph->inputs[i];
         InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
 
-        ist = ifilter->ist;
+        ist = ifp->ist;
         if (input_files[ist->file_index]->eagain || ifp->eof)
             continue;
         nb_requests = av_buffersrc_get_nb_failed_requests(ifilter->filter);
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 18/36] fftools/ffmpeg_filter: move InputFilter.type to private data
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (15 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 17/36] fftools/ffmpeg_filter: move InputFilter.ist to private data Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 19/36] fftools/ffmpeg_filter: keep track of the real filter input type Anton Khirnov
                   ` (17 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

It is not accessed outside of ffmpeg_filter.
---
 fftools/ffmpeg.h        |  1 -
 fftools/ffmpeg_filter.c | 12 +++++++-----
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index c33e537faa..04c41a5311 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -281,7 +281,6 @@ typedef struct InputFilter {
     AVFilterContext    *filter;
     struct FilterGraph *graph;
     uint8_t            *name;
-    enum AVMediaType    type;   // AVMEDIA_TYPE_SUBTITLE for sub2video
 } InputFilter;
 
 typedef struct OutputFilter {
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index e6e9e00985..5656fa87df 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -60,6 +60,9 @@ typedef struct InputFilterPriv {
     // used to hold submitted input
     AVFrame *frame;
 
+    // AVMEDIA_TYPE_SUBTITLE for sub2video
+    enum AVMediaType type;
+
     int eof;
 
     // parameters configured for this input
@@ -264,6 +267,7 @@ static InputFilter *ifilter_alloc(FilterGraph *fg, InputStream *ist)
     ifp->format          = -1;
     ifp->fallback.format = -1;
     ifp->ist             = ist;
+    ifp->type            = ist->st->codecpar->codec_type;
 
     ifp->frame_queue = av_fifo_alloc2(8, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW);
     if (!ifp->frame_queue)
@@ -440,8 +444,6 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
     av_assert0(ist);
 
     ifilter         = ifilter_alloc(fg, ist);
-
-    ifilter->type   = ist->st->codecpar->codec_type;
     ifilter->name   = describe_filter_link(fg, in, 1);
 
     ret = ist_filter_add(ist, ifilter, 0);
@@ -1457,8 +1459,8 @@ int ifilter_has_all_input_formats(FilterGraph *fg)
     int i;
     for (i = 0; i < fg->nb_inputs; i++) {
         InputFilterPriv *ifp = ifp_from_ifilter(fg->inputs[i]);
-        if (ifp->format < 0 && (fg->inputs[i]->type == AVMEDIA_TYPE_AUDIO ||
-                                fg->inputs[i]->type == AVMEDIA_TYPE_VIDEO))
+        if (ifp->format < 0 && (ifp->type == AVMEDIA_TYPE_AUDIO ||
+                                ifp->type == AVMEDIA_TYPE_VIDEO))
             return 0;
     }
     return 1;
@@ -1562,7 +1564,7 @@ int ifilter_send_eof(InputFilter *ifilter, int64_t pts, AVRational tb)
             }
         }
 
-        if (ifp->format < 0 && (ifilter->type == AVMEDIA_TYPE_AUDIO || ifilter->type == AVMEDIA_TYPE_VIDEO)) {
+        if (ifp->format < 0 && (ifp->type == AVMEDIA_TYPE_AUDIO || ifp->type == AVMEDIA_TYPE_VIDEO)) {
             av_log(NULL, AV_LOG_ERROR,
                    "Cannot determine format of input stream %d:%d after EOF\n",
                    ifp->ist->file_index, ifp->ist->st->index);
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 19/36] fftools/ffmpeg_filter: keep track of the real filter input type
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (16 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 18/36] fftools/ffmpeg_filter: move InputFilter.type " Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 20/36] fftools/ffmpeg_filter: embed displaymatrix into private context Anton Khirnov
                   ` (16 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

Avoid extracting it from various remote sources.
---
 fftools/ffmpeg_filter.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 5656fa87df..c699431831 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -60,8 +60,11 @@ typedef struct InputFilterPriv {
     // used to hold submitted input
     AVFrame *frame;
 
-    // AVMEDIA_TYPE_SUBTITLE for sub2video
+    // filter data type
     enum AVMediaType type;
+    // source data type: AVMEDIA_TYPE_SUBTITLE for sub2video,
+    // same as type otherwise
+    enum AVMediaType type_src;
 
     int eof;
 
@@ -267,7 +270,9 @@ static InputFilter *ifilter_alloc(FilterGraph *fg, InputStream *ist)
     ifp->format          = -1;
     ifp->fallback.format = -1;
     ifp->ist             = ist;
-    ifp->type            = ist->st->codecpar->codec_type;
+    ifp->type_src        = ist->st->codecpar->codec_type;
+    ifp->type            = ifp->type_src == AVMEDIA_TYPE_SUBTITLE ?
+                           AVMEDIA_TYPE_VIDEO : ifp->type_src;
 
     ifp->frame_queue = av_fifo_alloc2(8, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW);
     if (!ifp->frame_queue)
@@ -1205,7 +1210,7 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
 static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
                                   AVFilterInOut *in)
 {
-    switch (avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx)) {
+    switch (ifp_from_ifilter(ifilter)->type) {
     case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, ifilter, in);
     case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, ifilter, in);
     default: av_assert0(0); return 0;
@@ -1459,8 +1464,8 @@ int ifilter_has_all_input_formats(FilterGraph *fg)
     int i;
     for (i = 0; i < fg->nb_inputs; i++) {
         InputFilterPriv *ifp = ifp_from_ifilter(fg->inputs[i]);
-        if (ifp->format < 0 && (ifp->type == AVMEDIA_TYPE_AUDIO ||
-                                ifp->type == AVMEDIA_TYPE_VIDEO))
+        if (ifp->format < 0 && (ifp->type_src == AVMEDIA_TYPE_AUDIO ||
+                                ifp->type_src == AVMEDIA_TYPE_VIDEO))
             return 0;
     }
     return 1;
@@ -1564,7 +1569,9 @@ int ifilter_send_eof(InputFilter *ifilter, int64_t pts, AVRational tb)
             }
         }
 
-        if (ifp->format < 0 && (ifp->type == AVMEDIA_TYPE_AUDIO || ifp->type == AVMEDIA_TYPE_VIDEO)) {
+        if (ifp->format < 0 &&
+            (ifp->type_src == AVMEDIA_TYPE_AUDIO ||
+             ifp->type_src == AVMEDIA_TYPE_VIDEO)) {
             av_log(NULL, AV_LOG_ERROR,
                    "Cannot determine format of input stream %d:%d after EOF\n",
                    ifp->ist->file_index, ifp->ist->st->index);
@@ -1585,7 +1592,7 @@ int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_reference)
     /* determine if the parameters for this input changed */
     need_reinit = ifp->format != frame->format;
 
-    switch (ifp->ist->par->codec_type) {
+    switch (ifp->type) {
     case AVMEDIA_TYPE_AUDIO:
         need_reinit |= ifp->sample_rate    != frame->sample_rate ||
                        av_channel_layout_compare(&ifp->ch_layout, &frame->ch_layout);
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 20/36] fftools/ffmpeg_filter: embed displaymatrix into private context
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (17 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 19/36] fftools/ffmpeg_filter: keep track of the real filter input type Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 21/36] fftools/cmdutils: constify the argument of get_rotation() Anton Khirnov
                   ` (15 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

It has a small fixed size, so it is better to embed it rather than deal
with dynamic allocation.
---
 fftools/ffmpeg_filter.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index c699431831..6f842f6b46 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -83,7 +83,8 @@ typedef struct InputFilterPriv {
 
     AVBufferRef *hw_frames_ctx;
 
-    int32_t *displaymatrix;
+    int     displaymatrix_present;
+    int32_t displaymatrix[9];
 
     // fallback parameters to use when no input is ever sent
     struct {
@@ -302,7 +303,6 @@ void fg_free(FilterGraph **pfg)
                 av_frame_free(&frame);
             av_fifo_freep2(&ifp->frame_queue);
         }
-        av_freep(&ifp->displaymatrix);
         if (ist->sub2video.sub_queue) {
             AVSubtitle sub;
             while (av_fifo_read(ist->sub2video.sub_queue, &sub, 1) >= 0)
@@ -1094,7 +1094,7 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
         int32_t *displaymatrix = ifp->displaymatrix;
         double theta;
 
-        if (!displaymatrix)
+        if (!ifp->displaymatrix_present)
             displaymatrix = (int32_t *)av_stream_get_side_data(ist->st, AV_PKT_DATA_DISPLAYMATRIX, NULL);
         theta = get_rotation(displaymatrix);
 
@@ -1450,10 +1450,10 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr
     if (ret < 0)
         return ret;
 
-    av_freep(&ifp->displaymatrix);
     sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX);
     if (sd)
-        ifp->displaymatrix = av_memdup(sd->data, sizeof(int32_t) * 9);
+        memcpy(ifp->displaymatrix, sd->data, sizeof(ifp->displaymatrix));
+    ifp->displaymatrix_present = !!sd;
 
     return 0;
 }
@@ -1611,9 +1611,10 @@ int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_reference)
         need_reinit = 1;
 
     if (sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX)) {
-        if (!ifp->displaymatrix || memcmp(sd->data, ifp->displaymatrix, sizeof(int32_t) * 9))
+        if (!ifp->displaymatrix_present ||
+            memcmp(sd->data, ifp->displaymatrix, sizeof(ifp->displaymatrix)))
             need_reinit = 1;
-    } else if (ifp->displaymatrix)
+    } else if (ifp->displaymatrix_present)
         need_reinit = 1;
 
     if (need_reinit) {
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 21/36] fftools/cmdutils: constify the argument of get_rotation()
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (18 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 20/36] fftools/ffmpeg_filter: embed displaymatrix into private context Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 22/36] fftools/ffmpeg: drop an obsolete hack Anton Khirnov
                   ` (14 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

---
 fftools/cmdutils.c | 2 +-
 fftools/cmdutils.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c
index a1de621d1c..9ec00add30 100644
--- a/fftools/cmdutils.c
+++ b/fftools/cmdutils.c
@@ -994,7 +994,7 @@ void *allocate_array_elem(void *ptr, size_t elem_size, int *nb_elems)
     return new_elem;
 }
 
-double get_rotation(int32_t *displaymatrix)
+double get_rotation(const int32_t *displaymatrix)
 {
     double theta = 0;
     if (displaymatrix)
diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h
index 4496221983..0115940225 100644
--- a/fftools/cmdutils.h
+++ b/fftools/cmdutils.h
@@ -461,6 +461,6 @@ void *allocate_array_elem(void *array, size_t elem_size, int *nb_elems);
     char name[16];\
     snprintf(name, sizeof(name), "%d", rate);
 
-double get_rotation(int32_t *displaymatrix);
+double get_rotation(const int32_t *displaymatrix);
 
 #endif /* FFTOOLS_CMDUTILS_H */
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 22/36] fftools/ffmpeg: drop an obsolete hack
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (19 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 21/36] fftools/cmdutils: constify the argument of get_rotation() Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-26  6:22   ` Wang, Fei W
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 23/36] fftools/ffmpeg: eliminate InputStream.got_output Anton Khirnov
                   ` (13 subsequent siblings)
  34 siblings, 1 reply; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

This special handling for decoder flushing has not been needed since
af1761f7b5, as the filtergraph actually is drained after that commit.
---
 fftools/ffmpeg.c | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 9d554e2fb0..49313edebc 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1418,17 +1418,6 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo
         if (!got_output)
             break;
 
-        // During draining, we might get multiple output frames in this loop.
-        // ffmpeg.c does not drain the filter chain on configuration changes,
-        // which means if we send multiple frames at once to the filters, and
-        // one of those frames changes configuration, the buffered frames will
-        // be lost. This can upset certain FATE tests.
-        // Decode only 1 frame per call on EOF to appease these FATE tests.
-        // The ideal solution would be to rewrite decoding to use the new
-        // decoding API in a better way.
-        if (!pkt)
-            break;
-
         repeating = 1;
     }
 
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 23/36] fftools/ffmpeg: eliminate InputStream.got_output
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (20 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 22/36] fftools/ffmpeg: drop an obsolete hack Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 24/36] fftools/ffmpeg: replace an unreachable return with av_assert0(0) Anton Khirnov
                   ` (12 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

It tracks whether the decoder for this stream ever produced any frames
and its only use is for checking whether a filter input ever received a
frame - those that did not are prioritized by the scheduler.

This is awkward and unnecessarily complicated - checking whether the
filtergraph input format is valid works just as well and does not
require maintaining an extra variable.
---
 fftools/ffmpeg.c        | 3 ---
 fftools/ffmpeg.h        | 2 --
 fftools/ffmpeg_filter.c | 2 +-
 3 files changed, 1 insertion(+), 6 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 49313edebc..62620bacce 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1412,9 +1412,6 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo
             break;
         }
 
-        if (got_output)
-            ist->got_output = 1;
-
         if (!got_output)
             break;
 
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 04c41a5311..3a332768df 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -413,8 +413,6 @@ typedef struct InputStream {
     // number of frames/samples retrieved from the decoder
     uint64_t frames_decoded;
     uint64_t samples_decoded;
-
-    int got_output;
 } InputStream;
 
 typedef struct LastFrameDuration {
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 6f842f6b46..640ecec067 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -1700,7 +1700,7 @@ int fg_transcode_step(FilterGraph *graph, InputStream **best_ist)
         for (int i = 0; i < graph->nb_inputs; i++) {
             InputFilter *ifilter = graph->inputs[i];
             InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
-            if (!ifp->ist->got_output && !ifp->eof) {
+            if (ifp->format < 0 && !ifp->eof) {
                 *best_ist = ifp->ist;
                 return 0;
             }
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 24/36] fftools/ffmpeg: replace an unreachable return with av_assert0(0)
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (21 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 23/36] fftools/ffmpeg: eliminate InputStream.got_output Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 25/36] fftools/ffmpeg: deobfuscate check_decode_result() call Anton Khirnov
                   ` (11 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

This cannot be reached, because initialization will fail if decoding is
requested for a stream but no decoder can be found.
---
 fftools/ffmpeg.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 62620bacce..1fcabd123a 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1390,8 +1390,7 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo
                 ret = AVERROR_EOF;
             av_packet_unref(avpkt);
             break;
-        default:
-            return -1;
+        default: av_assert0(0);
         }
 
         if (ret == AVERROR_EOF) {
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 25/36] fftools/ffmpeg: deobfuscate check_decode_result() call
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (22 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 24/36] fftools/ffmpeg: replace an unreachable return with av_assert0(0) Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 26/36] fftools/ffmpeg: rework handling -max_error_rate Anton Khirnov
                   ` (10 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

Passing ist=NULL is currently used to identify stream types that do not
decode into AVFrames, i.e. subtitles. That is highly non-obvious -
always pass a non-NULL InputStream and just check the type explicitly.
---
 fftools/ffmpeg.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 1fcabd123a..537f287637 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -777,7 +777,7 @@ static void check_decode_result(InputStream *ist, int *got_output, int ret)
     if (ret < 0 && exit_on_error)
         exit_program(1);
 
-    if (*got_output && ist) {
+    if (*got_output && ist->dec_ctx->codec_type != AVMEDIA_TYPE_SUBTITLE) {
         if (ist->decoded_frame->decode_error_flags || (ist->decoded_frame->flags & AV_FRAME_FLAG_CORRUPT)) {
             av_log(ist, exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING,
                    "corrupt decoded frame\n");
@@ -1317,7 +1317,7 @@ static int transcode_subtitles(InputStream *ist, const AVPacket *pkt,
     int ret = avcodec_decode_subtitle2(ist->dec_ctx,
                                        &subtitle, got_output, pkt);
 
-    check_decode_result(NULL, got_output, ret);
+    check_decode_result(ist, got_output, ret);
 
     if (ret < 0 || !*got_output) {
         *decode_failed = 1;
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 26/36] fftools/ffmpeg: rework handling -max_error_rate
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (23 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 25/36] fftools/ffmpeg: deobfuscate check_decode_result() call Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-18  6:19   ` [FFmpeg-devel] [PATCH] " Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 27/36] fftools/ffmpeg: move a block to a more appropriate place Anton Khirnov
                   ` (9 subsequent siblings)
  34 siblings, 1 reply; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

Replace the decode_error_stat global with a per-input-stream variable.
Also, print an error message when the error rate is exceeded.
---
 fftools/ffmpeg.c       | 28 ++++++++++++++++------------
 fftools/ffmpeg.h       |  1 +
 fftools/ffmpeg_demux.c |  5 +++--
 3 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 537f287637..2e9a2b940a 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -121,7 +121,6 @@ static int64_t getmaxrss(void);
 
 int64_t nb_frames_dup = 0;
 int64_t nb_frames_drop = 0;
-static int64_t decode_error_stat[2];
 unsigned nb_output_dumped = 0;
 
 static BenchmarkTimeStamps current_time;
@@ -771,8 +770,8 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
 
 static void check_decode_result(InputStream *ist, int *got_output, int ret)
 {
-    if (*got_output || ret<0)
-        decode_error_stat[ret<0] ++;
+    if (ret < 0)
+        ist->decode_errors++;
 
     if (ret < 0 && exit_on_error)
         exit_program(1);
@@ -1807,14 +1806,15 @@ static int transcode_step(OutputStream *ost)
 /*
  * The following code is the main loop of the file converter
  */
-static int transcode(void)
+static int transcode(int *err_rate_exceeded)
 {
-    int ret, i;
+    int ret = 0, i;
     InputStream *ist;
     int64_t timer_start;
 
     print_stream_maps();
 
+    *err_rate_exceeded = 0;
     atomic_store(&transcode_init_done, 1);
 
     if (stdin_interaction) {
@@ -1858,6 +1858,12 @@ static int transcode(void)
         if (!input_files[ist->file_index]->eof_reached) {
             process_input_packet(ist, NULL, 0);
         }
+
+        if ((ist->frames_decoded + ist->decode_errors) * max_error_rate < ist->decode_errors) {
+            av_log(ist, AV_LOG_FATAL, "Maximum error rate %g exceeded\n", max_error_rate);
+            *err_rate_exceeded = 1;
+        }
+
     }
     enc_flush();
 
@@ -1921,7 +1927,7 @@ static int64_t getmaxrss(void)
 
 int main(int argc, char **argv)
 {
-    int ret;
+    int ret, err_rate_exceeded;
     BenchmarkTimeStamps ti;
 
     init_dynload();
@@ -1958,7 +1964,7 @@ int main(int argc, char **argv)
     }
 
     current_time = ti = get_benchmark_time_stamps();
-    ret = transcode();
+    ret = transcode(&err_rate_exceeded);
     if (ret >= 0 && do_benchmark) {
         int64_t utime, stime, rtime;
         current_time = get_benchmark_time_stamps();
@@ -1969,12 +1975,10 @@ int main(int argc, char **argv)
                "bench: utime=%0.3fs stime=%0.3fs rtime=%0.3fs\n",
                utime / 1000000.0, stime / 1000000.0, rtime / 1000000.0);
     }
-    av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" frames successfully decoded, %"PRIu64" decoding errors\n",
-           decode_error_stat[0], decode_error_stat[1]);
-    if ((decode_error_stat[0] + decode_error_stat[1]) * max_error_rate < decode_error_stat[1])
-        exit_program(69);
 
-    ret = received_nb_signals ? 255 : ret;
+    ret = received_nb_signals ? 255 :
+          err_rate_exceeded   ?  69 : ret;
+
     exit_program(ret);
     return ret;
 }
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 3a332768df..87e684a147 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -413,6 +413,7 @@ typedef struct InputStream {
     // number of frames/samples retrieved from the decoder
     uint64_t frames_decoded;
     uint64_t samples_decoded;
+    uint64_t decode_errors;
 } InputStream;
 
 typedef struct LastFrameDuration {
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index df87e0f30a..401ae1f850 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -786,8 +786,9 @@ static void demux_final_stats(Demuxer *d)
                ds->nb_packets, ds->data_size);
 
         if (ist->decoding_needed) {
-            av_log(f, AV_LOG_VERBOSE, "%"PRIu64" frames decoded",
-                   ist->frames_decoded);
+            av_log(f, AV_LOG_VERBOSE,
+                   "%"PRIu64" frames decoded; %"PRIu64" decode errors",
+                   ist->frames_decoded, ist->decode_errors);
             if (type == AVMEDIA_TYPE_AUDIO)
                 av_log(f, AV_LOG_VERBOSE, " (%"PRIu64" samples)", ist->samples_decoded);
             av_log(f, AV_LOG_VERBOSE, "; ");
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 27/36] fftools/ffmpeg: move a block to a more appropriate place
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (24 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 26/36] fftools/ffmpeg: rework handling -max_error_rate Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 28/36] fftools/ffmpeg: split decoding loop out of process_input_packet() Anton Khirnov
                   ` (8 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

New placement requires fewer explicit conditions and is easier to
understand.
The logic should be exactly equivalent, since this is the only place
where eof_reached is set for decoding.
---
 fftools/ffmpeg.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 2e9a2b940a..4cf8b54dc0 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1393,6 +1393,16 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo
         }
 
         if (ret == AVERROR_EOF) {
+            /* after flushing, send an EOF on all the filter inputs attached to the stream */
+            /* except when looping we need to flush but not to send an EOF */
+            if (!no_eof) {
+                ret = send_filter_eof(ist);
+                if (ret < 0) {
+                    av_log(NULL, AV_LOG_FATAL, "Error marking filters as finished\n");
+                    exit_program(1);
+                }
+            }
+
             eof_reached = 1;
             break;
         }
@@ -1416,16 +1426,6 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo
         repeating = 1;
     }
 
-    /* after flushing, send an EOF on all the filter inputs attached to the stream */
-    /* except when looping we need to flush but not to send an EOF */
-    if (!pkt && ist->decoding_needed && eof_reached && !no_eof) {
-        int ret = send_filter_eof(ist);
-        if (ret < 0) {
-            av_log(NULL, AV_LOG_FATAL, "Error marking filters as finished\n");
-            exit_program(1);
-        }
-    }
-
     if (!pkt && !ist->decoding_needed)
         eof_reached = 1;
 
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 28/36] fftools/ffmpeg: split decoding loop out of process_input_packet()
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (25 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 27/36] fftools/ffmpeg: move a block to a more appropriate place Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 29/36] fftools/ffmpeg: move decoding code to ffmpeg_dec Anton Khirnov
                   ` (7 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

process_input_packet() contains two non-interacting pieces of nontrivial
size and complexity - decoding and streamcopy. Separating them makes the
code easier to read.
---
 fftools/ffmpeg.c | 37 ++++++++++++++++++++-----------------
 1 file changed, 20 insertions(+), 17 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 4cf8b54dc0..e84add50e5 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1344,18 +1344,10 @@ static int send_filter_eof(InputStream *ist)
     return 0;
 }
 
-/* pkt = NULL means EOF (needed to flush decoder buffers) */
-static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
+static int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
 {
-    InputFile *f = input_files[ist->file_index];
-    const AVCodecParameters *par = ist->par;
-    int64_t dts_est = AV_NOPTS_VALUE;
-    int ret = 0;
-    int repeating = 0;
-    int eof_reached = 0;
-    int duration_exceeded;
-
     AVPacket *avpkt = ist->pkt;
+    int ret, repeating = 0;
 
     if (pkt) {
         av_packet_unref(avpkt);
@@ -1365,11 +1357,11 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo
     }
 
     // while we have more to decode or while the decoder did output something on EOF
-    while (ist->decoding_needed) {
+    while (1) {
         int got_output = 0;
         int decode_failed = 0;
 
-        switch (par->codec_type) {
+        switch (ist->par->codec_type) {
         case AVMEDIA_TYPE_AUDIO:
             ret = decode_audio    (ist, repeating ? NULL : avpkt, &got_output,
                                    &decode_failed);
@@ -1403,8 +1395,7 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo
                 }
             }
 
-            eof_reached = 1;
-            break;
+            return AVERROR_EOF;
         }
 
         if (ret < 0) {
@@ -1417,16 +1408,28 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo
             }
             if (!decode_failed || exit_on_error)
                 exit_program(1);
-            break;
+            return ret;
         }
 
         if (!got_output)
-            break;
+            return 0;
 
         repeating = 1;
     }
+}
+
+/* pkt = NULL means EOF (needed to flush decoder buffers) */
+static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
+{
+    InputFile *f = input_files[ist->file_index];
+    int64_t dts_est = AV_NOPTS_VALUE;
+    int ret = 0;
+    int eof_reached = 0;
+    int duration_exceeded;
 
-    if (!pkt && !ist->decoding_needed)
+    if (ist->decoding_needed)
+        ret = dec_packet(ist, pkt, no_eof);
+    if (ret == AVERROR_EOF || (!pkt && !ist->decoding_needed))
         eof_reached = 1;
 
     if (pkt && pkt->opaque_ref) {
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 29/36] fftools/ffmpeg: move decoding code to ffmpeg_dec
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (26 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 28/36] fftools/ffmpeg: split decoding loop out of process_input_packet() Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 30/36] fftools/ffmpeg_dec: deobfuscate subtitle decoding Anton Khirnov
                   ` (6 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

---
 fftools/ffmpeg.c     | 534 ------------------------------------------
 fftools/ffmpeg.h     |  12 +
 fftools/ffmpeg_dec.c | 538 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 550 insertions(+), 534 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index e84add50e5..baa2f95f5d 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -283,20 +283,6 @@ static void sub2video_heartbeat(InputStream *ist, int64_t pts)
     }
 }
 
-static void sub2video_flush(InputStream *ist)
-{
-    int i;
-    int ret;
-
-    if (ist->sub2video.end_pts < INT64_MAX)
-        sub2video_update(ist, INT64_MAX, NULL);
-    for (i = 0; i < ist->nb_filters; i++) {
-        ret = av_buffersrc_add_frame(ist->filters[i]->filter, NULL);
-        if (ret != AVERROR_EOF && ret < 0)
-            av_log(NULL, AV_LOG_WARNING, "Flush the frame error.\n");
-    }
-}
-
 /* end of sub2video hack */
 
 static void term_exit_sigsafe(void)
@@ -768,417 +754,6 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
     first_report = 0;
 }
 
-static void check_decode_result(InputStream *ist, int *got_output, int ret)
-{
-    if (ret < 0)
-        ist->decode_errors++;
-
-    if (ret < 0 && exit_on_error)
-        exit_program(1);
-
-    if (*got_output && ist->dec_ctx->codec_type != AVMEDIA_TYPE_SUBTITLE) {
-        if (ist->decoded_frame->decode_error_flags || (ist->decoded_frame->flags & AV_FRAME_FLAG_CORRUPT)) {
-            av_log(ist, exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING,
-                   "corrupt decoded frame\n");
-            if (exit_on_error)
-                exit_program(1);
-        }
-    }
-}
-
-// This does not quite work like avcodec_decode_audio4/avcodec_decode_video2.
-// There is the following difference: if you got a frame, you must call
-// it again with pkt=NULL. pkt==NULL is treated differently from pkt->size==0
-// (pkt==NULL means get more output, pkt->size==0 is a flush/drain packet)
-static int decode(InputStream *ist, AVCodecContext *avctx,
-                  AVFrame *frame, int *got_frame, const AVPacket *pkt)
-{
-    int ret;
-
-    *got_frame = 0;
-
-    if (pkt) {
-        ret = avcodec_send_packet(avctx, pkt);
-        // In particular, we don't expect AVERROR(EAGAIN), because we read all
-        // decoded frames with avcodec_receive_frame() until done.
-        if (ret < 0 && ret != AVERROR_EOF)
-            return ret;
-    }
-
-    ret = avcodec_receive_frame(avctx, frame);
-    if (ret < 0 && ret != AVERROR(EAGAIN))
-        return ret;
-    if (ret >= 0) {
-        if (ist->want_frame_data) {
-            FrameData *fd;
-
-            av_assert0(!frame->opaque_ref);
-            frame->opaque_ref = av_buffer_allocz(sizeof(*fd));
-            if (!frame->opaque_ref) {
-                av_frame_unref(frame);
-                return AVERROR(ENOMEM);
-            }
-            fd      = (FrameData*)frame->opaque_ref->data;
-            fd->pts = frame->pts;
-            fd->tb  = avctx->pkt_timebase;
-            fd->idx = avctx->frame_num - 1;
-        }
-
-        frame->time_base = avctx->pkt_timebase;
-
-        *got_frame = 1;
-    }
-
-    return 0;
-}
-
-static int send_frame_to_filters(InputStream *ist, AVFrame *decoded_frame)
-{
-    int i, ret;
-
-    av_assert1(ist->nb_filters > 0); /* ensure ret is initialized */
-    for (i = 0; i < ist->nb_filters; i++) {
-        ret = ifilter_send_frame(ist->filters[i], decoded_frame, i < ist->nb_filters - 1);
-        if (ret == AVERROR_EOF)
-            ret = 0; /* ignore */
-        if (ret < 0) {
-            av_log(NULL, AV_LOG_ERROR,
-                   "Failed to inject frame into filter network: %s\n", av_err2str(ret));
-            break;
-        }
-    }
-    return ret;
-}
-
-static AVRational audio_samplerate_update(InputStream *ist, const AVFrame *frame)
-{
-    const int prev = ist->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)
-        goto finish;
-
-    gcd  = av_gcd(prev, sr);
-
-    if (prev / gcd >= INT_MAX / sr) {
-        av_log(ist, AV_LOG_WARNING,
-               "Audio timestamps cannot be represented exactly after "
-               "sample rate change: %d -> %d\n", prev, sr);
-
-        // LCM of 192000, 44100, allows to represent all common samplerates
-        tb_new = (AVRational){ 1, 28224000 };
-    } else
-        tb_new = (AVRational){ 1, prev / gcd * sr };
-
-    // keep the frame timebase if it is strictly better than
-    // the samplerate-defined one
-    if (frame->time_base.num == 1 && frame->time_base.den > tb_new.den &&
-        !(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);
-
-    ist->last_frame_tb          = tb_new;
-    ist->last_frame_sample_rate = frame->sample_rate;
-
-finish:
-    return ist->last_frame_tb;
-}
-
-static void audio_ts_process(InputStream *ist, AVFrame *frame)
-{
-    AVRational tb_filter = (AVRational){1, frame->sample_rate};
-    AVRational tb;
-    int64_t pts_pred;
-
-    // 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;
-
-    if (frame->pts == AV_NOPTS_VALUE) {
-        frame->pts = pts_pred;
-        frame->time_base = tb;
-    } else if (ist->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;
-    }
-
-    frame->pts = av_rescale_delta(frame->time_base, frame->pts,
-                                  tb, frame->nb_samples,
-                                  &ist->filter_in_rescale_delta_last, tb);
-
-    ist->last_frame_pts          = frame->pts;
-    ist->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);
-    frame->duration  = frame->nb_samples;
-    frame->time_base = tb_filter;
-}
-
-static int decode_audio(InputStream *ist, const AVPacket *pkt, int *got_output,
-                        int *decode_failed)
-{
-    AVFrame *decoded_frame = ist->decoded_frame;
-    AVCodecContext *avctx = ist->dec_ctx;
-    int ret, err = 0;
-
-    update_benchmark(NULL);
-    ret = decode(ist, avctx, decoded_frame, got_output, pkt);
-    update_benchmark("decode_audio %d.%d", ist->file_index, ist->st->index);
-    if (ret < 0)
-        *decode_failed = 1;
-
-    if (ret != AVERROR_EOF)
-        check_decode_result(ist, got_output, ret);
-
-    if (!*got_output || ret < 0)
-        return ret;
-
-    ist->samples_decoded += decoded_frame->nb_samples;
-    ist->frames_decoded++;
-
-    audio_ts_process(ist, decoded_frame);
-
-    ist->nb_samples = decoded_frame->nb_samples;
-    err = send_frame_to_filters(ist, decoded_frame);
-
-    av_frame_unref(decoded_frame);
-    return err < 0 ? err : ret;
-}
-
-static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *frame)
-{
-    const InputFile   *ifile = input_files[ist->file_index];
-    int64_t codec_duration = 0;
-
-    // XXX lavf currently makes up frame durations when they are not provided by
-    // the container. As there is no way to reliably distinguish real container
-    // durations from the fake made-up ones, we use heuristics based on whether
-    // the container has timestamps. Eventually lavf should stop making up
-    // durations, then this should be simplified.
-
-    // prefer frame duration for containers with timestamps
-    if (frame->duration > 0 && (!ifile->format_nots || ist->framerate.num))
-        return frame->duration;
-
-    if (ist->dec_ctx->framerate.den && ist->dec_ctx->framerate.num) {
-        int fields = frame->repeat_pict + 2;
-        AVRational field_rate = av_mul_q(ist->dec_ctx->framerate,
-                                         (AVRational){ 2, 1 });
-        codec_duration = av_rescale_q(fields, av_inv_q(field_rate),
-                                      frame->time_base);
-    }
-
-    // prefer codec-layer duration for containers without timestamps
-    if (codec_duration > 0 && ifile->format_nots)
-        return codec_duration;
-
-    // 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;
-
-    // try frame/codec duration
-    if (frame->duration > 0)
-        return frame->duration;
-    if (codec_duration > 0)
-        return codec_duration;
-
-    // try average framerate
-    if (ist->st->avg_frame_rate.num && ist->st->avg_frame_rate.den) {
-        int64_t d = av_rescale_q(1, av_inv_q(ist->st->avg_frame_rate),
-                                 frame->time_base);
-        if (d > 0)
-            return d;
-    }
-
-    // last resort is last frame's estimated duration, and 1
-    return FFMAX(ist->last_frame_duration_est, 1);
-}
-
-static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
-                        int eof, int *decode_failed)
-{
-    AVFrame *frame = ist->decoded_frame;
-    int ret = 0, err = 0;
-
-    // With fate-indeo3-2, we're getting 0-sized packets before EOF for some
-    // reason. This seems like a semi-critical bug. Don't trigger EOF, and
-    // skip the packet.
-    if (!eof && pkt && pkt->size == 0)
-        return 0;
-
-    update_benchmark(NULL);
-    ret = decode(ist, ist->dec_ctx, frame, got_output, pkt);
-    update_benchmark("decode_video %d.%d", ist->file_index, ist->st->index);
-    if (ret < 0)
-        *decode_failed = 1;
-
-    // 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) {
-        if (ist->dec_ctx->codec_id == AV_CODEC_ID_H264) {
-            ist->par->video_delay = ist->dec_ctx->has_b_frames;
-        } else
-            av_log(ist->dec_ctx, AV_LOG_WARNING,
-                   "video_delay is larger in decoder than demuxer %d > %d.\n"
-                   "If you want to help, upload a sample "
-                   "of this file to https://streams.videolan.org/upload/ "
-                   "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)\n",
-                   ist->dec_ctx->has_b_frames,
-                   ist->par->video_delay);
-    }
-
-    if (ret != AVERROR_EOF)
-        check_decode_result(ist, got_output, ret);
-
-    if (*got_output && ret >= 0) {
-        if (ist->dec_ctx->width  != frame->width ||
-            ist->dec_ctx->height != frame->height ||
-            ist->dec_ctx->pix_fmt != frame->format) {
-            av_log(NULL, AV_LOG_DEBUG, "Frame parameters mismatch context %d,%d,%d != %d,%d,%d\n",
-                frame->width,
-                frame->height,
-                frame->format,
-                ist->dec_ctx->width,
-                ist->dec_ctx->height,
-                ist->dec_ctx->pix_fmt);
-        }
-    }
-
-    if (!*got_output || ret < 0)
-        return ret;
-
-    if(ist->top_field_first>=0)
-        frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
-
-    ist->frames_decoded++;
-
-    if (ist->hwaccel_retrieve_data && frame->format == ist->hwaccel_pix_fmt) {
-        err = ist->hwaccel_retrieve_data(ist->dec_ctx, frame);
-        if (err < 0)
-            goto fail;
-    }
-
-    frame->pts = frame->best_effort_timestamp;
-
-    // forced fixed framerate
-    if (ist->framerate.num) {
-        frame->pts       = AV_NOPTS_VALUE;
-        frame->duration  = 1;
-        frame->time_base = av_inv_q(ist->framerate);
-    }
-
-    // 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;
-
-    // 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;
-
-    if (debug_ts) {
-        av_log(ist, AV_LOG_INFO,
-               "decoder -> pts:%s pts_time:%s "
-               "pkt_dts:%s pkt_dts_time:%s "
-               "duration:%s duration_time:%s "
-               "keyframe:%d frame_type:%d time_base:%d/%d\n",
-               av_ts2str(frame->pts),
-               av_ts2timestr(frame->pts, &frame->time_base),
-               av_ts2str(frame->pkt_dts),
-               av_ts2timestr(frame->pkt_dts, &frame->time_base),
-               av_ts2str(frame->duration),
-               av_ts2timestr(frame->duration, &frame->time_base),
-               !!(frame->flags & AV_FRAME_FLAG_KEY), frame->pict_type,
-               frame->time_base.num, frame->time_base.den);
-    }
-
-    if (ist->st->sample_aspect_ratio.num)
-        frame->sample_aspect_ratio = ist->st->sample_aspect_ratio;
-
-    err = send_frame_to_filters(ist, frame);
-
-fail:
-    av_frame_unref(frame);
-    return err < 0 ? err : ret;
-}
-
-static int process_subtitle(InputStream *ist, AVSubtitle *subtitle, int *got_output)
-{
-    int ret = 0;
-    int free_sub = 1;
-
-    if (ist->fix_sub_duration) {
-        int end = 1;
-        if (ist->prev_sub.got_output) {
-            end = av_rescale(subtitle->pts - ist->prev_sub.subtitle.pts,
-                             1000, AV_TIME_BASE);
-            if (end < ist->prev_sub.subtitle.end_display_time) {
-                av_log(NULL, AV_LOG_DEBUG,
-                       "Subtitle duration reduced from %"PRId32" to %d%s\n",
-                       ist->prev_sub.subtitle.end_display_time, end,
-                       end <= 0 ? ", dropping it" : "");
-                ist->prev_sub.subtitle.end_display_time = end;
-            }
-        }
-        FFSWAP(int,        *got_output, ist->prev_sub.got_output);
-        FFSWAP(int,        ret,         ist->prev_sub.ret);
-        FFSWAP(AVSubtitle, *subtitle,   ist->prev_sub.subtitle);
-        if (end <= 0)
-            goto out;
-    }
-
-    if (!*got_output)
-        return ret;
-
-    if (ist->sub2video.frame) {
-        sub2video_update(ist, INT64_MIN, subtitle);
-    } else if (ist->nb_filters) {
-        if (!ist->sub2video.sub_queue)
-            ist->sub2video.sub_queue = av_fifo_alloc2(8, sizeof(AVSubtitle), AV_FIFO_FLAG_AUTO_GROW);
-        if (!ist->sub2video.sub_queue)
-            report_and_exit(AVERROR(ENOMEM));
-
-        ret = av_fifo_write(ist->sub2video.sub_queue, subtitle, 1);
-        if (ret < 0)
-            exit_program(1);
-        free_sub = 0;
-    }
-
-    if (!subtitle->num_rects)
-        goto out;
-
-    for (int oidx = 0; oidx < ist->nb_outputs; oidx++) {
-        OutputStream *ost = ist->outputs[oidx];
-        if (!ost->enc || ost->type != AVMEDIA_TYPE_SUBTITLE)
-            continue;
-
-        enc_subtitle(output_files[ost->file_index], ost, subtitle);
-    }
-
-out:
-    if (free_sub)
-        avsubtitle_free(subtitle);
-    return ret;
-}
-
 static int copy_av_subtitle(AVSubtitle *dst, AVSubtitle *src)
 {
     int ret = AVERROR_BUG;
@@ -1309,115 +884,6 @@ int trigger_fix_sub_duration_heartbeat(OutputStream *ost, const AVPacket *pkt)
     return 0;
 }
 
-static int transcode_subtitles(InputStream *ist, const AVPacket *pkt,
-                               int *got_output, int *decode_failed)
-{
-    AVSubtitle subtitle;
-    int ret = avcodec_decode_subtitle2(ist->dec_ctx,
-                                       &subtitle, got_output, pkt);
-
-    check_decode_result(ist, got_output, ret);
-
-    if (ret < 0 || !*got_output) {
-        *decode_failed = 1;
-        if (!pkt->size)
-            sub2video_flush(ist);
-        return ret;
-    }
-
-    ist->frames_decoded++;
-
-    return process_subtitle(ist, &subtitle, got_output);
-}
-
-static int send_filter_eof(InputStream *ist)
-{
-    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);
-        if (ret < 0)
-            return ret;
-    }
-    return 0;
-}
-
-static int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
-{
-    AVPacket *avpkt = ist->pkt;
-    int ret, repeating = 0;
-
-    if (pkt) {
-        av_packet_unref(avpkt);
-        ret = av_packet_ref(avpkt, pkt);
-        if (ret < 0)
-            return ret;
-    }
-
-    // while we have more to decode or while the decoder did output something on EOF
-    while (1) {
-        int got_output = 0;
-        int decode_failed = 0;
-
-        switch (ist->par->codec_type) {
-        case AVMEDIA_TYPE_AUDIO:
-            ret = decode_audio    (ist, repeating ? NULL : avpkt, &got_output,
-                                   &decode_failed);
-            av_packet_unref(avpkt);
-            break;
-        case AVMEDIA_TYPE_VIDEO:
-            ret = decode_video    (ist, repeating ? NULL : avpkt, &got_output, !pkt,
-                                   &decode_failed);
-
-            av_packet_unref(avpkt);
-            break;
-        case AVMEDIA_TYPE_SUBTITLE:
-            if (repeating)
-                break;
-            ret = transcode_subtitles(ist, avpkt, &got_output, &decode_failed);
-            if (!pkt && ret >= 0)
-                ret = AVERROR_EOF;
-            av_packet_unref(avpkt);
-            break;
-        default: av_assert0(0);
-        }
-
-        if (ret == AVERROR_EOF) {
-            /* after flushing, send an EOF on all the filter inputs attached to the stream */
-            /* except when looping we need to flush but not to send an EOF */
-            if (!no_eof) {
-                ret = send_filter_eof(ist);
-                if (ret < 0) {
-                    av_log(NULL, AV_LOG_FATAL, "Error marking filters as finished\n");
-                    exit_program(1);
-                }
-            }
-
-            return AVERROR_EOF;
-        }
-
-        if (ret < 0) {
-            if (decode_failed) {
-                av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",
-                       ist->file_index, ist->st->index, av_err2str(ret));
-            } else {
-                av_log(NULL, AV_LOG_FATAL, "Error while processing the decoded "
-                       "data for stream #%d:%d\n", ist->file_index, ist->st->index);
-            }
-            if (!decode_failed || exit_on_error)
-                exit_program(1);
-            return ret;
-        }
-
-        if (!got_output)
-            return 0;
-
-        repeating = 1;
-    }
-}
-
 /* pkt = NULL means EOF (needed to flush decoder buffers) */
 static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
 {
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 87e684a147..45be3b1823 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -811,6 +811,17 @@ int hwaccel_decode_init(AVCodecContext *avctx);
 
 int dec_open(InputStream *ist);
 
+/**
+ * Submit a packet for decoding
+ *
+ * When pkt==NULL and no_eof=0, there will be no more input. Flush decoders and
+ * mark all downstreams as finished.
+ *
+ * When pkt==NULL and no_eof=1, the stream was reset (e.g. after a seek). Flush
+ * decoders and await further input.
+ */
+int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof);
+
 int enc_alloc(Encoder **penc, const AVCodec *codec);
 void enc_free(Encoder **penc);
 
@@ -885,6 +896,7 @@ OutputStream *ost_iter(OutputStream *prev);
 
 void close_output_stream(OutputStream *ost);
 int trigger_fix_sub_duration_heartbeat(OutputStream *ost, const AVPacket *pkt);
+int process_subtitle(InputStream *ist, AVSubtitle *subtitle, int *got_output);
 void update_benchmark(const char *fmt, ...);
 
 /**
diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index 658e7418e9..30fe75d8a6 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -16,17 +16,555 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/avassert.h"
 #include "libavutil/dict.h"
 #include "libavutil/error.h"
 #include "libavutil/log.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/pixfmt.h"
+#include "libavutil/timestamp.h"
 
 #include "libavcodec/avcodec.h"
 #include "libavcodec/codec.h"
 
+#include "libavfilter/buffersrc.h"
+
 #include "ffmpeg.h"
 
+static void check_decode_result(InputStream *ist, int *got_output, int ret)
+{
+    if (ret < 0)
+        ist->decode_errors++;
+
+    if (ret < 0 && exit_on_error)
+        exit_program(1);
+
+    if (*got_output && ist->dec_ctx->codec_type != AVMEDIA_TYPE_SUBTITLE) {
+        if (ist->decoded_frame->decode_error_flags || (ist->decoded_frame->flags & AV_FRAME_FLAG_CORRUPT)) {
+            av_log(ist, exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING,
+                   "corrupt decoded frame\n");
+            if (exit_on_error)
+                exit_program(1);
+        }
+    }
+}
+
+// This does not quite work like avcodec_decode_audio4/avcodec_decode_video2.
+// There is the following difference: if you got a frame, you must call
+// it again with pkt=NULL. pkt==NULL is treated differently from pkt->size==0
+// (pkt==NULL means get more output, pkt->size==0 is a flush/drain packet)
+static int decode(InputStream *ist, AVCodecContext *avctx,
+                  AVFrame *frame, int *got_frame, const AVPacket *pkt)
+{
+    int ret;
+
+    *got_frame = 0;
+
+    if (pkt) {
+        ret = avcodec_send_packet(avctx, pkt);
+        // In particular, we don't expect AVERROR(EAGAIN), because we read all
+        // decoded frames with avcodec_receive_frame() until done.
+        if (ret < 0 && ret != AVERROR_EOF)
+            return ret;
+    }
+
+    ret = avcodec_receive_frame(avctx, frame);
+    if (ret < 0 && ret != AVERROR(EAGAIN))
+        return ret;
+    if (ret >= 0) {
+        if (ist->want_frame_data) {
+            FrameData *fd;
+
+            av_assert0(!frame->opaque_ref);
+            frame->opaque_ref = av_buffer_allocz(sizeof(*fd));
+            if (!frame->opaque_ref) {
+                av_frame_unref(frame);
+                return AVERROR(ENOMEM);
+            }
+            fd      = (FrameData*)frame->opaque_ref->data;
+            fd->pts = frame->pts;
+            fd->tb  = avctx->pkt_timebase;
+            fd->idx = avctx->frame_num - 1;
+        }
+
+        frame->time_base = avctx->pkt_timebase;
+
+        *got_frame = 1;
+    }
+
+    return 0;
+}
+
+static int send_frame_to_filters(InputStream *ist, AVFrame *decoded_frame)
+{
+    int i, ret;
+
+    av_assert1(ist->nb_filters > 0); /* ensure ret is initialized */
+    for (i = 0; i < ist->nb_filters; i++) {
+        ret = ifilter_send_frame(ist->filters[i], decoded_frame, i < ist->nb_filters - 1);
+        if (ret == AVERROR_EOF)
+            ret = 0; /* ignore */
+        if (ret < 0) {
+            av_log(NULL, AV_LOG_ERROR,
+                   "Failed to inject frame into filter network: %s\n", av_err2str(ret));
+            break;
+        }
+    }
+    return ret;
+}
+
+static AVRational audio_samplerate_update(InputStream *ist, const AVFrame *frame)
+{
+    const int prev = ist->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)
+        goto finish;
+
+    gcd  = av_gcd(prev, sr);
+
+    if (prev / gcd >= INT_MAX / sr) {
+        av_log(ist, AV_LOG_WARNING,
+               "Audio timestamps cannot be represented exactly after "
+               "sample rate change: %d -> %d\n", prev, sr);
+
+        // LCM of 192000, 44100, allows to represent all common samplerates
+        tb_new = (AVRational){ 1, 28224000 };
+    } else
+        tb_new = (AVRational){ 1, prev / gcd * sr };
+
+    // keep the frame timebase if it is strictly better than
+    // the samplerate-defined one
+    if (frame->time_base.num == 1 && frame->time_base.den > tb_new.den &&
+        !(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);
+
+    ist->last_frame_tb          = tb_new;
+    ist->last_frame_sample_rate = frame->sample_rate;
+
+finish:
+    return ist->last_frame_tb;
+}
+
+static void audio_ts_process(InputStream *ist, AVFrame *frame)
+{
+    AVRational tb_filter = (AVRational){1, frame->sample_rate};
+    AVRational tb;
+    int64_t pts_pred;
+
+    // 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;
+
+    if (frame->pts == AV_NOPTS_VALUE) {
+        frame->pts = pts_pred;
+        frame->time_base = tb;
+    } else if (ist->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;
+    }
+
+    frame->pts = av_rescale_delta(frame->time_base, frame->pts,
+                                  tb, frame->nb_samples,
+                                  &ist->filter_in_rescale_delta_last, tb);
+
+    ist->last_frame_pts          = frame->pts;
+    ist->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);
+    frame->duration  = frame->nb_samples;
+    frame->time_base = tb_filter;
+}
+
+static int decode_audio(InputStream *ist, const AVPacket *pkt, int *got_output,
+                        int *decode_failed)
+{
+    AVFrame *decoded_frame = ist->decoded_frame;
+    AVCodecContext *avctx = ist->dec_ctx;
+    int ret, err = 0;
+
+    update_benchmark(NULL);
+    ret = decode(ist, avctx, decoded_frame, got_output, pkt);
+    update_benchmark("decode_audio %d.%d", ist->file_index, ist->st->index);
+    if (ret < 0)
+        *decode_failed = 1;
+
+    if (ret != AVERROR_EOF)
+        check_decode_result(ist, got_output, ret);
+
+    if (!*got_output || ret < 0)
+        return ret;
+
+    ist->samples_decoded += decoded_frame->nb_samples;
+    ist->frames_decoded++;
+
+    audio_ts_process(ist, decoded_frame);
+
+    ist->nb_samples = decoded_frame->nb_samples;
+    err = send_frame_to_filters(ist, decoded_frame);
+
+    av_frame_unref(decoded_frame);
+    return err < 0 ? err : ret;
+}
+
+static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *frame)
+{
+    const InputFile   *ifile = input_files[ist->file_index];
+    int64_t codec_duration = 0;
+
+    // XXX lavf currently makes up frame durations when they are not provided by
+    // the container. As there is no way to reliably distinguish real container
+    // durations from the fake made-up ones, we use heuristics based on whether
+    // the container has timestamps. Eventually lavf should stop making up
+    // durations, then this should be simplified.
+
+    // prefer frame duration for containers with timestamps
+    if (frame->duration > 0 && (!ifile->format_nots || ist->framerate.num))
+        return frame->duration;
+
+    if (ist->dec_ctx->framerate.den && ist->dec_ctx->framerate.num) {
+        int fields = frame->repeat_pict + 2;
+        AVRational field_rate = av_mul_q(ist->dec_ctx->framerate,
+                                         (AVRational){ 2, 1 });
+        codec_duration = av_rescale_q(fields, av_inv_q(field_rate),
+                                      frame->time_base);
+    }
+
+    // prefer codec-layer duration for containers without timestamps
+    if (codec_duration > 0 && ifile->format_nots)
+        return codec_duration;
+
+    // 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;
+
+    // try frame/codec duration
+    if (frame->duration > 0)
+        return frame->duration;
+    if (codec_duration > 0)
+        return codec_duration;
+
+    // try average framerate
+    if (ist->st->avg_frame_rate.num && ist->st->avg_frame_rate.den) {
+        int64_t d = av_rescale_q(1, av_inv_q(ist->st->avg_frame_rate),
+                                 frame->time_base);
+        if (d > 0)
+            return d;
+    }
+
+    // last resort is last frame's estimated duration, and 1
+    return FFMAX(ist->last_frame_duration_est, 1);
+}
+
+static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
+                        int eof, int *decode_failed)
+{
+    AVFrame *frame = ist->decoded_frame;
+    int ret = 0, err = 0;
+
+    // With fate-indeo3-2, we're getting 0-sized packets before EOF for some
+    // reason. This seems like a semi-critical bug. Don't trigger EOF, and
+    // skip the packet.
+    if (!eof && pkt && pkt->size == 0)
+        return 0;
+
+    update_benchmark(NULL);
+    ret = decode(ist, ist->dec_ctx, frame, got_output, pkt);
+    update_benchmark("decode_video %d.%d", ist->file_index, ist->st->index);
+    if (ret < 0)
+        *decode_failed = 1;
+
+    // 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) {
+        if (ist->dec_ctx->codec_id == AV_CODEC_ID_H264) {
+            ist->par->video_delay = ist->dec_ctx->has_b_frames;
+        } else
+            av_log(ist->dec_ctx, AV_LOG_WARNING,
+                   "video_delay is larger in decoder than demuxer %d > %d.\n"
+                   "If you want to help, upload a sample "
+                   "of this file to https://streams.videolan.org/upload/ "
+                   "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)\n",
+                   ist->dec_ctx->has_b_frames,
+                   ist->par->video_delay);
+    }
+
+    if (ret != AVERROR_EOF)
+        check_decode_result(ist, got_output, ret);
+
+    if (*got_output && ret >= 0) {
+        if (ist->dec_ctx->width  != frame->width ||
+            ist->dec_ctx->height != frame->height ||
+            ist->dec_ctx->pix_fmt != frame->format) {
+            av_log(NULL, AV_LOG_DEBUG, "Frame parameters mismatch context %d,%d,%d != %d,%d,%d\n",
+                frame->width,
+                frame->height,
+                frame->format,
+                ist->dec_ctx->width,
+                ist->dec_ctx->height,
+                ist->dec_ctx->pix_fmt);
+        }
+    }
+
+    if (!*got_output || ret < 0)
+        return ret;
+
+    if(ist->top_field_first>=0)
+        frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
+
+    ist->frames_decoded++;
+
+    if (ist->hwaccel_retrieve_data && frame->format == ist->hwaccel_pix_fmt) {
+        err = ist->hwaccel_retrieve_data(ist->dec_ctx, frame);
+        if (err < 0)
+            goto fail;
+    }
+
+    frame->pts = frame->best_effort_timestamp;
+
+    // forced fixed framerate
+    if (ist->framerate.num) {
+        frame->pts       = AV_NOPTS_VALUE;
+        frame->duration  = 1;
+        frame->time_base = av_inv_q(ist->framerate);
+    }
+
+    // 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;
+
+    // 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;
+
+    if (debug_ts) {
+        av_log(ist, AV_LOG_INFO,
+               "decoder -> pts:%s pts_time:%s "
+               "pkt_dts:%s pkt_dts_time:%s "
+               "duration:%s duration_time:%s "
+               "keyframe:%d frame_type:%d time_base:%d/%d\n",
+               av_ts2str(frame->pts),
+               av_ts2timestr(frame->pts, &frame->time_base),
+               av_ts2str(frame->pkt_dts),
+               av_ts2timestr(frame->pkt_dts, &frame->time_base),
+               av_ts2str(frame->duration),
+               av_ts2timestr(frame->duration, &frame->time_base),
+               !!(frame->flags & AV_FRAME_FLAG_KEY), frame->pict_type,
+               frame->time_base.num, frame->time_base.den);
+    }
+
+    if (ist->st->sample_aspect_ratio.num)
+        frame->sample_aspect_ratio = ist->st->sample_aspect_ratio;
+
+    err = send_frame_to_filters(ist, frame);
+
+fail:
+    av_frame_unref(frame);
+    return err < 0 ? err : ret;
+}
+
+static void sub2video_flush(InputStream *ist)
+{
+    int i;
+    int ret;
+
+    if (ist->sub2video.end_pts < INT64_MAX)
+        sub2video_update(ist, INT64_MAX, NULL);
+    for (i = 0; i < ist->nb_filters; i++) {
+        ret = av_buffersrc_add_frame(ist->filters[i]->filter, NULL);
+        if (ret != AVERROR_EOF && ret < 0)
+            av_log(NULL, AV_LOG_WARNING, "Flush the frame error.\n");
+    }
+}
+
+int process_subtitle(InputStream *ist, AVSubtitle *subtitle, int *got_output)
+{
+    int ret = 0;
+    int free_sub = 1;
+
+    if (ist->fix_sub_duration) {
+        int end = 1;
+        if (ist->prev_sub.got_output) {
+            end = av_rescale(subtitle->pts - ist->prev_sub.subtitle.pts,
+                             1000, AV_TIME_BASE);
+            if (end < ist->prev_sub.subtitle.end_display_time) {
+                av_log(NULL, AV_LOG_DEBUG,
+                       "Subtitle duration reduced from %"PRId32" to %d%s\n",
+                       ist->prev_sub.subtitle.end_display_time, end,
+                       end <= 0 ? ", dropping it" : "");
+                ist->prev_sub.subtitle.end_display_time = end;
+            }
+        }
+        FFSWAP(int,        *got_output, ist->prev_sub.got_output);
+        FFSWAP(int,        ret,         ist->prev_sub.ret);
+        FFSWAP(AVSubtitle, *subtitle,   ist->prev_sub.subtitle);
+        if (end <= 0)
+            goto out;
+    }
+
+    if (!*got_output)
+        return ret;
+
+    if (ist->sub2video.frame) {
+        sub2video_update(ist, INT64_MIN, subtitle);
+    } else if (ist->nb_filters) {
+        if (!ist->sub2video.sub_queue)
+            ist->sub2video.sub_queue = av_fifo_alloc2(8, sizeof(AVSubtitle), AV_FIFO_FLAG_AUTO_GROW);
+        if (!ist->sub2video.sub_queue)
+            report_and_exit(AVERROR(ENOMEM));
+
+        ret = av_fifo_write(ist->sub2video.sub_queue, subtitle, 1);
+        if (ret < 0)
+            exit_program(1);
+        free_sub = 0;
+    }
+
+    if (!subtitle->num_rects)
+        goto out;
+
+    for (int oidx = 0; oidx < ist->nb_outputs; oidx++) {
+        OutputStream *ost = ist->outputs[oidx];
+        if (!ost->enc || ost->type != AVMEDIA_TYPE_SUBTITLE)
+            continue;
+
+        enc_subtitle(output_files[ost->file_index], ost, subtitle);
+    }
+
+out:
+    if (free_sub)
+        avsubtitle_free(subtitle);
+    return ret;
+}
+
+static int transcode_subtitles(InputStream *ist, const AVPacket *pkt,
+                               int *got_output, int *decode_failed)
+{
+    AVSubtitle subtitle;
+    int ret = avcodec_decode_subtitle2(ist->dec_ctx,
+                                       &subtitle, got_output, pkt);
+
+    check_decode_result(ist, got_output, ret);
+
+    if (ret < 0 || !*got_output) {
+        *decode_failed = 1;
+        if (!pkt->size)
+            sub2video_flush(ist);
+        return ret;
+    }
+
+    ist->frames_decoded++;
+
+    return process_subtitle(ist, &subtitle, got_output);
+}
+
+static int send_filter_eof(InputStream *ist)
+{
+    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);
+        if (ret < 0)
+            return ret;
+    }
+    return 0;
+}
+
+int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
+{
+    AVPacket *avpkt = ist->pkt;
+    int ret, repeating = 0;
+
+    if (pkt) {
+        av_packet_unref(avpkt);
+        ret = av_packet_ref(avpkt, pkt);
+        if (ret < 0)
+            return ret;
+    }
+
+    // while we have more to decode or while the decoder did output something on EOF
+    while (1) {
+        int got_output = 0;
+        int decode_failed = 0;
+
+        switch (ist->par->codec_type) {
+        case AVMEDIA_TYPE_AUDIO:
+            ret = decode_audio    (ist, repeating ? NULL : avpkt, &got_output,
+                                   &decode_failed);
+            av_packet_unref(avpkt);
+            break;
+        case AVMEDIA_TYPE_VIDEO:
+            ret = decode_video    (ist, repeating ? NULL : avpkt, &got_output, !pkt,
+                                   &decode_failed);
+
+            av_packet_unref(avpkt);
+            break;
+        case AVMEDIA_TYPE_SUBTITLE:
+            if (repeating)
+                break;
+            ret = transcode_subtitles(ist, avpkt, &got_output, &decode_failed);
+            if (!pkt && ret >= 0)
+                ret = AVERROR_EOF;
+            av_packet_unref(avpkt);
+            break;
+        default: av_assert0(0);
+        }
+
+        if (ret == AVERROR_EOF) {
+            /* after flushing, send an EOF on all the filter inputs attached to the stream */
+            /* except when looping we need to flush but not to send an EOF */
+            if (!no_eof) {
+                ret = send_filter_eof(ist);
+                if (ret < 0) {
+                    av_log(NULL, AV_LOG_FATAL, "Error marking filters as finished\n");
+                    exit_program(1);
+                }
+            }
+
+            return AVERROR_EOF;
+        }
+
+        if (ret < 0) {
+            if (decode_failed) {
+                av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",
+                       ist->file_index, ist->st->index, av_err2str(ret));
+            } else {
+                av_log(NULL, AV_LOG_FATAL, "Error while processing the decoded "
+                       "data for stream #%d:%d\n", ist->file_index, ist->st->index);
+            }
+            if (!decode_failed || exit_on_error)
+                exit_program(1);
+            return ret;
+        }
+
+        if (!got_output)
+            return 0;
+
+        repeating = 1;
+    }
+}
+
 static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts)
 {
     InputStream *ist = s->opaque;
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 30/36] fftools/ffmpeg_dec: deobfuscate subtitle decoding
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (27 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 29/36] fftools/ffmpeg: move decoding code to ffmpeg_dec Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 20:15   ` Michael Niedermayer
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 31/36] fftools/ffmpeg_dec: restructure audio/video decoding loop Anton Khirnov
                   ` (5 subsequent siblings)
  34 siblings, 1 reply; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

It is currently handled in the same loop as audio and video, but this
obscures the actual flow, because only one iteration is ever performed
for subtitles.

Also, avoid a pointless packet reference.
---
 fftools/ffmpeg_dec.c | 34 ++++++++++++++++++----------------
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index 30fe75d8a6..646b587f9e 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -456,25 +456,31 @@ out:
     return ret;
 }
 
-static int transcode_subtitles(InputStream *ist, const AVPacket *pkt,
-                               int *got_output, int *decode_failed)
+static int transcode_subtitles(InputStream *ist, const AVPacket *pkt)
 {
     AVSubtitle subtitle;
+    int got_output;
     int ret = avcodec_decode_subtitle2(ist->dec_ctx,
-                                       &subtitle, got_output, pkt);
+                                       &subtitle, &got_output, pkt);
 
-    check_decode_result(ist, got_output, ret);
+    if (ret < 0) {
+        av_log(ist, AV_LOG_ERROR, "Error decoding subtitles: %s\n",
+                av_err2str(ret));
+        if (exit_on_error)
+            exit_program(1);
+    }
 
-    if (ret < 0 || !*got_output) {
-        *decode_failed = 1;
+    check_decode_result(ist, &got_output, ret);
+
+    if (ret < 0 || !got_output) {
         if (!pkt->size)
             sub2video_flush(ist);
-        return ret;
+        return ret < 0 ? ret : AVERROR_EOF;
     }
 
     ist->frames_decoded++;
 
-    return process_subtitle(ist, &subtitle, got_output);
+    return process_subtitle(ist, &subtitle, &got_output);
 }
 
 static int send_filter_eof(InputStream *ist)
@@ -493,9 +499,13 @@ static int send_filter_eof(InputStream *ist)
 
 int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
 {
+    AVCodecContext *dec = ist->dec_ctx;
     AVPacket *avpkt = ist->pkt;
     int ret, repeating = 0;
 
+    if (dec->codec_type == AVMEDIA_TYPE_SUBTITLE)
+        return transcode_subtitles(ist, pkt ? pkt : ist->pkt);
+
     if (pkt) {
         av_packet_unref(avpkt);
         ret = av_packet_ref(avpkt, pkt);
@@ -520,14 +530,6 @@ int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
 
             av_packet_unref(avpkt);
             break;
-        case AVMEDIA_TYPE_SUBTITLE:
-            if (repeating)
-                break;
-            ret = transcode_subtitles(ist, avpkt, &got_output, &decode_failed);
-            if (!pkt && ret >= 0)
-                ret = AVERROR_EOF;
-            av_packet_unref(avpkt);
-            break;
         default: av_assert0(0);
         }
 
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 31/36] fftools/ffmpeg_dec: restructure audio/video decoding loop
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (28 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 30/36] fftools/ffmpeg_dec: deobfuscate subtitle decoding Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 20:04   ` Michael Niedermayer
  2023-05-18  6:36   ` [FFmpeg-devel] [PATCH] " Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 32/36] fftools/ffmpeg: reindent after previous commit Anton Khirnov
                   ` (4 subsequent siblings)
  34 siblings, 2 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

It currently emulates the long-removed
avcodec_decode_audio4/avcodec_decode_video2 APIs, which obfuscates the
actual decoding flow. Restructure the decoding calls so that they
naturally follow the new avcodec_send_packet()/avcodec_receive_frame()
design.

This is not only significantly easier to read, but also shorter.
---
 fftools/ffmpeg_dec.c | 187 ++++++++++++++-----------------------------
 1 file changed, 61 insertions(+), 126 deletions(-)

diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index 646b587f9e..73f826c76a 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -31,7 +31,7 @@
 
 #include "ffmpeg.h"
 
-static void check_decode_result(InputStream *ist, int *got_output, int ret)
+static void check_decode_result(InputStream *ist, int got_output, int ret)
 {
     if (ret < 0)
         ist->decode_errors++;
@@ -39,7 +39,7 @@ static void check_decode_result(InputStream *ist, int *got_output, int ret)
     if (ret < 0 && exit_on_error)
         exit_program(1);
 
-    if (*got_output && ist->dec_ctx->codec_type != AVMEDIA_TYPE_SUBTITLE) {
+    if (got_output && ist->dec_ctx->codec_type != AVMEDIA_TYPE_SUBTITLE) {
         if (ist->decoded_frame->decode_error_flags || (ist->decoded_frame->flags & AV_FRAME_FLAG_CORRUPT)) {
             av_log(ist, exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING,
                    "corrupt decoded frame\n");
@@ -49,52 +49,6 @@ static void check_decode_result(InputStream *ist, int *got_output, int ret)
     }
 }
 
-// This does not quite work like avcodec_decode_audio4/avcodec_decode_video2.
-// There is the following difference: if you got a frame, you must call
-// it again with pkt=NULL. pkt==NULL is treated differently from pkt->size==0
-// (pkt==NULL means get more output, pkt->size==0 is a flush/drain packet)
-static int decode(InputStream *ist, AVCodecContext *avctx,
-                  AVFrame *frame, int *got_frame, const AVPacket *pkt)
-{
-    int ret;
-
-    *got_frame = 0;
-
-    if (pkt) {
-        ret = avcodec_send_packet(avctx, pkt);
-        // In particular, we don't expect AVERROR(EAGAIN), because we read all
-        // decoded frames with avcodec_receive_frame() until done.
-        if (ret < 0 && ret != AVERROR_EOF)
-            return ret;
-    }
-
-    ret = avcodec_receive_frame(avctx, frame);
-    if (ret < 0 && ret != AVERROR(EAGAIN))
-        return ret;
-    if (ret >= 0) {
-        if (ist->want_frame_data) {
-            FrameData *fd;
-
-            av_assert0(!frame->opaque_ref);
-            frame->opaque_ref = av_buffer_allocz(sizeof(*fd));
-            if (!frame->opaque_ref) {
-                av_frame_unref(frame);
-                return AVERROR(ENOMEM);
-            }
-            fd      = (FrameData*)frame->opaque_ref->data;
-            fd->pts = frame->pts;
-            fd->tb  = avctx->pkt_timebase;
-            fd->idx = avctx->frame_num - 1;
-        }
-
-        frame->time_base = avctx->pkt_timebase;
-
-        *got_frame = 1;
-    }
-
-    return 0;
-}
-
 static int send_frame_to_filters(InputStream *ist, AVFrame *decoded_frame)
 {
     int i, ret;
@@ -192,25 +146,10 @@ static void audio_ts_process(InputStream *ist, AVFrame *frame)
     frame->time_base = tb_filter;
 }
 
-static int decode_audio(InputStream *ist, const AVPacket *pkt, int *got_output,
-                        int *decode_failed)
+static int decode_audio(InputStream *ist, AVFrame *decoded_frame)
 {
-    AVFrame *decoded_frame = ist->decoded_frame;
-    AVCodecContext *avctx = ist->dec_ctx;
     int ret, err = 0;
 
-    update_benchmark(NULL);
-    ret = decode(ist, avctx, decoded_frame, got_output, pkt);
-    update_benchmark("decode_audio %d.%d", ist->file_index, ist->st->index);
-    if (ret < 0)
-        *decode_failed = 1;
-
-    if (ret != AVERROR_EOF)
-        check_decode_result(ist, got_output, ret);
-
-    if (!*got_output || ret < 0)
-        return ret;
-
     ist->samples_decoded += decoded_frame->nb_samples;
     ist->frames_decoded++;
 
@@ -274,24 +213,10 @@ static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *fr
     return FFMAX(ist->last_frame_duration_est, 1);
 }
 
-static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
-                        int eof, int *decode_failed)
+static int decode_video(InputStream *ist, AVFrame *frame)
 {
-    AVFrame *frame = ist->decoded_frame;
     int ret = 0, err = 0;
 
-    // With fate-indeo3-2, we're getting 0-sized packets before EOF for some
-    // reason. This seems like a semi-critical bug. Don't trigger EOF, and
-    // skip the packet.
-    if (!eof && pkt && pkt->size == 0)
-        return 0;
-
-    update_benchmark(NULL);
-    ret = decode(ist, ist->dec_ctx, frame, got_output, pkt);
-    update_benchmark("decode_video %d.%d", ist->file_index, ist->st->index);
-    if (ret < 0)
-        *decode_failed = 1;
-
     // 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) {
@@ -307,10 +232,6 @@ static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
                    ist->par->video_delay);
     }
 
-    if (ret != AVERROR_EOF)
-        check_decode_result(ist, got_output, ret);
-
-    if (*got_output && ret >= 0) {
         if (ist->dec_ctx->width  != frame->width ||
             ist->dec_ctx->height != frame->height ||
             ist->dec_ctx->pix_fmt != frame->format) {
@@ -322,10 +243,6 @@ static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
                 ist->dec_ctx->height,
                 ist->dec_ctx->pix_fmt);
         }
-    }
-
-    if (!*got_output || ret < 0)
-        return ret;
 
     if(ist->top_field_first>=0)
         frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
@@ -470,7 +387,7 @@ static int transcode_subtitles(InputStream *ist, const AVPacket *pkt)
             exit_program(1);
     }
 
-    check_decode_result(ist, &got_output, ret);
+    check_decode_result(ist, got_output, ret);
 
     if (ret < 0 || !got_output) {
         if (!pkt->size)
@@ -500,40 +417,44 @@ static int send_filter_eof(InputStream *ist)
 int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
 {
     AVCodecContext *dec = ist->dec_ctx;
-    AVPacket *avpkt = ist->pkt;
-    int ret, repeating = 0;
+    const char *type_desc = av_get_media_type_string(dec->codec_type);
+    int ret;
 
     if (dec->codec_type == AVMEDIA_TYPE_SUBTITLE)
         return transcode_subtitles(ist, pkt ? pkt : ist->pkt);
 
-    if (pkt) {
-        av_packet_unref(avpkt);
-        ret = av_packet_ref(avpkt, pkt);
-        if (ret < 0)
-            return ret;
+    // With fate-indeo3-2, we're getting 0-sized packets before EOF for some
+    // reason. This seems like a semi-critical bug. Don't trigger EOF, and
+    // skip the packet.
+    if (pkt && pkt->size == 0)
+        return 0;
+
+    ret = avcodec_send_packet(dec, pkt);
+    if (ret < 0 && !(ret == AVERROR_EOF && !pkt)) {
+        // In particular, we don't expect AVERROR(EAGAIN), because we read all
+        // decoded frames with avcodec_receive_frame() until done.
+        av_log(ist, AV_LOG_ERROR, "Error submitting %s to decoder: %s\n",
+               pkt ? "packet" : "EOF", av_err2str(ret));
+        if (exit_on_error)
+            exit_program(1);
+        return ret;
     }
 
-    // while we have more to decode or while the decoder did output something on EOF
     while (1) {
-        int got_output = 0;
-        int decode_failed = 0;
-
-        switch (ist->par->codec_type) {
-        case AVMEDIA_TYPE_AUDIO:
-            ret = decode_audio    (ist, repeating ? NULL : avpkt, &got_output,
-                                   &decode_failed);
-            av_packet_unref(avpkt);
-            break;
-        case AVMEDIA_TYPE_VIDEO:
-            ret = decode_video    (ist, repeating ? NULL : avpkt, &got_output, !pkt,
-                                   &decode_failed);
+        AVFrame *frame = ist->decoded_frame;
 
-            av_packet_unref(avpkt);
-            break;
-        default: av_assert0(0);
-        }
+        update_benchmark(NULL);
+        ret = avcodec_receive_frame(dec, frame);
+        update_benchmark("decode_%s %d.%d", type_desc,
+                         ist->file_index, ist->st->index);
 
-        if (ret == AVERROR_EOF) {
+        if (ret != AVERROR_EOF && ret != AVERROR(EAGAIN))
+            check_decode_result(ist, ret >= 0, ret);
+
+        if (ret == AVERROR(EAGAIN)) {
+            av_assert0(pkt); // should never happen during flushing
+            return 0;
+        } else if (ret == AVERROR_EOF) {
             /* after flushing, send an EOF on all the filter inputs attached to the stream */
             /* except when looping we need to flush but not to send an EOF */
             if (!no_eof) {
@@ -545,25 +466,39 @@ int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
             }
 
             return AVERROR_EOF;
+        } else if (ret < 0) {
+            av_log(ist, AV_LOG_ERROR, "Decoding error: %s\n", av_err2str(ret));
+            if (exit_on_error)
+                exit_program(1);
+            return ret;
         }
 
-        if (ret < 0) {
-            if (decode_failed) {
-                av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",
-                       ist->file_index, ist->st->index, av_err2str(ret));
-            } else {
-                av_log(NULL, AV_LOG_FATAL, "Error while processing the decoded "
-                       "data for stream #%d:%d\n", ist->file_index, ist->st->index);
+        if (ist->want_frame_data) {
+            FrameData *fd;
+
+            av_assert0(!frame->opaque_ref);
+            frame->opaque_ref = av_buffer_allocz(sizeof(*fd));
+            if (!frame->opaque_ref) {
+                av_frame_unref(frame);
+                report_and_exit(AVERROR(ENOMEM));
             }
-            if (!decode_failed || exit_on_error)
-                exit_program(1);
-            return ret;
+            fd      = (FrameData*)frame->opaque_ref->data;
+            fd->pts = frame->pts;
+            fd->tb  = dec->pkt_timebase;
+            fd->idx = dec->frame_num - 1;
         }
 
-        if (!got_output)
-            return 0;
+        frame->time_base = dec->pkt_timebase;
+
+        ret = dec->codec_type == AVMEDIA_TYPE_AUDIO ?
+                decode_audio(ist, frame)            :
+                decode_video(ist, frame);
 
-        repeating = 1;
+        if (ret < 0) {
+            av_log(NULL, AV_LOG_FATAL, "Error while processing the decoded "
+                   "data for stream #%d:%d\n", ist->file_index, ist->st->index);
+            exit_program(1);
+        }
     }
 }
 
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 32/36] fftools/ffmpeg: reindent after previous commit
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (29 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 31/36] fftools/ffmpeg_dec: restructure audio/video decoding loop Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 33/36] fftools/ffmpeg_dec: merge check_decode_result() into its callers Anton Khirnov
                   ` (3 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

---
 fftools/ffmpeg_dec.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index 73f826c76a..58bb7a7344 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -232,17 +232,17 @@ static int decode_video(InputStream *ist, AVFrame *frame)
                    ist->par->video_delay);
     }
 
-        if (ist->dec_ctx->width  != frame->width ||
-            ist->dec_ctx->height != frame->height ||
-            ist->dec_ctx->pix_fmt != frame->format) {
-            av_log(NULL, AV_LOG_DEBUG, "Frame parameters mismatch context %d,%d,%d != %d,%d,%d\n",
-                frame->width,
-                frame->height,
-                frame->format,
-                ist->dec_ctx->width,
-                ist->dec_ctx->height,
-                ist->dec_ctx->pix_fmt);
-        }
+    if (ist->dec_ctx->width  != frame->width ||
+        ist->dec_ctx->height != frame->height ||
+        ist->dec_ctx->pix_fmt != frame->format) {
+        av_log(NULL, AV_LOG_DEBUG, "Frame parameters mismatch context %d,%d,%d != %d,%d,%d\n",
+            frame->width,
+            frame->height,
+            frame->format,
+            ist->dec_ctx->width,
+            ist->dec_ctx->height,
+            ist->dec_ctx->pix_fmt);
+    }
 
     if(ist->top_field_first>=0)
         frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 33/36] fftools/ffmpeg_dec: merge check_decode_result() into its callers
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (30 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 32/36] fftools/ffmpeg: reindent after previous commit Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 34/36] fftools/ffmpeg_dec: deduplicate code in decode_audio/video() Anton Khirnov
                   ` (2 subsequent siblings)
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

Not only is this easier to read, this also makes the code shorter.
---
 fftools/ffmpeg_dec.c | 32 +++++++++-----------------------
 1 file changed, 9 insertions(+), 23 deletions(-)

diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index 58bb7a7344..79e9c04fc1 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -31,24 +31,6 @@
 
 #include "ffmpeg.h"
 
-static void check_decode_result(InputStream *ist, int got_output, int ret)
-{
-    if (ret < 0)
-        ist->decode_errors++;
-
-    if (ret < 0 && exit_on_error)
-        exit_program(1);
-
-    if (got_output && ist->dec_ctx->codec_type != AVMEDIA_TYPE_SUBTITLE) {
-        if (ist->decoded_frame->decode_error_flags || (ist->decoded_frame->flags & AV_FRAME_FLAG_CORRUPT)) {
-            av_log(ist, exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING,
-                   "corrupt decoded frame\n");
-            if (exit_on_error)
-                exit_program(1);
-        }
-    }
-}
-
 static int send_frame_to_filters(InputStream *ist, AVFrame *decoded_frame)
 {
     int i, ret;
@@ -385,10 +367,9 @@ static int transcode_subtitles(InputStream *ist, const AVPacket *pkt)
                 av_err2str(ret));
         if (exit_on_error)
             exit_program(1);
+        ist->decode_errors++;
     }
 
-    check_decode_result(ist, got_output, ret);
-
     if (ret < 0 || !got_output) {
         if (!pkt->size)
             sub2video_flush(ist);
@@ -448,9 +429,6 @@ int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
         update_benchmark("decode_%s %d.%d", type_desc,
                          ist->file_index, ist->st->index);
 
-        if (ret != AVERROR_EOF && ret != AVERROR(EAGAIN))
-            check_decode_result(ist, ret >= 0, ret);
-
         if (ret == AVERROR(EAGAIN)) {
             av_assert0(pkt); // should never happen during flushing
             return 0;
@@ -470,9 +448,17 @@ int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
             av_log(ist, AV_LOG_ERROR, "Decoding error: %s\n", av_err2str(ret));
             if (exit_on_error)
                 exit_program(1);
+            ist->decode_errors++;
             return ret;
         }
 
+        if (frame->decode_error_flags || (frame->flags & AV_FRAME_FLAG_CORRUPT)) {
+            av_log(ist, exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING,
+                   "corrupt decoded frame\n");
+            if (exit_on_error)
+                exit_program(1);
+        }
+
         if (ist->want_frame_data) {
             FrameData *fd;
 
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 34/36] fftools/ffmpeg_dec: deduplicate code in decode_audio/video()
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (31 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 33/36] fftools/ffmpeg_dec: merge check_decode_result() into its callers Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 35/36] fftools/ffmpeg_dec: inline decode_audio() into dec_packet() Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 36/36] fftools/ffmpeg_dec: rename decode_video() to video_frame_process() Anton Khirnov
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

---
 fftools/ffmpeg_dec.c | 28 +++++++++++-----------------
 1 file changed, 11 insertions(+), 17 deletions(-)

diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index 79e9c04fc1..4662d0a265 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -130,18 +130,13 @@ static void audio_ts_process(InputStream *ist, AVFrame *frame)
 
 static int decode_audio(InputStream *ist, AVFrame *decoded_frame)
 {
-    int ret, err = 0;
-
     ist->samples_decoded += decoded_frame->nb_samples;
-    ist->frames_decoded++;
 
     audio_ts_process(ist, decoded_frame);
 
     ist->nb_samples = decoded_frame->nb_samples;
-    err = send_frame_to_filters(ist, decoded_frame);
 
-    av_frame_unref(decoded_frame);
-    return err < 0 ? err : ret;
+    return 0;
 }
 
 static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *frame)
@@ -197,8 +192,6 @@ static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *fr
 
 static int decode_video(InputStream *ist, AVFrame *frame)
 {
-    int ret = 0, err = 0;
-
     // 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) {
@@ -229,12 +222,10 @@ static int decode_video(InputStream *ist, AVFrame *frame)
     if(ist->top_field_first>=0)
         frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
 
-    ist->frames_decoded++;
-
     if (ist->hwaccel_retrieve_data && frame->format == ist->hwaccel_pix_fmt) {
-        err = ist->hwaccel_retrieve_data(ist->dec_ctx, frame);
+        int err = ist->hwaccel_retrieve_data(ist->dec_ctx, frame);
         if (err < 0)
-            goto fail;
+            return err;
     }
 
     frame->pts = frame->best_effort_timestamp;
@@ -275,11 +266,7 @@ static int decode_video(InputStream *ist, AVFrame *frame)
     if (ist->st->sample_aspect_ratio.num)
         frame->sample_aspect_ratio = ist->st->sample_aspect_ratio;
 
-    err = send_frame_to_filters(ist, frame);
-
-fail:
-    av_frame_unref(frame);
-    return err < 0 ? err : ret;
+    return 0;
 }
 
 static void sub2video_flush(InputStream *ist)
@@ -485,6 +472,13 @@ int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
                    "data for stream #%d:%d\n", ist->file_index, ist->st->index);
             exit_program(1);
         }
+
+        ist->frames_decoded++;
+
+        ret = send_frame_to_filters(ist, frame);
+        av_frame_unref(frame);
+        if (ret < 0)
+            exit_program(1);
     }
 }
 
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 35/36] fftools/ffmpeg_dec: inline decode_audio() into dec_packet()
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (32 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 34/36] fftools/ffmpeg_dec: deduplicate code in decode_audio/video() Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 36/36] fftools/ffmpeg_dec: rename decode_video() to video_frame_process() Anton Khirnov
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

The former function is now trivial - it has 3 lines and cannot fail.
---
 fftools/ffmpeg_dec.c | 29 +++++++++++------------------
 1 file changed, 11 insertions(+), 18 deletions(-)

diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index 4662d0a265..c8f9ba0f0c 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -128,17 +128,6 @@ static void audio_ts_process(InputStream *ist, AVFrame *frame)
     frame->time_base = tb_filter;
 }
 
-static int decode_audio(InputStream *ist, AVFrame *decoded_frame)
-{
-    ist->samples_decoded += decoded_frame->nb_samples;
-
-    audio_ts_process(ist, decoded_frame);
-
-    ist->nb_samples = decoded_frame->nb_samples;
-
-    return 0;
-}
-
 static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *frame)
 {
     const InputFile   *ifile = input_files[ist->file_index];
@@ -463,14 +452,18 @@ int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
 
         frame->time_base = dec->pkt_timebase;
 
-        ret = dec->codec_type == AVMEDIA_TYPE_AUDIO ?
-                decode_audio(ist, frame)            :
-                decode_video(ist, frame);
+        if (dec->codec_type == AVMEDIA_TYPE_AUDIO) {
+            ist->samples_decoded += frame->nb_samples;
+            ist->nb_samples       = frame->nb_samples;
 
-        if (ret < 0) {
-            av_log(NULL, AV_LOG_FATAL, "Error while processing the decoded "
-                   "data for stream #%d:%d\n", ist->file_index, ist->st->index);
-            exit_program(1);
+            audio_ts_process(ist, frame);
+        } else {
+            ret = decode_video(ist, frame);
+            if (ret < 0) {
+                av_log(NULL, AV_LOG_FATAL, "Error while processing the decoded "
+                       "data for stream #%d:%d\n", ist->file_index, ist->st->index);
+                exit_program(1);
+            }
         }
 
         ist->frames_decoded++;
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH 36/36] fftools/ffmpeg_dec: rename decode_video() to video_frame_process()
  2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
                   ` (33 preceding siblings ...)
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 35/36] fftools/ffmpeg_dec: inline decode_audio() into dec_packet() Anton Khirnov
@ 2023-05-17 10:20 ` Anton Khirnov
  34 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-17 10:20 UTC (permalink / raw)
  To: ffmpeg-devel

This function does not do any decoding anymore.
---
 fftools/ffmpeg_dec.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index c8f9ba0f0c..b541d30214 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -179,7 +179,7 @@ static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *fr
     return FFMAX(ist->last_frame_duration_est, 1);
 }
 
-static int decode_video(InputStream *ist, AVFrame *frame)
+static int video_frame_process(InputStream *ist, AVFrame *frame)
 {
     // The following line may be required in some cases where there is no parser
     // or the parser does not has_b_frames correctly
@@ -458,7 +458,7 @@ int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
 
             audio_ts_process(ist, frame);
         } else {
-            ret = decode_video(ist, frame);
+            ret = video_frame_process(ist, frame);
             if (ret < 0) {
                 av_log(NULL, AV_LOG_FATAL, "Error while processing the decoded "
                        "data for stream #%d:%d\n", ist->file_index, ist->st->index);
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [FFmpeg-devel] [PATCH 31/36] fftools/ffmpeg_dec: restructure audio/video decoding loop
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 31/36] fftools/ffmpeg_dec: restructure audio/video decoding loop Anton Khirnov
@ 2023-05-17 20:04   ` Michael Niedermayer
  2023-05-17 20:06     ` Michael Niedermayer
  2023-05-18  6:41     ` Anton Khirnov
  2023-05-18  6:36   ` [FFmpeg-devel] [PATCH] " Anton Khirnov
  1 sibling, 2 replies; 44+ messages in thread
From: Michael Niedermayer @ 2023-05-17 20:04 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


[-- Attachment #1.1: Type: text/plain, Size: 1291 bytes --]

On Wed, May 17, 2023 at 12:20:24PM +0200, Anton Khirnov wrote:
> It currently emulates the long-removed
> avcodec_decode_audio4/avcodec_decode_video2 APIs, which obfuscates the
> actual decoding flow. Restructure the decoding calls so that they
> naturally follow the new avcodec_send_packet()/avcodec_receive_frame()
> design.
> 
> This is not only significantly easier to read, but also shorter.

with this:
./ffmpeg -y -threads:a 1 -i tickets/1208/702121h264-TTA.mkvtest82.mkv -bitexact -vn file1208.mp3

Both before and afterwards the output is empty and we see

Finishing stream without any data written to it.
Output file is empty, nothing was encoded

after this patch while the output is not any better, now ffmpeg proclaims
success with its return code

just to be sure i try reading the output

[mp3 @ 0x5635bab17900] Format mp3 detected only with low score of 1, misdetection possible!
[mp3 @ 0x5635bab17900] Failed to read frame size: Could not seek to 1026.
[in#0 @ 0x5635bab177c0] Error opening input: Invalid argument

I dont think that convertion was successfull

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

I am the wisest man alive, for I know one thing, and that is that I know
nothing. -- Socrates

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

[-- Attachment #2: Type: text/plain, Size: 251 bytes --]

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [FFmpeg-devel] [PATCH 31/36] fftools/ffmpeg_dec: restructure audio/video decoding loop
  2023-05-17 20:04   ` Michael Niedermayer
@ 2023-05-17 20:06     ` Michael Niedermayer
  2023-05-18  6:41     ` Anton Khirnov
  1 sibling, 0 replies; 44+ messages in thread
From: Michael Niedermayer @ 2023-05-17 20:06 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


[-- Attachment #1.1: Type: text/plain, Size: 1501 bytes --]

On Wed, May 17, 2023 at 10:04:09PM +0200, Michael Niedermayer wrote:
> On Wed, May 17, 2023 at 12:20:24PM +0200, Anton Khirnov wrote:
> > It currently emulates the long-removed
> > avcodec_decode_audio4/avcodec_decode_video2 APIs, which obfuscates the
> > actual decoding flow. Restructure the decoding calls so that they
> > naturally follow the new avcodec_send_packet()/avcodec_receive_frame()
> > design.
> > 
> > This is not only significantly easier to read, but also shorter.
> 
> with this:
> ./ffmpeg -y -threads:a 1 -i tickets/1208/702121h264-TTA.mkvtest82.mkv -bitexact -vn file1208.mp3
> 
> Both before and afterwards the output is empty and we see
> 
> Finishing stream without any data written to it.
> Output file is empty, nothing was encoded
> 
> after this patch while the output is not any better, now ffmpeg proclaims
> success with its return code
> 
> just to be sure i try reading the output
> 
> [mp3 @ 0x5635bab17900] Format mp3 detected only with low score of 1, misdetection possible!
> [mp3 @ 0x5635bab17900] Failed to read frame size: Could not seek to 1026.
> [in#0 @ 0x5635bab177c0] Error opening input: Invalid argument
> 
> I dont think that convertion was successfull

fiel seems here:
ffmpeg-bugs/trac/ticket1208/702121h264-TTA.mkvtest82.mkv

[...]


-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

During times of universal deceit, telling the truth becomes a
revolutionary act. -- George Orwell

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

[-- Attachment #2: Type: text/plain, Size: 251 bytes --]

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [FFmpeg-devel] [PATCH 30/36] fftools/ffmpeg_dec: deobfuscate subtitle decoding
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 30/36] fftools/ffmpeg_dec: deobfuscate subtitle decoding Anton Khirnov
@ 2023-05-17 20:15   ` Michael Niedermayer
  2023-05-18 14:34     ` Anton Khirnov
  0 siblings, 1 reply; 44+ messages in thread
From: Michael Niedermayer @ 2023-05-17 20:15 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


[-- Attachment #1.1: Type: text/plain, Size: 852 bytes --]

On Wed, May 17, 2023 at 12:20:23PM +0200, Anton Khirnov wrote:
> It is currently handled in the same loop as audio and video, but this
> obscures the actual flow, because only one iteration is ever performed
> for subtitles.
> 
> Also, avoid a pointless packet reference.
> ---
>  fftools/ffmpeg_dec.c | 34 ++++++++++++++++++----------------
>  1 file changed, 18 insertions(+), 16 deletions(-)

The following results in a really large file now: (i stoped it so maybe infinite loop)
./ffmpeg -f lavfi -i "movie=tickets/1332/Starship_Troopers.vob[out0+subcc]"  -vn -map s -y eia608.srt

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

The bravest are surely those who have the clearest vision
of what is before them, glory and danger alike, and yet
notwithstanding go out to meet it. -- Thucydides

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

[-- Attachment #2: Type: text/plain, Size: 251 bytes --]

_______________________________________________
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH] fftools/ffmpeg: rework handling -max_error_rate
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 26/36] fftools/ffmpeg: rework handling -max_error_rate Anton Khirnov
@ 2023-05-18  6:19   ` Anton Khirnov
  0 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-18  6:19 UTC (permalink / raw)
  To: ffmpeg-devel

Replace the decode_error_stat global with a per-input-stream variable.
Also, print an error message when the error rate is exceeded.
---
Now also printing the error rate value.
---
 fftools/ffmpeg.c       | 33 +++++++++++++++++++++------------
 fftools/ffmpeg.h       |  1 +
 fftools/ffmpeg_demux.c |  5 +++--
 3 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 537f287637..414bae1747 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -121,7 +121,6 @@ static int64_t getmaxrss(void);
 
 int64_t nb_frames_dup = 0;
 int64_t nb_frames_drop = 0;
-static int64_t decode_error_stat[2];
 unsigned nb_output_dumped = 0;
 
 static BenchmarkTimeStamps current_time;
@@ -771,8 +770,8 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
 
 static void check_decode_result(InputStream *ist, int *got_output, int ret)
 {
-    if (*got_output || ret<0)
-        decode_error_stat[ret<0] ++;
+    if (ret < 0)
+        ist->decode_errors++;
 
     if (ret < 0 && exit_on_error)
         exit_program(1);
@@ -1807,14 +1806,15 @@ static int transcode_step(OutputStream *ost)
 /*
  * The following code is the main loop of the file converter
  */
-static int transcode(void)
+static int transcode(int *err_rate_exceeded)
 {
-    int ret, i;
+    int ret = 0, i;
     InputStream *ist;
     int64_t timer_start;
 
     print_stream_maps();
 
+    *err_rate_exceeded = 0;
     atomic_store(&transcode_init_done, 1);
 
     if (stdin_interaction) {
@@ -1855,9 +1855,20 @@ static int transcode(void)
 
     /* at the end of stream, we must flush the decoder buffers */
     for (ist = ist_iter(NULL); ist; ist = ist_iter(ist)) {
+        float err_rate;
+
         if (!input_files[ist->file_index]->eof_reached) {
             process_input_packet(ist, NULL, 0);
         }
+
+        err_rate = (ist->frames_decoded || ist->decode_errors) ?
+                   ist->decode_errors / (ist->frames_decoded + ist->decode_errors) : 0.f;
+        if (err_rate > max_error_rate) {
+            av_log(ist, AV_LOG_FATAL, "Decode error rate %g exceeds maximum %g\n",
+                   err_rate, max_error_rate);
+            *err_rate_exceeded = 1;
+        } else if (err_rate)
+            av_log(ist, AV_LOG_VERBOSE, "Decode error rate %g\n", err_rate);
     }
     enc_flush();
 
@@ -1921,7 +1932,7 @@ static int64_t getmaxrss(void)
 
 int main(int argc, char **argv)
 {
-    int ret;
+    int ret, err_rate_exceeded;
     BenchmarkTimeStamps ti;
 
     init_dynload();
@@ -1958,7 +1969,7 @@ int main(int argc, char **argv)
     }
 
     current_time = ti = get_benchmark_time_stamps();
-    ret = transcode();
+    ret = transcode(&err_rate_exceeded);
     if (ret >= 0 && do_benchmark) {
         int64_t utime, stime, rtime;
         current_time = get_benchmark_time_stamps();
@@ -1969,12 +1980,10 @@ int main(int argc, char **argv)
                "bench: utime=%0.3fs stime=%0.3fs rtime=%0.3fs\n",
                utime / 1000000.0, stime / 1000000.0, rtime / 1000000.0);
     }
-    av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" frames successfully decoded, %"PRIu64" decoding errors\n",
-           decode_error_stat[0], decode_error_stat[1]);
-    if ((decode_error_stat[0] + decode_error_stat[1]) * max_error_rate < decode_error_stat[1])
-        exit_program(69);
 
-    ret = received_nb_signals ? 255 : ret;
+    ret = received_nb_signals ? 255 :
+          err_rate_exceeded   ?  69 : ret;
+
     exit_program(ret);
     return ret;
 }
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 3a332768df..87e684a147 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -413,6 +413,7 @@ typedef struct InputStream {
     // number of frames/samples retrieved from the decoder
     uint64_t frames_decoded;
     uint64_t samples_decoded;
+    uint64_t decode_errors;
 } InputStream;
 
 typedef struct LastFrameDuration {
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index df87e0f30a..401ae1f850 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -786,8 +786,9 @@ static void demux_final_stats(Demuxer *d)
                ds->nb_packets, ds->data_size);
 
         if (ist->decoding_needed) {
-            av_log(f, AV_LOG_VERBOSE, "%"PRIu64" frames decoded",
-                   ist->frames_decoded);
+            av_log(f, AV_LOG_VERBOSE,
+                   "%"PRIu64" frames decoded; %"PRIu64" decode errors",
+                   ist->frames_decoded, ist->decode_errors);
             if (type == AVMEDIA_TYPE_AUDIO)
                 av_log(f, AV_LOG_VERBOSE, " (%"PRIu64" samples)", ist->samples_decoded);
             av_log(f, AV_LOG_VERBOSE, "; ");
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [FFmpeg-devel] [PATCH] fftools/ffmpeg_dec: restructure audio/video decoding loop
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 31/36] fftools/ffmpeg_dec: restructure audio/video decoding loop Anton Khirnov
  2023-05-17 20:04   ` Michael Niedermayer
@ 2023-05-18  6:36   ` Anton Khirnov
  1 sibling, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-18  6:36 UTC (permalink / raw)
  To: ffmpeg-devel

It currently emulates the long-removed
avcodec_decode_audio4/avcodec_decode_video2 APIs, which obfuscates the
actual decoding flow. Restructure the decoding calls so that they
naturally follow the new avcodec_send_packet()/avcodec_receive_frame()
design.

This is not only significantly easier to read, but also shorter.
---
Now increments error rate for errors from avcodec_send_packet()
---
 fftools/ffmpeg_dec.c | 191 +++++++++++++++----------------------------
 1 file changed, 65 insertions(+), 126 deletions(-)

diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index 646b587f9e..ab8c6205c6 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -31,7 +31,7 @@
 
 #include "ffmpeg.h"
 
-static void check_decode_result(InputStream *ist, int *got_output, int ret)
+static void check_decode_result(InputStream *ist, int got_output, int ret)
 {
     if (ret < 0)
         ist->decode_errors++;
@@ -39,7 +39,7 @@ static void check_decode_result(InputStream *ist, int *got_output, int ret)
     if (ret < 0 && exit_on_error)
         exit_program(1);
 
-    if (*got_output && ist->dec_ctx->codec_type != AVMEDIA_TYPE_SUBTITLE) {
+    if (got_output && ist->dec_ctx->codec_type != AVMEDIA_TYPE_SUBTITLE) {
         if (ist->decoded_frame->decode_error_flags || (ist->decoded_frame->flags & AV_FRAME_FLAG_CORRUPT)) {
             av_log(ist, exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING,
                    "corrupt decoded frame\n");
@@ -49,52 +49,6 @@ static void check_decode_result(InputStream *ist, int *got_output, int ret)
     }
 }
 
-// This does not quite work like avcodec_decode_audio4/avcodec_decode_video2.
-// There is the following difference: if you got a frame, you must call
-// it again with pkt=NULL. pkt==NULL is treated differently from pkt->size==0
-// (pkt==NULL means get more output, pkt->size==0 is a flush/drain packet)
-static int decode(InputStream *ist, AVCodecContext *avctx,
-                  AVFrame *frame, int *got_frame, const AVPacket *pkt)
-{
-    int ret;
-
-    *got_frame = 0;
-
-    if (pkt) {
-        ret = avcodec_send_packet(avctx, pkt);
-        // In particular, we don't expect AVERROR(EAGAIN), because we read all
-        // decoded frames with avcodec_receive_frame() until done.
-        if (ret < 0 && ret != AVERROR_EOF)
-            return ret;
-    }
-
-    ret = avcodec_receive_frame(avctx, frame);
-    if (ret < 0 && ret != AVERROR(EAGAIN))
-        return ret;
-    if (ret >= 0) {
-        if (ist->want_frame_data) {
-            FrameData *fd;
-
-            av_assert0(!frame->opaque_ref);
-            frame->opaque_ref = av_buffer_allocz(sizeof(*fd));
-            if (!frame->opaque_ref) {
-                av_frame_unref(frame);
-                return AVERROR(ENOMEM);
-            }
-            fd      = (FrameData*)frame->opaque_ref->data;
-            fd->pts = frame->pts;
-            fd->tb  = avctx->pkt_timebase;
-            fd->idx = avctx->frame_num - 1;
-        }
-
-        frame->time_base = avctx->pkt_timebase;
-
-        *got_frame = 1;
-    }
-
-    return 0;
-}
-
 static int send_frame_to_filters(InputStream *ist, AVFrame *decoded_frame)
 {
     int i, ret;
@@ -192,25 +146,10 @@ static void audio_ts_process(InputStream *ist, AVFrame *frame)
     frame->time_base = tb_filter;
 }
 
-static int decode_audio(InputStream *ist, const AVPacket *pkt, int *got_output,
-                        int *decode_failed)
+static int decode_audio(InputStream *ist, AVFrame *decoded_frame)
 {
-    AVFrame *decoded_frame = ist->decoded_frame;
-    AVCodecContext *avctx = ist->dec_ctx;
     int ret, err = 0;
 
-    update_benchmark(NULL);
-    ret = decode(ist, avctx, decoded_frame, got_output, pkt);
-    update_benchmark("decode_audio %d.%d", ist->file_index, ist->st->index);
-    if (ret < 0)
-        *decode_failed = 1;
-
-    if (ret != AVERROR_EOF)
-        check_decode_result(ist, got_output, ret);
-
-    if (!*got_output || ret < 0)
-        return ret;
-
     ist->samples_decoded += decoded_frame->nb_samples;
     ist->frames_decoded++;
 
@@ -274,24 +213,10 @@ static int64_t video_duration_estimate(const InputStream *ist, const AVFrame *fr
     return FFMAX(ist->last_frame_duration_est, 1);
 }
 
-static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
-                        int eof, int *decode_failed)
+static int decode_video(InputStream *ist, AVFrame *frame)
 {
-    AVFrame *frame = ist->decoded_frame;
     int ret = 0, err = 0;
 
-    // With fate-indeo3-2, we're getting 0-sized packets before EOF for some
-    // reason. This seems like a semi-critical bug. Don't trigger EOF, and
-    // skip the packet.
-    if (!eof && pkt && pkt->size == 0)
-        return 0;
-
-    update_benchmark(NULL);
-    ret = decode(ist, ist->dec_ctx, frame, got_output, pkt);
-    update_benchmark("decode_video %d.%d", ist->file_index, ist->st->index);
-    if (ret < 0)
-        *decode_failed = 1;
-
     // 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) {
@@ -307,10 +232,6 @@ static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
                    ist->par->video_delay);
     }
 
-    if (ret != AVERROR_EOF)
-        check_decode_result(ist, got_output, ret);
-
-    if (*got_output && ret >= 0) {
         if (ist->dec_ctx->width  != frame->width ||
             ist->dec_ctx->height != frame->height ||
             ist->dec_ctx->pix_fmt != frame->format) {
@@ -322,10 +243,6 @@ static int decode_video(InputStream *ist, const AVPacket *pkt, int *got_output,
                 ist->dec_ctx->height,
                 ist->dec_ctx->pix_fmt);
         }
-    }
-
-    if (!*got_output || ret < 0)
-        return ret;
 
     if(ist->top_field_first>=0)
         frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
@@ -470,7 +387,7 @@ static int transcode_subtitles(InputStream *ist, const AVPacket *pkt)
             exit_program(1);
     }
 
-    check_decode_result(ist, &got_output, ret);
+    check_decode_result(ist, got_output, ret);
 
     if (ret < 0 || !got_output) {
         if (!pkt->size)
@@ -500,40 +417,48 @@ static int send_filter_eof(InputStream *ist)
 int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
 {
     AVCodecContext *dec = ist->dec_ctx;
-    AVPacket *avpkt = ist->pkt;
-    int ret, repeating = 0;
+    const char *type_desc = av_get_media_type_string(dec->codec_type);
+    int ret;
 
     if (dec->codec_type == AVMEDIA_TYPE_SUBTITLE)
         return transcode_subtitles(ist, pkt ? pkt : ist->pkt);
 
-    if (pkt) {
-        av_packet_unref(avpkt);
-        ret = av_packet_ref(avpkt, pkt);
-        if (ret < 0)
-            return ret;
+    // With fate-indeo3-2, we're getting 0-sized packets before EOF for some
+    // reason. This seems like a semi-critical bug. Don't trigger EOF, and
+    // skip the packet.
+    if (pkt && pkt->size == 0)
+        return 0;
+
+    ret = avcodec_send_packet(dec, pkt);
+    if (ret < 0 && !(ret == AVERROR_EOF && !pkt)) {
+        // In particular, we don't expect AVERROR(EAGAIN), because we read all
+        // decoded frames with avcodec_receive_frame() until done.
+        av_log(ist, AV_LOG_ERROR, "Error submitting %s to decoder: %s\n",
+               pkt ? "packet" : "EOF", av_err2str(ret));
+        if (exit_on_error)
+            exit_program(1);
+
+        if (ret != AVERROR_EOF)
+            ist->decode_errors++;
+
+        return ret;
     }
 
-    // while we have more to decode or while the decoder did output something on EOF
     while (1) {
-        int got_output = 0;
-        int decode_failed = 0;
-
-        switch (ist->par->codec_type) {
-        case AVMEDIA_TYPE_AUDIO:
-            ret = decode_audio    (ist, repeating ? NULL : avpkt, &got_output,
-                                   &decode_failed);
-            av_packet_unref(avpkt);
-            break;
-        case AVMEDIA_TYPE_VIDEO:
-            ret = decode_video    (ist, repeating ? NULL : avpkt, &got_output, !pkt,
-                                   &decode_failed);
+        AVFrame *frame = ist->decoded_frame;
 
-            av_packet_unref(avpkt);
-            break;
-        default: av_assert0(0);
-        }
+        update_benchmark(NULL);
+        ret = avcodec_receive_frame(dec, frame);
+        update_benchmark("decode_%s %d.%d", type_desc,
+                         ist->file_index, ist->st->index);
+
+        if (ret != AVERROR_EOF && ret != AVERROR(EAGAIN))
+            check_decode_result(ist, ret >= 0, ret);
 
-        if (ret == AVERROR_EOF) {
+        if (ret == AVERROR(EAGAIN)) {
+            av_assert0(pkt); // should never happen during flushing
+            return 0;
+        } else if (ret == AVERROR_EOF) {
             /* after flushing, send an EOF on all the filter inputs attached to the stream */
             /* except when looping we need to flush but not to send an EOF */
             if (!no_eof) {
@@ -545,25 +470,39 @@ int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
             }
 
             return AVERROR_EOF;
+        } else if (ret < 0) {
+            av_log(ist, AV_LOG_ERROR, "Decoding error: %s\n", av_err2str(ret));
+            if (exit_on_error)
+                exit_program(1);
+            return ret;
         }
 
-        if (ret < 0) {
-            if (decode_failed) {
-                av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",
-                       ist->file_index, ist->st->index, av_err2str(ret));
-            } else {
-                av_log(NULL, AV_LOG_FATAL, "Error while processing the decoded "
-                       "data for stream #%d:%d\n", ist->file_index, ist->st->index);
+        if (ist->want_frame_data) {
+            FrameData *fd;
+
+            av_assert0(!frame->opaque_ref);
+            frame->opaque_ref = av_buffer_allocz(sizeof(*fd));
+            if (!frame->opaque_ref) {
+                av_frame_unref(frame);
+                report_and_exit(AVERROR(ENOMEM));
             }
-            if (!decode_failed || exit_on_error)
-                exit_program(1);
-            return ret;
+            fd      = (FrameData*)frame->opaque_ref->data;
+            fd->pts = frame->pts;
+            fd->tb  = dec->pkt_timebase;
+            fd->idx = dec->frame_num - 1;
         }
 
-        if (!got_output)
-            return 0;
+        frame->time_base = dec->pkt_timebase;
+
+        ret = dec->codec_type == AVMEDIA_TYPE_AUDIO ?
+                decode_audio(ist, frame)            :
+                decode_video(ist, frame);
 
-        repeating = 1;
+        if (ret < 0) {
+            av_log(NULL, AV_LOG_FATAL, "Error while processing the decoded "
+                   "data for stream #%d:%d\n", ist->file_index, ist->st->index);
+            exit_program(1);
+        }
     }
 }
 
-- 
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [FFmpeg-devel] [PATCH 31/36] fftools/ffmpeg_dec: restructure audio/video decoding loop
  2023-05-17 20:04   ` Michael Niedermayer
  2023-05-17 20:06     ` Michael Niedermayer
@ 2023-05-18  6:41     ` Anton Khirnov
  1 sibling, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-18  6:41 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Quoting Michael Niedermayer (2023-05-17 22:04:09)
> On Wed, May 17, 2023 at 12:20:24PM +0200, Anton Khirnov wrote:
> > It currently emulates the long-removed
> > avcodec_decode_audio4/avcodec_decode_video2 APIs, which obfuscates the
> > actual decoding flow. Restructure the decoding calls so that they
> > naturally follow the new avcodec_send_packet()/avcodec_receive_frame()
> > design.
> > 
> > This is not only significantly easier to read, but also shorter.
> 
> with this:
> ./ffmpeg -y -threads:a 1 -i tickets/1208/702121h264-TTA.mkvtest82.mkv -bitexact -vn file1208.mp3
> 
> Both before and afterwards the output is empty and we see
> 
> Finishing stream without any data written to it.
> Output file is empty, nothing was encoded
> 
> after this patch while the output is not any better, now ffmpeg proclaims
> success with its return code
> 
> just to be sure i try reading the output
> 
> [mp3 @ 0x5635bab17900] Format mp3 detected only with low score of 1, misdetection possible!
> [mp3 @ 0x5635bab17900] Failed to read frame size: Could not seek to 1026.
> [in#0 @ 0x5635bab177c0] Error opening input: Invalid argument
> 
> I dont think that convertion was successfull

Your original failure has nothing to do with the output file being
empty, as that is not considered an error unless you specify
 -abort_on empty_output

Rather the failure comes from the default maximum error rate of 2/3
being exceeded, since no frame could be decoded successfully. The reason
was that the patch did not count avcodec_send_packet() errors into error
rate, I've fixed that in a new version. I've also updated the
-max_error_rate patch to make the situation clearer.

-- 
Anton Khirnov
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [FFmpeg-devel] [PATCH 30/36] fftools/ffmpeg_dec: deobfuscate subtitle decoding
  2023-05-17 20:15   ` Michael Niedermayer
@ 2023-05-18 14:34     ` Anton Khirnov
  0 siblings, 0 replies; 44+ messages in thread
From: Anton Khirnov @ 2023-05-18 14:34 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Quoting Michael Niedermayer (2023-05-17 22:15:37)
> On Wed, May 17, 2023 at 12:20:23PM +0200, Anton Khirnov wrote:
> > It is currently handled in the same loop as audio and video, but this
> > obscures the actual flow, because only one iteration is ever performed
> > for subtitles.
> > 
> > Also, avoid a pointless packet reference.
> > ---
> >  fftools/ffmpeg_dec.c | 34 ++++++++++++++++++----------------
> >  1 file changed, 18 insertions(+), 16 deletions(-)
> 
> The following results in a really large file now: (i stoped it so maybe infinite loop)
> ./ffmpeg -f lavfi -i "movie=tickets/1332/Starship_Troopers.vob[out0+subcc]"  -vn -map s -y eia608.srt

This was a bug in ccaption decoder, fixed by Paul in c48eff209c.

-- 
Anton Khirnov
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [FFmpeg-devel] [PATCH 22/36] fftools/ffmpeg: drop an obsolete hack
  2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 22/36] fftools/ffmpeg: drop an obsolete hack Anton Khirnov
@ 2023-05-26  6:22   ` Wang, Fei W
  0 siblings, 0 replies; 44+ messages in thread
From: Wang, Fei W @ 2023-05-26  6:22 UTC (permalink / raw)
  To: ffmpeg-devel

On Wed, 2023-05-17 at 12:20 +0200, Anton Khirnov wrote:
> This special handling for decoder flushing has not been needed since
> af1761f7b5, as the filtergraph actually is drained after that commit.
> ---
>  fftools/ffmpeg.c | 11 -----------
>  1 file changed, 11 deletions(-)
> 
> diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
> index 9d554e2fb0..49313edebc 100644
> --- a/fftools/ffmpeg.c
> +++ b/fftools/ffmpeg.c
> @@ -1418,17 +1418,6 @@ static int process_input_packet(InputStream
> *ist, const AVPacket *pkt, int no_eo
>          if (!got_output)
>              break;
>  
> -        // During draining, we might get multiple output frames in
> this loop.
> -        // ffmpeg.c does not drain the filter chain on configuration
> changes,
> -        // which means if we send multiple frames at once to the
> filters, and
> -        // one of those frames changes configuration, the buffered
> frames will
> -        // be lost. This can upset certain FATE tests.
> -        // Decode only 1 frame per call on EOF to appease these FATE
> tests.
> -        // The ideal solution would be to rewrite decoding to use
> the new
> -        // decoding API in a better way.
> -        if (!pkt)
> -            break;
> -
Hi,

This will drain out HW filter's output frames if it uses fixed number
which is less than frame threads of decoder. Decoded frame keep sending
to filter in flushing while filtered frames can't be reaped. An example
cmd:

ffmpeg -threads 20 -v verbose -init_hw_device
vaapi=hw:/dev/dri/renderD128 -hwaccel_output_format vaapi -hwaccel
vaapi -i avc.mp4 -vf 'scale_va
api=w=720:h=480' -f null -

...
Error while filtering: Cannot allocate memory
Failed to inject frame into filter network: Cannot allocate memory
Error while processing the decoded data for stream #0:0

Thanks

>          repeating = 1;
>      }
>  
_______________________________________________
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".

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2023-05-26  6:22 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-17 10:19 [FFmpeg-devel] [PATCH 01/36] fftools/ffmpeg: shorten a variable name Anton Khirnov
2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 02/36] fftools/ffmpeg: drop a useless local variable Anton Khirnov
2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 03/36] fftools/ffmpeg: replace stream timebase with decoded frame one Anton Khirnov
2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 04/36] fftools/ffmpeg_filter: convert input frame timestamps Anton Khirnov
2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 05/36] fftools/ffmpeg_filter: make sure pkt_duration matches duration Anton Khirnov
2023-05-17 10:19 ` [FFmpeg-devel] [PATCH 06/36] fftools/ffmpeg: rework applying input -r Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 07/36] tests/fate/ffmpeg: move a misplaced line Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 08/36] tests/fate/ffmpeg: add a test for input -r option Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 09/36] fftools/ffmpeg_filter: split finding an unused stream into a function Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 10/36] fftools/ffmpeg: return error codes from ist_*_add() Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 11/36] fftools/ffmpeg_demux: disallow using disabled input streams Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 12/36] fftools/ffmpeg_filter: only use fallback parameters when necessary Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 13/36] fftools/ffmpeg_filter: try configuring graphs from input EOF Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 14/36] fftools/ffmpeg: move ifilter_has_all_input_formats() to ffmpeg_filter Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 15/36] fftools/ffmpeg_filter: make input filter configured parameters private Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 16/36] fftools/ffmpeg_filter: drop a redundant error message Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 17/36] fftools/ffmpeg_filter: move InputFilter.ist to private data Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 18/36] fftools/ffmpeg_filter: move InputFilter.type " Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 19/36] fftools/ffmpeg_filter: keep track of the real filter input type Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 20/36] fftools/ffmpeg_filter: embed displaymatrix into private context Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 21/36] fftools/cmdutils: constify the argument of get_rotation() Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 22/36] fftools/ffmpeg: drop an obsolete hack Anton Khirnov
2023-05-26  6:22   ` Wang, Fei W
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 23/36] fftools/ffmpeg: eliminate InputStream.got_output Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 24/36] fftools/ffmpeg: replace an unreachable return with av_assert0(0) Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 25/36] fftools/ffmpeg: deobfuscate check_decode_result() call Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 26/36] fftools/ffmpeg: rework handling -max_error_rate Anton Khirnov
2023-05-18  6:19   ` [FFmpeg-devel] [PATCH] " Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 27/36] fftools/ffmpeg: move a block to a more appropriate place Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 28/36] fftools/ffmpeg: split decoding loop out of process_input_packet() Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 29/36] fftools/ffmpeg: move decoding code to ffmpeg_dec Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 30/36] fftools/ffmpeg_dec: deobfuscate subtitle decoding Anton Khirnov
2023-05-17 20:15   ` Michael Niedermayer
2023-05-18 14:34     ` Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 31/36] fftools/ffmpeg_dec: restructure audio/video decoding loop Anton Khirnov
2023-05-17 20:04   ` Michael Niedermayer
2023-05-17 20:06     ` Michael Niedermayer
2023-05-18  6:41     ` Anton Khirnov
2023-05-18  6:36   ` [FFmpeg-devel] [PATCH] " Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 32/36] fftools/ffmpeg: reindent after previous commit Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 33/36] fftools/ffmpeg_dec: merge check_decode_result() into its callers Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 34/36] fftools/ffmpeg_dec: deduplicate code in decode_audio/video() Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 35/36] fftools/ffmpeg_dec: inline decode_audio() into dec_packet() Anton Khirnov
2023-05-17 10:20 ` [FFmpeg-devel] [PATCH 36/36] fftools/ffmpeg_dec: rename decode_video() to video_frame_process() Anton Khirnov

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