[FFmpeg-devel] [PATCH 03/19] lavc: add a private cap for fake-delay encoders

Anton Khirnov anton at khirnov.net
Wed Jan 25 18:55:21 EET 2023


Some encoders (ffv1, flac, adx) are marked with AV_CODEC_CAP_DELAY onky
in order to be flushed at the end, otherwise they behave as no-delay
encoders.

Add a capability to mark these encoders. Use it for setting pts
generically.
---
 libavcodec/adxenc.c         | 3 +--
 libavcodec/codec_internal.h | 8 ++++++++
 libavcodec/encode.c         | 6 ++++--
 libavcodec/ffv1enc.c        | 4 +---
 libavcodec/flacenc.c        | 7 ++-----
 libavcodec/tests/avcodec.c  | 4 ++++
 6 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/libavcodec/adxenc.c b/libavcodec/adxenc.c
index 153c91b852..6e12a58b16 100644
--- a/libavcodec/adxenc.c
+++ b/libavcodec/adxenc.c
@@ -183,8 +183,6 @@ static int adx_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
         dst += BLOCK_SIZE;
     }
 
-    avpkt->pts = frame->pts;
-    avpkt->duration = frame->nb_samples;
     *got_packet_ptr = 1;
     return 0;
 }
@@ -200,4 +198,5 @@ const FFCodec ff_adpcm_adx_encoder = {
     FF_CODEC_ENCODE_CB(adx_encode_frame),
     .p.sample_fmts  = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16,
                                                       AV_SAMPLE_FMT_NONE },
+    .caps_internal  = FF_CODEC_CAP_EOF_FLUSH,
 };
diff --git a/libavcodec/codec_internal.h b/libavcodec/codec_internal.h
index e3b77e6dea..130a7dc3cd 100644
--- a/libavcodec/codec_internal.h
+++ b/libavcodec/codec_internal.h
@@ -80,6 +80,14 @@
  * Codec supports embedded ICC profiles (AV_FRAME_DATA_ICC_PROFILE).
  */
 #define FF_CODEC_CAP_ICC_PROFILES           (1 << 9)
+/**
+ * The encoder has AV_CODEC_CAP_DELAY set, but does not actually have delay - it
+ * only wants to be flushed at the end to update some context variables (e.g.
+ * 2pass stats) or produce a trailing packet. Besides that it immediately
+ * produces exactly one output packet per each input frame, just as no-delay
+ * encoders do.
+ */
+#define FF_CODEC_CAP_EOF_FLUSH              (1 << 10)
 
 /**
  * FFCodec.codec_tags termination value
diff --git a/libavcodec/encode.c b/libavcodec/encode.c
index fbe2c97cd6..e0b3e43840 100644
--- a/libavcodec/encode.c
+++ b/libavcodec/encode.c
@@ -211,7 +211,8 @@ int ff_encode_encode_cb(AVCodecContext *avctx, AVPacket *avpkt,
 
         // set the timestamps for the simple no-delay case
         // encoders with delay have to set the timestamps themselves
-        if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY)) {
+        if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY) ||
+            (frame && (codec->caps_internal & FF_CODEC_CAP_EOF_FLUSH))) {
             if (avpkt->pts == AV_NOPTS_VALUE)
                 avpkt->pts = frame->pts;
 
@@ -225,7 +226,8 @@ int ff_encode_encode_cb(AVCodecContext *avctx, AVPacket *avpkt,
         // dts equals pts unless there is reordering
         // there can be no reordering if there is no encoder delay
         if (!(avctx->codec_descriptor->props & AV_CODEC_PROP_REORDER) ||
-            !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY))
+            !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY)        ||
+            (codec->caps_internal & FF_CODEC_CAP_EOF_FLUSH))
             avpkt->dts = avpkt->pts;
     } else {
 unref:
diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c
index 0237ac48eb..6649ec7e88 100644
--- a/libavcodec/ffv1enc.c
+++ b/libavcodec/ffv1enc.c
@@ -1231,8 +1231,6 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 
     f->picture_number++;
     pkt->size   = buf_p - pkt->data;
-    pkt->pts    =
-    pkt->dts    = pict->pts;
     pkt->flags |= AV_PKT_FLAG_KEY * f->key_frame;
     *got_packet = 1;
 
@@ -1301,5 +1299,5 @@ const FFCodec ff_ffv1_encoder = {
 
     },
     .p.priv_class   = &ffv1_class,
-    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
+    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_EOF_FLUSH,
 };
diff --git a/libavcodec/flacenc.c b/libavcodec/flacenc.c
index 8aacc93e28..9a9835dfa6 100644
--- a/libavcodec/flacenc.c
+++ b/libavcodec/flacenc.c
@@ -1690,10 +1690,7 @@ static int flac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
     if (out_bytes < s->min_framesize)
         s->min_framesize = out_bytes;
 
-    avpkt->pts      = frame->pts;
-    avpkt->duration = ff_samples_to_time_base(avctx, frame->nb_samples);
-
-    s->next_pts = avpkt->pts + avpkt->duration;
+    s->next_pts = frame->pts + ff_samples_to_time_base(avctx, frame->nb_samples);
 
     av_shrink_packet(avpkt, out_bytes);
 
@@ -1766,5 +1763,5 @@ const FFCodec ff_flac_encoder = {
                                                      AV_SAMPLE_FMT_S32,
                                                      AV_SAMPLE_FMT_NONE },
     .p.priv_class   = &flac_encoder_class,
-    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
+    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_EOF_FLUSH,
 };
diff --git a/libavcodec/tests/avcodec.c b/libavcodec/tests/avcodec.c
index 3288a85f64..4c1730425d 100644
--- a/libavcodec/tests/avcodec.c
+++ b/libavcodec/tests/avcodec.c
@@ -158,6 +158,10 @@ int main(void){
             if (codec->capabilities & AV_CODEC_CAP_FRAME_THREADS &&
                 codec->capabilities & AV_CODEC_CAP_DELAY)
                 ERR("Frame-threaded encoder %s claims to have delay\n");
+
+            if (codec2->caps_internal & FF_CODEC_CAP_EOF_FLUSH &&
+                !(codec->capabilities & AV_CODEC_CAP_DELAY))
+                ERR("EOF_FLUSH encoder %s is not marked as having delay\n");
         } else {
             if ((codec->type == AVMEDIA_TYPE_SUBTITLE) != (codec2->cb_type == FF_CODEC_CB_TYPE_DECODE_SUB))
                 ERR("Subtitle decoder %s does not implement decode_sub callback\n");
-- 
2.35.1



More information about the ffmpeg-devel mailing list