[FFmpeg-devel] [PATCH v2] avformat/tee: Move to new BSF API

Ján Sebechlebský sebechlebskyjan at gmail.com
Sat Jun 4 21:24:05 CEST 2016


Nicolas, Marton just pointed me to the code you referenced, so I know this is not what you wanted. So please ignore this patch, I'll send another.

Regards,
Jan

4. června 2016 20:24:40 CEST, sebechlebskyjan at gmail.com napsal:
>From: Jan Sebechlebsky <sebechlebskyjan at gmail.com>
>
>Signed-off-by: Jan Sebechlebsky <sebechlebskyjan at gmail.com>
>---
> I've rewritten the patch rapidly. Instead of using recursion it
> accumulates bitstream filtered packets in fifo buffer and
> dynamic array is used instead of linked list to store chain of
> bitstream filters.
>
>libavformat/tee.c | 301
>+++++++++++++++++++++++++++++++++++++++++++++---------
> 1 file changed, 255 insertions(+), 46 deletions(-)
>
>diff --git a/libavformat/tee.c b/libavformat/tee.c
>index 806beaa..0e394ea 100644
>--- a/libavformat/tee.c
>+++ b/libavformat/tee.c
>@@ -23,6 +23,7 @@
> #include "libavutil/avutil.h"
> #include "libavutil/avstring.h"
> #include "libavutil/opt.h"
>+#include "libavutil/fifo.h"
> #include "internal.h"
> #include "avformat.h"
> #include "avio_internal.h"
>@@ -37,8 +38,15 @@ typedef enum {
> #define DEFAULT_SLAVE_FAILURE_POLICY ON_SLAVE_FAILURE_ABORT
> 
> typedef struct {
>+    AVBSFContext **bsfs_ctxs;
>+    unsigned bsfs_ctxs_nr;
>+} TeeBSFList;
>+
>+typedef struct {
>     AVFormatContext *avf;
>-    AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream
>+    TeeBSFList *bsfs; // bitstream filters per stream
>+
>+    AVFifoBuffer *fifo; // fifo buffer used for bsf processing
> 
>     SlaveFailurePolicy on_fail;
> 
>@@ -106,6 +114,46 @@ fail:
>     return ret;
> }
> 
>+static int initialize_bsf(AVFormatContext *avf, const char * bsf_name,
>+                          AVCodecParameters *par_in, AVRational tb_in,
>+                          AVBSFContext ** bsf_ctx)
>+{
>+    int ret = 0;
>+    const AVBitStreamFilter *filter = av_bsf_get_by_name(bsf_name);
>+    AVBSFContext *bsf_ctx_tmp;
>+
>+    if (!filter) {
>+        av_log(avf, AV_LOG_ERROR, "Unknown bitstream filter '%s'\n",
>+                           bsf_name);
>+                    ret = AVERROR(EINVAL);
>+                    return ret;
>+    }
>+
>+    if ((ret = av_bsf_alloc(filter, &bsf_ctx_tmp)) < 0) {
>+        av_log(avf, AV_LOG_ERROR, "Cannot initialize bitstream filter
>'%s'",
>+               bsf_name);
>+        return ret;
>+    }
>+
>+    ret = avcodec_parameters_copy(bsf_ctx_tmp->par_in, par_in);
>+    if (ret < 0) {
>+        goto fail;
>+    }
>+
>+    bsf_ctx_tmp->time_base_in = tb_in;
>+
>+    if ((ret = av_bsf_init(bsf_ctx_tmp)) < 0) {
>+        goto fail;
>+    }
>+
>+    *bsf_ctx = bsf_ctx_tmp;
>+
>+    return ret;
>+fail:
>+    av_bsf_free(&bsf_ctx_tmp);
>+    return ret;
>+}
>+
> /**
>  * Parse list of bitstream filters and add them to the list of filters
>  * pointed to by bsfs.
>@@ -113,37 +161,49 @@ fail:
>  * The list must be specified in the form:
>  * BSFS ::= BSF[,BSFS]
>  */
>-static int parse_bsfs(void *log_ctx, const char *bsfs_spec,
>-                      AVBitStreamFilterContext **bsfs)
>+static int parse_bsfs(AVFormatContext *avf, const char *bsfs_spec,
>+                      TeeBSFList * bsf_list, int stream_nr)
> {
>     char *bsf_name, *buf, *dup, *saveptr;
>-    int ret = 0;
>+    int ret = 0, i;
>+    AVBSFContext *bsf_ctx;
>+    AVStream *stream = avf->streams[stream_nr];
>+    AVCodecParameters *last_codecpar = stream->codecpar;
>+    AVRational last_tb = stream->time_base;
> 
>-    if (!(dup = buf = av_strdup(bsfs_spec)))
>-        return AVERROR(ENOMEM);
>+    if (!(dup = buf = av_strdup(bsfs_spec))) {
>+        ret = AVERROR(ENOMEM);
>+        goto fail;
>+    }
> 
>     while (bsf_name = av_strtok(buf, ",", &saveptr)) {
>-        AVBitStreamFilterContext *bsf =
>av_bitstream_filter_init(bsf_name);
>-
>-        if (!bsf) {
>-            av_log(log_ctx, AV_LOG_ERROR,
>-                   "Cannot initialize bitstream filter with name '%s',
>"
>-                   "unknown filter or internal error happened\n",
>-                   bsf_name);
>-            ret = AVERROR_UNKNOWN;
>-            goto end;
>+        ret = initialize_bsf(avf, bsf_name, last_codecpar, last_tb,
>&bsf_ctx);
>+        if (ret < 0) {
>+            goto fail;
>         }
> 
>-        /* append bsf context to the list of bsf contexts */
>-        *bsfs = bsf;
>-        bsfs = &bsf->next;
>+        last_tb = bsf_ctx->time_base_out;
>+        last_codecpar = bsf_ctx->par_out;
>+
>+        ret = av_dynarray_add_nofree(&bsf_list->bsfs_ctxs,
>&bsf_list->bsfs_ctxs_nr, bsf_ctx);
>+        if (ret < 0) {
>+            goto fail;
>+        }
> 
>         buf = NULL;
>+        bsf_ctx = NULL;
>     }
> 
>-end:
>     av_free(dup);
>     return ret;
>+fail:
>+    for (i = 0; i < bsf_list->bsfs_ctxs_nr; ++i) {
>+        av_bsf_free(&bsf_list->bsfs_ctxs[i]);
>+    }
>+    bsf_list->bsfs_ctxs_nr = 0;
>+    av_free(dup);
>+    av_bsf_free(&bsf_ctx);
>+    return ret;
> }
> 
>static inline int parse_slave_failure_policy_option(const char *opt,
>TeeSlave *tee_slave)
>@@ -163,6 +223,154 @@ static inline int
>parse_slave_failure_policy_option(const char *opt, TeeSlave *t
>     return AVERROR(EINVAL);
> }
> 
>+/*
>+ * Applies single bitstream filter to single packet, all resulting
>filtered packets
>+ * are pushed to fifo buffer
>+ */
>+static int tee_apply_bsf(AVFifoBuffer *fifo, AVBSFContext *bsf_ctx,
>AVPacket *pkt)
>+{
>+    int ret = 0;
>+    ret = av_bsf_send_packet(bsf_ctx, pkt);
>+    if (ret < 0)
>+        return ret;
>+
>+    do {
>+        ret = av_bsf_receive_packet(bsf_ctx, pkt);
>+        if (ret) {
>+            ret = 0;
>+            break;
>+        }
>+
>+        if ( av_fifo_space(fifo) < sizeof(AVPacket)) {
>+            ret = av_fifo_grow(fifo, sizeof(AVPacket));
>+            if (ret < 0)
>+                return ret;
>+        }
>+        av_fifo_generic_write(fifo, pkt, sizeof(AVPacket), NULL);
>+    } while(1);
>+
>+    return ret;
>+}
>+
>+/*
>+ * Applies sequence of bitstream filters to all packets in fifo
>buffer.
>+ * At the return point fifo will contain resulting filtered packets,
>+ * time base pointed by tb will be set to ouput time base of last
>bitstream filter.
>+ * If flushing != 0, each bitstream filter will be flushed
>+ */
>+static int tee_apply_bsfs(AVFifoBuffer *fifo, TeeBSFList *bsfs,
>AVRational *tb, int flushing)
>+{
>+    int ret = 0;
>+    int i, j;
>+    AVPacket pkt;
>+
>+    if (!bsfs || !bsfs->bsfs_ctxs_nr)
>+        return 0;
>+
>+    for (i = 0; i < bsfs->bsfs_ctxs_nr; ++i ) {
>+        int pkt_nr = av_fifo_size(fifo) / sizeof(AVPacket);
>+
>+        for (j = 0; j < pkt_nr; ++j) {
>+            av_fifo_generic_read(fifo, &pkt, sizeof(AVPacket), NULL);
>+            ret = tee_apply_bsf(fifo, bsfs->bsfs_ctxs[i], &pkt);
>+            if (ret < 0) {
>+                return ret;
>+            }
>+        }
>+
>+        if (flushing) {
>+            ret = tee_apply_bsf(fifo, bsfs->bsfs_ctxs[i], NULL);
>+            if (ret < 0)
>+                return ret;
>+        }
>+    }
>+
>+    *tb = bsfs->bsfs_ctxs[bsfs->bsfs_ctxs_nr-1]->time_base_out;
>+
>+    return ret;
>+}
>+
>+/*
>+ * Apply bitstream filters and write frame. If pkt == NULL bitstream
>filters
>+ * will be flushed.
>+ */
>+static int tee_process_packet(TeeSlave * tee_slave, AVPacket *pkt,
>+                              int stream_nr, AVRational pkt_tb)
>+{
>+    int ret = 0, pkt_nr, i;
>+    AVPacket proc_pkt;
>+    AVFormatContext *avf = tee_slave->avf;
>+    TeeBSFList * bsf = &tee_slave->bsfs[stream_nr];
>+    AVFifoBuffer * fifo = tee_slave->fifo;
>+    AVRational out_tb = avf->streams[stream_nr]->time_base;
>+    AVRational in_tb = pkt_tb;
>+
>+    if (pkt) {
>+        av_fifo_generic_write(fifo, pkt, sizeof(AVPacket), NULL);
>+        ret = tee_apply_bsfs(fifo, bsf, &in_tb, 0);
>+    } else {
>+        ret = tee_apply_bsfs(fifo, bsf, &in_tb, 1);
>+    }
>+    if (ret < 0)
>+        goto fail;
>+
>+    pkt_nr = av_fifo_size(fifo) / sizeof(AVPacket);
>+    for (i = 0; i < pkt_nr; ++i) {
>+        av_fifo_generic_read(fifo, &proc_pkt, sizeof(AVPacket), NULL);
>+
>+        proc_pkt.pts = av_rescale_q(proc_pkt.pts, in_tb, out_tb);
>+        proc_pkt.dts = av_rescale_q(proc_pkt.dts, in_tb, out_tb);
>+        proc_pkt.duration = av_rescale_q(proc_pkt.duration, in_tb,
>out_tb);
>+        proc_pkt.stream_index = stream_nr;
>+
>+        ret = av_interleaved_write_frame(avf, &proc_pkt);
>+        if (ret < 0)
>+            goto fail;
>+    }
>+
>+    return ret;
>+fail:
>+    /* Unreference unprocessed packets in fifo */
>+    pkt_nr = av_fifo_size(fifo) / sizeof(AVPacket);
>+    for (i = 0; i < pkt_nr; ++i) {
>+        av_fifo_generic_read(fifo, &proc_pkt, sizeof(AVPacket), NULL);
>+        av_packet_unref(&proc_pkt);
>+    }
>+    return ret;
>+}
>+
>+static int flush_bsfs(TeeSlave *tee_slave)
>+{
>+    AVFormatContext *avf = tee_slave->avf;
>+    int i;
>+    int ret, ret_all = 0;
>+
>+    for (i = 0; i < avf->nb_streams; i++) {
>+        if (tee_slave->bsfs) {
>+            ret = tee_process_packet(tee_slave, NULL, i,
>av_make_q(1,0));
>+            if (!ret_all && ret < 0) {
>+                ret_all = ret;
>+            }
>+        }
>+    }
>+
>+    return ret_all;
>+}
>+
>+static void free_bsf_list(TeeBSFList * bsf_list) {
>+    int i;
>+
>+    if (!bsf_list) {
>+        return;
>+    }
>+
>+    for (i = 0; i < bsf_list->bsfs_ctxs_nr; ++i ) {
>+        av_bsf_free(&bsf_list->bsfs_ctxs[i]);
>+    }
>+    bsf_list->bsfs_ctxs_nr = 0;
>+    av_freep(&bsf_list->bsfs_ctxs);
>+}
>+
> static int close_slave(TeeSlave *tee_slave)
> {
>     AVFormatContext *avf;
>@@ -173,21 +381,23 @@ static int close_slave(TeeSlave *tee_slave)
>     if (!avf)
>         return 0;
> 
>-    if (tee_slave->header_written)
>+    if (tee_slave->header_written) {
>+        ret = flush_bsfs(tee_slave);
>+        if (ret < 0) {
>+            av_log(avf, AV_LOG_ERROR, "Error flushing bitstream
>filters: %s\n",
>+                   av_err2str(ret));
>+        }
>         ret = av_write_trailer(avf);
>+    }
> 
>     if (tee_slave->bsfs) {
>         for (i = 0; i < avf->nb_streams; ++i) {
>-            AVBitStreamFilterContext *bsf_next, *bsf =
>tee_slave->bsfs[i];
>-            while (bsf) {
>-                bsf_next = bsf->next;
>-                av_bitstream_filter_close(bsf);
>-                bsf = bsf_next;
>-            }
>+            free_bsf_list(&tee_slave->bsfs[i]);
>         }
>     }
>     av_freep(&tee_slave->stream_map);
>     av_freep(&tee_slave->bsfs);
>+    av_fifo_freep(&tee_slave->fifo);
> 
>     ff_format_io_close(avf, &avf->pb);
>     avformat_free_context(avf);
>@@ -330,6 +540,12 @@ static int open_slave(AVFormatCo
-- 
Odesláno z mého telefonu s Androidem pomocí pošty K-9 Mail. Omluvte prosím moji stručnost.


More information about the ffmpeg-devel mailing list