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, sebechlebsky...@gmail.com napsal: >From: Jan Sebechlebsky <sebechlebsky...@gmail.com> > >Signed-off-by: Jan Sebechlebsky <sebechlebsky...@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. _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel