[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