[FFmpeg-devel] [PATCH 1/2] avcodec/bsf: use simplified algorithm for bsf_list chained filtering
Andreas Rheinhardt
andreas.rheinhardt at gmail.com
Thu Apr 9 22:53:11 EEST 2020
Marton Balint:
> Based on the one in ffmpeg.c and it is not using an extra flush_idx variable.
>
> Signed-off-by: Marton Balint <cus at passwd.hu>
> ---
> libavcodec/bsf.c | 64 ++++++++++++++++++++++----------------------------------
> 1 file changed, 25 insertions(+), 39 deletions(-)
>
> diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c
> index 7b96183e64..b9fc771a88 100644
> --- a/libavcodec/bsf.c
> +++ b/libavcodec/bsf.c
> @@ -18,6 +18,7 @@
>
> #include <string.h>
>
> +#include "libavutil/avassert.h"
> #include "libavutil/log.h"
> #include "libavutil/mem.h"
> #include "libavutil/opt.h"
> @@ -266,7 +267,6 @@ typedef struct BSFListContext {
> int nb_bsfs;
>
> unsigned idx; // index of currently processed BSF
> - unsigned flushed_idx; // index of BSF being flushed
>
> char * item_name;
> } BSFListContext;
> @@ -304,57 +304,43 @@ fail:
> static int bsf_list_filter(AVBSFContext *bsf, AVPacket *out)
> {
> BSFListContext *lst = bsf->priv_data;
> - int ret;
> + int ret, eof = 0;
>
> if (!lst->nb_bsfs)
> return ff_bsf_get_packet_ref(bsf, out);
>
> while (1) {
> - if (lst->idx > lst->flushed_idx) {
> + /* get a packet from the previous filter up the chain */
> + if (lst->idx)
> ret = av_bsf_receive_packet(lst->bsfs[lst->idx-1], out);
> - if (ret == AVERROR(EAGAIN)) {
> - /* no more packets from idx-1, try with previous */
> - lst->idx--;
> - continue;
> - } else if (ret == AVERROR_EOF) {
> - /* filter idx-1 is done, continue with idx...nb_bsfs */
> - lst->flushed_idx = lst->idx;
> - continue;
Is it just me or did this continue make no sense at all? It claims to
continue with idx...nb_bsf, yet it actually tried to get a new packet
via ff_bsf_get_packet_ref().
> - }else if (ret < 0) {
> - /* filtering error */
> - break;
> - }
> - } else {
> + else
> ret = ff_bsf_get_packet_ref(bsf, out);
> - if (ret == AVERROR_EOF) {
> - lst->idx = lst->flushed_idx;
> - } else if (ret < 0)
> - break;
> - }
> + if (ret == AVERROR(EAGAIN)) {
> + if (!lst->idx)
> + return ret;
> + lst->idx--;
> + continue;
> + } else if (ret == AVERROR_EOF) {
> + eof = 1;
> + } else if (ret < 0)
> + return ret;
If you return here, the chain may not be completely drained (e.g. bsf 0
may still have packets ready to be output even if bsf 1 returned an
error while filtering a packet obtained from bsf 0) and despite this
error, the caller is responsible (according to the doc of
av_bsf_send/receive_packet) to drain the chain completely before sending
new packets.
In particular, if you use this in mux.c, you will have to keep calling
av_bsf_receive_packet() until the chain is drained even when the bsf
returns an error or when a write error occurs and you have to do this
even on AV_EF_EXPLODE. (Otherwise there might be a situation where the
next packet to be written can't even be sent to the chain because it is
not drained.)
(The code in ffmpeg.c is buggy in this regard.)
>
> + /* send it to the next filter down the chain */
> if (lst->idx < lst->nb_bsfs) {
> - AVPacket *pkt;
> - if (ret == AVERROR_EOF && lst->idx == lst->flushed_idx) {
> - /* ff_bsf_get_packet_ref returned EOF and idx is first
> - * filter of yet not flushed filter chain */
> - pkt = NULL;
> - } else {
> - pkt = out;
> + ret = av_bsf_send_packet(lst->bsfs[lst->idx], eof ? NULL : out);
The BSF API treats a blank packet (no data, no side_data) as indicating
eof, so you can simply always send out. (More on this later.)
- Andreas
> + av_assert1(ret != AVERROR(EAGAIN));
> + if (ret < 0) {
> + av_packet_unref(out);
> + return ret;
> }
> - ret = av_bsf_send_packet(lst->bsfs[lst->idx], pkt);
> - if (ret < 0)
> - break;
> lst->idx++;
> + eof = 0;
> + } else if (eof) {
> + return ret;
> } else {
> - /* The end of filter chain, break to return result */
> - break;
> + return 0;
> }
> }
> -
> - if (ret < 0)
> - av_packet_unref(out);
> -
> - return ret;
> }
>
> static void bsf_list_flush(AVBSFContext *bsf)
> @@ -363,7 +349,7 @@ static void bsf_list_flush(AVBSFContext *bsf)
>
> for (int i = 0; i < lst->nb_bsfs; i++)
> av_bsf_flush(lst->bsfs[i]);
> - lst->idx = lst->flushed_idx = 0;
> + lst->idx = 0;
> }
>
> static void bsf_list_close(AVBSFContext *bsf)
>
More information about the ffmpeg-devel
mailing list