From patchwork Thu Jul 28 16:18:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: sebechlebskyjan@gmail.com X-Patchwork-Id: 17 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.140.67 with SMTP id o64csp885851vsd; Thu, 28 Jul 2016 09:30:55 -0700 (PDT) X-Received: by 10.194.58.112 with SMTP id p16mr35033949wjq.24.1469723455848; Thu, 28 Jul 2016 09:30:55 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id n1si14425075wme.114.2016.07.28.09.30.55; Thu, 28 Jul 2016 09:30:55 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 1922568A31B; Thu, 28 Jul 2016 19:30:41 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm0-f65.google.com (mail-wm0-f65.google.com [74.125.82.65]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1DAAF68A31B for ; Thu, 28 Jul 2016 19:30:30 +0300 (EEST) Received: by mail-wm0-f65.google.com with SMTP id i5so11943795wmg.2 for ; Thu, 28 Jul 2016 09:30:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=wHjDKnfR4LTW5ReS438RdxCMN2SXomuFmdK9yzz2RLU=; b=ZlX8Cs2YGn1Vi9gfi4fRt5NmwFsPMAr0Zx01rOFKJRXiVL/NlOJCr0/30m7Au/B7nJ g5ER0JuqJMIfG5zWgJkqVLbHVyiKqGI68kzJKvnLYRiW6tn3pGzk6SGqEeMzzdO5OUi7 TZZ6qKAs3jnYsOCpH1hSTlpe4OwZJ6Oo7YVWoSFCwmZv/qb59m5OkHNG0CqslzerBuEQ dnKt4YRm67Ice9qbpg2tBe12EeqgPdigg5XbH07vLCQ+eqVBzRULRFi3ItyRa6QVmTQJ VkXDoezDHRxRumRDy8V7jusMGPkpDn3Y2StobIaKj7zzwAuM/IwA4g3ZAUE/K5lETMSV dApg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=wHjDKnfR4LTW5ReS438RdxCMN2SXomuFmdK9yzz2RLU=; b=RsH6Db9jTp2PRN/+QodVPZq+fVcJs2qQSHclxQcxtOdGT8bEv9RXBE9MRBE1hnPu3N MhoN2yxA9AxgtG3AZXuQ1QmtUg6kfRpuYR/LhUfWSUxfbELSgZMJFH82LrWbMt0GBERR fpInuOGJNM4HnJgbh7jhwxgFu70xS9mcEpCH7jvgv8KfDv3iY07PIV4AQsYuAqCHjiZC /rJ5dncGujPfBkwYS4nmQKAOSM0eKe50boDafU74L70dii3764ZZgfhU0HkjWnEBU8W0 z/FWdE94P3xaciGmaZ36EmFrPHYFWB75fK0mULnbWI2FniSBsmy62rICMO+N71dSMQhP uOcw== X-Gm-Message-State: AEkoouvBoVFqH2Ny8Ums4dzvhRuFTufWG3HQsICUtOZgBFqAWHuzhKibwY6XMci8IRTp9A== X-Received: by 10.194.187.7 with SMTP id fo7mr34397392wjc.162.1469722715484; Thu, 28 Jul 2016 09:18:35 -0700 (PDT) Received: from localhost.localdomain (157.174.broadband3.iol.cz. [85.70.174.157]) by smtp.gmail.com with ESMTPSA id i80sm12961969wmf.11.2016.07.28.09.18.34 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 28 Jul 2016 09:18:34 -0700 (PDT) From: sebechlebskyjan@gmail.com To: ffmpeg-devel@ffmpeg.org Date: Thu, 28 Jul 2016 18:18:14 +0200 Message-Id: <1469722696-2018-3-git-send-email-sebechlebskyjan@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1469722696-2018-1-git-send-email-sebechlebskyjan@gmail.com> References: <1469722696-2018-1-git-send-email-sebechlebskyjan@gmail.com> Subject: [FFmpeg-devel] [PATCH 3/5] avcodec/bsf: Add list BSF API 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: Jan Sebechlebsky MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: Jan Sebechlebsky --- libavcodec/avcodec.h | 74 ++++++++++++++ libavcodec/bsf.c | 284 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 358 insertions(+) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 36f7935..39106ee 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -5949,6 +5949,80 @@ void av_bsf_free(AVBSFContext **ctx); */ const AVClass *av_bsf_get_class(void); +/** + * Structure for chain/list of bitstream filters. + * Empty list can be allocated by av_bsf_list_alloc(). + */ +typedef struct AVBSFList AVBSFList; + +/** + * Allocate empty list of bitstream filters. + * The list must be later freed by av_bsf_list_free() + * or finalized by av_bsf_list_finalize(). + * + * @return pointer to AVBSFList on success, NULL in case of failure + */ +AVBSFList *av_bsf_list_alloc(void); + +/** + * Free list of bitstream filters. + * + * @param lst pointer to pointer returned by av_bsf_list_alloc() + */ +void av_bsf_list_free(AVBSFList **lst); + +/** + * Append bitstream filter to the list of bitstream filters. + * + * @param lst list to append to + * @param bsf AVBSFContext to be appended + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_append(AVBSFList *lst, AVBSFContext *bsf); + +/** + * Finalize list of bitstream filters. + * + * This function will transform AVBSFList to single AVBSFContext, + * so the whole chain of bitstream filters can be treated as single filter + * freshly allocated by av_bsf_alloc(). + * The AVBSFList structure is destroyed after this call and must not + * be accessed. + * + * @param lst AVBSFList structure to be transformed + * @param bsf[out] pointer to be set to newly created AVBSFContext structure + * representing the chain of bitstream filters + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_finalize(AVBSFList **lst, AVBSFContext **bsf); + +/** + * Parse string describing list of bitstream filters and create single + * AVBSFContext describing the whole chain of bitstream filters. + * Resulting AVBSFContext can be treated as any other AVBSFContext freshly + * allocated by av_bsf_alloc(). + * + * @param str string describing chain of bitstream filters in format + * bsf1[=opt1=val1:opt2=val2][,bsf2] + * @param bsf[out] pointer to be set to newly created AVBSFContext structure + * representing the chain of bitstream filters + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_parse_str(const char *str, AVBSFContext **bsf); + +/** + * Get null/pass-through bitstream filter. + * + * @param bsf[out] pointer to be set to new instance of pass-through + * bitstream filter + * + * @return + */ +int av_bsf_get_null_filter(AVBSFContext **bsf); + /* memory */ /** diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c index 40fc925..3ae0a2b 100644 --- a/libavcodec/bsf.c +++ b/libavcodec/bsf.c @@ -22,6 +22,7 @@ #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/avassert.h" +#include "libavutil/avstring.h" #include "avcodec.h" #include "bsf.h" @@ -236,3 +237,286 @@ int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket *pkt) return 0; } + +typedef struct BSFListContext { + const AVClass *class; + + AVBSFContext **bsf_lst; + int ctx_nr; + + int idx; // index of currently processed BSF + int flushed_idx; // index of BSF being flushed + +} BSFListContext; + + +static int bsf_list_init(AVBSFContext *bsf) +{ + BSFListContext *lst = bsf->priv_data; + int ret, i; + const AVCodecParameters *cod_par = bsf->par_in; + AVRational tb = bsf->time_base_in; + + for (i = 0; i < lst->ctx_nr; ++i) { + ret = avcodec_parameters_copy(lst->bsf_lst[i]->par_in, cod_par); + if (ret < 0) + goto fail; + + lst->bsf_lst[i]->time_base_in = tb; + + ret = av_bsf_init(lst->bsf_lst[i]); + if (ret < 0) + goto fail; + + cod_par = lst->bsf_lst[i]->par_out; + tb = lst->bsf_lst[i]->time_base_out; + } + + bsf->time_base_out = tb; + ret = avcodec_parameters_copy(bsf->par_out, cod_par); + +fail: + return ret; +} + +static int bsf_list_flush(AVBSFContext *bsf, AVPacket *out) +{ + BSFListContext *lst = bsf->priv_data; + int ret; + + if (lst->flushed_idx == lst->ctx_nr) + return AVERROR_EOF; + + while (1) { + if (lst->idx > lst->flushed_idx) { + ret = av_bsf_receive_packet(lst->bsf_lst[lst->idx-1], out); + if (ret == AVERROR(EAGAIN)) { + ret = 0; + lst->idx--; + continue; + } else if (ret == AVERROR_EOF) { + /* filter idx-1 is done, let's flush filter idx */ + lst->flushed_idx = lst->idx; + continue; + } else if (ret < 0) { + /* filtering error */ + break; + } + } + + if (lst->idx < lst->ctx_nr) { + AVPacket *pkt = (lst->idx == lst->flushed_idx) ? NULL : out; + ret = av_bsf_send_packet(lst->bsf_lst[lst->idx], pkt); + if (ret < 0) + break; + lst->idx++; + } else { + /* The end of filter chain, break to return result */ + break; + } + } + + return ret; +} + +static int bsf_list_filter(AVBSFContext *bsf, AVPacket *out) +{ + BSFListContext *lst = bsf->priv_data; + int ret; + + if (!lst->ctx_nr) + return ff_bsf_get_packet_ref(bsf, out); + + while (1) { + if (lst->idx) { + ret = av_bsf_receive_packet(lst->bsf_lst[lst->idx-1], out); + if (ret == AVERROR(EAGAIN)) { + ret = 0; + lst->idx--; + continue; + } else if (ret < 0) { + break; + } + } else { + ret = ff_bsf_get_packet_ref(bsf, out); + if (ret < 0) + break; + } + + if (lst->idx < lst->ctx_nr) { + ret = av_bsf_send_packet(lst->bsf_lst[lst->idx], out); + if (ret < 0) + break; + lst->idx++; + } else { + break; + } + } + + if (ret == AVERROR_EOF) + ret = bsf_list_flush(bsf, out); + + if (ret < 0) + av_packet_unref(out); + + return ret; +} + +static void bsf_list_close(AVBSFContext *bsf) +{ + BSFListContext *lst = bsf->priv_data; + int i; + + for (i = 0; i < lst->ctx_nr; ++i) + av_bsf_free(&lst->bsf_lst[i]); + av_freep(&lst->bsf_lst); +} + +static const AVClass bsf_list_class = { + .class_name = "bsf_list", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVBitStreamFilter ff_list_bsf = { + .name = "bsf_list", + .priv_data_size = sizeof(BSFListContext), + .priv_class = &bsf_list_class, + .init = bsf_list_init, + .filter = bsf_list_filter, + .close = bsf_list_close, +}; + +typedef struct AVBSFList { + AVBSFContext **bsf_lst; + int ctx_nr; +} AVBSFList; + +AVBSFList *av_bsf_list_alloc(void) +{ + return av_mallocz(sizeof(AVBSFList)); +} + +void av_bsf_list_free(AVBSFList **lst) +{ + int i; + for (i = 0; i < (*lst)->ctx_nr; ++i) + av_bsf_free(&(*lst)->bsf_lst[i]); + av_free((*lst)->bsf_lst); + av_freep(lst); +} + +int av_bsf_list_append(AVBSFList *lst, AVBSFContext *bsf) +{ + return av_dynarray_add_nofree(&lst->bsf_lst, &lst->ctx_nr, bsf); +} + +int av_bsf_list_finalize(AVBSFList **lst, AVBSFContext **bsf) +{ + int ret = 0; + BSFListContext *ctx; + + if ((*lst)->ctx_nr == 1) { + *bsf = (*lst)->bsf_lst[0]; + (*lst)->bsf_lst = NULL; + (*lst)->ctx_nr = 0; + goto end; + } + + ret = av_bsf_alloc(&ff_list_bsf, bsf); + if (ret < 0) + return ret; + + ctx = (*bsf)->priv_data; + + ctx->bsf_lst = (*lst)->bsf_lst; + ctx->ctx_nr = (*lst)->ctx_nr; + +end: + av_freep(lst); + return ret; +} + +static int bsf_parse_str(const char *str, AVBSFContext **bsf) +{ + const AVBitStreamFilter *filter; + char *bsf_name, *bsf_options_str, *buf; + int ret = 0; + + if (!(buf = av_strdup(str))) + return AVERROR(ENOMEM); + + bsf_name = av_strtok(buf, "=", &bsf_options_str); + if (!bsf_name) { + ret = AVERROR(EINVAL); + goto end; + } + + filter = av_bsf_get_by_name(bsf_name); + if (!filter) { + ret = AVERROR_BSF_NOT_FOUND; + goto end; + } + + ret = av_bsf_alloc(filter, bsf); + if (ret < 0) + goto end; + + if (bsf_options_str) { + ret = av_set_options_string(*bsf, bsf_options_str, "=", ":"); + if (ret < 0) + av_bsf_free(bsf); + } + +end: + av_free(buf); + return ret; +} + +int av_bsf_list_parse_str(const char *str, AVBSFContext **bsf_lst) +{ + AVBSFList *lst; + char *bsf_str, *buf, *dup, *saveptr; + int ret; + + if (!str) + return av_bsf_get_null_filter(bsf_lst); + + lst = av_bsf_list_alloc(); + if (!lst) + return AVERROR(ENOMEM); + + if (!(dup = buf = av_strdup(str))) + return AVERROR(ENOMEM); + + while (1) { + AVBSFContext *bsf; + bsf_str = av_strtok(buf, ",", &saveptr); + if (!bsf_str) + break; + + ret = bsf_parse_str(bsf_str, &bsf); + if (ret < 0) + goto end; + + ret = av_bsf_list_append(lst, bsf); + if (ret < 0) { + av_bsf_free(&bsf); + goto end; + } + + buf = NULL; + } + + ret = av_bsf_list_finalize(&lst, bsf_lst); +end: + if (ret < 0) + av_bsf_list_free(&lst); + av_free(dup); + return ret; +} + +int av_bsf_get_null_filter(AVBSFContext **bsf) +{ + return av_bsf_alloc(&ff_list_bsf, bsf); +}