[FFmpeg-devel] [PATCH] avcodec/bsf: restructure the internal implementation of the bistream filter API

James Almer jamrial at gmail.com
Mon Apr 13 21:43:06 EEST 2020


Process input data as soon as it's fed to av_bsf_send_packet(), instead of
storing a single packet and expecting the user to call av_bsf_receive_packet()
in order to trigger the decoding process before they are allowed to feed more
data.

This puts the bsf API more in line with the decoupled decode API, without
breaking existing code using it.

Signed-off-by: James Almer <jamrial at gmail.com>
---
Benefits from this change include less constrains to how to use the API (Now
you can feed as many packets as the filter will accept, including the flush
call, before attempting to fetch the first output packet), and actually
honoring the part of the doxy for av_bsf_receive_packet() that says that pkt is
not touched on failure.

Drawback from this change is that now all bsfs will always receive non-writable
packets, so filters like noise and mpeg4_unpack_bframes will not be able to
do their work in-place anymore. This is because av_bsf_send_packet() will now
trigger the filtering process, and by passing the input packet reference to the
underlying bsf, any alteration in case of failure would go against the doxy
statement that pkt is untouched on such scenarios. So a new reference must be
used instead.

 libavcodec/avcodec.h |  6 +---
 libavcodec/bsf.c     | 68 +++++++++++++++++++++++++++-----------------
 2 files changed, 43 insertions(+), 31 deletions(-)

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 55151a0b71..e60f2ac1ce 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -4720,10 +4720,6 @@ int av_bsf_init(AVBSFContext *ctx);
 /**
  * Submit a packet for filtering.
  *
- * After sending each packet, the filter must be completely drained by calling
- * av_bsf_receive_packet() repeatedly until it returns AVERROR(EAGAIN) or
- * AVERROR_EOF.
- *
  * @param pkt the packet to filter. The bitstream filter will take ownership of
  * the packet and reset the contents of pkt. pkt is not touched if an error occurs.
  * If pkt is empty (i.e. NULL, or pkt->data is NULL and pkt->side_data_elems zero),
@@ -4755,7 +4751,7 @@ int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt);
  * an error occurs.
  *
  * @note one input packet may result in several output packets, so after sending
- * a packet with av_bsf_send_packet(), this function needs to be called
+ * a packet with av_bsf_send_packet(), this function may need to be called
  * repeatedly until it stops returning 0. It is also possible for a filter to
  * output fewer packets than were sent to it, so this function may return
  * AVERROR(EAGAIN) immediately after a successful av_bsf_send_packet() call.
diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c
index 7b96183e64..97d86beb6f 100644
--- a/libavcodec/bsf.c
+++ b/libavcodec/bsf.c
@@ -28,7 +28,8 @@
 #include "bsf.h"
 
 struct AVBSFInternal {
-    AVPacket *buffer_pkt;
+    AVPacket *in_pkt;
+    AVPacket *out_pkt;
     int eof;
 };
 
@@ -45,8 +46,10 @@ void av_bsf_free(AVBSFContext **pctx)
     if (ctx->filter->priv_class && ctx->priv_data)
         av_opt_free(ctx->priv_data);
 
-    if (ctx->internal)
-        av_packet_free(&ctx->internal->buffer_pkt);
+    if (ctx->internal) {
+        av_packet_free(&ctx->internal->in_pkt);
+        av_packet_free(&ctx->internal->out_pkt);
+    }
     av_freep(&ctx->internal);
     av_freep(&ctx->priv_data);
 
@@ -110,8 +113,9 @@ int av_bsf_alloc(const AVBitStreamFilter *filter, AVBSFContext **pctx)
     }
     ctx->internal = bsfi;
 
-    bsfi->buffer_pkt = av_packet_alloc();
-    if (!bsfi->buffer_pkt) {
+    bsfi->in_pkt = av_packet_alloc();
+    bsfi->out_pkt = av_packet_alloc();
+    if (!bsfi->in_pkt || !bsfi->out_pkt) {
         ret = AVERROR(ENOMEM);
         goto fail;
     }
@@ -183,7 +187,8 @@ void av_bsf_flush(AVBSFContext *ctx)
 
     bsfi->eof = 0;
 
-    av_packet_unref(bsfi->buffer_pkt);
+    av_packet_unref(bsfi->in_pkt);
+    av_packet_unref(bsfi->out_pkt);
 
     if (ctx->filter->flush)
         ctx->filter->flush(ctx);
@@ -204,21 +209,38 @@ int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt)
         return AVERROR(EINVAL);
     }
 
-    if (bsfi->buffer_pkt->data ||
-        bsfi->buffer_pkt->side_data_elems)
+    if (bsfi->in_pkt->data ||
+        bsfi->in_pkt->side_data_elems)
         return AVERROR(EAGAIN);
 
-    ret = av_packet_make_refcounted(pkt);
+    ret = av_packet_ref(bsfi->in_pkt, pkt);
     if (ret < 0)
         return ret;
-    av_packet_move_ref(bsfi->buffer_pkt, pkt);
+
+    if (!bsfi->out_pkt->data && !bsfi->out_pkt->side_data_elems) {
+        ret = ctx->filter->filter(ctx, bsfi->out_pkt);
+        if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
+            return ret;
+    }
+
+    av_packet_unref(pkt);
 
     return 0;
 }
 
 int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt)
 {
-    return ctx->filter->filter(ctx, pkt);
+    AVBSFInternal *bsfi = ctx->internal;
+    int ret;
+
+    if (!bsfi->out_pkt->data && !bsfi->out_pkt->side_data_elems) {
+        ret = ctx->filter->filter(ctx, bsfi->out_pkt);
+        if (ret < 0)
+            return ret;
+    }
+    av_packet_move_ref(pkt, bsfi->out_pkt);
+
+    return 0;
 }
 
 int ff_bsf_get_packet(AVBSFContext *ctx, AVPacket **pkt)
@@ -226,19 +248,16 @@ int ff_bsf_get_packet(AVBSFContext *ctx, AVPacket **pkt)
     AVBSFInternal *bsfi = ctx->internal;
     AVPacket *tmp_pkt;
 
-    if (bsfi->eof)
-        return AVERROR_EOF;
-
-    if (!bsfi->buffer_pkt->data &&
-        !bsfi->buffer_pkt->side_data_elems)
-        return AVERROR(EAGAIN);
+    if (!bsfi->in_pkt->data &&
+        !bsfi->in_pkt->side_data_elems)
+        return bsfi->eof ? AVERROR_EOF : AVERROR(EAGAIN);
 
     tmp_pkt = av_packet_alloc();
     if (!tmp_pkt)
         return AVERROR(ENOMEM);
 
-    *pkt = bsfi->buffer_pkt;
-    bsfi->buffer_pkt = tmp_pkt;
+    *pkt = bsfi->in_pkt;
+    bsfi->in_pkt = tmp_pkt;
 
     return 0;
 }
@@ -247,14 +266,11 @@ int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket *pkt)
 {
     AVBSFInternal *bsfi = ctx->internal;
 
-    if (bsfi->eof)
-        return AVERROR_EOF;
-
-    if (!bsfi->buffer_pkt->data &&
-        !bsfi->buffer_pkt->side_data_elems)
-        return AVERROR(EAGAIN);
+    if (!bsfi->in_pkt->data &&
+        !bsfi->in_pkt->side_data_elems)
+        return bsfi->eof ? AVERROR_EOF : AVERROR(EAGAIN);
 
-    av_packet_move_ref(pkt, bsfi->buffer_pkt);
+    av_packet_move_ref(pkt, bsfi->in_pkt);
 
     return 0;
 }
-- 
2.26.0



More information about the ffmpeg-devel mailing list