From patchwork Sun Oct 8 20:01:37 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Thompson X-Patchwork-Id: 5462 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.161.90 with SMTP id m26csp1904828jah; Sun, 8 Oct 2017 13:02:39 -0700 (PDT) X-Received: by 10.223.186.82 with SMTP id t18mr7942271wrg.19.1507492959505; Sun, 08 Oct 2017 13:02:39 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1507492959; cv=none; d=google.com; s=arc-20160816; b=lr1NRWPwBpnYbWkmMhLstAf4MWJwF3bJE88wuV5grG5pVNDpuVOoK2VvgizFuHPdyq dDijD1E16dw1U8lZVl2h/VDDFtEa7yodUWcyzH5hAs9qx6xV3ildk0obH6ItFz+sBC8z OJG6YfZHDBb48NTHHX4I8zX9cHUS2t/y0XRjxdtB9YehYdURNX64lTAUqKQstxYzqhNn IHZfFxymv9UmGZj3JEJI/0SFfiKoioP2bs0K7CRSW7hhpTCqcMuMgSgmYkY+3c0qSt7G XbxYwJfEOLcVL+Sv3Kqse8FBYmIub93L9Rmune25pOg8KFgxdtCu0joD5HRuOaOES1Qc eumw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to:arc-authentication-results; bh=NRJl2Jvpr3d5D8V+y3dx2FVNi3M+6FpOVfE94VmXEj0=; b=BLemmtG5rhCjFEiRctFXSskLA4+tl4u7XwasOjZvR+uiR9PWLLXW7zOWwPfx1Az81x qwLN+Wiv7Z+oZdxhgSu42hyzDyY+Yt6gGHonZvnJ58dFYBVS04/0zK9BIu8QcNYhNgxN qjVyaRsJFBlGGmmWLFnFrMksNeuunb4JXu+acWPenAl2w/Fa7dfQUbL5sYI7Fmm0k6mz TkbLBUqat4D4ztZ2egw4dxUJGGx9HxUJx8Dr8UGb+f7DnxYgdSkD4V7vazIXACtT+ep9 ygqP7istooMb9OpSmxDiYcEnxWRMx2LzpKAunPlmg8MDGNvUDeLVoo0LEd0OpJWQlCSV RO5A== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@jkqxz-net.20150623.gappssmtp.com header.s=20150623 header.b=A8XHJzbq; 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 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id s5si5668459wra.178.2017.10.08.13.02.39; Sun, 08 Oct 2017 13:02:39 -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=@jkqxz-net.20150623.gappssmtp.com header.s=20150623 header.b=A8XHJzbq; 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 Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 44764689D60; Sun, 8 Oct 2017 23:02:06 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm0-f52.google.com (mail-wm0-f52.google.com [74.125.82.52]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id EFFE1689D30 for ; Sun, 8 Oct 2017 23:01:59 +0300 (EEST) Received: by mail-wm0-f52.google.com with SMTP id f4so18506633wme.0 for ; Sun, 08 Oct 2017 13:02:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jkqxz-net.20150623.gappssmtp.com; s=20150623; h=from:to:subject:date:message-id:in-reply-to:references; bh=7hw6IrwLD6ZfU2q7UcaO56hCqY37uCvFaWR7tw6HXfw=; b=A8XHJzbqmPmNTm/ucfMlDXp+0XLLtqOVtsZgjrdGwl9ld0SiYnzOJvIVfPBxcpUyuU QhVUjyDYSiqDgkN0y1izKMAUYOM+waMnpS3gnajoAE04wVUHojQCToNrwSaogLma5ic2 khFhGlQTqbn2uw9DBCG5HDM4xcKx68XdEcsaifSUmcf8VcToxcxRQQJ0pSXRpJlf0h3g 8/SoisUXMtMY57Q3Acw9wUlmIIjrwh5DmAHzZwoWTyHZUVd6zEvH6KFl9fU2fxm9tmhK 5Cv8GP3el0zmYvyn4MaeYaWi+Jkoj3RFndd25fzZLpgIrrl4OIKvfnenNeUREYkImNWG S6sQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=7hw6IrwLD6ZfU2q7UcaO56hCqY37uCvFaWR7tw6HXfw=; b=blmHs67IAWFlZlI9NqUgbmq2L5IrY/GrsaCVw0YmU9acSXFM8vI5T1kxgFNs/nCZxm actUALEMfnpg4CvG1KGHKpMCWejb76D3kfqnSoFte3rfCYHM3smNqy2mheaxQYC/f9mY GtprXAO9Jh9ehzpHSGwpihloA5F+Tec9HxK8Y2A7wEWpAWix+dPcGcgC3kKuNJxzFOwt 1ITqQLLnJGiNrhoRIKgX/DD3PjkqsenajEQRvcW/hZCDA9AsZVSwgAkN0pZFbdKwz+5k dJ1YBK1w7eDwMU59BcCP5CnIScMpXKNAfX7lOdRwqSumxsPeYRiJYpsI3V5nCstwi+ES O+1g== X-Gm-Message-State: AMCzsaWk9WELAEdvIQsYnPxUJFF0+waBlpEbA1l94nFb4OybcHJK7ZrM 2KbCPoXBk5rZs6HHaGjF4UihbJN6 X-Google-Smtp-Source: AOwi7QCKBk1utxelyVXX7RxSsZ97IoQD/qUTqrv9G9Y681M8ugTyEbqu1swU9XG3nIuj8ry+vLdG0w== X-Received: by 10.223.182.80 with SMTP id i16mr6421256wre.110.1507492920553; Sun, 08 Oct 2017 13:02:00 -0700 (PDT) Received: from rywe.jkqxz.net (cpc91242-cmbg18-2-0-cust650.5-4.cable.virginm.net. [82.8.130.139]) by smtp.gmail.com with ESMTPSA id x49sm2897856wrb.25.2017.10.08.13.01.59 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 08 Oct 2017 13:01:59 -0700 (PDT) From: Mark Thompson To: ffmpeg-devel@ffmpeg.org Date: Sun, 8 Oct 2017 21:01:37 +0100 Message-Id: <20171008200154.4873-4-sw@jkqxz.net> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20171008200154.4873-1-sw@jkqxz.net> References: <20171008200154.4873-1-sw@jkqxz.net> Subject: [FFmpeg-devel] [PATCH 03/20] lavc: Add coded bitstream read/write 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 MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" (cherry picked from commit 18f1706f331bf5dd565774eae680508c8d3a97ad) (cherry picked from commit 44cde38c8acbef7d5250e6d1b52b1020871e093b) --- configure | 1 + libavcodec/Makefile | 1 + libavcodec/cbs.c | 479 ++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/cbs.h | 283 +++++++++++++++++++++++++++ libavcodec/cbs_internal.h | 86 +++++++++ 5 files changed, 850 insertions(+) create mode 100644 libavcodec/cbs.c create mode 100644 libavcodec/cbs.h create mode 100644 libavcodec/cbs_internal.h diff --git a/configure b/configure index 77c9a18c3c..b238293cc1 100755 --- a/configure +++ b/configure @@ -2142,6 +2142,7 @@ CONFIG_EXTRA=" blockdsp bswapdsp cabac + cbs dirac_parse dvprofile exif diff --git a/libavcodec/Makefile b/libavcodec/Makefile index c4ec09b1c4..9680553c90 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -59,6 +59,7 @@ OBJS-$(CONFIG_AUDIODSP) += audiodsp.o OBJS-$(CONFIG_BLOCKDSP) += blockdsp.o OBJS-$(CONFIG_BSWAPDSP) += bswapdsp.o OBJS-$(CONFIG_CABAC) += cabac.o +OBJS-$(CONFIG_CBS) += cbs.o OBJS-$(CONFIG_CRYSTALHD) += crystalhd.o OBJS-$(CONFIG_DCT) += dct.o dct32_fixed.o dct32_float.o OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c new file mode 100644 index 0000000000..a3b487b529 --- /dev/null +++ b/libavcodec/cbs.c @@ -0,0 +1,479 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" + +#include "libavutil/avassert.h" +#include "libavutil/common.h" + +#include "cbs.h" +#include "cbs_internal.h" + + +static const CodedBitstreamType *cbs_type_table[] = { +}; + +int ff_cbs_init(CodedBitstreamContext **ctx_ptr, + enum AVCodecID codec_id, void *log_ctx) +{ + CodedBitstreamContext *ctx; + const CodedBitstreamType *type; + int i; + + type = NULL; + for (i = 0; i < FF_ARRAY_ELEMS(cbs_type_table); i++) { + if (cbs_type_table[i]->codec_id == codec_id) { + type = cbs_type_table[i]; + break; + } + } + if (!type) + return AVERROR(EINVAL); + + ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return AVERROR(ENOMEM); + + ctx->log_ctx = log_ctx; + ctx->codec = type; + + ctx->priv_data = av_mallocz(ctx->codec->priv_data_size); + if (!ctx->priv_data) { + av_freep(&ctx); + return AVERROR(ENOMEM); + } + + ctx->decompose_unit_types = NULL; + + ctx->trace_enable = 0; + ctx->trace_level = AV_LOG_TRACE; + + *ctx_ptr = ctx; + return 0; +} + +void ff_cbs_close(CodedBitstreamContext **ctx_ptr) +{ + CodedBitstreamContext *ctx = *ctx_ptr; + + if (ctx->codec && ctx->codec->close) + ctx->codec->close(ctx); + + av_freep(&ctx->priv_data); + av_freep(ctx_ptr); +} + +static void cbs_unit_uninit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + if (ctx->codec->free_unit && unit->content && !unit->content_external) + ctx->codec->free_unit(unit); + + av_freep(&unit->data); + unit->data_size = 0; + unit->data_bit_padding = 0; +} + +void ff_cbs_fragment_uninit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + int i; + + for (i = 0; i < frag->nb_units; i++) + cbs_unit_uninit(ctx, &frag->units[i]); + av_freep(&frag->units); + frag->nb_units = 0; + + av_freep(&frag->data); + frag->data_size = 0; + frag->data_bit_padding = 0; +} + +static int cbs_read_fragment_content(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + int err, i, j; + + for (i = 0; i < frag->nb_units; i++) { + if (ctx->decompose_unit_types) { + for (j = 0; j < ctx->nb_decompose_unit_types; j++) { + if (ctx->decompose_unit_types[j] == frag->units[i].type) + break; + } + if (j >= ctx->nb_decompose_unit_types) + continue; + } + + err = ctx->codec->read_unit(ctx, &frag->units[i]); + if (err == AVERROR(ENOSYS)) { + av_log(ctx->log_ctx, AV_LOG_WARNING, + "Decomposition unimplemented for unit %d " + "(type %"PRIu32").\n", i, frag->units[i].type); + } else if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d " + "(type %"PRIu32").\n", i, frag->units[i].type); + return err; + } + } + + return 0; +} + +int ff_cbs_read_extradata(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVCodecParameters *par) +{ + int err; + + memset(frag, 0, sizeof(*frag)); + + frag->data = par->extradata; + frag->data_size = par->extradata_size; + + err = ctx->codec->split_fragment(ctx, frag, 1); + if (err < 0) + return err; + + frag->data = NULL; + frag->data_size = 0; + + return cbs_read_fragment_content(ctx, frag); +} + +int ff_cbs_read_packet(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVPacket *pkt) +{ + int err; + + memset(frag, 0, sizeof(*frag)); + + frag->data = pkt->data; + frag->data_size = pkt->size; + + err = ctx->codec->split_fragment(ctx, frag, 0); + if (err < 0) + return err; + + frag->data = NULL; + frag->data_size = 0; + + return cbs_read_fragment_content(ctx, frag); +} + +int ff_cbs_read(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const uint8_t *data, size_t size) +{ + int err; + + memset(frag, 0, sizeof(*frag)); + + // (We won't write to this during split.) + frag->data = (uint8_t*)data; + frag->data_size = size; + + err = ctx->codec->split_fragment(ctx, frag, 0); + if (err < 0) + return err; + + frag->data = NULL; + frag->data_size = 0; + + return cbs_read_fragment_content(ctx, frag); +} + + +int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + int err, i; + + for (i = 0; i < frag->nb_units; i++) { + if (!frag->units[i].content) + continue; + + err = ctx->codec->write_unit(ctx, &frag->units[i]); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write unit %d " + "(type %"PRIu32").\n", i, frag->units[i].type); + return err; + } + } + + err = ctx->codec->assemble_fragment(ctx, frag); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to assemble fragment.\n"); + return err; + } + + return 0; +} + +int ff_cbs_write_extradata(CodedBitstreamContext *ctx, + AVCodecParameters *par, + CodedBitstreamFragment *frag) +{ + int err; + + err = ff_cbs_write_fragment_data(ctx, frag); + if (err < 0) + return err; + + av_freep(&par->extradata); + + par->extradata = av_malloc(frag->data_size + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!par->extradata) + return AVERROR(ENOMEM); + + memcpy(par->extradata, frag->data, frag->data_size); + memset(par->extradata + frag->data_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + par->extradata_size = frag->data_size; + + return 0; +} + +int ff_cbs_write_packet(CodedBitstreamContext *ctx, + AVPacket *pkt, + CodedBitstreamFragment *frag) +{ + int err; + + err = ff_cbs_write_fragment_data(ctx, frag); + if (err < 0) + return err; + + err = av_new_packet(pkt, frag->data_size); + if (err < 0) + return err; + + memcpy(pkt->data, frag->data, frag->data_size); + pkt->size = frag->data_size; + + return 0; +} + + +void ff_cbs_trace_header(CodedBitstreamContext *ctx, + const char *name) +{ + if (!ctx->trace_enable) + return; + + av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name); +} + +void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position, + const char *name, const char *bits, + int64_t value) +{ + size_t name_len, bits_len; + int pad; + + if (!ctx->trace_enable) + return; + + av_assert0(value >= INT_MIN && value <= UINT32_MAX); + + name_len = strlen(name); + bits_len = strlen(bits); + + if (name_len + bits_len > 60) + pad = bits_len + 2; + else + pad = 61 - name_len; + + av_log(ctx->log_ctx, ctx->trace_level, "%-10d %s%*s = %"PRId64"\n", + position, name, pad, bits, value); +} + +int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, + int width, const char *name, uint32_t *write_to, + uint32_t range_min, uint32_t range_max) +{ + uint32_t value; + int position; + + av_assert0(width > 0 && width <= 32); + + if (get_bits_left(gbc) < width) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + + if (ctx->trace_enable) + position = get_bits_count(gbc); + + value = get_bits_long(gbc, width); + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (i = 0; i < width; i++) + bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; + bits[i] = 0; + + ff_cbs_trace_syntax_element(ctx, position, name, bits, value); + } + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + *write_to = value; + return 0; +} + +int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, uint32_t value, + uint32_t range_min, uint32_t range_max) +{ + av_assert0(width > 0 && width <= 32); + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + if (put_bits_left(pbc) < width) + return AVERROR(ENOSPC); + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (i = 0; i < width; i++) + bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; + bits[i] = 0; + + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), name, bits, value); + } + + if (width < 32) + put_bits(pbc, width, value); + else + put_bits32(pbc, value); + + return 0; +} + + +static int cbs_insert_unit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position) +{ + CodedBitstreamUnit *units; + + units = av_malloc_array(frag->nb_units + 1, sizeof(*units)); + if (!units) + return AVERROR(ENOMEM); + + if (position > 0) + memcpy(units, frag->units, position * sizeof(*units)); + if (position < frag->nb_units) + memcpy(units + position + 1, frag->units + position, + (frag->nb_units - position) * sizeof(*units)); + + memset(units + position, 0, sizeof(*units)); + + av_freep(&frag->units); + frag->units = units; + ++frag->nb_units; + + return 0; +} + +int ff_cbs_insert_unit_content(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + void *content) +{ + int err; + + if (position == -1) + position = frag->nb_units; + av_assert0(position >= 0 && position <= frag->nb_units); + + err = cbs_insert_unit(ctx, frag, position); + if (err < 0) + return err; + + frag->units[position].type = type; + frag->units[position].content = content; + frag->units[position].content_external = 1; + + return 0; +} + +int ff_cbs_insert_unit_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + uint8_t *data, size_t data_size) +{ + int err; + + if (position == -1) + position = frag->nb_units; + av_assert0(position >= 0 && position <= frag->nb_units); + + err = cbs_insert_unit(ctx, frag, position); + if (err < 0) + return err; + + frag->units[position].type = type; + frag->units[position].data = data; + frag->units[position].data_size = data_size; + + return 0; +} + +int ff_cbs_delete_unit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position) +{ + if (position < 0 || position >= frag->nb_units) + return AVERROR(EINVAL); + + cbs_unit_uninit(ctx, &frag->units[position]); + + --frag->nb_units; + + if (frag->nb_units == 0) { + av_freep(&frag->units); + + } else { + memmove(frag->units + position, + frag->units + position + 1, + (frag->nb_units - position) * sizeof(*frag->units)); + + // Don't bother reallocating the unit array. + } + + return 0; +} diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h new file mode 100644 index 0000000000..e35175fc74 --- /dev/null +++ b/libavcodec/cbs.h @@ -0,0 +1,283 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CBS_H +#define AVCODEC_CBS_H + +#include +#include + +#include "avcodec.h" + + +struct CodedBitstreamType; + +/** + * The codec-specific type of a bitstream unit. + */ +typedef uint32_t CodedBitstreamUnitType; + +/** + * Coded bitstream unit structure. + * + * A bitstream unit the smallest element of a bitstream which + * is meaningful on its own. For example, an H.264 NAL unit. + * + * See the codec-specific header for the meaning of this for any + * particular codec. + */ +typedef struct CodedBitstreamUnit { + /** + * Codec-specific type of this unit. + */ + CodedBitstreamUnitType type; + + /** + * Pointer to the bitstream form of this unit. + * + * May be NULL if the unit currently only exists in decomposed form. + */ + uint8_t *data; + /** + * The number of bytes in the bitstream (including any padding bits + * in the final byte). + */ + size_t data_size; + /** + * The number of bits which should be ignored in the final byte. + * + * This supports non-byte-aligned bitstreams. + */ + size_t data_bit_padding; + + /** + * Pointer to the decomposed form of this unit. + * + * The type of this structure depends on both the codec and the + * type of this unit. May be NULL if the unit only exists in + * bitstream form. + */ + void *content; + /** + * Whether the content was supplied externally. + * + * If so, it should not be freed when freeing the unit. + */ + int content_external; +} CodedBitstreamUnit; + +/** + * Coded bitstream fragment structure, combining one or more units. + * + * This is any sequence of units. It need not form some greater whole, + * though in many cases it will. For example, an H.264 access unit, + * which is composed of a sequence of H.264 NAL units. + */ +typedef struct CodedBitstreamFragment { + /** + * Pointer to the bitstream form of this fragment. + * + * May be NULL if the fragment only exists as component units. + */ + uint8_t *data; + /** + * The number of bytes in the bitstream. + * + * The number of bytes in the bitstream (including any padding bits + * in the final byte). + */ + size_t data_size; + /** + * The number of bits which should be ignored in the final byte. + */ + size_t data_bit_padding; + + /** + * Number of units in this fragment. + * + * This may be zero if the fragment only exists in bitstream form + * and has not been decomposed. + */ + int nb_units; + /** + * Pointer to an array of units of length nb_units. + * + * Must be NULL if nb_units is zero. + */ + CodedBitstreamUnit *units; +} CodedBitstreamFragment; + +/** + * Context structure for coded bitstream operations. + */ +typedef struct CodedBitstreamContext { + /** + * Logging context to be passed to all av_log() calls associated + * with this context. + */ + void *log_ctx; + + /** + * Internal codec-specific hooks. + */ + const struct CodedBitstreamType *codec; + + /** + * Internal codec-specific data. + * + * This contains any information needed when reading/writing + * bitsteams which will not necessarily be present in a fragment. + * For example, for H.264 it contains all currently visible + * parameter sets - they are required to determine the bitstream + * syntax but need not be present in every access unit. + */ + void *priv_data; + + /** + * Array of unit types which should be decomposed when reading. + * + * Types not in this list will be available in bitstream form only. + * If NULL, all supported types will be decomposed. + */ + CodedBitstreamUnitType *decompose_unit_types; + /** + * Length of the decompose_unit_types array. + */ + int nb_decompose_unit_types; + + /** + * Enable trace output during read/write operations. + */ + int trace_enable; + /** + * Log level to use for trace output. + * + * From AV_LOG_*; defaults to AV_LOG_TRACE. + */ + int trace_level; +} CodedBitstreamContext; + + +/** + * Create and initialise a new context for the given codec. + */ +int ff_cbs_init(CodedBitstreamContext **ctx, + enum AVCodecID codec_id, void *log_ctx); + +/** + * Close a context and free all internal state. + */ +void ff_cbs_close(CodedBitstreamContext **ctx); + + +/** + * Read the extradata bitstream found in codec parameters into a + * fragment, then split into units and decompose. + * + * This also updates the internal state, so will need to be called for + * codecs with extradata to read parameter sets necessary for further + * parsing even if the fragment itself is not desired. + */ +int ff_cbs_read_extradata(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVCodecParameters *par); + +/** + * Read the data bitstream from a packet into a fragment, then + * split into units and decompose. + */ +int ff_cbs_read_packet(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVPacket *pkt); + +/** + * Read a bitstream from a memory region into a fragment, then + * split into units and decompose. + */ +int ff_cbs_read(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const uint8_t *data, size_t size); + + +/** + * Write the content of the fragment to its own internal buffer. + * + * Writes the content of all units and then assembles them into a new + * data buffer. When modifying the content of decomposed units, this + * can be used to regenerate the bitstream form of units or the whole + * fragment so that it can be extracted for other use. + */ +int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag); + +/** + * Write the bitstream of a fragment to the extradata in codec parameters. + * + * This replaces any existing extradata in the structure. + */ +int ff_cbs_write_extradata(CodedBitstreamContext *ctx, + AVCodecParameters *par, + CodedBitstreamFragment *frag); + +/** + * Write the bitstream of a fragment to a packet. + */ +int ff_cbs_write_packet(CodedBitstreamContext *ctx, + AVPacket *pkt, + CodedBitstreamFragment *frag); + + +/** + * Free all allocated memory in a fragment. + */ +void ff_cbs_fragment_uninit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag); + + +/** + * Insert a new unit into a fragment with the given content. + * + * The content structure continues to be owned by the caller, and + * will not be freed when the unit is. + */ +int ff_cbs_insert_unit_content(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + void *content); + +/** + * Insert a new unit into a fragment with the given data bitstream. + * + * The data buffer will be owned by the unit after this operation. + */ +int ff_cbs_insert_unit_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + uint8_t *data, size_t data_size); + +/** + * Delete a unit from a fragment and free all memory it uses. + */ +int ff_cbs_delete_unit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position); + + +#endif /* AVCODEC_CBS_H */ diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h new file mode 100644 index 0000000000..f6a42beea3 --- /dev/null +++ b/libavcodec/cbs_internal.h @@ -0,0 +1,86 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CBS_INTERNAL_H +#define AVCODEC_CBS_INTERNAL_H + +#include "avcodec.h" +#include "cbs.h" +#include "get_bits.h" +#include "put_bits.h" + + +typedef struct CodedBitstreamType { + enum AVCodecID codec_id; + + size_t priv_data_size; + + // Split frag->data into coded bitstream units, creating the + // frag->units array. Fill data but not content on each unit. + // header is set if the fragment came from a header block, which + // may require different parsing for some codecs (e.g. the AVCC + // header in H.264). + int (*split_fragment)(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header); + + // Read the unit->data bitstream and decompose it, creating + // unit->content. + int (*read_unit)(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit); + + // Write the unit->data bitstream from unit->content. + int (*write_unit)(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit); + + // Read the data from all of frag->units and assemble it into + // a bitstream for the whole fragment. + int (*assemble_fragment)(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag); + + // Free the content and data of a single unit. + void (*free_unit)(CodedBitstreamUnit *unit); + + // Free the codec internal state. + void (*close)(CodedBitstreamContext *ctx); +} CodedBitstreamType; + + +// Helper functions for trace output. + +void ff_cbs_trace_header(CodedBitstreamContext *ctx, + const char *name); + +void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, + int position, const char *name, + const char *bitstring, int64_t value); + + +// Helper functions for read/write of common bitstream elements, including +// generation of trace output. + +int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, + int width, const char *name, uint32_t *write_to, + uint32_t range_min, uint32_t range_max); + +int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, uint32_t value, + uint32_t range_min, uint32_t range_max); + + +#endif /* AVCODEC_CBS_INTERNAL_H */