From patchwork Sat Mar 28 18:15:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marton Balint X-Patchwork-Id: 18468 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id EDF6144B3B0 for ; Sat, 28 Mar 2020 20:15:45 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id D9D9E68B614; Sat, 28 Mar 2020 20:15:45 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from iq.passwd.hu (iq.passwd.hu [217.27.212.140]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 199B768B4A2 for ; Sat, 28 Mar 2020 20:15:40 +0200 (EET) Received: from localhost (localhost [127.0.0.1]) by iq.passwd.hu (Postfix) with ESMTP id 7955BE1D61; Sat, 28 Mar 2020 19:15:39 +0100 (CET) X-Virus-Scanned: amavisd-new at passwd.hu Received: from iq.passwd.hu ([127.0.0.1]) by localhost (iq.passwd.hu [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 7NM_K6qBZtdy; Sat, 28 Mar 2020 19:15:38 +0100 (CET) Received: from bluegene.passwd.hu (localhost [127.0.0.1]) by iq.passwd.hu (Postfix) with ESMTP id 74E16E33DE; Sat, 28 Mar 2020 19:15:37 +0100 (CET) From: Marton Balint To: ffmpeg-devel@ffmpeg.org Date: Sat, 28 Mar 2020 19:15:12 +0100 Message-Id: <20200328181515.5333-5-cus@passwd.hu> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20200328181515.5333-1-cus@passwd.hu> References: <20200328181515.5333-1-cus@passwd.hu> Subject: [FFmpeg-devel] [PATCH 5/8] avformat/mux: add proper support for full N:M bitstream filtering X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Marton Balint MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Previously only 1:1 bitstream filters were supported, the end of the stream was not signalled to the bitstream filters and time base changes were ignored. Signed-off-by: Marton Balint --- libavformat/internal.h | 1 + libavformat/mux.c | 128 ++++++++++++++++++++++++++++++++++--------------- 2 files changed, 91 insertions(+), 38 deletions(-) diff --git a/libavformat/internal.h b/libavformat/internal.h index 332477a532..45aeef717a 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -158,6 +158,7 @@ struct AVStreamInternal { */ AVBSFContext **bsfcs; int nb_bsfcs; + int bsfcs_idx; /** * Whether or not check_bitstream should still be run on each packet diff --git a/libavformat/mux.c b/libavformat/mux.c index 8c2d6a8060..3054ab8644 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -840,14 +840,48 @@ static int prepare_input_packet(AVFormatContext *s, AVPacket *pkt) return 0; } -static int do_packet_auto_bsf(AVFormatContext *s, AVPacket *pkt) { - AVStream *st = s->streams[pkt->stream_index]; - int i, ret; +static int auto_bsf_receive_packet(AVFormatContext *s, AVStream *st, AVPacket *pkt) +{ + AVStreamInternal *sti = st->internal; + int ret = AVERROR(EAGAIN); + int eof = 0; + + while (sti->bsfcs_idx) { + /* get a packet from the previous filter up the chain */ + ret = av_bsf_receive_packet(sti->bsfcs[sti->bsfcs_idx - 1], pkt); + if (ret == AVERROR(EAGAIN)) { + sti->bsfcs_idx--; + continue; + } else if (ret == AVERROR_EOF) { + eof = 1; + } else if (ret < 0) + break; + + /* send it to the next filter down the chain */ + if (sti->bsfcs_idx < sti->nb_bsfcs) { + ret = av_bsf_send_packet(sti->bsfcs[sti->bsfcs_idx], eof ? NULL : pkt); + av_assert2(ret != AVERROR(EAGAIN)); + if (ret < 0) + break; + sti->bsfcs_idx++; + eof = 0; + } else if (eof) { + break; + } else { + return 0; + } + } + + return ret; +} + +static int need_auto_bsf(AVFormatContext *s, AVStream *st, AVPacket *pkt) { + int ret; if (!(s->flags & AVFMT_FLAG_AUTO_BSF)) - return 1; + return 0; - if (s->oformat->check_bitstream) { + if (pkt && s->oformat->check_bitstream) { if (!st->internal->bitstream_checked) { if ((ret = s->oformat->check_bitstream(s, pkt)) < 0) return ret; @@ -856,31 +890,7 @@ static int do_packet_auto_bsf(AVFormatContext *s, AVPacket *pkt) { } } - for (i = 0; i < st->internal->nb_bsfcs; i++) { - AVBSFContext *ctx = st->internal->bsfcs[i]; - // TODO: when any bitstream filter requires flushing at EOF, we'll need to - // flush each stream's BSF chain on write_trailer. - if ((ret = av_bsf_send_packet(ctx, pkt)) < 0) { - av_log(ctx, AV_LOG_ERROR, - "Failed to send packet to filter %s for stream %d\n", - ctx->filter->name, pkt->stream_index); - return ret; - } - // TODO: when any automatically-added bitstream filter is generating multiple - // output packets for a single input one, we'll need to call this in a loop - // and write each output packet. - if ((ret = av_bsf_receive_packet(ctx, pkt)) < 0) { - if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) - return 0; - av_log(ctx, AV_LOG_ERROR, - "Failed to receive packet from filter %s for stream %d\n", - ctx->filter->name, pkt->stream_index); - if (s->error_recognition & AV_EF_EXPLODE) - return ret; - return 0; - } - } - return 1; + return st->internal->nb_bsfcs; } static int interleaved_write_packet(AVFormatContext *s, AVPacket *pkt, int flush); @@ -909,19 +919,54 @@ static int write_packet_common(AVFormatContext *s, AVStream *st, AVPacket *pkt, static int write_packets_common(AVFormatContext *s, AVStream *st, AVPacket *pkt, int interleaved) { - int ret = do_packet_auto_bsf(s, pkt); - if (ret == 0) - return 0; - else if (ret < 0) + AVStreamInternal *sti = st->internal; + int ret; + + ret = need_auto_bsf(s, st, pkt); + if (ret < 0) goto fail; - ret = write_packet_common(s, st, pkt, interleaved); + if (ret) { + AVPacket opkt = {0}; + int consumed_packet = 0; + + do { + ret = auto_bsf_receive_packet(s, st, &opkt); + if (ret < 0) { + if (ret == AVERROR(EAGAIN) && !consumed_packet) { + av_assert2(sti->bsfcs_idx == 0); + ret = av_bsf_send_packet(sti->bsfcs[0], pkt); + av_assert2(ret != AVERROR(EAGAIN)); + if (ret >= 0) { + consumed_packet = 1; + sti->bsfcs_idx = 1; + continue; + } + } + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + ret = 0; + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Error applying bitstream filters to an output " + "packet for stream #%d: %s\n", st->index, av_err2str(ret)); + if (!(s->error_recognition & AV_EF_EXPLODE)) + ret = 0; + } + goto fail; + } + av_packet_rescale_ts(&opkt, sti->bsfcs[sti->nb_bsfcs-1]->time_base_out, st->time_base); + ret = write_packet_common(s, st, &opkt, interleaved); + if (!interleaved) + av_packet_unref(&opkt); + } while (ret >= 0); + } else { + ret = pkt ? write_packet_common(s, st, pkt, interleaved) : 0; + } if (ret < 0) goto fail; return ret; fail: - if (interleaved) + if (interleaved && pkt) av_packet_unref(pkt); return ret; } @@ -1264,9 +1309,16 @@ fail: int av_write_trailer(AVFormatContext *s) { - int ret, i; + int i, ret1, ret = 0; - ret = interleaved_write_packet(s, NULL, 1); + for (i = 0; i < s->nb_streams; i++) { + ret1 = write_packets_common(s, s->streams[i], NULL, 1/*interleaved*/); + if (ret >= 0) + ret = ret1; + } + ret1 = interleaved_write_packet(s, NULL, 1); + if (ret >= 0) + ret = ret1; if (s->oformat->write_trailer) { if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)