On 21/11/2020 02:19, James Almer wrote:
On 11/20/2020 10:55 PM, Nuo Mi wrote:
Hi Mark, James and all,
There are two ways to implement the parser.
1. use cbs like av1 parser.
2. follow h264/h265 parser method.
Which is your preferred?
thanks
A CBS module for VVC is needed regardless of how the parser is ultimately
implemented (There will be other uses, like bitstream filters), so might as
well use it for it, like with AV1.
+1.
Attached is some initial investigation I did recently into CBS implementation.
The non-CBS parts are all hacks to get a raw stream fed into trace_headers, and
can be ignored for non-test purposes.
My thoughts emerging from that:
* The commonality with H.26[45] is sufficient that it's probably best to extend
that into CBS H.26[456].
* All of the styling is the same, so doing that avoids duplicating a lot of
templating code.
* I haven't done that here because it was easier to hack in by starting with
a new file.
* Separately I've been looking at merging the implementation of more common
elements of H.26[45], and that will apply here too (SEI in particular, where
H.274 matches in parts as well).
* There is /a lot/ of boilerplate needed to get even a minimal version working.
* The parameter sets are even bigger and more complex than they were in H.265
(and the VUI that you want for metadata is still right at the end of the SPS).
* The clean specification is very appreciated - I haven't found any nasty
interdependencies yet, though I haven't read all of it in detail.
* Given the huge surface area for errors here, it may not be a good idea to
include it until we have the full conformance test suite (like H.265.1) to test
it with.
* It seemed like the right choice on naming was to use H.266 as the name
everywhere and always refer to that:
* It stays consistent with the most common name for H.264 (still the
most-used codec).
* It's a formal standard, unlike the JVET drafts.
* Anyone can download the full specification for free
(<https://www.itu.int/rec/T-REC-H.266-202008-I/en>), unlike the ISO/IEC 23090-3
version.
I'm not working on this right now, but I'll probably come back to it in the
not-too-distant future.
So, any thoughts welcome - given the scope of this we should probably agree
roughly what the intended structure will be before writing much more.
Thanks,
- Mark
>From 9cee4d68d00f42a5ba97e044f5312dbe6c59a63e Mon Sep 17 00:00:00 2001
From: Mark Thompson <s...@jkqxz.net>
Date: Sat, 21 Nov 2020 16:41:45 +0000
Subject: [PATCH] WIP CBS H.266
---
configure | 4 +-
libavcodec/Makefile | 2 +
libavcodec/cbs.c | 6 +
libavcodec/cbs_h266.c | 652 ++++++++++++++++++++++++++
libavcodec/cbs_h266.h | 196 ++++++++
libavcodec/cbs_h266_syntax_template.c | 365 ++++++++++++++
libavcodec/cbs_internal.h | 1 +
libavcodec/codec_desc.c | 7 +
libavcodec/codec_id.h | 1 +
libavcodec/h266.h | 89 ++++
libavcodec/h266_parser.c | 45 ++
libavcodec/parsers.c | 1 +
libavformat/Makefile | 1 +
libavformat/allformats.c | 1 +
libavformat/h266dec.c | 29 ++
libavformat/rawdec.c | 2 +
16 files changed, 1401 insertions(+), 1 deletion(-)
create mode 100644 libavcodec/cbs_h266.c
create mode 100644 libavcodec/cbs_h266.h
create mode 100644 libavcodec/cbs_h266_syntax_template.c
create mode 100644 libavcodec/h266.h
create mode 100644 libavcodec/h266_parser.c
create mode 100644 libavformat/h266dec.c
diff --git a/configure b/configure
index 51e43fbf66..b9356f3a82 100755
--- a/configure
+++ b/configure
@@ -2354,6 +2354,7 @@ CONFIG_EXTRA="
cbs_av1
cbs_h264
cbs_h265
+ cbs_h266
cbs_jpeg
cbs_mpeg2
cbs_vp9
@@ -2622,6 +2623,7 @@ threads_if_any="$THREADS_LIST"
cbs_av1_select="cbs"
cbs_h264_select="cbs"
cbs_h265_select="cbs"
+cbs_h266_select="cbs"
cbs_jpeg_select="cbs"
cbs_mpeg2_select="cbs"
cbs_vp9_select="cbs"
@@ -3176,7 +3178,7 @@ h264_redundant_pps_bsf_select="cbs_h264"
hevc_metadata_bsf_select="cbs_h265"
mjpeg2jpeg_bsf_select="jpegtables"
mpeg2_metadata_bsf_select="cbs_mpeg2"
-trace_headers_bsf_select="cbs"
+trace_headers_bsf_select="cbs cbs_h266"
vp9_metadata_bsf_select="cbs_vp9"
# external libraries
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index b4777be4d4..c41b892063 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -73,6 +73,7 @@ OBJS-$(CONFIG_CBS) += cbs.o
OBJS-$(CONFIG_CBS_AV1) += cbs_av1.o
OBJS-$(CONFIG_CBS_H264) += cbs_h2645.o h2645_parse.o
OBJS-$(CONFIG_CBS_H265) += cbs_h2645.o h2645_parse.o
+OBJS-$(CONFIG_CBS_H266) += cbs_h266.o
OBJS-$(CONFIG_CBS_JPEG) += cbs_jpeg.o
OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o
OBJS-$(CONFIG_CBS_VP9) += cbs_vp9.o
@@ -1095,6 +1096,7 @@ OBJS-$(CONFIG_GSM_PARSER) += gsm_parser.o
OBJS-$(CONFIG_H261_PARSER) += h261_parser.o
OBJS-$(CONFIG_H263_PARSER) += h263_parser.o
OBJS-$(CONFIG_H264_PARSER) += h264_parser.o h264_sei.o h264data.o
+OBJS-$(CONFIG_H266_PARSER) += h266_parser.o
OBJS-$(CONFIG_HEVC_PARSER) += hevc_parser.o hevc_data.o
OBJS-$(CONFIG_IPU_PARSER) += ipu_parser.o
OBJS-$(CONFIG_JPEG2000_PARSER) += jpeg2000_parser.o
diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
index c8c526ab12..90de0c6330 100644
--- a/libavcodec/cbs.c
+++ b/libavcodec/cbs.c
@@ -38,6 +38,9 @@ static const CodedBitstreamType *cbs_type_table[] = {
#if CONFIG_CBS_H265
&ff_cbs_type_h265,
#endif
+#if CONFIG_CBS_H266
+ &ff_cbs_type_h266,
+#endif
#if CONFIG_CBS_JPEG
&ff_cbs_type_jpeg,
#endif
@@ -59,6 +62,9 @@ const enum AVCodecID ff_cbs_all_codec_ids[] = {
#if CONFIG_CBS_H265
AV_CODEC_ID_H265,
#endif
+#if CONFIG_CBS_H266
+ AV_CODEC_ID_H266,
+#endif
#if CONFIG_CBS_JPEG
AV_CODEC_ID_MJPEG,
#endif
diff --git a/libavcodec/cbs_h266.c b/libavcodec/cbs_h266.c
new file mode 100644
index 0000000000..0032cf4144
--- /dev/null
+++ b/libavcodec/cbs_h266.c
@@ -0,0 +1,652 @@
+/*
+ * 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 "libavutil/attributes.h"
+#include "libavutil/avassert.h"
+
+#include "bytestream.h"
+#include "cbs.h"
+#include "cbs_internal.h"
+#include "cbs_h266.h"
+
+
+static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ const char *name, const int *subscripts,
+ uint32_t *write_to,
+ uint32_t range_min, uint32_t range_max)
+{
+ uint32_t value;
+ int position, i, j;
+ unsigned int k;
+ char bits[65];
+
+ position = get_bits_count(gbc);
+
+ for (i = 0; i < 32; i++) {
+ if (get_bits_left(gbc) < i + 1) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at "
+ "%s: bitstream ended.\n", name);
+ return AVERROR_INVALIDDATA;
+ }
+ k = get_bits1(gbc);
+ bits[i] = k ? '1' : '0';
+ if (k)
+ break;
+ }
+ if (i >= 32) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at "
+ "%s: more than 31 zeroes.\n", name);
+ return AVERROR_INVALIDDATA;
+ }
+ value = 1;
+ for (j = 0; j < i; j++) {
+ k = get_bits1(gbc);
+ bits[i + j + 1] = k ? '1' : '0';
+ value = value << 1 | k;
+ }
+ bits[i + j + 1] = 0;
+ --value;
+
+ if (ctx->trace_enable)
+ ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
+ 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;
+}
+
+static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc,
+ const char *name, const int *subscripts,
+ int32_t *write_to,
+ int32_t range_min, int32_t range_max)
+{
+ int32_t value;
+ int position, i, j;
+ unsigned int k;
+ uint32_t v;
+ char bits[65];
+
+ position = get_bits_count(gbc);
+
+ for (i = 0; i < 32; i++) {
+ if (get_bits_left(gbc) < i + 1) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at "
+ "%s: bitstream ended.\n", name);
+ return AVERROR_INVALIDDATA;
+ }
+ k = get_bits1(gbc);
+ bits[i] = k ? '1' : '0';
+ if (k)
+ break;
+ }
+ if (i >= 32) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at "
+ "%s: more than 31 zeroes.\n", name);
+ return AVERROR_INVALIDDATA;
+ }
+ v = 1;
+ for (j = 0; j < i; j++) {
+ k = get_bits1(gbc);
+ bits[i + j + 1] = k ? '1' : '0';
+ v = v << 1 | k;
+ }
+ bits[i + j + 1] = 0;
+ if (v & 1)
+ value = -(int32_t)(v / 2);
+ else
+ value = v / 2;
+
+ if (ctx->trace_enable)
+ ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
+ bits, value);
+
+ if (value < range_min || value > range_max) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
+ "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n",
+ name, value, range_min, range_max);
+ return AVERROR_INVALIDDATA;
+ }
+
+ *write_to = value;
+ return 0;
+}
+
+static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ const char *name, const int *subscripts,
+ uint32_t value,
+ uint32_t range_min, uint32_t range_max)
+{
+ int len;
+
+ 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;
+ }
+ av_assert0(value != UINT32_MAX);
+
+ len = av_log2(value + 1);
+ if (put_bits_left(pbc) < 2 * len + 1)
+ return AVERROR(ENOSPC);
+
+ if (ctx->trace_enable) {
+ char bits[65];
+ int i;
+
+ for (i = 0; i < len; i++)
+ bits[i] = '0';
+ bits[len] = '1';
+ for (i = 0; i < len; i++)
+ bits[len + i + 1] = (value + 1) >> (len - i - 1) & 1 ? '1' : '0';
+ bits[len + len + 1] = 0;
+
+ ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
+ name, subscripts, bits, value);
+ }
+
+ put_bits(pbc, len, 0);
+ if (len + 1 < 32)
+ put_bits(pbc, len + 1, value + 1);
+ else
+ put_bits32(pbc, value + 1);
+
+ return 0;
+}
+
+static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
+ const char *name, const int *subscripts,
+ int32_t value,
+ int32_t range_min, int32_t range_max)
+{
+ int len;
+ uint32_t uvalue;
+
+ if (value < range_min || value > range_max) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
+ "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n",
+ name, value, range_min, range_max);
+ return AVERROR_INVALIDDATA;
+ }
+ av_assert0(value != INT32_MIN);
+
+ if (value == 0)
+ uvalue = 0;
+ else if (value > 0)
+ uvalue = 2 * (uint32_t)value - 1;
+ else
+ uvalue = 2 * (uint32_t)-value;
+
+ len = av_log2(uvalue + 1);
+ if (put_bits_left(pbc) < 2 * len + 1)
+ return AVERROR(ENOSPC);
+
+ if (ctx->trace_enable) {
+ char bits[65];
+ int i;
+
+ for (i = 0; i < len; i++)
+ bits[i] = '0';
+ bits[len] = '1';
+ for (i = 0; i < len; i++)
+ bits[len + i + 1] = (uvalue + 1) >> (len - i - 1) & 1 ? '1' : '0';
+ bits[len + len + 1] = 0;
+
+ ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
+ name, subscripts, bits, value);
+ }
+
+ put_bits(pbc, len, 0);
+ if (len + 1 < 32)
+ put_bits(pbc, len + 1, uvalue + 1);
+ else
+ put_bits32(pbc, uvalue + 1);
+
+ return 0;
+}
+
+#define HEADER(name) do { \
+ ff_cbs_trace_header(ctx, name); \
+ } while (0)
+
+#define CHECK(call) do { \
+ err = (call); \
+ if (err < 0) \
+ return err; \
+ } while (0)
+
+#define FUNC_NAME(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name
+#define FUNC_H266(rw, name) FUNC_NAME(rw, h266, name)
+
+#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
+
+#define u(width, name, range_min, range_max) \
+ xu(width, name, current->name, range_min, range_max, 0, )
+#define ub(width, name) \
+ xu(width, name, current->name, 0, MAX_UINT_BITS(width), 0, )
+#define flag(name) ub(1, name)
+#define ue(name, range_min, range_max) \
+ xue(name, current->name, range_min, range_max, 0, )
+#define i(width, name, range_min, range_max) \
+ xi(width, name, current->name, range_min, range_max, 0, )
+#define ib(width, name) \
+ xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), 0, )
+#define se(name, range_min, range_max) \
+ xse(name, current->name, range_min, range_max, 0, )
+
+#define us(width, name, range_min, range_max, subs, ...) \
+ xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__)
+#define ubs(width, name, subs, ...) \
+ xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__)
+#define flags(name, subs, ...) \
+ xu(1, name, current->name, 0, 1, subs, __VA_ARGS__)
+#define ues(name, range_min, range_max, subs, ...) \
+ xue(name, current->name, range_min, range_max, subs, __VA_ARGS__)
+#define is(width, name, range_min, range_max, subs, ...) \
+ xi(width, name, current->name, range_min, range_max, subs, __VA_ARGS__)
+#define ibs(width, name, subs, ...) \
+ xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), subs, __VA_ARGS__)
+#define ses(name, range_min, range_max, subs, ...) \
+ xse(name, current->name, range_min, range_max, subs, __VA_ARGS__)
+
+#define fixed(width, name, value) do { \
+ av_unused uint32_t fixed_value = value; \
+ xu(width, name, fixed_value, value, value, 0, ); \
+ } while (0)
+
+
+#define READ
+#define READWRITE read
+#define RWContext GetBitContext
+
+#define xu(width, name, var, range_min, range_max, subs, ...) do { \
+ uint32_t value; \
+ CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
+ SUBSCRIPTS(subs, __VA_ARGS__), \
+ &value, range_min, range_max)); \
+ var = value; \
+ } while (0)
+#define xue(name, var, range_min, range_max, subs, ...) do { \
+ uint32_t value; \
+ CHECK(cbs_read_ue_golomb(ctx, rw, #name, \
+ SUBSCRIPTS(subs, __VA_ARGS__), \
+ &value, range_min, range_max)); \
+ var = value; \
+ } while (0)
+#define xi(width, name, var, range_min, range_max, subs, ...) do { \
+ int32_t value; \
+ CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \
+ SUBSCRIPTS(subs, __VA_ARGS__), \
+ &value, range_min, range_max)); \
+ var = value; \
+ } while (0)
+#define xse(name, var, range_min, range_max, subs, ...) do { \
+ int32_t value; \
+ CHECK(cbs_read_se_golomb(ctx, rw, #name, \
+ SUBSCRIPTS(subs, __VA_ARGS__), \
+ &value, range_min, range_max)); \
+ var = value; \
+ } while (0)
+
+
+#define infer(name, value) do { \
+ current->name = value; \
+ } while (0)
+
+static int cbs_h266_read_more_rbsp_data(GetBitContext *gbc)
+{
+ int bits_left = get_bits_left(gbc);
+ if (bits_left > 8)
+ return 1;
+ if (bits_left == 0)
+ return 0;
+ if (show_bits(gbc, bits_left) & MAX_UINT_BITS(bits_left - 1))
+ return 1;
+ return 0;
+}
+
+#define more_rbsp_data(var) ((var) = cbs_h266_read_more_rbsp_data(rw))
+
+#define byte_alignment(rw) (get_bits_count(rw) % 8)
+
+#define allocate(name, size) do { \
+ name ## _ref = av_buffer_allocz(size + \
+ AV_INPUT_BUFFER_PADDING_SIZE); \
+ if (!name ## _ref) \
+ return AVERROR(ENOMEM); \
+ name = name ## _ref->data; \
+ } while (0)
+
+#define FUNC(name) FUNC_H266(READWRITE, name)
+#include "cbs_h266_syntax_template.c"
+#undef FUNC
+
+#undef READ
+#undef READWRITE
+#undef RWContext
+#undef xu
+#undef xi
+#undef xue
+#undef xse
+#undef infer
+#undef more_rbsp_data
+#undef byte_alignment
+#undef allocate
+
+
+#define WRITE
+#define READWRITE write
+#define RWContext PutBitContext
+
+#define xu(width, name, var, range_min, range_max, subs, ...) do { \
+ uint32_t value = var; \
+ CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
+ SUBSCRIPTS(subs, __VA_ARGS__), \
+ value, range_min, range_max)); \
+ } while (0)
+#define xue(name, var, range_min, range_max, subs, ...) do { \
+ uint32_t value = var; \
+ CHECK(cbs_write_ue_golomb(ctx, rw, #name, \
+ SUBSCRIPTS(subs, __VA_ARGS__), \
+ value, range_min, range_max)); \
+ } while (0)
+#define xi(width, name, var, range_min, range_max, subs, ...) do { \
+ int32_t value = var; \
+ CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \
+ SUBSCRIPTS(subs, __VA_ARGS__), \
+ value, range_min, range_max)); \
+ } while (0)
+#define xse(name, var, range_min, range_max, subs, ...) do { \
+ int32_t value = var; \
+ CHECK(cbs_write_se_golomb(ctx, rw, #name, \
+ SUBSCRIPTS(subs, __VA_ARGS__), \
+ value, range_min, range_max)); \
+ } while (0)
+
+#define infer(name, value) do { \
+ if (current->name != (value)) { \
+ av_log(ctx->log_ctx, AV_LOG_ERROR, \
+ "%s does not match inferred value: " \
+ "%"PRId64", but should be %"PRId64".\n", \
+ #name, (int64_t)current->name, (int64_t)(value)); \
+ return AVERROR_INVALIDDATA; \
+ } \
+ } while (0)
+
+#define more_rbsp_data(var) (var)
+
+#define byte_alignment(rw) (put_bits_count(rw) % 8)
+
+#define allocate(name, size) do { \
+ if (!name) { \
+ av_log(ctx->log_ctx, AV_LOG_ERROR, "%s must be set " \
+ "for writing.\n", #name); \
+ return AVERROR_INVALIDDATA; \
+ } \
+ } while (0)
+
+#define FUNC(name) FUNC_H266(READWRITE, name)
+#include "cbs_h266_syntax_template.c"
+#undef FUNC
+
+#undef WRITE
+#undef READWRITE
+#undef RWContext
+#undef xu
+#undef xi
+#undef xue
+#undef xse
+#undef u
+#undef i
+#undef flag
+#undef ue
+#undef se
+#undef infer
+#undef more_rbsp_data
+#undef byte_alignment
+#undef allocate
+
+
+static int cbs_h266_split_fragment(CodedBitstreamContext *ctx,
+ CodedBitstreamFragment *frag,
+ int header)
+{
+ uint8_t *start, *end, *next;
+ int err, trace;
+
+ // Don't include this parsing in trace output.
+ trace = ctx->trace_enable;
+ ctx->trace_enable = 0;
+
+ if (frag->data_size < 6) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR,
+ "Invalid fragment: too small.\n");
+ err = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ start = frag->data;
+
+ for (start = frag->data + 3;
+ start < frag->data + frag->data_size; start++) {
+
+ // Look for first start_code_prefix_one_3bytes.
+ if (start[-3] == 0x00 && start[-2] == 0x00 && start[-1] == 0x01)
+ break;
+ // Ensure that leading_zero_8bits are correct.
+ if (start[-3] != 0x00) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR,
+ "Invalid fragment: nonzero leading zeroes.\n");
+ err = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ }
+
+ if (start >= frag->data + frag->data_size) {
+ av_log(ctx->log_ctx, AV_LOG_ERROR,
+ "Invalid fragment: no start code found.\n");
+ err = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ while (start) {
+ H266RawNALUnitHeader header;
+ GetBitContext gbc;
+ uint8_t *buf;
+ size_t k, d, size;
+
+ // Look for next start_code_prefix_one_3bytes.
+ for (next = start + 1;
+ next < frag->data + frag->data_size; next++) {
+ if (next[-3] == 0x00 && next[-2] == 0x00 && next[-1] == 0x01)
+ break;
+ }
+ if (next >= frag->data + frag->data_size) {
+ end = next - 1;
+ next = NULL;
+ } else {
+ end = next - 4;
+ }
+ // Remove trailing_zero_8bits.
+ while (*end == 0 && end > start)
+ --end;
+ size = end - start;
+
+ init_get_bits8(&gbc, start, size);
+
+ err = cbs_h266_read_nal_unit_header(ctx, &gbc, &header);
+ if (err < 0)
+ goto fail;
+
+ buf = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!buf) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ for (d = k = 0; k < size; k++) {
+ if (k >= 2 && (start[k - 2] == 0x00 &&
+ start[k - 1] == 0x00 &&
+ start[k] == 0x03)) {
+ // Skip emulation_prevention_three_byte.
+ } else {
+ buf[d++] = start[k];
+ }
+ }
+
+ err = ff_cbs_insert_unit_data(frag, -1, header.nal_unit_type,
+ buf, d, NULL);
+ if (err < 0)
+ goto fail;
+
+ start = next;
+ }
+
+ err = 0;
+fail:
+ ctx->trace_enable = trace;
+ return err;
+}
+
+static int cbs_h266_read_nal_unit(CodedBitstreamContext *ctx,
+ CodedBitstreamUnit *unit)
+{
+ GetBitContext gbc;
+ int err;
+
+ err = ff_cbs_alloc_unit_content2(ctx, unit);
+ if (err)
+ return err;
+
+ err = init_get_bits8(&gbc, unit->data, unit->data_size);
+ if (err < 0)
+ return err;
+
+ switch (unit->type) {
+ case H266_NUT_SPS:
+ {
+ H266RawSPS *sps = unit->content;
+
+ err = cbs_h266_read_sps(ctx, &gbc, sps);
+ if (err < 0)
+ return err;
+ }
+ break;
+
+ case H266_NUT_PPS:
+ {
+ H266RawPPS *pps = unit->content;
+
+ err = cbs_h266_read_pps(ctx, &gbc, pps);
+ if (err < 0)
+ return err;
+ }
+ break;
+
+ case H266_NUT_TRAIL:
+ case H266_NUT_STSA:
+ case H266_NUT_RADL:
+ case H266_NUT_RASL:
+ case H266_NUT_IDR_W_RADL:
+ case H266_NUT_IDR_N_LP:
+ case H266_NUT_CRA:
+ case H266_NUT_GDR:
+ {
+ H266RawSlice *slice = unit->content;
+
+ err = cbs_h266_read_slice_header(ctx, &gbc, &slice->header);
+ if (err < 0)
+ return err;
+ }
+ break;
+ default:
+ {
+ err = cbs_h266_read_nal_unit_header(ctx, &gbc, unit->content);
+ if (err < 0)
+ return err;
+ }
+ break;
+ }
+
+ return AVERROR(ENOSYS);
+}
+
+static int cbs_h266_write_nal_unit(CodedBitstreamContext *ctx,
+ CodedBitstreamUnit *unit,
+ PutBitContext *pbc)
+{
+ return AVERROR(ENOSYS);
+}
+
+static int cbs_h266_assemble_fragment(CodedBitstreamContext *ctx,
+ CodedBitstreamFragment *frag)
+{
+ return AVERROR(ENOSYS);
+}
+
+static const CodedBitstreamUnitTypeDescriptor cbs_h266_unit_types[] = {
+ CBS_UNIT_TYPE_POD(H266_NUT_VPS, H266RawVPS),
+ CBS_UNIT_TYPE_POD(H266_NUT_SPS, H266RawSPS),
+ CBS_UNIT_TYPE_POD(H266_NUT_PPS, H266RawPPS),
+
+ {
+ // Slices of non-IRAP pictures.
+ .nb_unit_types = CBS_UNIT_TYPE_RANGE,
+ .unit_type_range_start = H266_NUT_TRAIL,
+ .unit_type_range_end = H266_NUT_RASL,
+
+ .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS,
+ .content_size = sizeof(H266RawSlice),
+ .nb_ref_offsets = 1,
+ .ref_offsets = { offsetof(H266RawSlice, data) },
+ },
+
+ {
+ // Slices of IRAP pictures.
+ .nb_unit_types = CBS_UNIT_TYPE_RANGE,
+ .unit_type_range_start = H266_NUT_IDR_W_RADL,
+ .unit_type_range_end = H266_NUT_GDR,
+
+ .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS,
+ .content_size = sizeof(H266RawSlice),
+ .nb_ref_offsets = 1,
+ .ref_offsets = { offsetof(H266RawSlice, data) },
+ },
+
+ CBS_UNIT_TYPE_END_OF_LIST
+};
+
+const CodedBitstreamType ff_cbs_type_h266 = {
+ .codec_id = AV_CODEC_ID_H266,
+
+ .priv_data_size = sizeof(CodedBitstreamH266Context),
+
+ .unit_types = cbs_h266_unit_types,
+
+ .split_fragment = &cbs_h266_split_fragment,
+ .read_unit = &cbs_h266_read_nal_unit,
+ .write_unit = &cbs_h266_write_nal_unit,
+ .assemble_fragment = &cbs_h266_assemble_fragment,
+};
diff --git a/libavcodec/cbs_h266.h b/libavcodec/cbs_h266.h
new file mode 100644
index 0000000000..564616b2ba
--- /dev/null
+++ b/libavcodec/cbs_h266.h
@@ -0,0 +1,196 @@
+/*
+ * 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_H266_H
+#define AVCODEC_CBS_H266_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "cbs.h"
+#include "h266.h"
+
+
+typedef struct H266RawNALUnitHeader {
+ uint8_t nuh_layer_id;
+ uint8_t nal_unit_type;
+ uint8_t nuh_temporal_id_plus1;
+} H266RawNALUnitHeader;
+
+typedef struct H266RawGeneralConstraintsInfo {
+ uint8_t gci_present_flag;
+} H266RawGeneralConstraintsInfo;
+
+typedef struct H266RawProfileTierLevel {
+ uint8_t general_profile_idc;
+ uint8_t general_tier_flag;
+ uint8_t general_level_idc;
+
+ uint8_t ptl_frame_only_constraint_flag;
+ uint8_t ptl_multilayer_enabled_flag;
+
+ H266RawGeneralConstraintsInfo general_constraints_info;
+
+ uint8_t ptl_sublayer_level_present_flag[H266_MAX_SUBLAYERS];
+ uint8_t sublayer_level_idc [H266_MAX_SUBLAYERS];
+
+ uint8_t ptl_num_sub_profiles;
+ uint32_t general_sub_profile_idc[H266_MAX_SUB_PROFILES];
+} H266RawProfileTierLevel;
+
+typedef struct H266RawDPBParameters {
+ uint8_t dpb_max_dec_pic_buffering_minus1[H266_MAX_SUBLAYERS];
+ uint8_t dpb_max_num_reorder_pics [H266_MAX_SUBLAYERS];
+ uint8_t dpb_max_latency_increase_plus1 [H266_MAX_SUBLAYERS];
+} H266RawDPBParameters;
+
+typedef struct H266RawVPS {
+ uint8_t vps_video_parameter_set_id;
+} H266RawVPS;
+
+typedef struct H266RawSPS {
+ H266RawNALUnitHeader nal_unit_header;
+
+ uint8_t sps_seq_parameter_set_id;
+ uint8_t sps_video_parameter_set_id;
+
+ uint8_t sps_max_sublayers_minus1;
+
+ uint8_t sps_chroma_format_idc;
+ uint8_t sps_log2_ctu_size_minus5;
+ uint8_t sps_ptl_dpb_hrd_params_present_flag;
+
+ H266RawProfileTierLevel profile_tier_level;
+
+ uint8_t sps_gdr_enabled_flag;
+ uint8_t sps_ref_pic_resampling_enabled_flag;
+ uint8_t sps_res_change_in_clvs_allowed_flag;
+
+ uint16_t sps_pic_width_max_in_luma_samples;
+ uint16_t sps_pic_height_max_in_luma_samples;
+
+ uint8_t sps_conformance_window_flag;
+ uint16_t sps_conf_win_left_offset;
+ uint16_t sps_conf_win_right_offset;
+ uint16_t sps_conf_win_top_offset;
+ uint16_t sps_conf_win_bottom_offset;
+
+ uint8_t sps_subpic_info_present_flag;
+ // subpic stuff.
+
+ uint8_t sps_bitdepth_minus8;
+
+ uint8_t sps_entropy_coding_sync_enabled_flag;
+ uint8_t sps_entry_point_offsets_present_flag;
+
+ uint8_t sps_log2_max_pic_order_cnt_lsb_minus4;
+ uint8_t sps_poc_msb_cycle_flag;
+ uint8_t sps_poc_msb_cycle_len_minus1;
+
+ uint8_t sps_num_extra_ph_bytes;
+ uint8_t sps_extra_ph_bit_present_flag[16];
+ uint8_t sps_num_extra_sh_bytes;
+ uint8_t sps_extra_sh_bit_present_flag[16];
+
+ uint8_t sps_sublayer_dpb_params_flag;
+ H266RawDPBParameters dpb_parameters;
+
+ uint8_t sps_log2_min_luma_coding_block_size_minus2;
+ uint8_t sps_partition_constraints_override_enabled_flag;
+ uint8_t sps_log2_diff_min_qt_min_cb_intra_slice_luma;
+ uint8_t sps_max_mtt_hierarchy_depth_intra_slice_luma;
+ uint8_t sps_log2_diff_max_bt_min_qt_intra_slice_luma;
+ uint8_t sps_log2_diff_max_tt_min_qt_intra_slice_luma;
+ uint8_t sps_qtbtt_dual_tree_intra_flag;
+ uint8_t sps_log2_diff_min_qt_min_cb_intra_slice_chroma;
+ uint8_t sps_max_mtt_hierarchy_depth_intra_slice_chroma;
+ uint8_t sps_log2_diff_max_bt_min_qt_intra_slice_chroma;
+ uint8_t sps_log2_diff_max_tt_min_qt_intra_slice_chroma;
+ uint8_t sps_log2_diff_min_qt_min_cb_inter_slice;
+ uint8_t sps_max_mtt_hierarchy_depth_inter_slice;
+ uint8_t sps_log2_diff_max_bt_min_qt_inter_slice;
+ uint8_t sps_log2_diff_max_tt_min_qt_inter_slice;
+
+ uint8_t sps_max_luma_transform_size_64_flag;
+ uint8_t sps_transform_skip_enabled_flag;
+ uint8_t sps_log2_transform_skip_max_size_minus2;
+ uint8_t sps_bdpcm_enabled_flag;
+
+ // ...
+} H266RawSPS;
+
+typedef struct H266RawPPS {
+ H266RawNALUnitHeader nal_unit_header;
+
+ uint8_t pps_pic_parameter_set_id;
+ uint8_t pps_seq_parameter_set_id;
+
+ uint8_t pps_mixed_nalu_types_in_pic_flag;
+
+ uint16_t pps_pic_width_in_luma_samples;
+ uint16_t pps_pic_height_in_luma_samples;
+
+ uint8_t pps_conformance_window_flag;
+ uint16_t pps_conf_win_left_offset;
+ uint16_t pps_conf_win_right_offset;
+ uint16_t pps_conf_win_top_offset;
+ uint16_t pps_conf_win_bottom_offset;
+} H266RawPPS;
+
+typedef struct H266RawPictureHeader {
+ uint8_t ph_gdr_or_irap_pic_flag;
+ uint8_t ph_non_ref_pic_flag;
+ uint8_t ph_gdr_pic_flag;
+} H266RawPictureHeader;
+
+typedef struct H266RawSliceHeader {
+ H266RawNALUnitHeader nal_unit_header;
+
+ uint8_t sh_picture_header_in_slice_header_flag;
+ H266RawPictureHeader picture_header;
+
+ uint8_t sh_subpic_id;
+ uint32_t sh_slice_address;
+
+ uint8_t sh_extra_bit[16];
+
+ uint16_t sh_num_tiles_in_slice_minus1;
+
+ uint8_t sh_slice_type;
+} H266RawSliceHeader;
+
+typedef struct H266RawSlice {
+ H266RawSliceHeader header;
+
+ uint8_t *data;
+ AVBufferRef *data_ref;
+ size_t data_size;
+} H266RawSlice;
+
+
+typedef struct CodedBitstreamH266Context {
+ //AVBufferRef *vps_ref[H266_MAX_VPS_COUNT];
+ AVBufferRef *sps_ref[H266_MAX_SPS_COUNT];
+ //AVBufferRef *pps_ref[H266_MAX_PPS_COUNT];
+ //H266RawVPS *vps[H266_MAX_VPS_COUNT];
+ H266RawSPS *sps[H266_MAX_SPS_COUNT];
+ //H266RawPPS *pps[H266_MAX_PPS_COUNT];
+} CodedBitstreamH266Context;
+
+
+#endif /* AVCODEC_CBS_H266_H */
diff --git a/libavcodec/cbs_h266_syntax_template.c b/libavcodec/cbs_h266_syntax_template.c
new file mode 100644
index 0000000000..946930bd9c
--- /dev/null
+++ b/libavcodec/cbs_h266_syntax_template.c
@@ -0,0 +1,365 @@
+/*
+ * 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
+ */
+
+static int FUNC(rbsp_trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw)
+{
+ int err;
+
+ fixed(1, rbsp_stop_one_bit, 1);
+ while (byte_alignment(rw) != 0)
+ fixed(1, rbsp_alignment_zero_bit, 0);
+
+ return 0;
+}
+
+static int FUNC(nal_unit_header)(CodedBitstreamContext *ctx, RWContext *rw,
+ H266RawNALUnitHeader *current)
+{
+ int err;
+
+ fixed(1, nuh_forbidden_zero_bit, 0);
+ fixed(1, nuh_reserved_zero_bit, 0);
+
+ u(6, nuh_layer_id, 0, H266_MAX_LAYER_ID);
+
+ ub(5, nal_unit_type);
+
+ u(3, nuh_temporal_id_plus1, 1, 7);
+
+ return 0;
+}
+
+static int FUNC(general_constraints_info)(CodedBitstreamContext *ctx,
+ RWContext *rw,
+ H266RawGeneralConstraintsInfo *current)
+{
+ int err;
+
+ flag(gci_present_flag);
+
+ if (current->gci_present_flag) {
+ abort();
+ }
+
+ while (byte_alignment(rw))
+ fixed(1, gci_alignment_zero_bit, 0);
+
+ return 0;
+}
+
+static int FUNC(profile_tier_level)(CodedBitstreamContext *ctx,
+ RWContext *rw,
+ H266RawProfileTierLevel *current,
+ int profile_tier_present_flag,
+ int max_num_sublayers_minus1)
+{
+ int err;
+
+ if (profile_tier_present_flag) {
+ ub(7, general_profile_idc);
+ flag(general_tier_flag);
+ }
+ ub(8, general_level_idc);
+
+ flag(ptl_frame_only_constraint_flag);
+ flag(ptl_multilayer_enabled_flag);
+
+ if (profile_tier_present_flag)
+ CHECK(FUNC(general_constraints_info)
+ (ctx, rw, ¤t->general_constraints_info));
+
+ for (int i = max_num_sublayers_minus1 - 1; i >= 0; i--)
+ flags(ptl_sublayer_level_present_flag[i], 1, i);
+ while (byte_alignment(rw))
+ fixed(1, ptl_reserved_zero_bit, 0);
+ for (int i = max_num_sublayers_minus1 - 1; i >= 0; i--) {
+ if (current->ptl_sublayer_level_present_flag[i])
+ ubs(8, sublayer_level_idc[i], 1, i);
+ }
+
+ if (profile_tier_present_flag) {
+ ub(8, ptl_num_sub_profiles);
+ for (int i = 0; i < current->ptl_num_sub_profiles; i++)
+ ubs(32, general_sub_profile_idc[i], 1, i);
+ }
+
+ return 0;
+}
+
+static int FUNC(dpb_parameters)(CodedBitstreamContext *ctx,
+ RWContext *rw,
+ H266RawDPBParameters *current,
+ int max_sublayers_minus1,
+ int sublayer_info_flag)
+{
+ int err;
+
+ for (int i = sublayer_info_flag ? 0 : max_sublayers_minus1;
+ i <= max_sublayers_minus1; i++) {
+ ues(dpb_max_dec_pic_buffering_minus1[i],
+ 0, H266_MAX_DPB_SIZE - 1, 1, i);
+ ues(dpb_max_num_reorder_pics[i],
+ 0, current->dpb_max_dec_pic_buffering_minus1[i], 1, i);
+ ues(dpb_max_latency_increase_plus1[i],
+ 0, UINT32_MAX - 1, 1, i);
+ }
+
+ return 0;
+}
+
+static int FUNC(vps)(CodedBitstreamContext *ctx, RWContext *rw,
+ H266RawVPS *current)
+{
+ int err;
+
+ HEADER("Video Parameter Set");
+
+ ub(4, vps_video_parameter_set_id);
+
+ return 0;
+}
+
+static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw,
+ H266RawSPS *current)
+{
+ int ctb_log2_size_y, ctb_size_y;
+ int min_cb_log2_size_y;
+ int min_qt_log2_size_intra_y, min_qt_log2_size_intra_c;
+ int min_qt_log2_size_inter_y;
+ int err;
+
+ HEADER("Sequence Parameter Set");
+
+ CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header));
+
+ ub(4, sps_seq_parameter_set_id);
+
+ ub(4, sps_video_parameter_set_id);
+ if (current->sps_video_parameter_set_id) {
+ abort();
+ } else {
+ // No video parameter set.
+ }
+
+ u(3, sps_max_sublayers_minus1, 0, 6);
+
+ ub(2, sps_chroma_format_idc);
+ ub(2, sps_log2_ctu_size_minus5);
+
+ ctb_log2_size_y = current->sps_log2_ctu_size_minus5 + 5;
+ ctb_size_y = 1 << ctb_log2_size_y;
+
+ flag(sps_ptl_dpb_hrd_params_present_flag);
+ if(current->sps_ptl_dpb_hrd_params_present_flag)
+ CHECK(FUNC(profile_tier_level)(ctx, rw, ¤t->profile_tier_level,
+ 1, current->sps_max_sublayers_minus1));
+
+ flag(sps_gdr_enabled_flag);
+ flag(sps_ref_pic_resampling_enabled_flag);
+ if(current->sps_ref_pic_resampling_enabled_flag)
+ flag(sps_res_change_in_clvs_allowed_flag);
+
+ ue(sps_pic_width_max_in_luma_samples, 1, H266_MAX_WIDTH);
+ ue(sps_pic_height_max_in_luma_samples, 1, H266_MAX_HEIGHT);
+
+ flag(sps_conformance_window_flag);
+ if(current->sps_conformance_window_flag) {
+ ue(sps_conf_win_left_offset, 0, H266_MAX_WIDTH);
+ ue(sps_conf_win_right_offset, 0, H266_MAX_WIDTH);
+ ue(sps_conf_win_top_offset, 0, H266_MAX_HEIGHT);
+ ue(sps_conf_win_bottom_offset, 0, H266_MAX_HEIGHT);
+ }
+
+ flag(sps_subpic_info_present_flag);
+ if (current->sps_subpic_info_present_flag) {
+ abort();
+ }
+
+ ue(sps_bitdepth_minus8, 0, 2);
+
+ flag(sps_entropy_coding_sync_enabled_flag);
+ flag(sps_entry_point_offsets_present_flag);
+
+ ub(4, sps_log2_max_pic_order_cnt_lsb_minus4);
+
+ flag(sps_poc_msb_cycle_flag);
+ if (current->sps_poc_msb_cycle_flag)
+ ue(sps_poc_msb_cycle_len_minus1,
+ 0, 32 - current->sps_log2_max_pic_order_cnt_lsb_minus4 - 5);
+
+ u(2, sps_num_extra_ph_bytes, 0, 2);
+ for (int i = 0; i < current->sps_num_extra_ph_bytes * 8; i++)
+ flags(sps_extra_ph_bit_present_flag[i], 1, i);
+ u(2, sps_num_extra_sh_bytes, 0, 2);
+ for (int i = 0; i < current->sps_num_extra_sh_bytes * 8; i++)
+ flags(sps_extra_sh_bit_present_flag[i], 1, i);
+
+ if (current->sps_ptl_dpb_hrd_params_present_flag) {
+ if (current->sps_max_sublayers_minus1 > 0)
+ flag(sps_sublayer_dpb_params_flag);
+ CHECK(FUNC(dpb_parameters)(ctx, rw, ¤t->dpb_parameters,
+ current->sps_max_sublayers_minus1,
+ current->sps_sublayer_dpb_params_flag));
+ }
+
+ ue(sps_log2_min_luma_coding_block_size_minus2,
+ 0, FFMIN(4, current->sps_log2_ctu_size_minus5 + 3));
+
+ min_cb_log2_size_y = current->sps_log2_min_luma_coding_block_size_minus2 + 2;
+
+ flag(sps_partition_constraints_override_enabled_flag);
+ ue(sps_log2_diff_min_qt_min_cb_intra_slice_luma,
+ 0, FFMIN(6, ctb_log2_size_y) - min_cb_log2_size_y);
+
+ min_qt_log2_size_intra_y =
+ current->sps_log2_diff_min_qt_min_cb_intra_slice_luma +
+ min_cb_log2_size_y;
+
+ ue(sps_max_mtt_hierarchy_depth_intra_slice_luma,
+ 0, 2 * (ctb_log2_size_y - min_cb_log2_size_y));
+ if (current->sps_max_mtt_hierarchy_depth_intra_slice_luma != 0) {
+ ue(sps_log2_diff_max_bt_min_qt_intra_slice_luma,
+ 0, ctb_log2_size_y - min_qt_log2_size_intra_y);
+ ue(sps_log2_diff_max_tt_min_qt_intra_slice_luma,
+ 0, FFMIN(6, ctb_log2_size_y) - min_qt_log2_size_intra_y);
+ } else {
+ infer(sps_log2_diff_max_bt_min_qt_intra_slice_luma, 0);
+ infer(sps_log2_diff_max_tt_min_qt_intra_slice_luma, 0);
+ }
+
+ if (current->sps_chroma_format_idc != 0)
+ flag(sps_qtbtt_dual_tree_intra_flag);
+ else
+ infer(sps_qtbtt_dual_tree_intra_flag, 0);
+
+ if (current->sps_qtbtt_dual_tree_intra_flag) {
+ ue(sps_log2_diff_min_qt_min_cb_intra_slice_chroma,
+ 0, FFMIN(6, ctb_log2_size_y) - min_cb_log2_size_y);
+
+ min_qt_log2_size_intra_c =
+ current->sps_log2_diff_min_qt_min_cb_intra_slice_chroma +
+ min_cb_log2_size_y;
+
+ ue(sps_max_mtt_hierarchy_depth_intra_slice_chroma,
+ 0, 2 * (ctb_log2_size_y - min_cb_log2_size_y));
+
+ if (current->sps_max_mtt_hierarchy_depth_intra_slice_chroma != 0) {
+ ue(sps_log2_diff_max_bt_min_qt_intra_slice_chroma,
+ 0, FFMIN(6, ctb_log2_size_y) - min_qt_log2_size_intra_c);
+ ue(sps_log2_diff_max_tt_min_qt_intra_slice_chroma,
+ 0, FFMIN(6, ctb_log2_size_y) - min_qt_log2_size_intra_c);
+ } else {
+ infer(sps_log2_diff_max_bt_min_qt_intra_slice_chroma, 0);
+ infer(sps_log2_diff_max_tt_min_qt_intra_slice_chroma, 0);
+ }
+ } else {
+ infer(sps_log2_diff_min_qt_min_cb_intra_slice_chroma, 0);
+ infer(sps_max_mtt_hierarchy_depth_intra_slice_chroma, 0);
+ infer(sps_log2_diff_max_bt_min_qt_intra_slice_chroma, 0);
+ infer(sps_log2_diff_max_tt_min_qt_intra_slice_chroma, 0);
+ }
+
+ ue(sps_log2_diff_min_qt_min_cb_inter_slice,
+ 0, FFMIN(6, ctb_log2_size_y) - min_cb_log2_size_y);
+
+ min_qt_log2_size_inter_y =
+ current->sps_log2_diff_min_qt_min_cb_inter_slice +
+ min_cb_log2_size_y;
+
+ ue(sps_max_mtt_hierarchy_depth_inter_slice,
+ 0, 2 * (ctb_log2_size_y - min_cb_log2_size_y));
+
+ if (current-> sps_max_mtt_hierarchy_depth_inter_slice != 0) {
+ ue(sps_log2_diff_max_bt_min_qt_inter_slice,
+ 0, ctb_log2_size_y - min_qt_log2_size_inter_y);
+ ue(sps_log2_diff_max_tt_min_qt_inter_slice,
+ 0, FFMIN(6, ctb_log2_size_y) - min_qt_log2_size_inter_y);
+ } else {
+ infer(sps_log2_diff_max_bt_min_qt_inter_slice, 0);
+ infer(sps_log2_diff_max_tt_min_qt_inter_slice, 0);
+ }
+
+ if (ctb_size_y > 32)
+ flag(sps_max_luma_transform_size_64_flag);
+
+ flag(sps_transform_skip_enabled_flag);
+ if (current->sps_transform_skip_enabled_flag) {
+ ue(sps_log2_transform_skip_max_size_minus2, 0, 3);
+ flag(sps_bdpcm_enabled_flag);
+ }
+
+ return 0;
+}
+
+static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw,
+ H266RawPPS *current)
+{
+ int err;
+
+ HEADER("Picture Parameter Set");
+
+ CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header));
+
+ ub(6, pps_pic_parameter_set_id);
+ ub(4, pps_seq_parameter_set_id);
+
+ flag(pps_mixed_nalu_types_in_pic_flag);
+
+ ue(pps_pic_width_in_luma_samples, 0, H266_MAX_WIDTH);
+ ue(pps_pic_height_in_luma_samples, 0, H266_MAX_HEIGHT);
+
+ flag(pps_conformance_window_flag);
+ if (current->pps_conformance_window_flag) {
+ ue(pps_conf_win_left_offset, 0, H266_MAX_WIDTH);
+ ue(pps_conf_win_right_offset, 0, H266_MAX_WIDTH);
+ ue(pps_conf_win_top_offset, 0, H266_MAX_HEIGHT);
+ ue(pps_conf_win_bottom_offset, 0, H266_MAX_HEIGHT);
+ }
+
+ return 0;
+}
+
+static int FUNC(picture_header_structure)(CodedBitstreamContext *ctx,
+ RWContext *rw,
+ H266RawPictureHeader *current)
+{
+ int err;
+
+ flag(ph_gdr_or_irap_pic_flag);
+ flag(ph_non_ref_pic_flag);
+ if (current->ph_gdr_or_irap_pic_flag)
+ flag(ph_gdr_pic_flag);
+
+ return 0;
+}
+
+static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw,
+ H266RawSliceHeader *current)
+{
+ int err;
+
+ HEADER("Slice Header");
+
+ CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header));
+
+ flag(sh_picture_header_in_slice_header_flag);
+ if (current->sh_picture_header_in_slice_header_flag)
+ CHECK(FUNC(picture_header_structure)(ctx, rw, ¤t->picture_header));
+
+ return 0;
+}
diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h
index faa847aad3..fadbbd702e 100644
--- a/libavcodec/cbs_internal.h
+++ b/libavcodec/cbs_internal.h
@@ -198,6 +198,7 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
extern const CodedBitstreamType ff_cbs_type_av1;
extern const CodedBitstreamType ff_cbs_type_h264;
extern const CodedBitstreamType ff_cbs_type_h265;
+extern const CodedBitstreamType ff_cbs_type_h266;
extern const CodedBitstreamType ff_cbs_type_jpeg;
extern const CodedBitstreamType ff_cbs_type_mpeg2;
extern const CodedBitstreamType ff_cbs_type_vp9;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 3b148883b8..8d8b5ba36c 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1419,6 +1419,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("AVS3-P2/IEEE1857.10"),
.props = AV_CODEC_PROP_LOSSY,
},
+ {
+ .id = AV_CODEC_ID_H266,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "h266",
+ .long_name = NULL_IF_CONFIG_SMALL("ITU H.266 / ISO MPEG-I Part 3 / VVC"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
{
.id = AV_CODEC_ID_Y41P,
.type = AVMEDIA_TYPE_VIDEO,
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index 668c565788..dbfa60cecb 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -243,6 +243,7 @@ enum AVCodecID {
AV_CODEC_ID_AVS2,
AV_CODEC_ID_PGX,
AV_CODEC_ID_AVS3,
+ AV_CODEC_ID_H266,
AV_CODEC_ID_Y41P = 0x8000,
AV_CODEC_ID_AVRP,
diff --git a/libavcodec/h266.h b/libavcodec/h266.h
new file mode 100644
index 0000000000..b5bce1e679
--- /dev/null
+++ b/libavcodec/h266.h
@@ -0,0 +1,89 @@
+/*
+ * 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_H266_H
+#define AVCODEC_H266_H
+
+/** From H.266 section 7.4.2.2 table 5. */
+enum {
+ H266_NUT_TRAIL,
+ H266_NUT_STSA,
+ H266_NUT_RADL,
+ H266_NUT_RASL,
+ H266_NUT_RSV_VCL_4,
+ H266_NUT_RSV_VCL_5,
+ H266_NUT_RSV_VCL_6,
+ H266_NUT_IDR_W_RADL,
+ H266_NUT_IDR_N_LP,
+ H266_NUT_CRA,
+ H266_NUT_GDR,
+ H266_RSV_IRAP_11,
+ H266_NUT_OPI,
+ H266_NUT_DCI,
+ H266_NUT_VPS,
+ H266_NUT_SPS,
+ H266_NUT_PPS,
+ H266_PREFIX_NUT_APS,
+ H266_SUFFIX_NUT_APS,
+ H266_NUT_PH,
+ H266_NUT_AUD,
+ H266_NUT_EOS,
+ H266_NUT_EOB,
+ H266_NUT_PREFIX_SEI,
+ H266_NUT_SUFFIX_SEI,
+ H266_NUT_FD,
+ H266_NUT_RSV_NVCL_26,
+ H266_NUT_RSV_NVCL_27,
+ H266_NUT_UNSPEC_28,
+ H266_NUT_UNSPEC_29,
+ H266_NUT_UNSPEC_30,
+ H266_NUT_UNSPEC_31,
+};
+
+
+enum {
+ // 7.4.2.2: nuh_layer_id in [0, 55].
+ H266_MAX_LAYER_ID = 55,
+
+ // 7.3.2.3: vps_video_parameter_set_id is u(4).
+ H266_MAX_VPS_COUNT = 16,
+
+ // 7.4.3.3: vps_max_sublayers_minus1 is in [0, 6].
+ H266_MAX_SUBLAYERS = 7,
+
+ // 7.3.3.1: ptl_num_sub_profiles is u(8).
+ H266_MAX_SUB_PROFILES = 256,
+
+ // 7.3.2.4: sps_seq_parameter_set_id is u(4).
+ H266_MAX_SPS_COUNT = 16,
+
+ // A.4.1: in table A.1 the highest level allows a MaxLumaPs of
+ // 35 651 584.
+ H266_MAX_LUMA_PS = 35651584,
+ // A.4.1: PicWidthMaxInSamplesY and PicHeightMaxInSamplesY are
+ // constrained to be less than or equal to sqrt(MaxLumaPs * 8).
+ // Hence height/width are bounded above by sqrt(35651584 * 8),
+ // which is 16888.2 luma samples.
+ H266_MAX_WIDTH = 16888,
+ H266_MAX_HEIGHT = 16888,
+
+ // A.4.2: MaxDpbSize is at most 2 * maxDpbPicBuf (8).
+ H266_MAX_DPB_SIZE = 16,
+};
+
+#endif /* AVCODEC_H266_H */
diff --git a/libavcodec/h266_parser.c b/libavcodec/h266_parser.c
new file mode 100644
index 0000000000..abd51ae213
--- /dev/null
+++ b/libavcodec/h266_parser.c
@@ -0,0 +1,45 @@
+/*
+ * 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 "parser.h"
+
+static int h266_parser_parse(AVCodecParserContext *ctx,
+ AVCodecContext *avctx,
+ const uint8_t **out_data, int *out_size,
+ const uint8_t *data, int size)
+{
+ *out_data = data;
+ *out_size = size;
+
+ return size;
+}
+
+static int h266_parser_split(AVCodecContext *avctx,
+ const uint8_t *buf, int buf_size)
+{
+ return buf_size;
+}
+
+AVCodecParser ff_h266_parser = {
+ .codec_ids = { AV_CODEC_ID_H266 },
+ .priv_data_size = 0,
+ .parser_init = NULL,
+ .parser_close = NULL,
+ .parser_parse = h266_parser_parse,
+ .split = h266_parser_split,
+};
diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c
index 83271d95a3..155aec71aa 100644
--- a/libavcodec/parsers.c
+++ b/libavcodec/parsers.c
@@ -49,6 +49,7 @@ extern AVCodecParser ff_gsm_parser;
extern AVCodecParser ff_h261_parser;
extern AVCodecParser ff_h263_parser;
extern AVCodecParser ff_h264_parser;
+extern AVCodecParser ff_h266_parser;
extern AVCodecParser ff_hevc_parser;
extern AVCodecParser ff_ipu_parser;
extern AVCodecParser ff_jpeg2000_parser;
diff --git a/libavformat/Makefile b/libavformat/Makefile
index be5a482b01..1bad4a8eb5 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -231,6 +231,7 @@ OBJS-$(CONFIG_H263_DEMUXER) += h263dec.o rawdec.o
OBJS-$(CONFIG_H263_MUXER) += rawenc.o
OBJS-$(CONFIG_H264_DEMUXER) += h264dec.o rawdec.o
OBJS-$(CONFIG_H264_MUXER) += rawenc.o
+OBJS-$(CONFIG_H266_DEMUXER) += h266dec.o rawdec.o
OBJS-$(CONFIG_HASH_MUXER) += hashenc.o
OBJS-$(CONFIG_HCA_DEMUXER) += hca.o
OBJS-$(CONFIG_HCOM_DEMUXER) += hcom.o pcm.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 53e5374255..b6b8e11c1c 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -189,6 +189,7 @@ extern AVInputFormat ff_h263_demuxer;
extern AVOutputFormat ff_h263_muxer;
extern AVInputFormat ff_h264_demuxer;
extern AVOutputFormat ff_h264_muxer;
+extern AVInputFormat ff_h266_demuxer;
extern AVOutputFormat ff_hash_muxer;
extern AVInputFormat ff_hca_demuxer;
extern AVInputFormat ff_hcom_demuxer;
diff --git a/libavformat/h266dec.c b/libavformat/h266dec.c
new file mode 100644
index 0000000000..e1d58adac5
--- /dev/null
+++ b/libavformat/h266dec.c
@@ -0,0 +1,29 @@
+/*
+ * 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 "libavcodec/hevc.h"
+
+#include "avformat.h"
+#include "rawdec.h"
+
+static int h266_probe(const AVProbeData *p)
+{
+ return AVPROBE_SCORE_EXTENSION + 1;
+}
+
+FF_DEF_RAWVIDEO_DEMUXER(h266, "raw H.266 video", h266_probe, "h266,266", AV_CODEC_ID_H266)
diff --git a/libavformat/rawdec.c b/libavformat/rawdec.c
index 10c37c5cb9..d0a5cfdfdb 100644
--- a/libavformat/rawdec.c
+++ b/libavformat/rawdec.c
@@ -83,6 +83,8 @@ int ff_raw_video_read_header(AVFormatContext *s)
st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
st->codecpar->codec_id = s->iformat->raw_codec_id;
+ st->codecpar->width = 256;
+ st->codecpar->height = 144;
st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
st->internal->avctx->framerate = s1->framerate;
--
2.29.2
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".