diff --git a/CMakeLists.txt b/CMakeLists.txt index bb7c8b5c..97142e78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ if(WIN32) QOS_NON_ADAPTIVE_FLOW=2) endif() add_subdirectory(third-party/moonlight-common-c/enet) +add_subdirectory(third-party/cbs) find_package(Threads REQUIRED) find_package(OpenSSL REQUIRED) @@ -186,6 +187,7 @@ set(SUNSHINE_TARGET_FILES include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/third-party + ${CMAKE_CURRENT_SOURCE_DIR}/third-party/cbs/include ${CMAKE_CURRENT_SOURCE_DIR}/third-party/moonlight-common-c/enet/include ${CMAKE_CURRENT_SOURCE_DIR}/third-party/moonlight-common-c/reedsolomon ${FFMPEG_INCLUDE_DIRS} @@ -207,7 +209,11 @@ if(NOT SUNSHINE_ASSETS_DIR) set(SUNSHINE_ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/assets") endif() +list(APPEND CBS_EXTERNAL_LIBRARIES + cbs) + list(APPEND SUNSHINE_EXTERNAL_LIBRARIES + ${CBS_EXTERNAL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} stdc++fs enet diff --git a/sunshine/video.cpp b/sunshine/video.cpp index 365cabf9..0f3bf8a0 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -7,6 +7,8 @@ #include extern "C" { +#include +#include #include } @@ -44,6 +46,43 @@ using buffer_t = util::safe_ptr; using sws_t = util::safe_ptr; using img_event_t = std::shared_ptr>>; +namespace cbs { +void close(CodedBitstreamContext *c) { + ff_cbs_close(&c); +} + +using ctx_t = util::safe_ptr; + +class frag_t : public CodedBitstreamFragment { +public: + frag_t(frag_t &&o) { + std::copy((std::uint8_t *)&o, (std::uint8_t *)(&o + 1), (std::uint8_t *)this); + + o.data = nullptr; + o.units = nullptr; + }; + + frag_t() { + std::fill_n((std::uint8_t *)this, sizeof(*this), 0); + } + + frag_t &operator=(frag_t &&o) { + std::copy((std::uint8_t *)&o, (std::uint8_t *)(&o + 1), (std::uint8_t *)this); + + o.data = nullptr; + o.units = nullptr; + + return *this; + }; + + + ~frag_t() { + if(data || units) { + ff_cbs_fragment_free(this); + } + } +}; +} // namespace cbs namespace nv { enum class profile_h264_e : int { @@ -243,6 +282,7 @@ struct encoder_t { REF_FRAMES_AUTOSELECT, // Allow encoder to select maximum reference frames (If !REF_FRAMES_RESTRICT --> REF_FRAMES_AUTOSELECT) SLICE, // Allow frame to be partitioned into multiple slices DYNAMIC_RANGE, // hdr + VUI_PARAMETERS, MAX_FLAGS }; @@ -256,6 +296,7 @@ struct encoder_t { _CONVERT(REF_FRAMES_AUTOSELECT); _CONVERT(SLICE); _CONVERT(DYNAMIC_RANGE); + _CONVERT(VUI_PARAMETERS); _CONVERT(MAX_FLAGS); } #undef _CONVERT @@ -1285,7 +1326,7 @@ void capture( } } -bool validate_config(std::shared_ptr &disp, const encoder_t &encoder, const config_t &config) { +bool validate_config(std::shared_ptr &disp, const encoder_t &encoder, const config_t &config, int validate_sps = -1) { reset_display(disp, encoder.dev_type); if(!disp) { return false; @@ -1315,11 +1356,52 @@ bool validate_config(std::shared_ptr &disp, const encoder_t &e frame->pict_type = AV_PICTURE_TYPE_I; auto packets = std::make_shared(30); - if(encode(1, session->ctx, frame, packets, nullptr)) { + while(!packets->peek()) { + if(encode(1, session->ctx, frame, packets, nullptr)) { + return false; + } + } + + auto packet = packets->pop(); + if(!(packet->flags & AV_PKT_FLAG_KEY)) { + BOOST_LOG(error) << "First packet type is not an IDR frame"sv; + return false; } - return true; + if(validate_sps < 0) { + return true; + } + + auto codec_id = (validate_sps == 0 ? AV_CODEC_ID_H264 : AV_CODEC_ID_H265); + + // validate sps + cbs::ctx_t ctx; + if(ff_cbs_init(&ctx, codec_id, nullptr)) { + return false; + } + + cbs::frag_t frag; + + int err = ff_cbs_read_packet(ctx.get(), &frag, &*packet); + if(err < 0) { + char err_str[AV_ERROR_MAX_STRING_SIZE] { 0 }; + BOOST_LOG(error) << "Couldn't read packet: "sv << av_make_error_string(err_str, AV_ERROR_MAX_STRING_SIZE, err); + + return false; + } + + if(validate_sps == 0) { + auto h264 = (CodedBitstreamH264Context *)ctx->priv_data; + + if(!h264->active_sps->vui_parameters_present_flag) { + return false; + } + + return true; + } + + return ((CodedBitstreamH265Context *)ctx->priv_data)->active_sps->vui_parameters_present_flag; } bool validate_encoder(encoder_t &encoder) { @@ -1389,6 +1471,24 @@ bool validate_encoder(encoder_t &encoder) { } } + // test for presence of vui-parameters in the sps header + config_autoselect.videoFormat = 0; + encoder.h264[encoder_t::VUI_PARAMETERS] = validate_config(disp, encoder, config_autoselect, 0); + + + if(encoder.hevc[encoder_t::PASSED]) { + config_autoselect.videoFormat = 1; + encoder.hevc[encoder_t::VUI_PARAMETERS] = validate_config(disp, encoder, config_autoselect, 1); + } + + if(!encoder.h264[encoder_t::VUI_PARAMETERS]) { + BOOST_LOG(warning) << encoder.name << ": h264 missing sps->vui parameters"sv; + } + if(encoder.hevc[encoder_t::PASSED] && !encoder.hevc[encoder_t::VUI_PARAMETERS]) { + BOOST_LOG(warning) << encoder.name << ": hevc missing sps->vui parameters"sv; + } + + fg.disable(); return true; } diff --git a/third-party/cbs/CMakeLists.txt b/third-party/cbs/CMakeLists.txt new file mode 100644 index 00000000..a0cec71f --- /dev/null +++ b/third-party/cbs/CMakeLists.txt @@ -0,0 +1,80 @@ +cmake_minimum_required(VERSION 3.0) + +project(CBS) + +SET(ARCH_SOURCE_FILES +x86/intmath.h +x86/asm.h +x86/mathops.h +) + +SET(CBS_SOURCE_FILES +include/cbs/av1.h +include/cbs/cbs_av1.h +include/cbs/cbs_bsf.h +include/cbs/cbs.h +include/cbs/cbs_h2645.h +include/cbs/cbs_h264.h +include/cbs/cbs_h265.h +include/cbs/cbs_jpeg.h +include/cbs/cbs_mpeg2.h +include/cbs/cbs_sei.h +include/cbs/cbs_vp9.h +include/cbs/h2645_parse.h +include/cbs/h264.h +include/cbs/hevc.h +include/cbs/sei.h + +cbs.c +cbs_h2645.c +cbs_av1.c +cbs_vp9.c +cbs_mpeg2.c +cbs_jpeg.c +cbs_sei.c +h2645_parse.c + +attributes.h +bytestream.h +cbs_internal.h +codec_id.h +defs.h +get_bits.h +h264_ps.h +h264_sei.h +hevc_sei.h +intmath.h +mathops.h +put_bits.h +vlc.h + +${ARCH_SOURCE_FILES} +) + +include_directories(include) + +add_compile_definitions( + ARCH_X86=1 + ARCH_X86_64=1 + HAVE_XMM_CLOBBERS=1 + HAVE_INLINE_ASM=1 + HAVE_INLINE_ASM_DIRECT_SYMBOL_REFS=1 + HAVE_THREADS=1 + HAVE_FAST_UNALIGNED + HAVE_FAST_CLZ=1 + + HAVE_FAST_64BIT + + PIC=1 + + CONFIG_CBS_AV1=1 + CONFIG_CBS_H264=1 + CONFIG_CBS_H265=1 + CONFIG_CBS_JPEG=1 + CONFIG_CBS_MPEG2=1 + CONFIG_CBS_VP9=1 + ) + + +add_library(cbs ${CBS_SOURCE_FILES}) +target_compile_options(cbs PRIVATE -Wall -Wno-incompatible-pointer-types) \ No newline at end of file diff --git a/third-party/cbs/arm/intmath.h b/third-party/cbs/arm/intmath.h new file mode 100644 index 00000000..8dcb78d7 --- /dev/null +++ b/third-party/cbs/arm/intmath.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2010 Mans Rullgard + * + * 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 AVUTIL_ARM_INTMATH_H +#define AVUTIL_ARM_INTMATH_H + +#include + +#include "../attributes.h" + +#if HAVE_INLINE_ASM + +#if HAVE_ARMV6_INLINE + +#define av_clip_uint8 av_clip_uint8_arm +static av_always_inline av_const int av_clip_uint8_arm(int a) { + int x; + __asm__("usat %0, #8, %1" + : "=r"(x) + : "r"(a)); + return x; +} + +#define av_clip_int8 av_clip_int8_arm +static av_always_inline av_const int av_clip_int8_arm(int a) { + int x; + __asm__("ssat %0, #8, %1" + : "=r"(x) + : "r"(a)); + return x; +} + +#define av_clip_uint16 av_clip_uint16_arm +static av_always_inline av_const int av_clip_uint16_arm(int a) { + int x; + __asm__("usat %0, #16, %1" + : "=r"(x) + : "r"(a)); + return x; +} + +#define av_clip_int16 av_clip_int16_arm +static av_always_inline av_const int av_clip_int16_arm(int a) { + int x; + __asm__("ssat %0, #16, %1" + : "=r"(x) + : "r"(a)); + return x; +} + +#define av_clip_intp2 av_clip_intp2_arm +static av_always_inline av_const int av_clip_intp2_arm(int a, int p) { + unsigned x; + __asm__("ssat %0, %2, %1" + : "=r"(x) + : "r"(a), "i"(p + 1)); + return x; +} + +#define av_clip_uintp2 av_clip_uintp2_arm +static av_always_inline av_const unsigned av_clip_uintp2_arm(int a, int p) { + unsigned x; + __asm__("usat %0, %2, %1" + : "=r"(x) + : "r"(a), "i"(p)); + return x; +} + +#define av_sat_add32 av_sat_add32_arm +static av_always_inline int av_sat_add32_arm(int a, int b) { + int r; + __asm__("qadd %0, %1, %2" + : "=r"(r) + : "r"(a), "r"(b)); + return r; +} + +#define av_sat_dadd32 av_sat_dadd32_arm +static av_always_inline int av_sat_dadd32_arm(int a, int b) { + int r; + __asm__("qdadd %0, %1, %2" + : "=r"(r) + : "r"(a), "r"(b)); + return r; +} + +#define av_sat_sub32 av_sat_sub32_arm +static av_always_inline int av_sat_sub32_arm(int a, int b) { + int r; + __asm__("qsub %0, %1, %2" + : "=r"(r) + : "r"(a), "r"(b)); + return r; +} + +#define av_sat_dsub32 av_sat_dsub32_arm +static av_always_inline int av_sat_dsub32_arm(int a, int b) { + int r; + __asm__("qdsub %0, %1, %2" + : "=r"(r) + : "r"(a), "r"(b)); + return r; +} + +#endif /* HAVE_ARMV6_INLINE */ + +#if HAVE_ASM_MOD_Q + +#define av_clipl_int32 av_clipl_int32_arm +static av_always_inline av_const int32_t av_clipl_int32_arm(int64_t a) { + int x, y; + __asm__("adds %1, %R2, %Q2, lsr #31 \n\t" + "itet ne \n\t" + "mvnne %1, #1<<31 \n\t" + "moveq %0, %Q2 \n\t" + "eorne %0, %1, %R2, asr #31 \n\t" + : "=r"(x), "=&r"(y) + : "r"(a) + : "cc"); + return x; +} + +#endif /* HAVE_ASM_MOD_Q */ + +#endif /* HAVE_INLINE_ASM */ + +#endif /* AVUTIL_ARM_INTMATH_H */ diff --git a/third-party/cbs/arm/mathops.h b/third-party/cbs/arm/mathops.h new file mode 100644 index 00000000..7e130674 --- /dev/null +++ b/third-party/cbs/arm/mathops.h @@ -0,0 +1,112 @@ +/* + * simple math operations + * Copyright (c) 2006 Michael Niedermayer et al + * + * 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_ARM_MATHOPS_H +#define AVCODEC_ARM_MATHOPS_H + +#include + +#include + +#if HAVE_INLINE_ASM + +#if HAVE_ARMV6_INLINE +#define MULH MULH +static inline av_const int MULH(int a, int b) { + int r; + __asm__("smmul %0, %1, %2" + : "=r"(r) + : "r"(a), "r"(b)); + return r; +} + +#define FASTDIV FASTDIV +static av_always_inline av_const int FASTDIV(int a, int b) { + int r; + __asm__("cmp %2, #2 \n\t" + "ldr %0, [%3, %2, lsl #2] \n\t" + "ite le \n\t" + "lsrle %0, %1, #1 \n\t" + "smmulgt %0, %0, %1 \n\t" + : "=&r"(r) + : "r"(a), "r"(b), "r"(ff_inverse) + : "cc"); + return r; +} + +#else /* HAVE_ARMV6_INLINE */ + +#define FASTDIV FASTDIV +static av_always_inline av_const int FASTDIV(int a, int b) { + int r, t; + __asm__("umull %1, %0, %2, %3" + : "=&r"(r), "=&r"(t) + : "r"(a), "r"(ff_inverse[b])); + return r; +} +#endif + +#define MLS64(d, a, b) MAC64(d, -(a), b) + +#if HAVE_ARMV5TE_INLINE + +/* signed 16x16 -> 32 multiply add accumulate */ +#define MAC16(rt, ra, rb) \ + __asm__("smlabb %0, %1, %2, %0" \ + : "+r"(rt) \ + : "r"(ra), "r"(rb)); + +/* signed 16x16 -> 32 multiply */ +#define MUL16 MUL16 +static inline av_const int MUL16(int ra, int rb) { + int rt; + __asm__("smulbb %0, %1, %2" + : "=r"(rt) + : "r"(ra), "r"(rb)); + return rt; +} + +#endif + +#define mid_pred mid_pred +static inline av_const int mid_pred(int a, int b, int c) { + int m; + __asm__( + "mov %0, %2 \n\t" + "cmp %1, %2 \n\t" + "itt gt \n\t" + "movgt %0, %1 \n\t" + "movgt %1, %2 \n\t" + "cmp %1, %3 \n\t" + "it le \n\t" + "movle %1, %3 \n\t" + "cmp %0, %1 \n\t" + "it gt \n\t" + "movgt %0, %1 \n\t" + : "=&r"(m), "+r"(a) + : "r"(b), "r"(c) + : "cc"); + return m; +} + +#endif /* HAVE_INLINE_ASM */ + +#endif /* AVCODEC_ARM_MATHOPS_H */ diff --git a/third-party/cbs/attributes.h b/third-party/cbs/attributes.h new file mode 100644 index 00000000..5f7fb0b6 --- /dev/null +++ b/third-party/cbs/attributes.h @@ -0,0 +1,173 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * 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 + */ + +/** + * @file + * Macro definitions for various function/variable attributes + */ + +#ifndef AVUTIL_ATTRIBUTES_H +#define AVUTIL_ATTRIBUTES_H + +#ifdef __GNUC__ +#define AV_GCC_VERSION_AT_LEAST(x, y) (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +#define AV_GCC_VERSION_AT_MOST(x, y) (__GNUC__ < (x) || __GNUC__ == (x) && __GNUC_MINOR__ <= (y)) +#else +#define AV_GCC_VERSION_AT_LEAST(x, y) 0 +#define AV_GCC_VERSION_AT_MOST(x, y) 0 +#endif + +#ifdef __has_builtin +#define AV_HAS_BUILTIN(x) __has_builtin(x) +#else +#define AV_HAS_BUILTIN(x) 0 +#endif + +#ifndef av_always_inline +#if AV_GCC_VERSION_AT_LEAST(3, 1) +#define av_always_inline __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +#define av_always_inline __forceinline +#else +#define av_always_inline inline +#endif +#endif + +#ifndef av_extern_inline +#if defined(__ICL) && __ICL >= 1210 || defined(__GNUC_STDC_INLINE__) +#define av_extern_inline extern inline +#else +#define av_extern_inline inline +#endif +#endif + +#if AV_GCC_VERSION_AT_LEAST(3, 4) +#define av_warn_unused_result __attribute__((warn_unused_result)) +#else +#define av_warn_unused_result +#endif + +#if AV_GCC_VERSION_AT_LEAST(3, 1) +#define av_noinline __attribute__((noinline)) +#elif defined(_MSC_VER) +#define av_noinline __declspec(noinline) +#else +#define av_noinline +#endif + +#if AV_GCC_VERSION_AT_LEAST(3, 1) || defined(__clang__) +#define av_pure __attribute__((pure)) +#else +#define av_pure +#endif + +#if AV_GCC_VERSION_AT_LEAST(2, 6) || defined(__clang__) +#define av_const __attribute__((const)) +#else +#define av_const +#endif + +#if AV_GCC_VERSION_AT_LEAST(4, 3) || defined(__clang__) +#define av_cold __attribute__((cold)) +#else +#define av_cold +#endif + +#if AV_GCC_VERSION_AT_LEAST(4, 1) && !defined(__llvm__) +#define av_flatten __attribute__((flatten)) +#else +#define av_flatten +#endif + +#if AV_GCC_VERSION_AT_LEAST(3, 1) +#define attribute_deprecated __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define attribute_deprecated __declspec(deprecated) +#else +#define attribute_deprecated +#endif + +/** + * Disable warnings about deprecated features + * This is useful for sections of code kept for backward compatibility and + * scheduled for removal. + */ +#ifndef AV_NOWARN_DEPRECATED +#if AV_GCC_VERSION_AT_LEAST(4, 6) +#define AV_NOWARN_DEPRECATED(code) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \ + code \ + _Pragma("GCC diagnostic pop") +#elif defined(_MSC_VER) +#define AV_NOWARN_DEPRECATED(code) \ + __pragma(warning(push)) \ + __pragma(warning(disable : 4996)) \ + code; \ + __pragma(warning(pop)) +#else +#define AV_NOWARN_DEPRECATED(code) code +#endif +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define av_unused __attribute__((unused)) +#else +#define av_unused +#endif + +/** + * Mark a variable as used and prevent the compiler from optimizing it + * away. This is useful for variables accessed only from inline + * assembler without the compiler being aware. + */ +#if AV_GCC_VERSION_AT_LEAST(3, 1) || defined(__clang__) +#define av_used __attribute__((used)) +#else +#define av_used +#endif + +#if AV_GCC_VERSION_AT_LEAST(3, 3) || defined(__clang__) +#define av_alias __attribute__((may_alias)) +#else +#define av_alias +#endif + +#if(defined(__GNUC__) || defined(__clang__)) && !defined(__INTEL_COMPILER) +#define av_uninit(x) x = x +#else +#define av_uninit(x) x +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define av_builtin_constant_p __builtin_constant_p +#define av_printf_format(fmtpos, attrpos) __attribute__((__format__(__printf__, fmtpos, attrpos))) +#else +#define av_builtin_constant_p(x) 0 +#define av_printf_format(fmtpos, attrpos) +#endif + +#if AV_GCC_VERSION_AT_LEAST(2, 5) || defined(__clang__) +#define av_noreturn __attribute__((noreturn)) +#else +#define av_noreturn +#endif + +#endif /* AVUTIL_ATTRIBUTES_H */ diff --git a/third-party/cbs/avr32/mathops.h b/third-party/cbs/avr32/mathops.h new file mode 100644 index 00000000..4e5ec515 --- /dev/null +++ b/third-party/cbs/avr32/mathops.h @@ -0,0 +1,111 @@ +/* + * Simple math operations + * Copyright (c) 2009 Mans Rullgard + * + * 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_AVR32_MATHOPS_H +#define AVCODEC_AVR32_MATHOPS_H + +#include + +#include + +#if HAVE_INLINE_ASM + +#define MULL MULL +static inline av_const int MULL(int a, int b, unsigned shift) { + union { + int64_t x; + int hl[2]; + } x; + __asm__("muls.d %0, %1, %2 \n\t" + "lsr %0, %3 \n\t" + "or %0, %0, %m0<<%4 \n\t" + : "=r"(x) + : "r"(b), "r"(a), "i"(shift), "i"(32 - shift)); + return x.hl[1]; +} + +#define MULH MULH +static inline av_const int MULH(int a, int b) { + union { + int64_t x; + int hl[2]; + } x; + __asm__("muls.d %0, %1, %2" + : "=r"(x.x) + : "r"(a), "r"(b)); + return x.hl[0]; +} + +#define MUL64 MUL64 +static inline av_const int64_t MUL64(int a, int b) { + int64_t x; + __asm__("muls.d %0, %1, %2" + : "=r"(x) + : "r"(a), "r"(b)); + return x; +} + +static inline av_const int64_t MAC64(int64_t d, int a, int b) { + __asm__("macs.d %0, %1, %2" + : "+r"(d) + : "r"(a), "r"(b)); + return d; +} +#define MAC64(d, a, b) ((d) = MAC64(d, a, b)) +#define MLS64(d, a, b) MAC64(d, -(a), b) + +static inline av_const int MAC16(int d, int a, int b) { + __asm__("machh.w %0, %1:b, %2:b" + : "+r"(d) + : "r"(a), "r"(b)); + return d; +} +#define MAC16(d, a, b) ((d) = MAC16(d, a, b)) +#define MLS16(d, a, b) MAC16(d, -(a), b) + +#define MUL16 MUL16 +static inline av_const int MUL16(int a, int b) { + int d; + __asm__("mulhh.w %0, %1:b, %2:b" + : "=r"(d) + : "r"(a), "r"(b)); + return d; +} + +#define mid_pred mid_pred +static inline av_const int mid_pred(int a, int b, int c) { + int m; + __asm__("mov %0, %2 \n\t" + "cp.w %1, %2 \n\t" + "movgt %0, %1 \n\t" + "movgt %1, %2 \n\t" + "cp.w %1, %3 \n\t" + "movle %1, %3 \n\t" + "cp.w %0, %1 \n\t" + "movgt %0, %1 \n\t" + : "=&r"(m), "+r"(a) + : "r"(b), "r"(c)); + return m; +} + +#endif /* HAVE_INLINE_ASM */ + +#endif /* AVCODEC_AVR32_MATHOPS_H */ diff --git a/third-party/cbs/bytestream.h b/third-party/cbs/bytestream.h new file mode 100644 index 00000000..64b04f7b --- /dev/null +++ b/third-party/cbs/bytestream.h @@ -0,0 +1,349 @@ +/* + * Bytestream functions + * copyright (c) 2006 Baptiste Coudurier + * Copyright (c) 2012 Aneesh Dogra (lionaneesh) + * + * 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_BYTESTREAM_H +#define AVCODEC_BYTESTREAM_H + +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/intreadwrite.h" + +typedef struct GetByteContext { + const uint8_t *buffer, *buffer_end, *buffer_start; +} GetByteContext; + +typedef struct PutByteContext { + uint8_t *buffer, *buffer_end, *buffer_start; + int eof; +} PutByteContext; + +#define DEF(type, name, bytes, read, write) \ + static av_always_inline type bytestream_get_##name(const uint8_t **b) { \ + (*b) += bytes; \ + return read(*b - bytes); \ + } \ + static av_always_inline void bytestream_put_##name(uint8_t **b, \ + const type value) { \ + write(*b, value); \ + (*b) += bytes; \ + } \ + static av_always_inline void bytestream2_put_##name##u(PutByteContext *p, \ + const type value) { \ + bytestream_put_##name(&p->buffer, value); \ + } \ + static av_always_inline void bytestream2_put_##name(PutByteContext *p, \ + const type value) { \ + if(!p->eof && (p->buffer_end - p->buffer >= bytes)) { \ + write(p->buffer, value); \ + p->buffer += bytes; \ + } \ + else \ + p->eof = 1; \ + } \ + static av_always_inline type bytestream2_get_##name##u(GetByteContext *g) { \ + return bytestream_get_##name(&g->buffer); \ + } \ + static av_always_inline type bytestream2_get_##name(GetByteContext *g) { \ + if(g->buffer_end - g->buffer < bytes) { \ + g->buffer = g->buffer_end; \ + return 0; \ + } \ + return bytestream2_get_##name##u(g); \ + } \ + static av_always_inline type bytestream2_peek_##name##u(GetByteContext *g) { \ + return read(g->buffer); \ + } \ + static av_always_inline type bytestream2_peek_##name(GetByteContext *g) { \ + if(g->buffer_end - g->buffer < bytes) \ + return 0; \ + return bytestream2_peek_##name##u(g); \ + } + +DEF(uint64_t, le64, 8, AV_RL64, AV_WL64) +DEF(unsigned int, le32, 4, AV_RL32, AV_WL32) +DEF(unsigned int, le24, 3, AV_RL24, AV_WL24) +DEF(unsigned int, le16, 2, AV_RL16, AV_WL16) +DEF(uint64_t, be64, 8, AV_RB64, AV_WB64) +DEF(unsigned int, be32, 4, AV_RB32, AV_WB32) +DEF(unsigned int, be24, 3, AV_RB24, AV_WB24) +DEF(unsigned int, be16, 2, AV_RB16, AV_WB16) +DEF(unsigned int, byte, 1, AV_RB8, AV_WB8) + +#if AV_HAVE_BIGENDIAN +#define bytestream2_get_ne16 bytestream2_get_be16 +#define bytestream2_get_ne24 bytestream2_get_be24 +#define bytestream2_get_ne32 bytestream2_get_be32 +#define bytestream2_get_ne64 bytestream2_get_be64 +#define bytestream2_get_ne16u bytestream2_get_be16u +#define bytestream2_get_ne24u bytestream2_get_be24u +#define bytestream2_get_ne32u bytestream2_get_be32u +#define bytestream2_get_ne64u bytestream2_get_be64u +#define bytestream2_put_ne16 bytestream2_put_be16 +#define bytestream2_put_ne24 bytestream2_put_be24 +#define bytestream2_put_ne32 bytestream2_put_be32 +#define bytestream2_put_ne64 bytestream2_put_be64 +#define bytestream2_peek_ne16 bytestream2_peek_be16 +#define bytestream2_peek_ne24 bytestream2_peek_be24 +#define bytestream2_peek_ne32 bytestream2_peek_be32 +#define bytestream2_peek_ne64 bytestream2_peek_be64 +#else +#define bytestream2_get_ne16 bytestream2_get_le16 +#define bytestream2_get_ne24 bytestream2_get_le24 +#define bytestream2_get_ne32 bytestream2_get_le32 +#define bytestream2_get_ne64 bytestream2_get_le64 +#define bytestream2_get_ne16u bytestream2_get_le16u +#define bytestream2_get_ne24u bytestream2_get_le24u +#define bytestream2_get_ne32u bytestream2_get_le32u +#define bytestream2_get_ne64u bytestream2_get_le64u +#define bytestream2_put_ne16 bytestream2_put_le16 +#define bytestream2_put_ne24 bytestream2_put_le24 +#define bytestream2_put_ne32 bytestream2_put_le32 +#define bytestream2_put_ne64 bytestream2_put_le64 +#define bytestream2_peek_ne16 bytestream2_peek_le16 +#define bytestream2_peek_ne24 bytestream2_peek_le24 +#define bytestream2_peek_ne32 bytestream2_peek_le32 +#define bytestream2_peek_ne64 bytestream2_peek_le64 +#endif + +static av_always_inline void bytestream2_init(GetByteContext *g, + const uint8_t *buf, + int buf_size) { + av_assert0(buf_size >= 0); + g->buffer = buf; + g->buffer_start = buf; + g->buffer_end = buf + buf_size; +} + +static av_always_inline void bytestream2_init_writer(PutByteContext *p, + uint8_t *buf, + int buf_size) { + av_assert0(buf_size >= 0); + p->buffer = buf; + p->buffer_start = buf; + p->buffer_end = buf + buf_size; + p->eof = 0; +} + +static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g) { + return g->buffer_end - g->buffer; +} + +static av_always_inline int bytestream2_get_bytes_left_p(PutByteContext *p) { + return p->buffer_end - p->buffer; +} + +static av_always_inline void bytestream2_skip(GetByteContext *g, + unsigned int size) { + g->buffer += FFMIN(g->buffer_end - g->buffer, size); +} + +static av_always_inline void bytestream2_skipu(GetByteContext *g, + unsigned int size) { + g->buffer += size; +} + +static av_always_inline void bytestream2_skip_p(PutByteContext *p, + unsigned int size) { + int size2; + if(p->eof) + return; + size2 = FFMIN(p->buffer_end - p->buffer, size); + if(size2 != size) + p->eof = 1; + p->buffer += size2; +} + +static av_always_inline int bytestream2_tell(GetByteContext *g) { + return (int)(g->buffer - g->buffer_start); +} + +static av_always_inline int bytestream2_tell_p(PutByteContext *p) { + return (int)(p->buffer - p->buffer_start); +} + +static av_always_inline int bytestream2_size(GetByteContext *g) { + return (int)(g->buffer_end - g->buffer_start); +} + +static av_always_inline int bytestream2_size_p(PutByteContext *p) { + return (int)(p->buffer_end - p->buffer_start); +} + +static av_always_inline int bytestream2_seek(GetByteContext *g, + int offset, + int whence) { + switch(whence) { + case SEEK_CUR: + offset = av_clip(offset, -(g->buffer - g->buffer_start), + g->buffer_end - g->buffer); + g->buffer += offset; + break; + case SEEK_END: + offset = av_clip(offset, -(g->buffer_end - g->buffer_start), 0); + g->buffer = g->buffer_end + offset; + break; + case SEEK_SET: + offset = av_clip(offset, 0, g->buffer_end - g->buffer_start); + g->buffer = g->buffer_start + offset; + break; + default: + return AVERROR(EINVAL); + } + return bytestream2_tell(g); +} + +static av_always_inline int bytestream2_seek_p(PutByteContext *p, + int offset, + int whence) { + p->eof = 0; + switch(whence) { + case SEEK_CUR: + if(p->buffer_end - p->buffer < offset) + p->eof = 1; + offset = av_clip(offset, -(p->buffer - p->buffer_start), + p->buffer_end - p->buffer); + p->buffer += offset; + break; + case SEEK_END: + if(offset > 0) + p->eof = 1; + offset = av_clip(offset, -(p->buffer_end - p->buffer_start), 0); + p->buffer = p->buffer_end + offset; + break; + case SEEK_SET: + if(p->buffer_end - p->buffer_start < offset) + p->eof = 1; + offset = av_clip(offset, 0, p->buffer_end - p->buffer_start); + p->buffer = p->buffer_start + offset; + break; + default: + return AVERROR(EINVAL); + } + return bytestream2_tell_p(p); +} + +static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, + uint8_t *dst, + unsigned int size) { + int size2 = FFMIN(g->buffer_end - g->buffer, size); + memcpy(dst, g->buffer, size2); + g->buffer += size2; + return size2; +} + +static av_always_inline unsigned int bytestream2_get_bufferu(GetByteContext *g, + uint8_t *dst, + unsigned int size) { + memcpy(dst, g->buffer, size); + g->buffer += size; + return size; +} + +static av_always_inline unsigned int bytestream2_put_buffer(PutByteContext *p, + const uint8_t *src, + unsigned int size) { + int size2; + if(p->eof) + return 0; + size2 = FFMIN(p->buffer_end - p->buffer, size); + if(size2 != size) + p->eof = 1; + memcpy(p->buffer, src, size2); + p->buffer += size2; + return size2; +} + +static av_always_inline unsigned int bytestream2_put_bufferu(PutByteContext *p, + const uint8_t *src, + unsigned int size) { + memcpy(p->buffer, src, size); + p->buffer += size; + return size; +} + +static av_always_inline void bytestream2_set_buffer(PutByteContext *p, + const uint8_t c, + unsigned int size) { + int size2; + if(p->eof) + return; + size2 = FFMIN(p->buffer_end - p->buffer, size); + if(size2 != size) + p->eof = 1; + memset(p->buffer, c, size2); + p->buffer += size2; +} + +static av_always_inline void bytestream2_set_bufferu(PutByteContext *p, + const uint8_t c, + unsigned int size) { + memset(p->buffer, c, size); + p->buffer += size; +} + +static av_always_inline unsigned int bytestream2_get_eof(PutByteContext *p) { + return p->eof; +} + +static av_always_inline unsigned int bytestream2_copy_bufferu(PutByteContext *p, + GetByteContext *g, + unsigned int size) { + memcpy(p->buffer, g->buffer, size); + p->buffer += size; + g->buffer += size; + return size; +} + +static av_always_inline unsigned int bytestream2_copy_buffer(PutByteContext *p, + GetByteContext *g, + unsigned int size) { + int size2; + + if(p->eof) + return 0; + size = FFMIN(g->buffer_end - g->buffer, size); + size2 = FFMIN(p->buffer_end - p->buffer, size); + if(size2 != size) + p->eof = 1; + + return bytestream2_copy_bufferu(p, g, size2); +} + +static av_always_inline unsigned int bytestream_get_buffer(const uint8_t **b, + uint8_t *dst, + unsigned int size) { + memcpy(dst, *b, size); + (*b) += size; + return size; +} + +static av_always_inline void bytestream_put_buffer(uint8_t **b, + const uint8_t *src, + unsigned int size) { + memcpy(*b, src, size); + (*b) += size; +} + +#endif /* AVCODEC_BYTESTREAM_H */ diff --git a/third-party/cbs/cbs.c b/third-party/cbs/cbs.c new file mode 100644 index 00000000..e0167d50 --- /dev/null +++ b/third-party/cbs/cbs.c @@ -0,0 +1,1039 @@ +/* + * 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 +#include +#include +#include + +#include + +#include "cbs/cbs.h" +#include "cbs_internal.h" + +#include "get_bits.h" + + +static const CodedBitstreamType *const cbs_type_table[] = { +#if CONFIG_CBS_AV1 + &ff_cbs_type_av1, +#endif +#if CONFIG_CBS_H264 + &ff_cbs_type_h264, +#endif +#if CONFIG_CBS_H265 + &ff_cbs_type_h265, +#endif +#if CONFIG_CBS_JPEG + &ff_cbs_type_jpeg, +#endif +#if CONFIG_CBS_MPEG2 + &ff_cbs_type_mpeg2, +#endif +#if CONFIG_CBS_VP9 + &ff_cbs_type_vp9, +#endif +}; + +const enum AVCodecID ff_cbs_all_codec_ids[] = { +#if CONFIG_CBS_AV1 + AV_CODEC_ID_AV1, +#endif +#if CONFIG_CBS_H264 + AV_CODEC_ID_H264, +#endif +#if CONFIG_CBS_H265 + AV_CODEC_ID_H265, +#endif +#if CONFIG_CBS_JPEG + AV_CODEC_ID_MJPEG, +#endif +#if CONFIG_CBS_MPEG2 + AV_CODEC_ID_MPEG2VIDEO, +#endif +#if CONFIG_CBS_VP9 + AV_CODEC_ID_VP9, +#endif + AV_CODEC_ID_NONE +}; + +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; /* Must be before any error */ + + if(type->priv_data_size) { + ctx->priv_data = av_mallocz(ctx->codec->priv_data_size); + if(!ctx->priv_data) { + av_freep(&ctx); + return AVERROR(ENOMEM); + } + if(type->priv_class) { + *(const AVClass **)ctx->priv_data = type->priv_class; + av_opt_set_defaults(ctx->priv_data); + } + } + + ctx->decompose_unit_types = NULL; + + ctx->trace_enable = 0; + ctx->trace_level = AV_LOG_TRACE; + + *ctx_ptr = ctx; + return 0; +} + +void ff_cbs_flush(CodedBitstreamContext *ctx) { + if(ctx->codec->flush) + ctx->codec->flush(ctx); +} + +void ff_cbs_close(CodedBitstreamContext **ctx_ptr) { + CodedBitstreamContext *ctx = *ctx_ptr; + + if(!ctx) + return; + + if(ctx->codec->close) + ctx->codec->close(ctx); + + av_freep(&ctx->write_buffer); + + if(ctx->codec->priv_class && ctx->priv_data) + av_opt_free(ctx->priv_data); + + av_freep(&ctx->priv_data); + av_freep(ctx_ptr); +} + +static void cbs_unit_uninit(CodedBitstreamUnit *unit) { + av_buffer_unref(&unit->content_ref); + unit->content = NULL; + + av_buffer_unref(&unit->data_ref); + unit->data = NULL; + unit->data_size = 0; + unit->data_bit_padding = 0; +} + +void ff_cbs_fragment_reset(CodedBitstreamFragment *frag) { + int i; + + for(i = 0; i < frag->nb_units; i++) + cbs_unit_uninit(&frag->units[i]); + frag->nb_units = 0; + + av_buffer_unref(&frag->data_ref); + frag->data = NULL; + frag->data_size = 0; + frag->data_bit_padding = 0; +} + +void ff_cbs_fragment_free(CodedBitstreamFragment *frag) { + ff_cbs_fragment_reset(frag); + + av_freep(&frag->units); + frag->nb_units_allocated = 0; +} + +static int cbs_read_fragment_content(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) { + int err, i, j; + + for(i = 0; i < frag->nb_units; i++) { + CodedBitstreamUnit *unit = &frag->units[i]; + + if(ctx->decompose_unit_types) { + for(j = 0; j < ctx->nb_decompose_unit_types; j++) { + if(ctx->decompose_unit_types[j] == unit->type) + break; + } + if(j >= ctx->nb_decompose_unit_types) + continue; + } + + av_buffer_unref(&unit->content_ref); + unit->content = NULL; + + av_assert0(unit->data && unit->data_ref); + + err = ctx->codec->read_unit(ctx, unit); + if(err == AVERROR(ENOSYS)) { + av_log(ctx->log_ctx, AV_LOG_VERBOSE, + "Decomposition unimplemented for unit %d " + "(type %" PRIu32 ").\n", + i, unit->type); + } + else if(err == AVERROR(EAGAIN)) { + av_log(ctx->log_ctx, AV_LOG_VERBOSE, + "Skipping decomposition of unit %d " + "(type %" PRIu32 ").\n", + i, unit->type); + av_buffer_unref(&unit->content_ref); + unit->content = NULL; + } + else if(err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d " + "(type %" PRIu32 ").\n", + i, unit->type); + return err; + } + } + + return 0; +} + +static int cbs_fill_fragment_data(CodedBitstreamFragment *frag, + const uint8_t *data, size_t size) { + av_assert0(!frag->data && !frag->data_ref); + + frag->data_ref = + av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if(!frag->data_ref) + return AVERROR(ENOMEM); + + frag->data = frag->data_ref->data; + frag->data_size = size; + + memcpy(frag->data, data, size); + memset(frag->data + size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + + return 0; +} + +static int cbs_read_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + AVBufferRef *buf, + const uint8_t *data, size_t size, + int header) { + int err; + + if(buf) { + frag->data_ref = av_buffer_ref(buf); + if(!frag->data_ref) + return AVERROR(ENOMEM); + + frag->data = (uint8_t *)data; + frag->data_size = size; + } + else { + err = cbs_fill_fragment_data(frag, data, size); + if(err < 0) + return err; + } + + err = ctx->codec->split_fragment(ctx, frag, header); + if(err < 0) + return err; + + return cbs_read_fragment_content(ctx, frag); +} + +int ff_cbs_read_extradata(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVCodecParameters *par) { + return cbs_read_data(ctx, frag, NULL, + par->extradata, + par->extradata_size, 1); +} + +int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVCodecContext *avctx) { + return cbs_read_data(ctx, frag, NULL, + avctx->extradata, + avctx->extradata_size, 1); +} + +int ff_cbs_read_packet(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVPacket *pkt) { + return cbs_read_data(ctx, frag, pkt->buf, + pkt->data, pkt->size, 0); +} + +int ff_cbs_read(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const uint8_t *data, size_t size) { + return cbs_read_data(ctx, frag, NULL, + data, size, 0); +} + +static int cbs_write_unit_data(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) { + PutBitContext pbc; + int ret; + + if(!ctx->write_buffer) { + // Initial write buffer size is 1MB. + ctx->write_buffer_size = 1024 * 1024; + + reallocate_and_try_again: + ret = av_reallocp(&ctx->write_buffer, ctx->write_buffer_size); + if(ret < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " + "sufficiently large write buffer (last attempt " + "%zu bytes).\n", + ctx->write_buffer_size); + return ret; + } + } + + init_put_bits(&pbc, ctx->write_buffer, ctx->write_buffer_size); + + ret = ctx->codec->write_unit(ctx, unit, &pbc); + if(ret < 0) { + if(ret == AVERROR(ENOSPC)) { + // Overflow. + if(ctx->write_buffer_size == INT_MAX / 8) + return AVERROR(ENOMEM); + ctx->write_buffer_size = FFMIN(2 * ctx->write_buffer_size, INT_MAX / 8); + goto reallocate_and_try_again; + } + // Write failed for some other reason. + return ret; + } + + // Overflow but we didn't notice. + av_assert0(put_bits_count(&pbc) <= 8 * ctx->write_buffer_size); + + if(put_bits_count(&pbc) % 8) + unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8; + else + unit->data_bit_padding = 0; + + flush_put_bits(&pbc); + + ret = ff_cbs_alloc_unit_data(unit, put_bytes_output(&pbc)); + if(ret < 0) + return ret; + + memcpy(unit->data, ctx->write_buffer, unit->data_size); + + return 0; +} + +int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) { + int err, i; + + for(i = 0; i < frag->nb_units; i++) { + CodedBitstreamUnit *unit = &frag->units[i]; + + if(!unit->content) + continue; + + av_buffer_unref(&unit->data_ref); + unit->data = NULL; + + err = cbs_write_unit_data(ctx, unit); + if(err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write unit %d " + "(type %" PRIu32 ").\n", + i, unit->type); + return err; + } + av_assert0(unit->data && unit->data_ref); + } + + av_buffer_unref(&frag->data_ref); + frag->data = NULL; + + 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; + } + av_assert0(frag->data && frag->data_ref); + + 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) { + AVBufferRef *buf; + int err; + + err = ff_cbs_write_fragment_data(ctx, frag); + if(err < 0) + return err; + + buf = av_buffer_ref(frag->data_ref); + if(!buf) + return AVERROR(ENOMEM); + + av_buffer_unref(&pkt->buf); + + pkt->buf = buf; + pkt->data = frag->data; + 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 *str, const int *subscripts, + const char *bits, int64_t value) { + char name[256]; + size_t name_len, bits_len; + int pad, subs, i, j, k, n; + + if(!ctx->trace_enable) + return; + + av_assert0(value >= INT_MIN && value <= UINT32_MAX); + + subs = subscripts ? subscripts[0] : 0; + n = 0; + for(i = j = 0; str[i];) { + if(str[i] == '[') { + if(n < subs) { + ++n; + k = snprintf(name + j, sizeof(name) - j, "[%d", subscripts[n]); + av_assert0(k > 0 && j + k < sizeof(name)); + j += k; + for(++i; str[i] && str[i] != ']'; i++) + ; + av_assert0(str[i] == ']'); + } + else { + while(str[i] && str[i] != ']') + name[j++] = str[i++]; + av_assert0(str[i] == ']'); + } + } + else { + av_assert0(j + 1 < sizeof(name)); + name[j++] = str[i++]; + } + } + av_assert0(j + 1 < sizeof(name)); + name[j] = 0; + av_assert0(n == subs); + + 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, + const int *subscripts, 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, 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; +} + +int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, + const int *subscripts, 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, subscripts, bits, value); + } + + if(width < 32) + put_bits(pbc, width, value); + else + put_bits32(pbc, value); + + return 0; +} + +int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc, + int width, const char *name, + const int *subscripts, int32_t *write_to, + int32_t range_min, int32_t range_max) { + int32_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_sbits_long(gbc, width); + + if(ctx->trace_enable) { + char bits[33]; + int i; + for(i = 0; i < width; i++) + bits[i] = value & (1U << (width - i - 1)) ? '1' : '0'; + bits[i] = 0; + + 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; +} + +int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, + const int *subscripts, int32_t value, + int32_t range_min, int32_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: " + "%" PRId32 ", but must be in [%" PRId32 ",%" PRId32 "].\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 & (1U << (width - i - 1)) ? '1' : '0'; + bits[i] = 0; + + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, subscripts, bits, value); + } + + if(width < 32) + put_sbits(pbc, width, value); + else + put_bits32(pbc, value); + + return 0; +} + + +int ff_cbs_alloc_unit_content(CodedBitstreamUnit *unit, + size_t size, + void (*free)(void *opaque, uint8_t *data)) { + av_assert0(!unit->content && !unit->content_ref); + + unit->content = av_mallocz(size); + if(!unit->content) + return AVERROR(ENOMEM); + + unit->content_ref = av_buffer_create(unit->content, size, + free, NULL, 0); + if(!unit->content_ref) { + av_freep(&unit->content); + return AVERROR(ENOMEM); + } + + return 0; +} + +int ff_cbs_alloc_unit_data(CodedBitstreamUnit *unit, + size_t size) { + av_assert0(!unit->data && !unit->data_ref); + + unit->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if(!unit->data_ref) + return AVERROR(ENOMEM); + + unit->data = unit->data_ref->data; + unit->data_size = size; + + memset(unit->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + return 0; +} + +static int cbs_insert_unit(CodedBitstreamFragment *frag, + int position) { + CodedBitstreamUnit *units; + + if(frag->nb_units < frag->nb_units_allocated) { + units = frag->units; + + if(position < frag->nb_units) + memmove(units + position + 1, units + position, + (frag->nb_units - position) * sizeof(*units)); + } + else { + units = av_malloc_array(frag->nb_units * 2 + 1, sizeof(*units)); + if(!units) + return AVERROR(ENOMEM); + + frag->nb_units_allocated = 2 * frag->nb_units_allocated + 1; + + 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)); + + if(units != frag->units) { + av_free(frag->units); + frag->units = units; + } + + ++frag->nb_units; + + return 0; +} + +int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + void *content, + AVBufferRef *content_buf) { + CodedBitstreamUnit *unit; + AVBufferRef *content_ref; + int err; + + if(position == -1) + position = frag->nb_units; + av_assert0(position >= 0 && position <= frag->nb_units); + + if(content_buf) { + content_ref = av_buffer_ref(content_buf); + if(!content_ref) + return AVERROR(ENOMEM); + } + else { + content_ref = NULL; + } + + err = cbs_insert_unit(frag, position); + if(err < 0) { + av_buffer_unref(&content_ref); + return err; + } + + unit = &frag->units[position]; + unit->type = type; + unit->content = content; + unit->content_ref = content_ref; + + return 0; +} + +int ff_cbs_insert_unit_data(CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + uint8_t *data, size_t data_size, + AVBufferRef *data_buf) { + CodedBitstreamUnit *unit; + AVBufferRef *data_ref; + int err; + + if(position == -1) + position = frag->nb_units; + av_assert0(position >= 0 && position <= frag->nb_units); + + if(data_buf) + data_ref = av_buffer_ref(data_buf); + else + data_ref = av_buffer_create(data, data_size, NULL, NULL, 0); + if(!data_ref) { + if(!data_buf) + av_free(data); + return AVERROR(ENOMEM); + } + + err = cbs_insert_unit(frag, position); + if(err < 0) { + av_buffer_unref(&data_ref); + return err; + } + + unit = &frag->units[position]; + unit->type = type; + unit->data = data; + unit->data_size = data_size; + unit->data_ref = data_ref; + + return 0; +} + +void ff_cbs_delete_unit(CodedBitstreamFragment *frag, + int position) { + av_assert0(0 <= position && position < frag->nb_units && "Unit to be deleted not in fragment."); + + cbs_unit_uninit(&frag->units[position]); + + --frag->nb_units; + + if(frag->nb_units > 0) + memmove(frag->units + position, + frag->units + position + 1, + (frag->nb_units - position) * sizeof(*frag->units)); +} + +static void cbs_default_free_unit_content(void *opaque, uint8_t *data) { + const CodedBitstreamUnitTypeDescriptor *desc = opaque; + if(desc->content_type == CBS_CONTENT_TYPE_INTERNAL_REFS) { + int i; + for(i = 0; i < desc->nb_ref_offsets; i++) { + void **ptr = (void **)(data + desc->ref_offsets[i]); + av_buffer_unref((AVBufferRef **)(ptr + 1)); + } + } + av_free(data); +} + +static const CodedBitstreamUnitTypeDescriptor + * + cbs_find_unit_type_desc(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) { + const CodedBitstreamUnitTypeDescriptor *desc; + int i, j; + + if(!ctx->codec->unit_types) + return NULL; + + for(i = 0;; i++) { + desc = &ctx->codec->unit_types[i]; + if(desc->nb_unit_types == 0) + break; + if(desc->nb_unit_types == CBS_UNIT_TYPE_RANGE) { + if(unit->type >= desc->unit_type_range_start && + unit->type <= desc->unit_type_range_end) + return desc; + } + else { + for(j = 0; j < desc->nb_unit_types; j++) { + if(desc->unit_types[j] == unit->type) + return desc; + } + } + } + return NULL; +} + +int ff_cbs_alloc_unit_content2(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) { + const CodedBitstreamUnitTypeDescriptor *desc; + + av_assert0(!unit->content && !unit->content_ref); + + desc = cbs_find_unit_type_desc(ctx, unit); + if(!desc) + return AVERROR(ENOSYS); + + unit->content = av_mallocz(desc->content_size); + if(!unit->content) + return AVERROR(ENOMEM); + + unit->content_ref = + av_buffer_create(unit->content, desc->content_size, + desc->content_free ? desc->content_free : cbs_default_free_unit_content, + (void *)desc, 0); + if(!unit->content_ref) { + av_freep(&unit->content); + return AVERROR(ENOMEM); + } + + return 0; +} + +static int cbs_clone_unit_content(AVBufferRef **clone_ref, + CodedBitstreamUnit *unit, + const CodedBitstreamUnitTypeDescriptor *desc) { + uint8_t *src, *copy; + uint8_t **src_ptr, **copy_ptr; + AVBufferRef **src_buf, **copy_buf; + int err, i; + + av_assert0(unit->content); + src = unit->content; + + copy = av_memdup(src, desc->content_size); + if(!copy) + return AVERROR(ENOMEM); + + for(i = 0; i < desc->nb_ref_offsets; i++) { + src_ptr = (uint8_t **)(src + desc->ref_offsets[i]); + src_buf = (AVBufferRef **)(src_ptr + 1); + copy_ptr = (uint8_t **)(copy + desc->ref_offsets[i]); + copy_buf = (AVBufferRef **)(copy_ptr + 1); + + if(!*src_ptr) { + av_assert0(!*src_buf); + continue; + } + if(!*src_buf) { + // We can't handle a non-refcounted pointer here - we don't + // have enough information to handle whatever structure lies + // at the other end of it. + err = AVERROR(EINVAL); + goto fail; + } + + // src_ptr is required to point somewhere inside src_buf. If it + // doesn't, there is a bug somewhere. + av_assert0(*src_ptr >= (*src_buf)->data && + *src_ptr < (*src_buf)->data + (*src_buf)->size); + + *copy_buf = av_buffer_ref(*src_buf); + if(!*copy_buf) { + err = AVERROR(ENOMEM); + goto fail; + } + *copy_ptr = (*copy_buf)->data + (*src_ptr - (*src_buf)->data); + } + + *clone_ref = av_buffer_create(copy, desc->content_size, + desc->content_free ? desc->content_free : + cbs_default_free_unit_content, + (void *)desc, 0); + if(!*clone_ref) { + err = AVERROR(ENOMEM); + goto fail; + } + + return 0; + +fail: + for(--i; i >= 0; i--) + av_buffer_unref((AVBufferRef **)(copy + desc->ref_offsets[i])); + av_freep(©); + *clone_ref = NULL; + return err; +} + +int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) { + const CodedBitstreamUnitTypeDescriptor *desc; + AVBufferRef *ref; + int err; + + av_assert0(unit->content); + if(unit->content_ref) { + // Already refcounted, nothing to do. + return 0; + } + + desc = cbs_find_unit_type_desc(ctx, unit); + if(!desc) + return AVERROR(ENOSYS); + + switch(desc->content_type) { + case CBS_CONTENT_TYPE_POD: + ref = av_buffer_alloc(desc->content_size); + if(!ref) + return AVERROR(ENOMEM); + memcpy(ref->data, unit->content, desc->content_size); + err = 0; + break; + + case CBS_CONTENT_TYPE_INTERNAL_REFS: + err = cbs_clone_unit_content(&ref, unit, desc); + break; + + case CBS_CONTENT_TYPE_COMPLEX: + if(!desc->content_clone) + return AVERROR_PATCHWELCOME; + err = desc->content_clone(&ref, unit); + break; + + default: + av_assert0(0 && "Invalid content type."); + } + + if(err < 0) + return err; + + unit->content_ref = ref; + unit->content = ref->data; + return 0; +} + +int ff_cbs_make_unit_writable(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) { + const CodedBitstreamUnitTypeDescriptor *desc; + AVBufferRef *ref; + int err; + + // This can only be applied to refcounted units. + err = ff_cbs_make_unit_refcounted(ctx, unit); + if(err < 0) + return err; + av_assert0(unit->content && unit->content_ref); + + if(av_buffer_is_writable(unit->content_ref)) + return 0; + + desc = cbs_find_unit_type_desc(ctx, unit); + if(!desc) + return AVERROR(ENOSYS); + + switch(desc->content_type) { + case CBS_CONTENT_TYPE_POD: + err = av_buffer_make_writable(&unit->content_ref); + break; + + case CBS_CONTENT_TYPE_INTERNAL_REFS: + err = cbs_clone_unit_content(&ref, unit, desc); + break; + + case CBS_CONTENT_TYPE_COMPLEX: + if(!desc->content_clone) + return AVERROR_PATCHWELCOME; + err = desc->content_clone(&ref, unit); + break; + + default: + av_assert0(0 && "Invalid content type."); + } + if(err < 0) + return err; + + if(desc->content_type != CBS_CONTENT_TYPE_POD) { + av_buffer_unref(&unit->content_ref); + unit->content_ref = ref; + } + unit->content = unit->content_ref->data; + return 0; +} diff --git a/third-party/cbs/cbs_av1.c b/third-party/cbs/cbs_av1.c new file mode 100644 index 00000000..7bb53b93 --- /dev/null +++ b/third-party/cbs/cbs_av1.c @@ -0,0 +1,1323 @@ +/* + * 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 +#include + +#include "cbs/cbs.h" +#include "cbs/cbs_av1.h" + +#include "cbs_internal.h" + + +static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc, + const char *name, uint32_t *write_to, + uint32_t range_min, uint32_t range_max) { + uint32_t zeroes, bits_value, value; + int position; + + if(ctx->trace_enable) + position = get_bits_count(gbc); + + zeroes = 0; + while(1) { + if(get_bits_left(gbc) < 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid uvlc code at " + "%s: bitstream ended.\n", + name); + return AVERROR_INVALIDDATA; + } + + if(get_bits1(gbc)) + break; + ++zeroes; + } + + if(zeroes >= 32) { + value = MAX_UINT_BITS(32); + } + else { + if(get_bits_left(gbc) < zeroes) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid uvlc code at " + "%s: bitstream ended.\n", + name); + return AVERROR_INVALIDDATA; + } + + bits_value = get_bits_long(gbc, zeroes); + value = bits_value + (UINT32_C(1) << zeroes) - 1; + } + + if(ctx->trace_enable) { + char bits[65]; + int i, j, k; + + if(zeroes >= 32) { + while(zeroes > 32) { + k = FFMIN(zeroes - 32, 32); + for(i = 0; i < k; i++) + bits[i] = '0'; + bits[i] = 0; + ff_cbs_trace_syntax_element(ctx, position, name, + NULL, bits, 0); + zeroes -= k; + position += k; + } + } + + for(i = 0; i < zeroes; i++) + bits[i] = '0'; + bits[i++] = '1'; + + if(zeroes < 32) { + for(j = 0; j < zeroes; j++) + bits[i++] = (bits_value >> (zeroes - j - 1) & 1) ? '1' : '0'; + } + + bits[i] = 0; + ff_cbs_trace_syntax_element(ctx, position, name, + NULL, 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_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc, + const char *name, uint32_t value, + uint32_t range_min, uint32_t range_max) { + uint32_t v; + int position, zeroes; + + 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(ctx->trace_enable) + position = put_bits_count(pbc); + + zeroes = av_log2(value + 1); + v = value - (1U << zeroes) + 1; + put_bits(pbc, zeroes, 0); + put_bits(pbc, 1, 1); + put_bits(pbc, zeroes, v); + + if(ctx->trace_enable) { + char bits[65]; + int i, j; + i = 0; + for(j = 0; j < zeroes; j++) + bits[i++] = '0'; + bits[i++] = '1'; + for(j = 0; j < zeroes; j++) + bits[i++] = (v >> (zeroes - j - 1) & 1) ? '1' : '0'; + bits[i++] = 0; + ff_cbs_trace_syntax_element(ctx, position, name, NULL, + bits, value); + } + + return 0; +} + +static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc, + const char *name, uint64_t *write_to) { + uint64_t value; + int position, err, i; + + if(ctx->trace_enable) + position = get_bits_count(gbc); + + value = 0; + for(i = 0; i < 8; i++) { + int subscript[2] = { 1, i }; + uint32_t byte; + err = ff_cbs_read_unsigned(ctx, gbc, 8, "leb128_byte[i]", subscript, + &byte, 0x00, 0xff); + if(err < 0) + return err; + + value |= (uint64_t)(byte & 0x7f) << (i * 7); + if(!(byte & 0x80)) + break; + } + + if(value > UINT32_MAX) + return AVERROR_INVALIDDATA; + + if(ctx->trace_enable) + ff_cbs_trace_syntax_element(ctx, position, name, NULL, "", value); + + *write_to = value; + return 0; +} + +static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext *pbc, + const char *name, uint64_t value) { + int position, err, len, i; + uint8_t byte; + + len = (av_log2(value) + 7) / 7; + + if(ctx->trace_enable) + position = put_bits_count(pbc); + + for(i = 0; i < len; i++) { + int subscript[2] = { 1, i }; + + byte = value >> (7 * i) & 0x7f; + if(i < len - 1) + byte |= 0x80; + + err = ff_cbs_write_unsigned(ctx, pbc, 8, "leb128_byte[i]", subscript, + byte, 0x00, 0xff); + if(err < 0) + return err; + } + + if(ctx->trace_enable) + ff_cbs_trace_syntax_element(ctx, position, name, NULL, "", value); + + return 0; +} + +static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc, + uint32_t n, const char *name, + const int *subscripts, uint32_t *write_to) { + uint32_t m, v, extra_bit, value; + int position, w; + + av_assert0(n > 0); + + if(ctx->trace_enable) + position = get_bits_count(gbc); + + w = av_log2(n) + 1; + m = (1 << w) - n; + + if(get_bits_left(gbc) < w) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid non-symmetric value at " + "%s: bitstream ended.\n", + name); + return AVERROR_INVALIDDATA; + } + + if(w - 1 > 0) + v = get_bits(gbc, w - 1); + else + v = 0; + + if(v < m) { + value = v; + } + else { + extra_bit = get_bits1(gbc); + value = (v << 1) - m + extra_bit; + } + + if(ctx->trace_enable) { + char bits[33]; + int i; + for(i = 0; i < w - 1; i++) + bits[i] = (v >> i & 1) ? '1' : '0'; + if(v >= m) + bits[i++] = extra_bit ? '1' : '0'; + bits[i] = 0; + + ff_cbs_trace_syntax_element(ctx, position, + name, subscripts, bits, value); + } + + *write_to = value; + return 0; +} + +static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc, + uint32_t n, const char *name, + const int *subscripts, uint32_t value) { + uint32_t w, m, v, extra_bit; + int position; + + if(value > n) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%" PRIu32 ", but must be in [0,%" PRIu32 "].\n", + name, value, n); + return AVERROR_INVALIDDATA; + } + + if(ctx->trace_enable) + position = put_bits_count(pbc); + + w = av_log2(n) + 1; + m = (1 << w) - n; + + if(put_bits_left(pbc) < w) + return AVERROR(ENOSPC); + + if(value < m) { + v = value; + put_bits(pbc, w - 1, v); + } + else { + v = m + ((value - m) >> 1); + extra_bit = (value - m) & 1; + put_bits(pbc, w - 1, v); + put_bits(pbc, 1, extra_bit); + } + + if(ctx->trace_enable) { + char bits[33]; + int i; + for(i = 0; i < w - 1; i++) + bits[i] = (v >> i & 1) ? '1' : '0'; + if(value >= m) + bits[i++] = extra_bit ? '1' : '0'; + bits[i] = 0; + + ff_cbs_trace_syntax_element(ctx, position, + name, subscripts, bits, value); + } + + return 0; +} + +static int cbs_av1_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc, + uint32_t range_min, uint32_t range_max, + const char *name, uint32_t *write_to) { + uint32_t value; + int position, i; + char bits[33]; + + av_assert0(range_min <= range_max && range_max - range_min < sizeof(bits) - 1); + if(ctx->trace_enable) + position = get_bits_count(gbc); + + for(i = 0, value = range_min; value < range_max;) { + if(get_bits_left(gbc) < 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid increment value at " + "%s: bitstream ended.\n", + name); + return AVERROR_INVALIDDATA; + } + if(get_bits1(gbc)) { + bits[i++] = '1'; + ++value; + } + else { + bits[i++] = '0'; + break; + } + } + + if(ctx->trace_enable) { + bits[i] = 0; + ff_cbs_trace_syntax_element(ctx, position, + name, NULL, bits, value); + } + + *write_to = value; + return 0; +} + +static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pbc, + uint32_t range_min, uint32_t range_max, + const char *name, uint32_t value) { + int len; + + av_assert0(range_min <= range_max && range_max - range_min < 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(value == range_max) + len = range_max - range_min; + else + len = value - range_min + 1; + if(put_bits_left(pbc) < len) + return AVERROR(ENOSPC); + + if(ctx->trace_enable) { + char bits[33]; + int i; + for(i = 0; i < len; i++) { + if(range_min + i == value) + bits[i] = '0'; + else + bits[i] = '1'; + } + bits[i] = 0; + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, NULL, bits, value); + } + + if(len > 0) + put_bits(pbc, len, (1 << len) - 1 - (value != range_max)); + + return 0; +} + +static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc, + uint32_t range_max, const char *name, + const int *subscripts, uint32_t *write_to) { + uint32_t value; + int position, err; + uint32_t max_len, len, range_offset, range_bits; + + if(ctx->trace_enable) + position = get_bits_count(gbc); + + av_assert0(range_max > 0); + max_len = av_log2(range_max - 1) - 3; + + err = cbs_av1_read_increment(ctx, gbc, 0, max_len, + "subexp_more_bits", &len); + if(err < 0) + return err; + + if(len) { + range_bits = 2 + len; + range_offset = 1 << range_bits; + } + else { + range_bits = 3; + range_offset = 0; + } + + if(len < max_len) { + err = ff_cbs_read_unsigned(ctx, gbc, range_bits, + "subexp_bits", NULL, &value, + 0, MAX_UINT_BITS(range_bits)); + if(err < 0) + return err; + } + else { + err = cbs_av1_read_ns(ctx, gbc, range_max - range_offset, + "subexp_final_bits", NULL, &value); + if(err < 0) + return err; + } + value += range_offset; + + if(ctx->trace_enable) + ff_cbs_trace_syntax_element(ctx, position, + name, subscripts, "", value); + + *write_to = value; + return err; +} + +static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc, + uint32_t range_max, const char *name, + const int *subscripts, uint32_t value) { + int position, err; + uint32_t max_len, len, range_offset, range_bits; + + if(value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%" PRIu32 ", but must be in [0,%" PRIu32 "].\n", + name, value, range_max); + return AVERROR_INVALIDDATA; + } + + if(ctx->trace_enable) + position = put_bits_count(pbc); + + av_assert0(range_max > 0); + max_len = av_log2(range_max - 1) - 3; + + if(value < 8) { + range_bits = 3; + range_offset = 0; + len = 0; + } + else { + range_bits = av_log2(value); + len = range_bits - 2; + if(len > max_len) { + // The top bin is combined with the one below it. + av_assert0(len == max_len + 1); + --range_bits; + len = max_len; + } + range_offset = 1 << range_bits; + } + + err = cbs_av1_write_increment(ctx, pbc, 0, max_len, + "subexp_more_bits", len); + if(err < 0) + return err; + + if(len < max_len) { + err = ff_cbs_write_unsigned(ctx, pbc, range_bits, + "subexp_bits", NULL, + value - range_offset, + 0, MAX_UINT_BITS(range_bits)); + if(err < 0) + return err; + } + else { + err = cbs_av1_write_ns(ctx, pbc, range_max - range_offset, + "subexp_final_bits", NULL, + value - range_offset); + if(err < 0) + return err; + } + + if(ctx->trace_enable) + ff_cbs_trace_syntax_element(ctx, position, + name, subscripts, "", value); + + return err; +} + + +static int cbs_av1_tile_log2(int blksize, int target) { + int k; + for(k = 0; (blksize << k) < target; k++) + ; + return k; +} + +static int cbs_av1_get_relative_dist(const AV1RawSequenceHeader *seq, + unsigned int a, unsigned int b) { + unsigned int diff, m; + if(!seq->enable_order_hint) + return 0; + diff = a - b; + m = 1 << seq->order_hint_bits_minus_1; + diff = (diff & (m - 1)) - (diff & m); + return diff; +} + +static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) { + GetBitContext tmp = *gbc; + size_t size = 0; + for(int i = 0; get_bits_left(&tmp) >= 8; i++) { + if(get_bits(&tmp, 8)) + size = i; + } + return size; +} + + +#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_AV1(rw, name) FUNC_NAME(rw, av1, name) +#define FUNC(name) FUNC_AV1(READWRITE, name) + +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]) { subs, __VA_ARGS__ }) : NULL) + +#define fb(width, name) \ + xf(width, name, current->name, 0, MAX_UINT_BITS(width), 0, ) +#define fc(width, name, range_min, range_max) \ + xf(width, name, current->name, range_min, range_max, 0, ) +#define flag(name) fb(1, name) +#define su(width, name) \ + xsu(width, name, current->name, 0, ) + +#define fbs(width, name, subs, ...) \ + xf(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__) +#define fcs(width, name, range_min, range_max, subs, ...) \ + xf(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define flags(name, subs, ...) \ + xf(1, name, current->name, 0, 1, subs, __VA_ARGS__) +#define sus(width, name, subs, ...) \ + xsu(width, name, current->name, subs, __VA_ARGS__) + +#define fixed(width, name, value) \ + do { \ + av_unused uint32_t fixed_value = value; \ + xf(width, name, fixed_value, value, value, 0, ); \ + } while(0) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define xf(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 xsu(width, name, var, subs, ...) \ + do { \ + int32_t value; \ + CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), &value, \ + MIN_INT_BITS(width), \ + MAX_INT_BITS(width))); \ + var = value; \ + } while(0) + +#define uvlc(name, range_min, range_max) \ + do { \ + uint32_t value; \ + CHECK(cbs_av1_read_uvlc(ctx, rw, #name, \ + &value, range_min, range_max)); \ + current->name = value; \ + } while(0) + +#define ns(max_value, name, subs, ...) \ + do { \ + uint32_t value; \ + CHECK(cbs_av1_read_ns(ctx, rw, max_value, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), &value)); \ + current->name = value; \ + } while(0) + +#define increment(name, min, max) \ + do { \ + uint32_t value; \ + CHECK(cbs_av1_read_increment(ctx, rw, min, max, #name, &value)); \ + current->name = value; \ + } while(0) + +#define subexp(name, max, subs, ...) \ + do { \ + uint32_t value; \ + CHECK(cbs_av1_read_subexp(ctx, rw, max, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), &value)); \ + current->name = value; \ + } while(0) + +#define delta_q(name) \ + do { \ + uint8_t delta_coded; \ + int8_t delta_q; \ + xf(1, name.delta_coded, delta_coded, 0, 1, 0, ); \ + if(delta_coded) \ + xsu(1 + 6, name.delta_q, delta_q, 0, ); \ + else \ + delta_q = 0; \ + current->name = delta_q; \ + } while(0) + +#define leb128(name) \ + do { \ + uint64_t value; \ + CHECK(cbs_av1_read_leb128(ctx, rw, #name, &value)); \ + current->name = value; \ + } while(0) + +#define infer(name, value) \ + do { \ + current->name = value; \ + } while(0) + +#define byte_alignment(rw) (get_bits_count(rw) % 8) + +#include "cbs_av1_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef xf +#undef xsu +#undef uvlc +#undef ns +#undef increment +#undef subexp +#undef delta_q +#undef leb128 +#undef infer +#undef byte_alignment + + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define xf(width, name, var, range_min, range_max, subs, ...) \ + do { \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + var, range_min, range_max)); \ + } while(0) + +#define xsu(width, name, var, subs, ...) \ + do { \ + CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), var, \ + MIN_INT_BITS(width), \ + MAX_INT_BITS(width))); \ + } while(0) + +#define uvlc(name, range_min, range_max) \ + do { \ + CHECK(cbs_av1_write_uvlc(ctx, rw, #name, current->name, \ + range_min, range_max)); \ + } while(0) + +#define ns(max_value, name, subs, ...) \ + do { \ + CHECK(cbs_av1_write_ns(ctx, rw, max_value, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + current->name)); \ + } while(0) + +#define increment(name, min, max) \ + do { \ + CHECK(cbs_av1_write_increment(ctx, rw, min, max, #name, \ + current->name)); \ + } while(0) + +#define subexp(name, max, subs, ...) \ + do { \ + CHECK(cbs_av1_write_subexp(ctx, rw, max, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + current->name)); \ + } while(0) + +#define delta_q(name) \ + do { \ + xf(1, name.delta_coded, current->name != 0, 0, 1, 0, ); \ + if(current->name) \ + xsu(1 + 6, name.delta_q, current->name, 0, ); \ + } while(0) + +#define leb128(name) \ + do { \ + CHECK(cbs_av1_write_leb128(ctx, rw, #name, current->name)); \ + } 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 byte_alignment(rw) (put_bits_count(rw) % 8) + +#include "cbs_av1_syntax_template.c" + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef xf +#undef xsu +#undef uvlc +#undef ns +#undef increment +#undef subexp +#undef delta_q +#undef leb128 +#undef infer +#undef byte_alignment + + +static int cbs_av1_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) { + GetBitContext gbc; + uint8_t *data; + size_t size; + uint64_t obu_length; + int pos, err, trace; + + // Don't include this parsing in trace output. + trace = ctx->trace_enable; + ctx->trace_enable = 0; + + data = frag->data; + size = frag->data_size; + + if(INT_MAX / 8 < size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid fragment: " + "too large (%zu bytes).\n", + size); + err = AVERROR_INVALIDDATA; + goto fail; + } + + if(header && size && data[0] & 0x80) { + // first bit is nonzero, the extradata does not consist purely of + // OBUs. Expect MP4/Matroska AV1CodecConfigurationRecord + int config_record_version = data[0] & 0x7f; + + if(config_record_version != 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Unknown version %d of AV1CodecConfigurationRecord " + "found!\n", + config_record_version); + err = AVERROR_INVALIDDATA; + goto fail; + } + + if(size <= 4) { + if(size < 4) { + av_log(ctx->log_ctx, AV_LOG_WARNING, + "Undersized AV1CodecConfigurationRecord v%d found!\n", + config_record_version); + err = AVERROR_INVALIDDATA; + goto fail; + } + + goto success; + } + + // In AV1CodecConfigurationRecord v1, actual OBUs start after + // four bytes. Thus set the offset as required for properly + // parsing them. + data += 4; + size -= 4; + } + + while(size > 0) { + AV1RawOBUHeader header; + uint64_t obu_size; + + init_get_bits(&gbc, data, 8 * size); + + err = cbs_av1_read_obu_header(ctx, &gbc, &header); + if(err < 0) + goto fail; + + if(header.obu_has_size_field) { + if(get_bits_left(&gbc) < 8) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid OBU: fragment " + "too short (%zu bytes).\n", + size); + err = AVERROR_INVALIDDATA; + goto fail; + } + err = cbs_av1_read_leb128(ctx, &gbc, "obu_size", &obu_size); + if(err < 0) + goto fail; + } + else + obu_size = size - 1 - header.obu_extension_flag; + + pos = get_bits_count(&gbc); + av_assert0(pos % 8 == 0 && pos / 8 <= size); + + obu_length = pos / 8 + obu_size; + + if(size < obu_length) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid OBU length: " + "%" PRIu64 ", but only %zu bytes remaining in fragment.\n", + obu_length, size); + err = AVERROR_INVALIDDATA; + goto fail; + } + + err = ff_cbs_insert_unit_data(frag, -1, header.obu_type, + data, obu_length, frag->data_ref); + if(err < 0) + goto fail; + + data += obu_length; + size -= obu_length; + } + +success: + err = 0; +fail: + ctx->trace_enable = trace; + return err; +} + +static int cbs_av1_ref_tile_data(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + GetBitContext *gbc, + AV1RawTileData *td) { + int pos; + + pos = get_bits_count(gbc); + if(pos >= 8 * unit->data_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Bitstream ended before " + "any data in tile group (%d bits read).\n", + pos); + return AVERROR_INVALIDDATA; + } + // Must be byte-aligned at this point. + av_assert0(pos % 8 == 0); + + td->data_ref = av_buffer_ref(unit->data_ref); + if(!td->data_ref) + return AVERROR(ENOMEM); + + td->data = unit->data + pos / 8; + td->data_size = unit->data_size - pos / 8; + + return 0; +} + +static int cbs_av1_read_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + AV1RawOBU *obu; + GetBitContext gbc; + int err, start_pos, end_pos; + + err = ff_cbs_alloc_unit_content2(ctx, unit); + if(err < 0) + return err; + obu = unit->content; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if(err < 0) + return err; + + err = cbs_av1_read_obu_header(ctx, &gbc, &obu->header); + if(err < 0) + return err; + av_assert0(obu->header.obu_type == unit->type); + + if(obu->header.obu_has_size_field) { + uint64_t obu_size; + err = cbs_av1_read_leb128(ctx, &gbc, "obu_size", &obu_size); + if(err < 0) + return err; + obu->obu_size = obu_size; + } + else { + if(unit->data_size < 1 + obu->header.obu_extension_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid OBU length: " + "unit too short (%zu).\n", + unit->data_size); + return AVERROR_INVALIDDATA; + } + obu->obu_size = unit->data_size - 1 - obu->header.obu_extension_flag; + } + + start_pos = get_bits_count(&gbc); + + if(obu->header.obu_extension_flag) { + if(obu->header.obu_type != AV1_OBU_SEQUENCE_HEADER && + obu->header.obu_type != AV1_OBU_TEMPORAL_DELIMITER && + priv->operating_point_idc) { + int in_temporal_layer = + (priv->operating_point_idc >> priv->temporal_id) & 1; + int in_spatial_layer = + (priv->operating_point_idc >> (priv->spatial_id + 8)) & 1; + if(!in_temporal_layer || !in_spatial_layer) { + return AVERROR(EAGAIN); // drop_obu() + } + } + } + + switch(obu->header.obu_type) { + case AV1_OBU_SEQUENCE_HEADER: { + err = cbs_av1_read_sequence_header_obu(ctx, &gbc, + &obu->obu.sequence_header); + if(err < 0) + return err; + + if(priv->operating_point >= 0) { + AV1RawSequenceHeader *sequence_header = &obu->obu.sequence_header; + + if(priv->operating_point > sequence_header->operating_points_cnt_minus_1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid Operating Point %d requested. " + "Must not be higher than %u.\n", + priv->operating_point, sequence_header->operating_points_cnt_minus_1); + return AVERROR(EINVAL); + } + priv->operating_point_idc = sequence_header->operating_point_idc[priv->operating_point]; + } + + av_buffer_unref(&priv->sequence_header_ref); + priv->sequence_header = NULL; + + priv->sequence_header_ref = av_buffer_ref(unit->content_ref); + if(!priv->sequence_header_ref) + return AVERROR(ENOMEM); + priv->sequence_header = &obu->obu.sequence_header; + } break; + case AV1_OBU_TEMPORAL_DELIMITER: { + err = cbs_av1_read_temporal_delimiter_obu(ctx, &gbc); + if(err < 0) + return err; + } break; + case AV1_OBU_FRAME_HEADER: + case AV1_OBU_REDUNDANT_FRAME_HEADER: { + err = cbs_av1_read_frame_header_obu(ctx, &gbc, + &obu->obu.frame_header, + obu->header.obu_type == + AV1_OBU_REDUNDANT_FRAME_HEADER, + unit->data_ref); + if(err < 0) + return err; + } break; + case AV1_OBU_TILE_GROUP: { + err = cbs_av1_read_tile_group_obu(ctx, &gbc, + &obu->obu.tile_group); + if(err < 0) + return err; + + err = cbs_av1_ref_tile_data(ctx, unit, &gbc, + &obu->obu.tile_group.tile_data); + if(err < 0) + return err; + } break; + case AV1_OBU_FRAME: { + err = cbs_av1_read_frame_obu(ctx, &gbc, &obu->obu.frame, + unit->data_ref); + if(err < 0) + return err; + + err = cbs_av1_ref_tile_data(ctx, unit, &gbc, + &obu->obu.frame.tile_group.tile_data); + if(err < 0) + return err; + } break; + case AV1_OBU_TILE_LIST: { + err = cbs_av1_read_tile_list_obu(ctx, &gbc, + &obu->obu.tile_list); + if(err < 0) + return err; + + err = cbs_av1_ref_tile_data(ctx, unit, &gbc, + &obu->obu.tile_list.tile_data); + if(err < 0) + return err; + } break; + case AV1_OBU_METADATA: { + err = cbs_av1_read_metadata_obu(ctx, &gbc, &obu->obu.metadata); + if(err < 0) + return err; + } break; + case AV1_OBU_PADDING: { + err = cbs_av1_read_padding_obu(ctx, &gbc, &obu->obu.padding); + if(err < 0) + return err; + } break; + default: + return AVERROR(ENOSYS); + } + + end_pos = get_bits_count(&gbc); + av_assert0(end_pos <= unit->data_size * 8); + + if(obu->obu_size > 0 && + obu->header.obu_type != AV1_OBU_TILE_GROUP && + obu->header.obu_type != AV1_OBU_TILE_LIST && + obu->header.obu_type != AV1_OBU_FRAME) { + int nb_bits = obu->obu_size * 8 + start_pos - end_pos; + + if(nb_bits <= 0) + return AVERROR_INVALIDDATA; + + err = cbs_av1_read_trailing_bits(ctx, &gbc, nb_bits); + if(err < 0) + return err; + } + + return 0; +} + +static int cbs_av1_write_obu(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + AV1RawOBU *obu = unit->content; + PutBitContext pbc_tmp; + AV1RawTileData *td; + size_t header_size; + int err, start_pos, end_pos, data_pos; + + // OBUs in the normal bitstream format must contain a size field + // in every OBU (in annex B it is optional, but we don't support + // writing that). + obu->header.obu_has_size_field = 1; + + err = cbs_av1_write_obu_header(ctx, pbc, &obu->header); + if(err < 0) + return err; + + if(obu->header.obu_has_size_field) { + pbc_tmp = *pbc; + // Add space for the size field to fill later. + put_bits32(pbc, 0); + put_bits32(pbc, 0); + } + + td = NULL; + start_pos = put_bits_count(pbc); + + switch(obu->header.obu_type) { + case AV1_OBU_SEQUENCE_HEADER: { + err = cbs_av1_write_sequence_header_obu(ctx, pbc, + &obu->obu.sequence_header); + if(err < 0) + return err; + + av_buffer_unref(&priv->sequence_header_ref); + priv->sequence_header = NULL; + + err = ff_cbs_make_unit_refcounted(ctx, unit); + if(err < 0) + return err; + + priv->sequence_header_ref = av_buffer_ref(unit->content_ref); + if(!priv->sequence_header_ref) + return AVERROR(ENOMEM); + priv->sequence_header = &obu->obu.sequence_header; + } break; + case AV1_OBU_TEMPORAL_DELIMITER: { + err = cbs_av1_write_temporal_delimiter_obu(ctx, pbc); + if(err < 0) + return err; + } break; + case AV1_OBU_FRAME_HEADER: + case AV1_OBU_REDUNDANT_FRAME_HEADER: { + err = cbs_av1_write_frame_header_obu(ctx, pbc, + &obu->obu.frame_header, + obu->header.obu_type == + AV1_OBU_REDUNDANT_FRAME_HEADER, + NULL); + if(err < 0) + return err; + } break; + case AV1_OBU_TILE_GROUP: { + err = cbs_av1_write_tile_group_obu(ctx, pbc, + &obu->obu.tile_group); + if(err < 0) + return err; + + td = &obu->obu.tile_group.tile_data; + } break; + case AV1_OBU_FRAME: { + err = cbs_av1_write_frame_obu(ctx, pbc, &obu->obu.frame, NULL); + if(err < 0) + return err; + + td = &obu->obu.frame.tile_group.tile_data; + } break; + case AV1_OBU_TILE_LIST: { + err = cbs_av1_write_tile_list_obu(ctx, pbc, &obu->obu.tile_list); + if(err < 0) + return err; + + td = &obu->obu.tile_list.tile_data; + } break; + case AV1_OBU_METADATA: { + err = cbs_av1_write_metadata_obu(ctx, pbc, &obu->obu.metadata); + if(err < 0) + return err; + } break; + case AV1_OBU_PADDING: { + err = cbs_av1_write_padding_obu(ctx, pbc, &obu->obu.padding); + if(err < 0) + return err; + } break; + default: + return AVERROR(ENOSYS); + } + + end_pos = put_bits_count(pbc); + header_size = (end_pos - start_pos + 7) / 8; + if(td) { + obu->obu_size = header_size + td->data_size; + } + else if(header_size > 0) { + // Add trailing bits and recalculate. + err = cbs_av1_write_trailing_bits(ctx, pbc, 8 - end_pos % 8); + if(err < 0) + return err; + end_pos = put_bits_count(pbc); + obu->obu_size = header_size = (end_pos - start_pos + 7) / 8; + } + else { + // Empty OBU. + obu->obu_size = 0; + } + + end_pos = put_bits_count(pbc); + // Must now be byte-aligned. + av_assert0(end_pos % 8 == 0); + flush_put_bits(pbc); + start_pos /= 8; + end_pos /= 8; + + *pbc = pbc_tmp; + err = cbs_av1_write_leb128(ctx, pbc, "obu_size", obu->obu_size); + if(err < 0) + return err; + + data_pos = put_bits_count(pbc) / 8; + flush_put_bits(pbc); + av_assert0(data_pos <= start_pos); + + if(8 * obu->obu_size > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + if(obu->obu_size > 0) { + memmove(pbc->buf + data_pos, + pbc->buf + start_pos, header_size); + skip_put_bytes(pbc, header_size); + + if(td) { + memcpy(pbc->buf + data_pos + header_size, + td->data, td->data_size); + skip_put_bytes(pbc, td->data_size); + } + } + + // OBU data must be byte-aligned. + av_assert0(put_bits_count(pbc) % 8 == 0); + + return 0; +} + +static int cbs_av1_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) { + size_t size, pos; + int i; + + size = 0; + for(i = 0; i < frag->nb_units; i++) + size += frag->units[i].data_size; + + frag->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if(!frag->data_ref) + return AVERROR(ENOMEM); + frag->data = frag->data_ref->data; + memset(frag->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + pos = 0; + for(i = 0; i < frag->nb_units; i++) { + memcpy(frag->data + pos, frag->units[i].data, + frag->units[i].data_size); + pos += frag->units[i].data_size; + } + av_assert0(pos == size); + frag->data_size = size; + + return 0; +} + +static void cbs_av1_flush(CodedBitstreamContext *ctx) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + + av_buffer_unref(&priv->frame_header_ref); + priv->sequence_header = NULL; + priv->frame_header = NULL; + + memset(priv->ref, 0, sizeof(priv->ref)); + priv->operating_point_idc = 0; + priv->seen_frame_header = 0; + priv->tile_num = 0; +} + +static void cbs_av1_close(CodedBitstreamContext *ctx) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + + av_buffer_unref(&priv->sequence_header_ref); + av_buffer_unref(&priv->frame_header_ref); +} + +static void cbs_av1_free_metadata(void *unit, uint8_t *content) { + AV1RawOBU *obu = (AV1RawOBU *)content; + AV1RawMetadata *md; + + av_assert0(obu->header.obu_type == AV1_OBU_METADATA); + md = &obu->obu.metadata; + + switch(md->metadata_type) { + case AV1_METADATA_TYPE_ITUT_T35: + av_buffer_unref(&md->metadata.itut_t35.payload_ref); + break; + } + av_free(content); +} + +static const CodedBitstreamUnitTypeDescriptor cbs_av1_unit_types[] = { + CBS_UNIT_TYPE_POD(AV1_OBU_SEQUENCE_HEADER, AV1RawOBU), + CBS_UNIT_TYPE_POD(AV1_OBU_TEMPORAL_DELIMITER, AV1RawOBU), + CBS_UNIT_TYPE_POD(AV1_OBU_FRAME_HEADER, AV1RawOBU), + CBS_UNIT_TYPE_POD(AV1_OBU_REDUNDANT_FRAME_HEADER, AV1RawOBU), + + CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_TILE_GROUP, AV1RawOBU, + obu.tile_group.tile_data.data), + CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_FRAME, AV1RawOBU, + obu.frame.tile_group.tile_data.data), + CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_TILE_LIST, AV1RawOBU, + obu.tile_list.tile_data.data), + CBS_UNIT_TYPE_INTERNAL_REF(AV1_OBU_PADDING, AV1RawOBU, + obu.padding.payload), + + CBS_UNIT_TYPE_COMPLEX(AV1_OBU_METADATA, AV1RawOBU, + &cbs_av1_free_metadata), + + CBS_UNIT_TYPE_END_OF_LIST +}; + +#define OFFSET(x) offsetof(CodedBitstreamAV1Context, x) +static const AVOption cbs_av1_options[] = { + { "operating_point", "Set operating point to select layers to parse from a scalable bitstream", + OFFSET(operating_point), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AV1_MAX_OPERATING_POINTS - 1, 0 }, + { NULL } +}; + +static const AVClass cbs_av1_class = { + .class_name = "cbs_av1", + .item_name = av_default_item_name, + .option = cbs_av1_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const CodedBitstreamType ff_cbs_type_av1 = { + .codec_id = AV_CODEC_ID_AV1, + + .priv_class = &cbs_av1_class, + .priv_data_size = sizeof(CodedBitstreamAV1Context), + + .unit_types = cbs_av1_unit_types, + + .split_fragment = &cbs_av1_split_fragment, + .read_unit = &cbs_av1_read_unit, + .write_unit = &cbs_av1_write_obu, + .assemble_fragment = &cbs_av1_assemble_fragment, + + .flush = &cbs_av1_flush, + .close = &cbs_av1_close, +}; diff --git a/third-party/cbs/cbs_av1_syntax_template.c b/third-party/cbs/cbs_av1_syntax_template.c new file mode 100644 index 00000000..1768a6d2 --- /dev/null +++ b/third-party/cbs/cbs_av1_syntax_template.c @@ -0,0 +1,2063 @@ +/* + * 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(obu_header)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawOBUHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + int err; + + HEADER("OBU header"); + + fc(1, obu_forbidden_bit, 0, 0); + + fc(4, obu_type, 0, AV1_OBU_PADDING); + flag(obu_extension_flag); + flag(obu_has_size_field); + + fc(1, obu_reserved_1bit, 0, 0); + + if(current->obu_extension_flag) { + fb(3, temporal_id); + fb(2, spatial_id); + fc(3, extension_header_reserved_3bits, 0, 0); + } + else { + infer(temporal_id, 0); + infer(spatial_id, 0); + } + + priv->temporal_id = current->temporal_id; + priv->spatial_id = current->spatial_id; + + return 0; +} + +static int FUNC(trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw, int nb_bits) { + int err; + + av_assert0(nb_bits > 0); + + fixed(1, trailing_one_bit, 1); + --nb_bits; + + while(nb_bits > 0) { + fixed(1, trailing_zero_bit, 0); + --nb_bits; + } + + return 0; +} + +static int FUNC(byte_alignment)(CodedBitstreamContext *ctx, RWContext *rw) { + int err; + + while(byte_alignment(rw) != 0) + fixed(1, zero_bit, 0); + + return 0; +} + +static int FUNC(color_config)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawColorConfig *current, int seq_profile) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + int err; + + flag(high_bitdepth); + + if(seq_profile == FF_PROFILE_AV1_PROFESSIONAL && + current->high_bitdepth) { + flag(twelve_bit); + priv->bit_depth = current->twelve_bit ? 12 : 10; + } + else { + priv->bit_depth = current->high_bitdepth ? 10 : 8; + } + + if(seq_profile == FF_PROFILE_AV1_HIGH) + infer(mono_chrome, 0); + else + flag(mono_chrome); + priv->num_planes = current->mono_chrome ? 1 : 3; + + flag(color_description_present_flag); + if(current->color_description_present_flag) { + fb(8, color_primaries); + fb(8, transfer_characteristics); + fb(8, matrix_coefficients); + } + else { + infer(color_primaries, AVCOL_PRI_UNSPECIFIED); + infer(transfer_characteristics, AVCOL_TRC_UNSPECIFIED); + infer(matrix_coefficients, AVCOL_SPC_UNSPECIFIED); + } + + if(current->mono_chrome) { + flag(color_range); + + infer(subsampling_x, 1); + infer(subsampling_y, 1); + infer(chroma_sample_position, AV1_CSP_UNKNOWN); + infer(separate_uv_delta_q, 0); + } + else if(current->color_primaries == AVCOL_PRI_BT709 && + current->transfer_characteristics == AVCOL_TRC_IEC61966_2_1 && + current->matrix_coefficients == AVCOL_SPC_RGB) { + infer(color_range, 1); + infer(subsampling_x, 0); + infer(subsampling_y, 0); + flag(separate_uv_delta_q); + } + else { + flag(color_range); + + if(seq_profile == FF_PROFILE_AV1_MAIN) { + infer(subsampling_x, 1); + infer(subsampling_y, 1); + } + else if(seq_profile == FF_PROFILE_AV1_HIGH) { + infer(subsampling_x, 0); + infer(subsampling_y, 0); + } + else { + if(priv->bit_depth == 12) { + fb(1, subsampling_x); + if(current->subsampling_x) + fb(1, subsampling_y); + else + infer(subsampling_y, 0); + } + else { + infer(subsampling_x, 1); + infer(subsampling_y, 0); + } + } + if(current->subsampling_x && current->subsampling_y) { + fc(2, chroma_sample_position, AV1_CSP_UNKNOWN, + AV1_CSP_COLOCATED); + } + + flag(separate_uv_delta_q); + } + + return 0; +} + +static int FUNC(timing_info)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawTimingInfo *current) { + int err; + + fc(32, num_units_in_display_tick, 1, MAX_UINT_BITS(32)); + fc(32, time_scale, 1, MAX_UINT_BITS(32)); + + flag(equal_picture_interval); + if(current->equal_picture_interval) + uvlc(num_ticks_per_picture_minus_1, 0, MAX_UINT_BITS(32) - 1); + + return 0; +} + +static int FUNC(decoder_model_info)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawDecoderModelInfo *current) { + int err; + + fb(5, buffer_delay_length_minus_1); + fb(32, num_units_in_decoding_tick); + fb(5, buffer_removal_time_length_minus_1); + fb(5, frame_presentation_time_length_minus_1); + + return 0; +} + +static int FUNC(sequence_header_obu)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawSequenceHeader *current) { + int i, err; + + HEADER("Sequence Header"); + + fc(3, seq_profile, FF_PROFILE_AV1_MAIN, + FF_PROFILE_AV1_PROFESSIONAL); + flag(still_picture); + flag(reduced_still_picture_header); + + if(current->reduced_still_picture_header) { + infer(timing_info_present_flag, 0); + infer(decoder_model_info_present_flag, 0); + infer(initial_display_delay_present_flag, 0); + infer(operating_points_cnt_minus_1, 0); + infer(operating_point_idc[0], 0); + + fb(5, seq_level_idx[0]); + + infer(seq_tier[0], 0); + infer(decoder_model_present_for_this_op[0], 0); + infer(initial_display_delay_present_for_this_op[0], 0); + } + else { + flag(timing_info_present_flag); + if(current->timing_info_present_flag) { + CHECK(FUNC(timing_info)(ctx, rw, ¤t->timing_info)); + + flag(decoder_model_info_present_flag); + if(current->decoder_model_info_present_flag) { + CHECK(FUNC(decoder_model_info)(ctx, rw, ¤t->decoder_model_info)); + } + } + else { + infer(decoder_model_info_present_flag, 0); + } + + flag(initial_display_delay_present_flag); + + fb(5, operating_points_cnt_minus_1); + for(i = 0; i <= current->operating_points_cnt_minus_1; i++) { + fbs(12, operating_point_idc[i], 1, i); + fbs(5, seq_level_idx[i], 1, i); + + if(current->seq_level_idx[i] > 7) + flags(seq_tier[i], 1, i); + else + infer(seq_tier[i], 0); + + if(current->decoder_model_info_present_flag) { + flags(decoder_model_present_for_this_op[i], 1, i); + if(current->decoder_model_present_for_this_op[i]) { + int n = current->decoder_model_info.buffer_delay_length_minus_1 + 1; + fbs(n, decoder_buffer_delay[i], 1, i); + fbs(n, encoder_buffer_delay[i], 1, i); + flags(low_delay_mode_flag[i], 1, i); + } + } + else { + infer(decoder_model_present_for_this_op[i], 0); + } + + if(current->initial_display_delay_present_flag) { + flags(initial_display_delay_present_for_this_op[i], 1, i); + if(current->initial_display_delay_present_for_this_op[i]) + fbs(4, initial_display_delay_minus_1[i], 1, i); + } + } + } + + fb(4, frame_width_bits_minus_1); + fb(4, frame_height_bits_minus_1); + + fb(current->frame_width_bits_minus_1 + 1, max_frame_width_minus_1); + fb(current->frame_height_bits_minus_1 + 1, max_frame_height_minus_1); + + if(current->reduced_still_picture_header) + infer(frame_id_numbers_present_flag, 0); + else + flag(frame_id_numbers_present_flag); + if(current->frame_id_numbers_present_flag) { + fb(4, delta_frame_id_length_minus_2); + fb(3, additional_frame_id_length_minus_1); + } + + flag(use_128x128_superblock); + flag(enable_filter_intra); + flag(enable_intra_edge_filter); + + if(current->reduced_still_picture_header) { + infer(enable_interintra_compound, 0); + infer(enable_masked_compound, 0); + infer(enable_warped_motion, 0); + infer(enable_dual_filter, 0); + infer(enable_order_hint, 0); + infer(enable_jnt_comp, 0); + infer(enable_ref_frame_mvs, 0); + + infer(seq_force_screen_content_tools, + AV1_SELECT_SCREEN_CONTENT_TOOLS); + infer(seq_force_integer_mv, + AV1_SELECT_INTEGER_MV); + } + else { + flag(enable_interintra_compound); + flag(enable_masked_compound); + flag(enable_warped_motion); + flag(enable_dual_filter); + + flag(enable_order_hint); + if(current->enable_order_hint) { + flag(enable_jnt_comp); + flag(enable_ref_frame_mvs); + } + else { + infer(enable_jnt_comp, 0); + infer(enable_ref_frame_mvs, 0); + } + + flag(seq_choose_screen_content_tools); + if(current->seq_choose_screen_content_tools) + infer(seq_force_screen_content_tools, + AV1_SELECT_SCREEN_CONTENT_TOOLS); + else + fb(1, seq_force_screen_content_tools); + if(current->seq_force_screen_content_tools > 0) { + flag(seq_choose_integer_mv); + if(current->seq_choose_integer_mv) + infer(seq_force_integer_mv, + AV1_SELECT_INTEGER_MV); + else + fb(1, seq_force_integer_mv); + } + else { + infer(seq_force_integer_mv, AV1_SELECT_INTEGER_MV); + } + + if(current->enable_order_hint) + fb(3, order_hint_bits_minus_1); + } + + flag(enable_superres); + flag(enable_cdef); + flag(enable_restoration); + + CHECK(FUNC(color_config)(ctx, rw, ¤t->color_config, + current->seq_profile)); + + flag(film_grain_params_present); + + return 0; +} + +static int FUNC(temporal_delimiter_obu)(CodedBitstreamContext *ctx, RWContext *rw) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + + HEADER("Temporal Delimiter"); + + priv->seen_frame_header = 0; + + return 0; +} + +static int FUNC(set_frame_refs)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + static const uint8_t ref_frame_list[AV1_NUM_REF_FRAMES - 2] = { + AV1_REF_FRAME_LAST2, AV1_REF_FRAME_LAST3, AV1_REF_FRAME_BWDREF, + AV1_REF_FRAME_ALTREF2, AV1_REF_FRAME_ALTREF + }; + int8_t ref_frame_idx[AV1_REFS_PER_FRAME], used_frame[AV1_NUM_REF_FRAMES]; + int8_t shifted_order_hints[AV1_NUM_REF_FRAMES]; + int cur_frame_hint, latest_order_hint, earliest_order_hint, ref; + int i, j; + + for(i = 0; i < AV1_REFS_PER_FRAME; i++) + ref_frame_idx[i] = -1; + ref_frame_idx[AV1_REF_FRAME_LAST - AV1_REF_FRAME_LAST] = current->last_frame_idx; + ref_frame_idx[AV1_REF_FRAME_GOLDEN - AV1_REF_FRAME_LAST] = current->golden_frame_idx; + + for(i = 0; i < AV1_NUM_REF_FRAMES; i++) + used_frame[i] = 0; + used_frame[current->last_frame_idx] = 1; + used_frame[current->golden_frame_idx] = 1; + + cur_frame_hint = 1 << (seq->order_hint_bits_minus_1); + for(i = 0; i < AV1_NUM_REF_FRAMES; i++) + shifted_order_hints[i] = cur_frame_hint + + cbs_av1_get_relative_dist(seq, priv->ref[i].order_hint, + priv->order_hint); + + latest_order_hint = shifted_order_hints[current->last_frame_idx]; + earliest_order_hint = shifted_order_hints[current->golden_frame_idx]; + + ref = -1; + for(i = 0; i < AV1_NUM_REF_FRAMES; i++) { + int hint = shifted_order_hints[i]; + if(!used_frame[i] && hint >= cur_frame_hint && + (ref < 0 || hint >= latest_order_hint)) { + ref = i; + latest_order_hint = hint; + } + } + if(ref >= 0) { + ref_frame_idx[AV1_REF_FRAME_ALTREF - AV1_REF_FRAME_LAST] = ref; + used_frame[ref] = 1; + } + + ref = -1; + for(i = 0; i < AV1_NUM_REF_FRAMES; i++) { + int hint = shifted_order_hints[i]; + if(!used_frame[i] && hint >= cur_frame_hint && + (ref < 0 || hint < earliest_order_hint)) { + ref = i; + earliest_order_hint = hint; + } + } + if(ref >= 0) { + ref_frame_idx[AV1_REF_FRAME_BWDREF - AV1_REF_FRAME_LAST] = ref; + used_frame[ref] = 1; + } + + ref = -1; + for(i = 0; i < AV1_NUM_REF_FRAMES; i++) { + int hint = shifted_order_hints[i]; + if(!used_frame[i] && hint >= cur_frame_hint && + (ref < 0 || hint < earliest_order_hint)) { + ref = i; + earliest_order_hint = hint; + } + } + if(ref >= 0) { + ref_frame_idx[AV1_REF_FRAME_ALTREF2 - AV1_REF_FRAME_LAST] = ref; + used_frame[ref] = 1; + } + + for(i = 0; i < AV1_REFS_PER_FRAME - 2; i++) { + int ref_frame = ref_frame_list[i]; + if(ref_frame_idx[ref_frame - AV1_REF_FRAME_LAST] < 0) { + ref = -1; + for(j = 0; j < AV1_NUM_REF_FRAMES; j++) { + int hint = shifted_order_hints[j]; + if(!used_frame[j] && hint < cur_frame_hint && + (ref < 0 || hint >= latest_order_hint)) { + ref = j; + latest_order_hint = hint; + } + } + if(ref >= 0) { + ref_frame_idx[ref_frame - AV1_REF_FRAME_LAST] = ref; + used_frame[ref] = 1; + } + } + } + + ref = -1; + for(i = 0; i < AV1_NUM_REF_FRAMES; i++) { + int hint = shifted_order_hints[i]; + if(ref < 0 || hint < earliest_order_hint) { + ref = i; + earliest_order_hint = hint; + } + } + for(i = 0; i < AV1_REFS_PER_FRAME; i++) { + if(ref_frame_idx[i] < 0) + ref_frame_idx[i] = ref; + infer(ref_frame_idx[i], ref_frame_idx[i]); + } + + return 0; +} + +static int FUNC(superres_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int denom, err; + + if(seq->enable_superres) + flag(use_superres); + else + infer(use_superres, 0); + + if(current->use_superres) { + fb(3, coded_denom); + denom = current->coded_denom + AV1_SUPERRES_DENOM_MIN; + } + else { + denom = AV1_SUPERRES_NUM; + } + + priv->upscaled_width = priv->frame_width; + priv->frame_width = (priv->upscaled_width * AV1_SUPERRES_NUM + + denom / 2) / + denom; + + return 0; +} + +static int FUNC(frame_size)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int err; + + if(current->frame_size_override_flag) { + fb(seq->frame_width_bits_minus_1 + 1, frame_width_minus_1); + fb(seq->frame_height_bits_minus_1 + 1, frame_height_minus_1); + } + else { + infer(frame_width_minus_1, seq->max_frame_width_minus_1); + infer(frame_height_minus_1, seq->max_frame_height_minus_1); + } + + priv->frame_width = current->frame_width_minus_1 + 1; + priv->frame_height = current->frame_height_minus_1 + 1; + + CHECK(FUNC(superres_params)(ctx, rw, current)); + + return 0; +} + +static int FUNC(render_size)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + int err; + + flag(render_and_frame_size_different); + + if(current->render_and_frame_size_different) { + fb(16, render_width_minus_1); + fb(16, render_height_minus_1); + } + else { + infer(render_width_minus_1, current->frame_width_minus_1); + infer(render_height_minus_1, current->frame_height_minus_1); + } + + priv->render_width = current->render_width_minus_1 + 1; + priv->render_height = current->render_height_minus_1 + 1; + + return 0; +} + +static int FUNC(frame_size_with_refs)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + int i, err; + + for(i = 0; i < AV1_REFS_PER_FRAME; i++) { + flags(found_ref[i], 1, i); + if(current->found_ref[i]) { + AV1ReferenceFrameState *ref = + &priv->ref[current->ref_frame_idx[i]]; + + if(!ref->valid) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Missing reference frame needed for frame size " + "(ref = %d, ref_frame_idx = %d).\n", + i, current->ref_frame_idx[i]); + return AVERROR_INVALIDDATA; + } + + infer(frame_width_minus_1, ref->upscaled_width - 1); + infer(frame_height_minus_1, ref->frame_height - 1); + infer(render_width_minus_1, ref->render_width - 1); + infer(render_height_minus_1, ref->render_height - 1); + + priv->upscaled_width = ref->upscaled_width; + priv->frame_width = priv->upscaled_width; + priv->frame_height = ref->frame_height; + priv->render_width = ref->render_width; + priv->render_height = ref->render_height; + break; + } + } + + if(i >= AV1_REFS_PER_FRAME) { + CHECK(FUNC(frame_size)(ctx, rw, current)); + CHECK(FUNC(render_size)(ctx, rw, current)); + } + else { + CHECK(FUNC(superres_params)(ctx, rw, current)); + } + + return 0; +} + +static int FUNC(interpolation_filter)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + int err; + + flag(is_filter_switchable); + if(current->is_filter_switchable) + infer(interpolation_filter, + AV1_INTERPOLATION_FILTER_SWITCHABLE); + else + fb(2, interpolation_filter); + + return 0; +} + +static int FUNC(tile_info)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int mi_cols, mi_rows, sb_cols, sb_rows, sb_shift, sb_size; + int max_tile_width_sb, max_tile_height_sb, max_tile_area_sb; + int min_log2_tile_cols, max_log2_tile_cols, max_log2_tile_rows; + int min_log2_tiles, min_log2_tile_rows; + int i, err; + + mi_cols = 2 * ((priv->frame_width + 7) >> 3); + mi_rows = 2 * ((priv->frame_height + 7) >> 3); + + sb_cols = seq->use_128x128_superblock ? ((mi_cols + 31) >> 5) : ((mi_cols + 15) >> 4); + sb_rows = seq->use_128x128_superblock ? ((mi_rows + 31) >> 5) : ((mi_rows + 15) >> 4); + + sb_shift = seq->use_128x128_superblock ? 5 : 4; + sb_size = sb_shift + 2; + + max_tile_width_sb = AV1_MAX_TILE_WIDTH >> sb_size; + max_tile_area_sb = AV1_MAX_TILE_AREA >> (2 * sb_size); + + min_log2_tile_cols = cbs_av1_tile_log2(max_tile_width_sb, sb_cols); + max_log2_tile_cols = cbs_av1_tile_log2(1, FFMIN(sb_cols, AV1_MAX_TILE_COLS)); + max_log2_tile_rows = cbs_av1_tile_log2(1, FFMIN(sb_rows, AV1_MAX_TILE_ROWS)); + min_log2_tiles = FFMAX(min_log2_tile_cols, + cbs_av1_tile_log2(max_tile_area_sb, sb_rows * sb_cols)); + + flag(uniform_tile_spacing_flag); + + if(current->uniform_tile_spacing_flag) { + int tile_width_sb, tile_height_sb; + + increment(tile_cols_log2, min_log2_tile_cols, max_log2_tile_cols); + + tile_width_sb = (sb_cols + (1 << current->tile_cols_log2) - 1) >> + current->tile_cols_log2; + current->tile_cols = (sb_cols + tile_width_sb - 1) / tile_width_sb; + + min_log2_tile_rows = FFMAX(min_log2_tiles - current->tile_cols_log2, 0); + + increment(tile_rows_log2, min_log2_tile_rows, max_log2_tile_rows); + + tile_height_sb = (sb_rows + (1 << current->tile_rows_log2) - 1) >> + current->tile_rows_log2; + current->tile_rows = (sb_rows + tile_height_sb - 1) / tile_height_sb; + + for(i = 0; i < current->tile_cols - 1; i++) + infer(width_in_sbs_minus_1[i], tile_width_sb - 1); + infer(width_in_sbs_minus_1[i], + sb_cols - (current->tile_cols - 1) * tile_width_sb - 1); + for(i = 0; i < current->tile_rows - 1; i++) + infer(height_in_sbs_minus_1[i], tile_height_sb - 1); + infer(height_in_sbs_minus_1[i], + sb_rows - (current->tile_rows - 1) * tile_height_sb - 1); + } + else { + int widest_tile_sb, start_sb, size_sb, max_width, max_height; + + widest_tile_sb = 0; + + start_sb = 0; + for(i = 0; start_sb < sb_cols && i < AV1_MAX_TILE_COLS; i++) { + max_width = FFMIN(sb_cols - start_sb, max_tile_width_sb); + ns(max_width, width_in_sbs_minus_1[i], 1, i); + size_sb = current->width_in_sbs_minus_1[i] + 1; + widest_tile_sb = FFMAX(size_sb, widest_tile_sb); + start_sb += size_sb; + } + current->tile_cols_log2 = cbs_av1_tile_log2(1, i); + current->tile_cols = i; + + if(min_log2_tiles > 0) + max_tile_area_sb = (sb_rows * sb_cols) >> (min_log2_tiles + 1); + else + max_tile_area_sb = sb_rows * sb_cols; + max_tile_height_sb = FFMAX(max_tile_area_sb / widest_tile_sb, 1); + + start_sb = 0; + for(i = 0; start_sb < sb_rows && i < AV1_MAX_TILE_ROWS; i++) { + max_height = FFMIN(sb_rows - start_sb, max_tile_height_sb); + ns(max_height, height_in_sbs_minus_1[i], 1, i); + size_sb = current->height_in_sbs_minus_1[i] + 1; + start_sb += size_sb; + } + current->tile_rows_log2 = cbs_av1_tile_log2(1, i); + current->tile_rows = i; + } + + if(current->tile_cols_log2 > 0 || + current->tile_rows_log2 > 0) { + fb(current->tile_cols_log2 + current->tile_rows_log2, + context_update_tile_id); + fb(2, tile_size_bytes_minus1); + } + else { + infer(context_update_tile_id, 0); + } + + priv->tile_cols = current->tile_cols; + priv->tile_rows = current->tile_rows; + + return 0; +} + +static int FUNC(quantization_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int err; + + fb(8, base_q_idx); + + delta_q(delta_q_y_dc); + + if(priv->num_planes > 1) { + if(seq->color_config.separate_uv_delta_q) + flag(diff_uv_delta); + else + infer(diff_uv_delta, 0); + + delta_q(delta_q_u_dc); + delta_q(delta_q_u_ac); + + if(current->diff_uv_delta) { + delta_q(delta_q_v_dc); + delta_q(delta_q_v_ac); + } + else { + infer(delta_q_v_dc, current->delta_q_u_dc); + infer(delta_q_v_ac, current->delta_q_u_ac); + } + } + else { + infer(delta_q_u_dc, 0); + infer(delta_q_u_ac, 0); + infer(delta_q_v_dc, 0); + infer(delta_q_v_ac, 0); + } + + flag(using_qmatrix); + if(current->using_qmatrix) { + fb(4, qm_y); + fb(4, qm_u); + if(seq->color_config.separate_uv_delta_q) + fb(4, qm_v); + else + infer(qm_v, current->qm_u); + } + + return 0; +} + +static int FUNC(segmentation_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + static const uint8_t bits[AV1_SEG_LVL_MAX] = { 8, 6, 6, 6, 6, 3, 0, 0 }; + static const uint8_t sign[AV1_SEG_LVL_MAX] = { 1, 1, 1, 1, 1, 0, 0, 0 }; + static const uint8_t default_feature_enabled[AV1_SEG_LVL_MAX] = { 0 }; + static const int16_t default_feature_value[AV1_SEG_LVL_MAX] = { 0 }; + int i, j, err; + + flag(segmentation_enabled); + + if(current->segmentation_enabled) { + if(current->primary_ref_frame == AV1_PRIMARY_REF_NONE) { + infer(segmentation_update_map, 1); + infer(segmentation_temporal_update, 0); + infer(segmentation_update_data, 1); + } + else { + flag(segmentation_update_map); + if(current->segmentation_update_map) + flag(segmentation_temporal_update); + else + infer(segmentation_temporal_update, 0); + flag(segmentation_update_data); + } + + for(i = 0; i < AV1_MAX_SEGMENTS; i++) { + const uint8_t *ref_feature_enabled; + const int16_t *ref_feature_value; + + if(current->primary_ref_frame == AV1_PRIMARY_REF_NONE) { + ref_feature_enabled = default_feature_enabled; + ref_feature_value = default_feature_value; + } + else { + ref_feature_enabled = + priv->ref[current->ref_frame_idx[current->primary_ref_frame]].feature_enabled[i]; + ref_feature_value = + priv->ref[current->ref_frame_idx[current->primary_ref_frame]].feature_value[i]; + } + + for(j = 0; j < AV1_SEG_LVL_MAX; j++) { + if(current->segmentation_update_data) { + flags(feature_enabled[i][j], 2, i, j); + + if(current->feature_enabled[i][j] && bits[j] > 0) { + if(sign[j]) + sus(1 + bits[j], feature_value[i][j], 2, i, j); + else + fbs(bits[j], feature_value[i][j], 2, i, j); + } + else { + infer(feature_value[i][j], 0); + } + } + else { + infer(feature_enabled[i][j], ref_feature_enabled[j]); + infer(feature_value[i][j], ref_feature_value[j]); + } + } + } + } + else { + for(i = 0; i < AV1_MAX_SEGMENTS; i++) { + for(j = 0; j < AV1_SEG_LVL_MAX; j++) { + infer(feature_enabled[i][j], 0); + infer(feature_value[i][j], 0); + } + } + } + + return 0; +} + +static int FUNC(delta_q_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + int err; + + if(current->base_q_idx > 0) + flag(delta_q_present); + else + infer(delta_q_present, 0); + + if(current->delta_q_present) + fb(2, delta_q_res); + + return 0; +} + +static int FUNC(delta_lf_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + int err; + + if(current->delta_q_present) { + if(!current->allow_intrabc) + flag(delta_lf_present); + else + infer(delta_lf_present, 0); + if(current->delta_lf_present) { + fb(2, delta_lf_res); + flag(delta_lf_multi); + } + else { + infer(delta_lf_res, 0); + infer(delta_lf_multi, 0); + } + } + else { + infer(delta_lf_present, 0); + infer(delta_lf_res, 0); + infer(delta_lf_multi, 0); + } + + return 0; +} + +static int FUNC(loop_filter_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + static const int8_t default_loop_filter_ref_deltas[AV1_TOTAL_REFS_PER_FRAME] = { 1, 0, 0, 0, -1, 0, -1, -1 }; + static const int8_t default_loop_filter_mode_deltas[2] = { 0, 0 }; + int i, err; + + if(priv->coded_lossless || current->allow_intrabc) { + infer(loop_filter_level[0], 0); + infer(loop_filter_level[1], 0); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_INTRA], 1); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_LAST], 0); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_LAST2], 0); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_LAST3], 0); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_BWDREF], 0); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_GOLDEN], -1); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_ALTREF], -1); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_ALTREF2], -1); + for(i = 0; i < 2; i++) + infer(loop_filter_mode_deltas[i], 0); + return 0; + } + + fb(6, loop_filter_level[0]); + fb(6, loop_filter_level[1]); + + if(priv->num_planes > 1) { + if(current->loop_filter_level[0] || + current->loop_filter_level[1]) { + fb(6, loop_filter_level[2]); + fb(6, loop_filter_level[3]); + } + } + + fb(3, loop_filter_sharpness); + + flag(loop_filter_delta_enabled); + if(current->loop_filter_delta_enabled) { + const int8_t *ref_loop_filter_ref_deltas, *ref_loop_filter_mode_deltas; + + if(current->primary_ref_frame == AV1_PRIMARY_REF_NONE) { + ref_loop_filter_ref_deltas = default_loop_filter_ref_deltas; + ref_loop_filter_mode_deltas = default_loop_filter_mode_deltas; + } + else { + ref_loop_filter_ref_deltas = + priv->ref[current->ref_frame_idx[current->primary_ref_frame]].loop_filter_ref_deltas; + ref_loop_filter_mode_deltas = + priv->ref[current->ref_frame_idx[current->primary_ref_frame]].loop_filter_mode_deltas; + } + + flag(loop_filter_delta_update); + for(i = 0; i < AV1_TOTAL_REFS_PER_FRAME; i++) { + if(current->loop_filter_delta_update) + flags(update_ref_delta[i], 1, i); + else + infer(update_ref_delta[i], 0); + if(current->update_ref_delta[i]) + sus(1 + 6, loop_filter_ref_deltas[i], 1, i); + else + infer(loop_filter_ref_deltas[i], ref_loop_filter_ref_deltas[i]); + } + for(i = 0; i < 2; i++) { + if(current->loop_filter_delta_update) + flags(update_mode_delta[i], 1, i); + else + infer(update_mode_delta[i], 0); + if(current->update_mode_delta[i]) + sus(1 + 6, loop_filter_mode_deltas[i], 1, i); + else + infer(loop_filter_mode_deltas[i], ref_loop_filter_mode_deltas[i]); + } + } + else { + for(i = 0; i < AV1_TOTAL_REFS_PER_FRAME; i++) + infer(loop_filter_ref_deltas[i], default_loop_filter_ref_deltas[i]); + for(i = 0; i < 2; i++) + infer(loop_filter_mode_deltas[i], default_loop_filter_mode_deltas[i]); + } + + return 0; +} + +static int FUNC(cdef_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int i, err; + + if(priv->coded_lossless || current->allow_intrabc || + !seq->enable_cdef) { + infer(cdef_damping_minus_3, 0); + infer(cdef_bits, 0); + infer(cdef_y_pri_strength[0], 0); + infer(cdef_y_sec_strength[0], 0); + infer(cdef_uv_pri_strength[0], 0); + infer(cdef_uv_sec_strength[0], 0); + + return 0; + } + + fb(2, cdef_damping_minus_3); + fb(2, cdef_bits); + + for(i = 0; i < (1 << current->cdef_bits); i++) { + fbs(4, cdef_y_pri_strength[i], 1, i); + fbs(2, cdef_y_sec_strength[i], 1, i); + + if(priv->num_planes > 1) { + fbs(4, cdef_uv_pri_strength[i], 1, i); + fbs(2, cdef_uv_sec_strength[i], 1, i); + } + } + + return 0; +} + +static int FUNC(lr_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int uses_lr, uses_chroma_lr; + int i, err; + + if(priv->all_lossless || current->allow_intrabc || + !seq->enable_restoration) { + return 0; + } + + uses_lr = uses_chroma_lr = 0; + for(i = 0; i < priv->num_planes; i++) { + fbs(2, lr_type[i], 1, i); + + if(current->lr_type[i] != AV1_RESTORE_NONE) { + uses_lr = 1; + if(i > 0) + uses_chroma_lr = 1; + } + } + + if(uses_lr) { + if(seq->use_128x128_superblock) + increment(lr_unit_shift, 1, 2); + else + increment(lr_unit_shift, 0, 2); + + if(seq->color_config.subsampling_x && + seq->color_config.subsampling_y && uses_chroma_lr) { + fb(1, lr_uv_shift); + } + else { + infer(lr_uv_shift, 0); + } + } + + return 0; +} + +static int FUNC(read_tx_mode)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + int err; + + if(priv->coded_lossless) + infer(tx_mode, 0); + else + increment(tx_mode, 1, 2); + + return 0; +} + +static int FUNC(frame_reference_mode)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + int err; + + if(current->frame_type == AV1_FRAME_INTRA_ONLY || + current->frame_type == AV1_FRAME_KEY) + infer(reference_select, 0); + else + flag(reference_select); + + return 0; +} + +static int FUNC(skip_mode_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int skip_mode_allowed; + int err; + + if(current->frame_type == AV1_FRAME_KEY || + current->frame_type == AV1_FRAME_INTRA_ONLY || + !current->reference_select || !seq->enable_order_hint) { + skip_mode_allowed = 0; + } + else { + int forward_idx, backward_idx; + int forward_hint, backward_hint; + int ref_hint, dist, i; + + forward_idx = -1; + backward_idx = -1; + for(i = 0; i < AV1_REFS_PER_FRAME; i++) { + ref_hint = priv->ref[current->ref_frame_idx[i]].order_hint; + dist = cbs_av1_get_relative_dist(seq, ref_hint, + priv->order_hint); + if(dist < 0) { + if(forward_idx < 0 || + cbs_av1_get_relative_dist(seq, ref_hint, + forward_hint) > 0) { + forward_idx = i; + forward_hint = ref_hint; + } + } + else if(dist > 0) { + if(backward_idx < 0 || + cbs_av1_get_relative_dist(seq, ref_hint, + backward_hint) < 0) { + backward_idx = i; + backward_hint = ref_hint; + } + } + } + + if(forward_idx < 0) { + skip_mode_allowed = 0; + } + else if(backward_idx >= 0) { + skip_mode_allowed = 1; + // Frames for skip mode are forward_idx and backward_idx. + } + else { + int second_forward_idx; + int second_forward_hint; + + second_forward_idx = -1; + for(i = 0; i < AV1_REFS_PER_FRAME; i++) { + ref_hint = priv->ref[current->ref_frame_idx[i]].order_hint; + if(cbs_av1_get_relative_dist(seq, ref_hint, + forward_hint) < 0) { + if(second_forward_idx < 0 || + cbs_av1_get_relative_dist(seq, ref_hint, + second_forward_hint) > 0) { + second_forward_idx = i; + second_forward_hint = ref_hint; + } + } + } + + if(second_forward_idx < 0) { + skip_mode_allowed = 0; + } + else { + skip_mode_allowed = 1; + // Frames for skip mode are forward_idx and second_forward_idx. + } + } + } + + if(skip_mode_allowed) + flag(skip_mode_present); + else + infer(skip_mode_present, 0); + + return 0; +} + +static int FUNC(global_motion_param)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current, + int type, int ref, int idx) { + uint32_t abs_bits, prec_bits, num_syms; + int err; + + if(idx < 2) { + if(type == AV1_WARP_MODEL_TRANSLATION) { + abs_bits = AV1_GM_ABS_TRANS_ONLY_BITS - !current->allow_high_precision_mv; + prec_bits = AV1_GM_TRANS_ONLY_PREC_BITS - !current->allow_high_precision_mv; + } + else { + abs_bits = AV1_GM_ABS_TRANS_BITS; + prec_bits = AV1_GM_TRANS_PREC_BITS; + } + } + else { + abs_bits = AV1_GM_ABS_ALPHA_BITS; + prec_bits = AV1_GM_ALPHA_PREC_BITS; + } + + num_syms = 2 * (1 << abs_bits) + 1; + subexp(gm_params[ref][idx], num_syms, 2, ref, idx); + + // Actual gm_params value is not reconstructed here. + (void)prec_bits; + + return 0; +} + +static int FUNC(global_motion_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + int ref, type; + int err; + + if(current->frame_type == AV1_FRAME_KEY || + current->frame_type == AV1_FRAME_INTRA_ONLY) + return 0; + + for(ref = AV1_REF_FRAME_LAST; ref <= AV1_REF_FRAME_ALTREF; ref++) { + flags(is_global[ref], 1, ref); + if(current->is_global[ref]) { + flags(is_rot_zoom[ref], 1, ref); + if(current->is_rot_zoom[ref]) { + type = AV1_WARP_MODEL_ROTZOOM; + } + else { + flags(is_translation[ref], 1, ref); + type = current->is_translation[ref] ? AV1_WARP_MODEL_TRANSLATION : AV1_WARP_MODEL_AFFINE; + } + } + else { + type = AV1_WARP_MODEL_IDENTITY; + } + + if(type >= AV1_WARP_MODEL_ROTZOOM) { + CHECK(FUNC(global_motion_param)(ctx, rw, current, type, ref, 2)); + CHECK(FUNC(global_motion_param)(ctx, rw, current, type, ref, 3)); + if(type == AV1_WARP_MODEL_AFFINE) { + CHECK(FUNC(global_motion_param)(ctx, rw, current, type, ref, 4)); + CHECK(FUNC(global_motion_param)(ctx, rw, current, type, ref, 5)); + } + else { + // gm_params[ref][4] = -gm_params[ref][3] + // gm_params[ref][5] = gm_params[ref][2] + } + } + if(type >= AV1_WARP_MODEL_TRANSLATION) { + CHECK(FUNC(global_motion_param)(ctx, rw, current, type, ref, 0)); + CHECK(FUNC(global_motion_param)(ctx, rw, current, type, ref, 1)); + } + } + + return 0; +} + +static int FUNC(film_grain_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFilmGrainParams *current, + AV1RawFrameHeader *frame_header) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int num_pos_luma, num_pos_chroma; + int i, err; + + if(!seq->film_grain_params_present || + (!frame_header->show_frame && !frame_header->showable_frame)) + return 0; + + flag(apply_grain); + + if(!current->apply_grain) + return 0; + + fb(16, grain_seed); + + if(frame_header->frame_type == AV1_FRAME_INTER) + flag(update_grain); + else + infer(update_grain, 1); + + if(!current->update_grain) { + fb(3, film_grain_params_ref_idx); + return 0; + } + + fc(4, num_y_points, 0, 14); + for(i = 0; i < current->num_y_points; i++) { + fcs(8, point_y_value[i], + i ? current->point_y_value[i - 1] + 1 : 0, + MAX_UINT_BITS(8) - (current->num_y_points - i - 1), + 1, i); + fbs(8, point_y_scaling[i], 1, i); + } + + if(seq->color_config.mono_chrome) + infer(chroma_scaling_from_luma, 0); + else + flag(chroma_scaling_from_luma); + + if(seq->color_config.mono_chrome || + current->chroma_scaling_from_luma || + (seq->color_config.subsampling_x == 1 && + seq->color_config.subsampling_y == 1 && + current->num_y_points == 0)) { + infer(num_cb_points, 0); + infer(num_cr_points, 0); + } + else { + fc(4, num_cb_points, 0, 10); + for(i = 0; i < current->num_cb_points; i++) { + fcs(8, point_cb_value[i], + i ? current->point_cb_value[i - 1] + 1 : 0, + MAX_UINT_BITS(8) - (current->num_cb_points - i - 1), + 1, i); + fbs(8, point_cb_scaling[i], 1, i); + } + fc(4, num_cr_points, 0, 10); + for(i = 0; i < current->num_cr_points; i++) { + fcs(8, point_cr_value[i], + i ? current->point_cr_value[i - 1] + 1 : 0, + MAX_UINT_BITS(8) - (current->num_cr_points - i - 1), + 1, i); + fbs(8, point_cr_scaling[i], 1, i); + } + } + + fb(2, grain_scaling_minus_8); + fb(2, ar_coeff_lag); + num_pos_luma = 2 * current->ar_coeff_lag * (current->ar_coeff_lag + 1); + if(current->num_y_points) { + num_pos_chroma = num_pos_luma + 1; + for(i = 0; i < num_pos_luma; i++) + fbs(8, ar_coeffs_y_plus_128[i], 1, i); + } + else { + num_pos_chroma = num_pos_luma; + } + if(current->chroma_scaling_from_luma || current->num_cb_points) { + for(i = 0; i < num_pos_chroma; i++) + fbs(8, ar_coeffs_cb_plus_128[i], 1, i); + } + if(current->chroma_scaling_from_luma || current->num_cr_points) { + for(i = 0; i < num_pos_chroma; i++) + fbs(8, ar_coeffs_cr_plus_128[i], 1, i); + } + fb(2, ar_coeff_shift_minus_6); + fb(2, grain_scale_shift); + if(current->num_cb_points) { + fb(8, cb_mult); + fb(8, cb_luma_mult); + fb(9, cb_offset); + } + if(current->num_cr_points) { + fb(8, cr_mult); + fb(8, cr_luma_mult); + fb(9, cr_offset); + } + + flag(overlap_flag); + flag(clip_to_restricted_range); + + return 0; +} + +static int FUNC(uncompressed_header)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq; + int id_len, diff_len, all_frames, frame_is_intra, order_hint_bits; + int i, err; + + if(!priv->sequence_header) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "No sequence header available: " + "unable to decode frame header.\n"); + return AVERROR_INVALIDDATA; + } + seq = priv->sequence_header; + + id_len = seq->additional_frame_id_length_minus_1 + + seq->delta_frame_id_length_minus_2 + 3; + all_frames = (1 << AV1_NUM_REF_FRAMES) - 1; + + if(seq->reduced_still_picture_header) { + infer(show_existing_frame, 0); + infer(frame_type, AV1_FRAME_KEY); + infer(show_frame, 1); + infer(showable_frame, 0); + frame_is_intra = 1; + } + else { + flag(show_existing_frame); + + if(current->show_existing_frame) { + AV1ReferenceFrameState *ref; + + fb(3, frame_to_show_map_idx); + ref = &priv->ref[current->frame_to_show_map_idx]; + + if(!ref->valid) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Missing reference frame needed for " + "show_existing_frame (frame_to_show_map_idx = %d).\n", + current->frame_to_show_map_idx); + return AVERROR_INVALIDDATA; + } + + if(seq->decoder_model_info_present_flag && + !seq->timing_info.equal_picture_interval) { + fb(seq->decoder_model_info.frame_presentation_time_length_minus_1 + 1, + frame_presentation_time); + } + + if(seq->frame_id_numbers_present_flag) + fb(id_len, display_frame_id); + + infer(frame_type, ref->frame_type); + if(current->frame_type == AV1_FRAME_KEY) { + infer(refresh_frame_flags, all_frames); + + // Section 7.21 + infer(current_frame_id, ref->frame_id); + priv->upscaled_width = ref->upscaled_width; + priv->frame_width = ref->frame_width; + priv->frame_height = ref->frame_height; + priv->render_width = ref->render_width; + priv->render_height = ref->render_height; + priv->bit_depth = ref->bit_depth; + priv->order_hint = ref->order_hint; + } + else + infer(refresh_frame_flags, 0); + + infer(frame_width_minus_1, ref->upscaled_width - 1); + infer(frame_height_minus_1, ref->frame_height - 1); + infer(render_width_minus_1, ref->render_width - 1); + infer(render_height_minus_1, ref->render_height - 1); + + // Section 7.20 + goto update_refs; + } + + fb(2, frame_type); + frame_is_intra = (current->frame_type == AV1_FRAME_INTRA_ONLY || + current->frame_type == AV1_FRAME_KEY); + + flag(show_frame); + if(current->show_frame && + seq->decoder_model_info_present_flag && + !seq->timing_info.equal_picture_interval) { + fb(seq->decoder_model_info.frame_presentation_time_length_minus_1 + 1, + frame_presentation_time); + } + if(current->show_frame) + infer(showable_frame, current->frame_type != AV1_FRAME_KEY); + else + flag(showable_frame); + + if(current->frame_type == AV1_FRAME_SWITCH || + (current->frame_type == AV1_FRAME_KEY && current->show_frame)) + infer(error_resilient_mode, 1); + else + flag(error_resilient_mode); + } + + if(current->frame_type == AV1_FRAME_KEY && current->show_frame) { + for(i = 0; i < AV1_NUM_REF_FRAMES; i++) { + priv->ref[i].valid = 0; + priv->ref[i].order_hint = 0; + } + } + + flag(disable_cdf_update); + + if(seq->seq_force_screen_content_tools == + AV1_SELECT_SCREEN_CONTENT_TOOLS) { + flag(allow_screen_content_tools); + } + else { + infer(allow_screen_content_tools, + seq->seq_force_screen_content_tools); + } + if(current->allow_screen_content_tools) { + if(seq->seq_force_integer_mv == AV1_SELECT_INTEGER_MV) + flag(force_integer_mv); + else + infer(force_integer_mv, seq->seq_force_integer_mv); + } + else { + infer(force_integer_mv, 0); + } + + if(seq->frame_id_numbers_present_flag) { + fb(id_len, current_frame_id); + + diff_len = seq->delta_frame_id_length_minus_2 + 2; + for(i = 0; i < AV1_NUM_REF_FRAMES; i++) { + if(current->current_frame_id > (1 << diff_len)) { + if(priv->ref[i].frame_id > current->current_frame_id || + priv->ref[i].frame_id < (current->current_frame_id - + (1 << diff_len))) + priv->ref[i].valid = 0; + } + else { + if(priv->ref[i].frame_id > current->current_frame_id && + priv->ref[i].frame_id < ((1 << id_len) + + current->current_frame_id - + (1 << diff_len))) + priv->ref[i].valid = 0; + } + } + } + else { + infer(current_frame_id, 0); + } + + if(current->frame_type == AV1_FRAME_SWITCH) + infer(frame_size_override_flag, 1); + else if(seq->reduced_still_picture_header) + infer(frame_size_override_flag, 0); + else + flag(frame_size_override_flag); + + order_hint_bits = + seq->enable_order_hint ? seq->order_hint_bits_minus_1 + 1 : 0; + if(order_hint_bits > 0) + fb(order_hint_bits, order_hint); + else + infer(order_hint, 0); + priv->order_hint = current->order_hint; + + if(frame_is_intra || current->error_resilient_mode) + infer(primary_ref_frame, AV1_PRIMARY_REF_NONE); + else + fb(3, primary_ref_frame); + + if(seq->decoder_model_info_present_flag) { + flag(buffer_removal_time_present_flag); + if(current->buffer_removal_time_present_flag) { + for(i = 0; i <= seq->operating_points_cnt_minus_1; i++) { + if(seq->decoder_model_present_for_this_op[i]) { + int op_pt_idc = seq->operating_point_idc[i]; + int in_temporal_layer = (op_pt_idc >> priv->temporal_id) & 1; + int in_spatial_layer = (op_pt_idc >> (priv->spatial_id + 8)) & 1; + if(seq->operating_point_idc[i] == 0 || + (in_temporal_layer && in_spatial_layer)) { + fbs(seq->decoder_model_info.buffer_removal_time_length_minus_1 + 1, + buffer_removal_time[i], 1, i); + } + } + } + } + } + + if(current->frame_type == AV1_FRAME_SWITCH || + (current->frame_type == AV1_FRAME_KEY && current->show_frame)) + infer(refresh_frame_flags, all_frames); + else + fb(8, refresh_frame_flags); + + if(!frame_is_intra || current->refresh_frame_flags != all_frames) { + if(seq->enable_order_hint) { + for(i = 0; i < AV1_NUM_REF_FRAMES; i++) { + if(current->error_resilient_mode) + fbs(order_hint_bits, ref_order_hint[i], 1, i); + else + infer(ref_order_hint[i], priv->ref[i].order_hint); + if(current->ref_order_hint[i] != priv->ref[i].order_hint) + priv->ref[i].valid = 0; + } + } + } + + if(current->frame_type == AV1_FRAME_KEY || + current->frame_type == AV1_FRAME_INTRA_ONLY) { + CHECK(FUNC(frame_size)(ctx, rw, current)); + CHECK(FUNC(render_size)(ctx, rw, current)); + + if(current->allow_screen_content_tools && + priv->upscaled_width == priv->frame_width) + flag(allow_intrabc); + else + infer(allow_intrabc, 0); + } + else { + if(!seq->enable_order_hint) { + infer(frame_refs_short_signaling, 0); + } + else { + flag(frame_refs_short_signaling); + if(current->frame_refs_short_signaling) { + fb(3, last_frame_idx); + fb(3, golden_frame_idx); + CHECK(FUNC(set_frame_refs)(ctx, rw, current)); + } + } + + for(i = 0; i < AV1_REFS_PER_FRAME; i++) { + if(!current->frame_refs_short_signaling) + fbs(3, ref_frame_idx[i], 1, i); + if(seq->frame_id_numbers_present_flag) { + fbs(seq->delta_frame_id_length_minus_2 + 2, + delta_frame_id_minus1[i], 1, i); + } + } + + if(current->frame_size_override_flag && + !current->error_resilient_mode) { + CHECK(FUNC(frame_size_with_refs)(ctx, rw, current)); + } + else { + CHECK(FUNC(frame_size)(ctx, rw, current)); + CHECK(FUNC(render_size)(ctx, rw, current)); + } + + if(current->force_integer_mv) + infer(allow_high_precision_mv, 0); + else + flag(allow_high_precision_mv); + + CHECK(FUNC(interpolation_filter)(ctx, rw, current)); + + flag(is_motion_mode_switchable); + + if(current->error_resilient_mode || + !seq->enable_ref_frame_mvs) + infer(use_ref_frame_mvs, 0); + else + flag(use_ref_frame_mvs); + + infer(allow_intrabc, 0); + } + + if(!frame_is_intra) { + // Derive reference frame sign biases. + } + + if(seq->reduced_still_picture_header || current->disable_cdf_update) + infer(disable_frame_end_update_cdf, 1); + else + flag(disable_frame_end_update_cdf); + + if(current->primary_ref_frame == AV1_PRIMARY_REF_NONE) { + // Init non-coeff CDFs. + // Setup past independence. + } + else { + // Load CDF tables from previous frame. + // Load params from previous frame. + } + + if(current->use_ref_frame_mvs) { + // Perform motion field estimation process. + } + + CHECK(FUNC(tile_info)(ctx, rw, current)); + + CHECK(FUNC(quantization_params)(ctx, rw, current)); + + CHECK(FUNC(segmentation_params)(ctx, rw, current)); + + CHECK(FUNC(delta_q_params)(ctx, rw, current)); + + CHECK(FUNC(delta_lf_params)(ctx, rw, current)); + + // Init coeff CDFs / load previous segments. + + priv->coded_lossless = 1; + for(i = 0; i < AV1_MAX_SEGMENTS; i++) { + int qindex; + if(current->feature_enabled[i][AV1_SEG_LVL_ALT_Q]) { + qindex = (current->base_q_idx + + current->feature_value[i][AV1_SEG_LVL_ALT_Q]); + } + else { + qindex = current->base_q_idx; + } + qindex = av_clip_uintp2(qindex, 8); + + if(qindex || current->delta_q_y_dc || + current->delta_q_u_ac || current->delta_q_u_dc || + current->delta_q_v_ac || current->delta_q_v_dc) { + priv->coded_lossless = 0; + } + } + priv->all_lossless = priv->coded_lossless && + priv->frame_width == priv->upscaled_width; + + CHECK(FUNC(loop_filter_params)(ctx, rw, current)); + + CHECK(FUNC(cdef_params)(ctx, rw, current)); + + CHECK(FUNC(lr_params)(ctx, rw, current)); + + CHECK(FUNC(read_tx_mode)(ctx, rw, current)); + + CHECK(FUNC(frame_reference_mode)(ctx, rw, current)); + + CHECK(FUNC(skip_mode_params)(ctx, rw, current)); + + if(frame_is_intra || current->error_resilient_mode || + !seq->enable_warped_motion) + infer(allow_warped_motion, 0); + else + flag(allow_warped_motion); + + flag(reduced_tx_set); + + CHECK(FUNC(global_motion_params)(ctx, rw, current)); + + CHECK(FUNC(film_grain_params)(ctx, rw, ¤t->film_grain, current)); + + av_log(ctx->log_ctx, AV_LOG_DEBUG, "Frame %d: size %dx%d " + "upscaled %d render %dx%d subsample %dx%d " + "bitdepth %d tiles %dx%d.\n", + priv->order_hint, + priv->frame_width, priv->frame_height, priv->upscaled_width, + priv->render_width, priv->render_height, + seq->color_config.subsampling_x + 1, + seq->color_config.subsampling_y + 1, priv->bit_depth, + priv->tile_rows, priv->tile_cols); + +update_refs: + for(i = 0; i < AV1_NUM_REF_FRAMES; i++) { + if(current->refresh_frame_flags & (1 << i)) { + priv->ref[i] = (AV1ReferenceFrameState) { + .valid = 1, + .frame_id = current->current_frame_id, + .upscaled_width = priv->upscaled_width, + .frame_width = priv->frame_width, + .frame_height = priv->frame_height, + .render_width = priv->render_width, + .render_height = priv->render_height, + .frame_type = current->frame_type, + .subsampling_x = seq->color_config.subsampling_x, + .subsampling_y = seq->color_config.subsampling_y, + .bit_depth = priv->bit_depth, + .order_hint = priv->order_hint, + }; + memcpy(priv->ref[i].loop_filter_ref_deltas, current->loop_filter_ref_deltas, + sizeof(current->loop_filter_ref_deltas)); + memcpy(priv->ref[i].loop_filter_mode_deltas, current->loop_filter_mode_deltas, + sizeof(current->loop_filter_mode_deltas)); + memcpy(priv->ref[i].feature_enabled, current->feature_enabled, + sizeof(current->feature_enabled)); + memcpy(priv->ref[i].feature_value, current->feature_value, + sizeof(current->feature_value)); + } + } + + return 0; +} + +static int FUNC(frame_header_obu)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current, int redundant, + AVBufferRef *rw_buffer_ref) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + int start_pos, fh_bits, fh_bytes, err; + uint8_t *fh_start; + + if(priv->seen_frame_header) { + if(!redundant) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid repeated " + "frame header OBU.\n"); + return AVERROR_INVALIDDATA; + } + else { + GetBitContext fh; + size_t i, b; + uint32_t val; + + HEADER("Redundant Frame Header"); + + av_assert0(priv->frame_header_ref && priv->frame_header); + + init_get_bits(&fh, priv->frame_header, + priv->frame_header_size); + for(i = 0; i < priv->frame_header_size; i += 8) { + b = FFMIN(priv->frame_header_size - i, 8); + val = get_bits(&fh, b); + xf(b, frame_header_copy[i], + val, val, val, 1, i / 8); + } + } + } + else { + if(redundant) + HEADER("Redundant Frame Header (used as Frame Header)"); + else + HEADER("Frame Header"); + +#ifdef READ + start_pos = get_bits_count(rw); +#else + start_pos = put_bits_count(rw); +#endif + + CHECK(FUNC(uncompressed_header)(ctx, rw, current)); + + priv->tile_num = 0; + + if(current->show_existing_frame) { + priv->seen_frame_header = 0; + } + else { + priv->seen_frame_header = 1; + + av_buffer_unref(&priv->frame_header_ref); + +#ifdef READ + fh_bits = get_bits_count(rw) - start_pos; + fh_start = (uint8_t *)rw->buffer + start_pos / 8; +#else + // Need to flush the bitwriter so that we can copy its output, + // but use a copy so we don't affect the caller's structure. + { + PutBitContext tmp = *rw; + flush_put_bits(&tmp); + } + + fh_bits = put_bits_count(rw) - start_pos; + fh_start = rw->buf + start_pos / 8; +#endif + fh_bytes = (fh_bits + 7) / 8; + + priv->frame_header_size = fh_bits; + + if(rw_buffer_ref) { + priv->frame_header_ref = av_buffer_ref(rw_buffer_ref); + if(!priv->frame_header_ref) + return AVERROR(ENOMEM); + priv->frame_header = fh_start; + } + else { + priv->frame_header_ref = + av_buffer_alloc(fh_bytes + AV_INPUT_BUFFER_PADDING_SIZE); + if(!priv->frame_header_ref) + return AVERROR(ENOMEM); + priv->frame_header = priv->frame_header_ref->data; + memcpy(priv->frame_header, fh_start, fh_bytes); + } + } + } + + return 0; +} + +static int FUNC(tile_group_obu)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawTileGroup *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + int num_tiles, tile_bits; + int err; + + HEADER("Tile Group"); + + num_tiles = priv->tile_cols * priv->tile_rows; + if(num_tiles > 1) + flag(tile_start_and_end_present_flag); + else + infer(tile_start_and_end_present_flag, 0); + + if(num_tiles == 1 || !current->tile_start_and_end_present_flag) { + infer(tg_start, 0); + infer(tg_end, num_tiles - 1); + } + else { + tile_bits = cbs_av1_tile_log2(1, priv->tile_cols) + + cbs_av1_tile_log2(1, priv->tile_rows); + fc(tile_bits, tg_start, priv->tile_num, num_tiles - 1); + fc(tile_bits, tg_end, current->tg_start, num_tiles - 1); + } + + priv->tile_num = current->tg_end + 1; + + CHECK(FUNC(byte_alignment)(ctx, rw)); + + // Reset header for next frame. + if(current->tg_end == num_tiles - 1) + priv->seen_frame_header = 0; + + // Tile data follows. + + return 0; +} + +static int FUNC(frame_obu)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrame *current, + AVBufferRef *rw_buffer_ref) { + int err; + + CHECK(FUNC(frame_header_obu)(ctx, rw, ¤t->header, + 0, rw_buffer_ref)); + + CHECK(FUNC(byte_alignment)(ctx, rw)); + + CHECK(FUNC(tile_group_obu)(ctx, rw, ¤t->tile_group)); + + return 0; +} + +static int FUNC(tile_list_obu)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawTileList *current) { + int err; + + fb(8, output_frame_width_in_tiles_minus_1); + fb(8, output_frame_height_in_tiles_minus_1); + + fb(16, tile_count_minus_1); + + // Tile data follows. + + return 0; +} + +static int FUNC(metadata_hdr_cll)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawMetadataHDRCLL *current) { + int err; + + fb(16, max_cll); + fb(16, max_fall); + + return 0; +} + +static int FUNC(metadata_hdr_mdcv)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawMetadataHDRMDCV *current) { + int err, i; + + for(i = 0; i < 3; i++) { + fbs(16, primary_chromaticity_x[i], 1, i); + fbs(16, primary_chromaticity_y[i], 1, i); + } + + fb(16, white_point_chromaticity_x); + fb(16, white_point_chromaticity_y); + + fc(32, luminance_max, 1, MAX_UINT_BITS(32)); + // luminance_min must be lower than luminance_max. Convert luminance_max from + // 24.8 fixed point to 18.14 fixed point in order to compare them. + fc(32, luminance_min, 0, FFMIN(((uint64_t)current->luminance_max << 6) - 1, MAX_UINT_BITS(32))); + + return 0; +} + +static int FUNC(scalability_structure)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawMetadataScalability *current) { + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq; + int err, i, j; + + if(!priv->sequence_header) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "No sequence header available: " + "unable to parse scalability metadata.\n"); + return AVERROR_INVALIDDATA; + } + seq = priv->sequence_header; + + fb(2, spatial_layers_cnt_minus_1); + flag(spatial_layer_dimensions_present_flag); + flag(spatial_layer_description_present_flag); + flag(temporal_group_description_present_flag); + fc(3, scalability_structure_reserved_3bits, 0, 0); + if(current->spatial_layer_dimensions_present_flag) { + for(i = 0; i <= current->spatial_layers_cnt_minus_1; i++) { + fcs(16, spatial_layer_max_width[i], + 0, seq->max_frame_width_minus_1 + 1, 1, i); + fcs(16, spatial_layer_max_height[i], + 0, seq->max_frame_height_minus_1 + 1, 1, i); + } + } + if(current->spatial_layer_description_present_flag) { + for(i = 0; i <= current->spatial_layers_cnt_minus_1; i++) + fbs(8, spatial_layer_ref_id[i], 1, i); + } + if(current->temporal_group_description_present_flag) { + fb(8, temporal_group_size); + for(i = 0; i < current->temporal_group_size; i++) { + fbs(3, temporal_group_temporal_id[i], 1, i); + flags(temporal_group_temporal_switching_up_point_flag[i], 1, i); + flags(temporal_group_spatial_switching_up_point_flag[i], 1, i); + fbs(3, temporal_group_ref_cnt[i], 1, i); + for(j = 0; j < current->temporal_group_ref_cnt[i]; j++) { + fbs(8, temporal_group_ref_pic_diff[i][j], 2, i, j); + } + } + } + + return 0; +} + +static int FUNC(metadata_scalability)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawMetadataScalability *current) { + int err; + + fb(8, scalability_mode_idc); + + if(current->scalability_mode_idc == AV1_SCALABILITY_SS) + CHECK(FUNC(scalability_structure)(ctx, rw, current)); + + return 0; +} + +static int FUNC(metadata_itut_t35)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawMetadataITUTT35 *current) { + int err; + size_t i; + + fb(8, itu_t_t35_country_code); + if(current->itu_t_t35_country_code == 0xff) + fb(8, itu_t_t35_country_code_extension_byte); + +#ifdef READ + // The payload runs up to the start of the trailing bits, but there might + // be arbitrarily many trailing zeroes so we need to read through twice. + current->payload_size = cbs_av1_get_payload_bytes_left(rw); + + current->payload_ref = av_buffer_alloc(current->payload_size); + if(!current->payload_ref) + return AVERROR(ENOMEM); + current->payload = current->payload_ref->data; +#endif + + for(i = 0; i < current->payload_size; i++) + xf(8, itu_t_t35_payload_bytes[i], current->payload[i], + 0x00, 0xff, 1, i); + + return 0; +} + +static int FUNC(metadata_timecode)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawMetadataTimecode *current) { + int err; + + fb(5, counting_type); + flag(full_timestamp_flag); + flag(discontinuity_flag); + flag(cnt_dropped_flag); + fb(9, n_frames); + + if(current->full_timestamp_flag) { + fc(6, seconds_value, 0, 59); + fc(6, minutes_value, 0, 59); + fc(5, hours_value, 0, 23); + } + else { + flag(seconds_flag); + if(current->seconds_flag) { + fc(6, seconds_value, 0, 59); + flag(minutes_flag); + if(current->minutes_flag) { + fc(6, minutes_value, 0, 59); + flag(hours_flag); + if(current->hours_flag) + fc(5, hours_value, 0, 23); + } + } + } + + fb(5, time_offset_length); + if(current->time_offset_length > 0) + fb(current->time_offset_length, time_offset_value); + else + infer(time_offset_length, 0); + + return 0; +} + +static int FUNC(metadata_obu)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawMetadata *current) { + int err; + + leb128(metadata_type); + + switch(current->metadata_type) { + case AV1_METADATA_TYPE_HDR_CLL: + CHECK(FUNC(metadata_hdr_cll)(ctx, rw, ¤t->metadata.hdr_cll)); + break; + case AV1_METADATA_TYPE_HDR_MDCV: + CHECK(FUNC(metadata_hdr_mdcv)(ctx, rw, ¤t->metadata.hdr_mdcv)); + break; + case AV1_METADATA_TYPE_SCALABILITY: + CHECK(FUNC(metadata_scalability)(ctx, rw, ¤t->metadata.scalability)); + break; + case AV1_METADATA_TYPE_ITUT_T35: + CHECK(FUNC(metadata_itut_t35)(ctx, rw, ¤t->metadata.itut_t35)); + break; + case AV1_METADATA_TYPE_TIMECODE: + CHECK(FUNC(metadata_timecode)(ctx, rw, ¤t->metadata.timecode)); + break; + default: + // Unknown metadata type. + return AVERROR_PATCHWELCOME; + } + + return 0; +} + +static int FUNC(padding_obu)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawPadding *current) { + int i, err; + + HEADER("Padding"); + +#ifdef READ + // The payload runs up to the start of the trailing bits, but there might + // be arbitrarily many trailing zeroes so we need to read through twice. + current->payload_size = cbs_av1_get_payload_bytes_left(rw); + + current->payload_ref = av_buffer_alloc(current->payload_size); + if(!current->payload_ref) + return AVERROR(ENOMEM); + current->payload = current->payload_ref->data; +#endif + + for(i = 0; i < current->payload_size; i++) + xf(8, obu_padding_byte[i], current->payload[i], 0x00, 0xff, 1, i); + + return 0; +} diff --git a/third-party/cbs/cbs_h2645.c b/third-party/cbs/cbs_h2645.c new file mode 100644 index 00000000..4a60072d --- /dev/null +++ b/third-party/cbs/cbs_h2645.c @@ -0,0 +1,1632 @@ +/* + * 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 + +#include "cbs/cbs.h" +#include "cbs/cbs_h264.h" +#include "cbs/cbs_h265.h" +#include "cbs/h264.h" +#include "cbs/h2645_parse.h" +#include "cbs/hevc.h" + +#include "bytestream.h" +#include "cbs_internal.h" +#include "h264_sei.h" +#include "hevc_sei.h" +#include "intmath.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; +} + +// payload_extension_present() - true if we are before the last 1-bit +// in the payload structure, which must be in the last byte. +static int cbs_h265_payload_extension_present(GetBitContext *gbc, uint32_t payload_size, + int cur_pos) { + int bits_left = payload_size * 8 - cur_pos; + return (bits_left > 0 && + (bits_left > 7 || show_bits(gbc, bits_left) & MAX_UINT_BITS(bits_left - 1))); +} + +#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_NAME2(rw, codec, name) cbs_##codec##_##rw##_##name +#define FUNC_NAME1(rw, codec, name) FUNC_NAME2(rw, codec, name) +#define FUNC_H264(name) FUNC_NAME1(READWRITE, h264, name) +#define FUNC_H265(name) FUNC_NAME1(READWRITE, h265, name) +#define FUNC_SEI(name) FUNC_NAME1(READWRITE, sei, 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_h2645_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_h2645_read_more_rbsp_data(rw)) + +#define bit_position(rw) (get_bits_count(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_SEI(name) +#include "cbs_sei_syntax_template.c" +#undef FUNC + +#define FUNC(name) FUNC_H264(name) +#include "cbs_h264_syntax_template.c" +#undef FUNC + +#define FUNC(name) FUNC_H265(name) +#include "cbs_h265_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 bit_position +#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 bit_position(rw) (put_bits_count(rw)) +#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_SEI(name) +#include "cbs_sei_syntax_template.c" +#undef FUNC + +#define FUNC(name) FUNC_H264(name) +#include "cbs_h264_syntax_template.c" +#undef FUNC + +#define FUNC(name) FUNC_H265(name) +#include "cbs_h265_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 bit_position +#undef byte_alignment +#undef allocate + + +static int cbs_h2645_fragment_add_nals(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const H2645Packet *packet) { + int err, i; + + for(i = 0; i < packet->nb_nals; i++) { + const H2645NAL *nal = &packet->nals[i]; + AVBufferRef *ref; + size_t size = nal->size; + + if(nal->nuh_layer_id > 0) + continue; + + // Remove trailing zeroes. + while(size > 0 && nal->data[size - 1] == 0) + --size; + if(size == 0) { + av_log(ctx->log_ctx, AV_LOG_VERBOSE, "Discarding empty 0 NAL unit\n"); + continue; + } + + ref = (nal->data == nal->raw_data) ? frag->data_ref : packet->rbsp.rbsp_buffer_ref; + + err = ff_cbs_insert_unit_data(frag, -1, nal->type, + (uint8_t *)nal->data, size, ref); + if(err < 0) + return err; + } + + return 0; +} + +static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) { + enum AVCodecID codec_id = ctx->codec->codec_id; + CodedBitstreamH2645Context *priv = ctx->priv_data; + GetByteContext gbc; + int err; + + av_assert0(frag->data && frag->nb_units == 0); + if(frag->data_size == 0) + return 0; + + if(header && frag->data[0] && codec_id == AV_CODEC_ID_H264) { + // AVCC header. + size_t size, start, end; + int i, count, version; + + priv->mp4 = 1; + + bytestream2_init(&gbc, frag->data, frag->data_size); + + if(bytestream2_get_bytes_left(&gbc) < 6) + return AVERROR_INVALIDDATA; + + version = bytestream2_get_byte(&gbc); + if(version != 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid AVCC header: " + "first byte %u.\n", + version); + return AVERROR_INVALIDDATA; + } + + bytestream2_skip(&gbc, 3); + priv->nal_length_size = (bytestream2_get_byte(&gbc) & 3) + 1; + + // SPS array. + count = bytestream2_get_byte(&gbc) & 0x1f; + start = bytestream2_tell(&gbc); + for(i = 0; i < count; i++) { + if(bytestream2_get_bytes_left(&gbc) < 2 * (count - i)) + return AVERROR_INVALIDDATA; + size = bytestream2_get_be16(&gbc); + if(bytestream2_get_bytes_left(&gbc) < size) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gbc, size); + } + end = bytestream2_tell(&gbc); + + err = ff_h2645_packet_split(&priv->read_packet, + frag->data + start, end - start, + ctx->log_ctx, 1, 2, AV_CODEC_ID_H264, 1, 1); + if(err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split AVCC SPS array.\n"); + return err; + } + err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); + if(err < 0) + return err; + + // PPS array. + count = bytestream2_get_byte(&gbc); + start = bytestream2_tell(&gbc); + for(i = 0; i < count; i++) { + if(bytestream2_get_bytes_left(&gbc) < 2 * (count - i)) + return AVERROR_INVALIDDATA; + size = bytestream2_get_be16(&gbc); + if(bytestream2_get_bytes_left(&gbc) < size) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gbc, size); + } + end = bytestream2_tell(&gbc); + + err = ff_h2645_packet_split(&priv->read_packet, + frag->data + start, end - start, + ctx->log_ctx, 1, 2, AV_CODEC_ID_H264, 1, 1); + if(err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split AVCC PPS array.\n"); + return err; + } + err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); + if(err < 0) + return err; + + if(bytestream2_get_bytes_left(&gbc) > 0) { + av_log(ctx->log_ctx, AV_LOG_WARNING, "%u bytes left at end of AVCC " + "header.\n", + bytestream2_get_bytes_left(&gbc)); + } + } + else if(header && frag->data[0] && codec_id == AV_CODEC_ID_HEVC) { + // HVCC header. + size_t size, start, end; + int i, j, nb_arrays, nal_unit_type, nb_nals, version; + + priv->mp4 = 1; + + bytestream2_init(&gbc, frag->data, frag->data_size); + + if(bytestream2_get_bytes_left(&gbc) < 23) + return AVERROR_INVALIDDATA; + + version = bytestream2_get_byte(&gbc); + if(version != 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid HVCC header: " + "first byte %u.\n", + version); + return AVERROR_INVALIDDATA; + } + + bytestream2_skip(&gbc, 20); + priv->nal_length_size = (bytestream2_get_byte(&gbc) & 3) + 1; + + nb_arrays = bytestream2_get_byte(&gbc); + for(i = 0; i < nb_arrays; i++) { + nal_unit_type = bytestream2_get_byte(&gbc) & 0x3f; + nb_nals = bytestream2_get_be16(&gbc); + + start = bytestream2_tell(&gbc); + for(j = 0; j < nb_nals; j++) { + if(bytestream2_get_bytes_left(&gbc) < 2) + return AVERROR_INVALIDDATA; + size = bytestream2_get_be16(&gbc); + if(bytestream2_get_bytes_left(&gbc) < size) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gbc, size); + } + end = bytestream2_tell(&gbc); + + err = ff_h2645_packet_split(&priv->read_packet, + frag->data + start, end - start, + ctx->log_ctx, 1, 2, AV_CODEC_ID_HEVC, 1, 1); + if(err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split " + "HVCC array %d (%d NAL units of type %d).\n", + i, nb_nals, nal_unit_type); + return err; + } + err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); + if(err < 0) + return err; + } + } + else { + // Annex B, or later MP4 with already-known parameters. + + err = ff_h2645_packet_split(&priv->read_packet, + frag->data, frag->data_size, + ctx->log_ctx, + priv->mp4, priv->nal_length_size, + codec_id, 1, 1); + if(err < 0) + return err; + + err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); + if(err < 0) + return err; + } + + return 0; +} + +#define cbs_h2645_replace_ps(h26n, ps_name, ps_var, id_element) \ + static int cbs_h26##h26n##_replace_##ps_var(CodedBitstreamContext *ctx, \ + CodedBitstreamUnit *unit) { \ + CodedBitstreamH26##h26n##Context *priv = ctx->priv_data; \ + H26##h26n##Raw##ps_name *ps_var = unit->content; \ + unsigned int id = ps_var->id_element; \ + int err; \ + if(id >= FF_ARRAY_ELEMS(priv->ps_var)) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid " #ps_name " id : %d.\n", id); \ + return AVERROR_INVALIDDATA; \ + } \ + err = ff_cbs_make_unit_refcounted(ctx, unit); \ + if(err < 0) \ + return err; \ + if(priv->ps_var[id] == priv->active_##ps_var) \ + priv->active_##ps_var = NULL; \ + av_buffer_unref(&priv->ps_var##_ref[id]); \ + av_assert0(unit->content_ref); \ + priv->ps_var##_ref[id] = av_buffer_ref(unit->content_ref); \ + if(!priv->ps_var##_ref[id]) \ + return AVERROR(ENOMEM); \ + priv->ps_var[id] = (H26##h26n##Raw##ps_name *)priv->ps_var##_ref[id]->data; \ + return 0; \ + } + +cbs_h2645_replace_ps(4, SPS, sps, seq_parameter_set_id) + cbs_h2645_replace_ps(4, PPS, pps, pic_parameter_set_id) + cbs_h2645_replace_ps(5, VPS, vps, vps_video_parameter_set_id) + cbs_h2645_replace_ps(5, SPS, sps, sps_seq_parameter_set_id) + cbs_h2645_replace_ps(5, PPS, pps, pps_pic_parameter_set_id) + + static int cbs_h264_read_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) { + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if(err < 0) + return err; + + err = ff_cbs_alloc_unit_content2(ctx, unit); + if(err < 0) + return err; + + switch(unit->type) { + case H264_NAL_SPS: { + H264RawSPS *sps = unit->content; + + err = cbs_h264_read_sps(ctx, &gbc, sps); + if(err < 0) + return err; + + err = cbs_h264_replace_sps(ctx, unit); + if(err < 0) + return err; + } break; + + case H264_NAL_SPS_EXT: { + err = cbs_h264_read_sps_extension(ctx, &gbc, unit->content); + if(err < 0) + return err; + } break; + + case H264_NAL_PPS: { + H264RawPPS *pps = unit->content; + + err = cbs_h264_read_pps(ctx, &gbc, pps); + if(err < 0) + return err; + + err = cbs_h264_replace_pps(ctx, unit); + if(err < 0) + return err; + } break; + + case H264_NAL_SLICE: + case H264_NAL_IDR_SLICE: + case H264_NAL_AUXILIARY_SLICE: { + H264RawSlice *slice = unit->content; + int pos, len; + + err = cbs_h264_read_slice_header(ctx, &gbc, &slice->header); + if(err < 0) + return err; + + if(!cbs_h2645_read_more_rbsp_data(&gbc)) + return AVERROR_INVALIDDATA; + + pos = get_bits_count(&gbc); + len = unit->data_size; + + slice->data_size = len - pos / 8; + slice->data_ref = av_buffer_ref(unit->data_ref); + if(!slice->data_ref) + return AVERROR(ENOMEM); + slice->data = unit->data + pos / 8; + slice->data_bit_start = pos % 8; + } break; + + case H264_NAL_AUD: { + err = cbs_h264_read_aud(ctx, &gbc, unit->content); + if(err < 0) + return err; + } break; + + case H264_NAL_SEI: { + err = cbs_h264_read_sei(ctx, &gbc, unit->content); + if(err < 0) + return err; + } break; + + case H264_NAL_FILLER_DATA: { + err = cbs_h264_read_filler(ctx, &gbc, unit->content); + if(err < 0) + return err; + } break; + + case H264_NAL_END_SEQUENCE: + case H264_NAL_END_STREAM: { + err = (unit->type == H264_NAL_END_SEQUENCE ? + cbs_h264_read_end_of_sequence : + cbs_h264_read_end_of_stream)(ctx, &gbc, unit->content); + if(err < 0) + return err; + } break; + + default: + return AVERROR(ENOSYS); + } + + return 0; +} + +static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) { + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if(err < 0) + return err; + + err = ff_cbs_alloc_unit_content2(ctx, unit); + if(err < 0) + return err; + + switch(unit->type) { + case HEVC_NAL_VPS: { + H265RawVPS *vps = unit->content; + + err = cbs_h265_read_vps(ctx, &gbc, vps); + if(err < 0) + return err; + + err = cbs_h265_replace_vps(ctx, unit); + if(err < 0) + return err; + } break; + case HEVC_NAL_SPS: { + H265RawSPS *sps = unit->content; + + err = cbs_h265_read_sps(ctx, &gbc, sps); + if(err < 0) + return err; + + err = cbs_h265_replace_sps(ctx, unit); + if(err < 0) + return err; + } break; + + case HEVC_NAL_PPS: { + H265RawPPS *pps = unit->content; + + err = cbs_h265_read_pps(ctx, &gbc, pps); + if(err < 0) + return err; + + err = cbs_h265_replace_pps(ctx, unit); + if(err < 0) + return err; + } break; + + case HEVC_NAL_TRAIL_N: + case HEVC_NAL_TRAIL_R: + case HEVC_NAL_TSA_N: + case HEVC_NAL_TSA_R: + case HEVC_NAL_STSA_N: + case HEVC_NAL_STSA_R: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RADL_R: + case HEVC_NAL_RASL_N: + case HEVC_NAL_RASL_R: + case HEVC_NAL_BLA_W_LP: + case HEVC_NAL_BLA_W_RADL: + case HEVC_NAL_BLA_N_LP: + case HEVC_NAL_IDR_W_RADL: + case HEVC_NAL_IDR_N_LP: + case HEVC_NAL_CRA_NUT: { + H265RawSlice *slice = unit->content; + int pos, len; + + err = cbs_h265_read_slice_segment_header(ctx, &gbc, &slice->header); + if(err < 0) + return err; + + if(!cbs_h2645_read_more_rbsp_data(&gbc)) + return AVERROR_INVALIDDATA; + + pos = get_bits_count(&gbc); + len = unit->data_size; + + slice->data_size = len - pos / 8; + slice->data_ref = av_buffer_ref(unit->data_ref); + if(!slice->data_ref) + return AVERROR(ENOMEM); + slice->data = unit->data + pos / 8; + slice->data_bit_start = pos % 8; + } break; + + case HEVC_NAL_AUD: { + err = cbs_h265_read_aud(ctx, &gbc, unit->content); + if(err < 0) + return err; + } break; + + case HEVC_NAL_SEI_PREFIX: + case HEVC_NAL_SEI_SUFFIX: { + err = cbs_h265_read_sei(ctx, &gbc, unit->content, + unit->type == HEVC_NAL_SEI_PREFIX); + + if(err < 0) + return err; + } break; + + default: + return AVERROR(ENOSYS); + } + + return 0; +} + +static int cbs_h2645_write_slice_data(CodedBitstreamContext *ctx, + PutBitContext *pbc, const uint8_t *data, + size_t data_size, int data_bit_start) { + size_t rest = data_size - (data_bit_start + 7) / 8; + const uint8_t *pos = data + data_bit_start / 8; + + av_assert0(data_bit_start >= 0 && + data_size > data_bit_start / 8); + + if(data_size * 8 + 8 > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + if(!rest) + goto rbsp_stop_one_bit; + + // First copy the remaining bits of the first byte + // The above check ensures that we do not accidentally + // copy beyond the rbsp_stop_one_bit. + if(data_bit_start % 8) + put_bits(pbc, 8 - data_bit_start % 8, + *pos++ & MAX_UINT_BITS(8 - data_bit_start % 8)); + + if(put_bits_count(pbc) % 8 == 0) { + // If the writer is aligned at this point, + // memcpy can be used to improve performance. + // This happens normally for CABAC. + flush_put_bits(pbc); + memcpy(put_bits_ptr(pbc), pos, rest); + skip_put_bytes(pbc, rest); + } + else { + // If not, we have to copy manually. + // rbsp_stop_one_bit forces us to special-case + // the last byte. + uint8_t temp; + int i; + + for(; rest > 4; rest -= 4, pos += 4) + put_bits32(pbc, AV_RB32(pos)); + + for(; rest > 1; rest--, pos++) + put_bits(pbc, 8, *pos); + + rbsp_stop_one_bit: + temp = rest ? *pos : *pos & MAX_UINT_BITS(8 - data_bit_start % 8); + + av_assert0(temp); + i = ff_ctz(*pos); + temp = temp >> i; + i = rest ? (8 - i) : (8 - i - data_bit_start % 8); + put_bits(pbc, i, temp); + if(put_bits_count(pbc) % 8) + put_bits(pbc, 8 - put_bits_count(pbc) % 8, 0); + } + + return 0; +} + +static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) { + int err; + + switch(unit->type) { + case H264_NAL_SPS: { + H264RawSPS *sps = unit->content; + + err = cbs_h264_write_sps(ctx, pbc, sps); + if(err < 0) + return err; + + err = cbs_h264_replace_sps(ctx, unit); + if(err < 0) + return err; + } break; + + case H264_NAL_SPS_EXT: { + H264RawSPSExtension *sps_ext = unit->content; + + err = cbs_h264_write_sps_extension(ctx, pbc, sps_ext); + if(err < 0) + return err; + } break; + + case H264_NAL_PPS: { + H264RawPPS *pps = unit->content; + + err = cbs_h264_write_pps(ctx, pbc, pps); + if(err < 0) + return err; + + err = cbs_h264_replace_pps(ctx, unit); + if(err < 0) + return err; + } break; + + case H264_NAL_SLICE: + case H264_NAL_IDR_SLICE: + case H264_NAL_AUXILIARY_SLICE: { + H264RawSlice *slice = unit->content; + + err = cbs_h264_write_slice_header(ctx, pbc, &slice->header); + if(err < 0) + return err; + + if(slice->data) { + err = cbs_h2645_write_slice_data(ctx, pbc, slice->data, + slice->data_size, + slice->data_bit_start); + if(err < 0) + return err; + } + else { + // No slice data - that was just the header. + // (Bitstream may be unaligned!) + } + } break; + + case H264_NAL_AUD: { + err = cbs_h264_write_aud(ctx, pbc, unit->content); + if(err < 0) + return err; + } break; + + case H264_NAL_SEI: { + err = cbs_h264_write_sei(ctx, pbc, unit->content); + if(err < 0) + return err; + } break; + + case H264_NAL_FILLER_DATA: { + err = cbs_h264_write_filler(ctx, pbc, unit->content); + if(err < 0) + return err; + } break; + + case H264_NAL_END_SEQUENCE: { + err = cbs_h264_write_end_of_sequence(ctx, pbc, unit->content); + if(err < 0) + return err; + } break; + + case H264_NAL_END_STREAM: { + err = cbs_h264_write_end_of_stream(ctx, pbc, unit->content); + if(err < 0) + return err; + } break; + + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " + "NAL unit type %" PRIu32 ".\n", + unit->type); + return AVERROR_PATCHWELCOME; + } + + return 0; +} + +static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) { + int err; + + switch(unit->type) { + case HEVC_NAL_VPS: { + H265RawVPS *vps = unit->content; + + err = cbs_h265_write_vps(ctx, pbc, vps); + if(err < 0) + return err; + + err = cbs_h265_replace_vps(ctx, unit); + if(err < 0) + return err; + } break; + + case HEVC_NAL_SPS: { + H265RawSPS *sps = unit->content; + + err = cbs_h265_write_sps(ctx, pbc, sps); + if(err < 0) + return err; + + err = cbs_h265_replace_sps(ctx, unit); + if(err < 0) + return err; + } break; + + case HEVC_NAL_PPS: { + H265RawPPS *pps = unit->content; + + err = cbs_h265_write_pps(ctx, pbc, pps); + if(err < 0) + return err; + + err = cbs_h265_replace_pps(ctx, unit); + if(err < 0) + return err; + } break; + + case HEVC_NAL_TRAIL_N: + case HEVC_NAL_TRAIL_R: + case HEVC_NAL_TSA_N: + case HEVC_NAL_TSA_R: + case HEVC_NAL_STSA_N: + case HEVC_NAL_STSA_R: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RADL_R: + case HEVC_NAL_RASL_N: + case HEVC_NAL_RASL_R: + case HEVC_NAL_BLA_W_LP: + case HEVC_NAL_BLA_W_RADL: + case HEVC_NAL_BLA_N_LP: + case HEVC_NAL_IDR_W_RADL: + case HEVC_NAL_IDR_N_LP: + case HEVC_NAL_CRA_NUT: { + H265RawSlice *slice = unit->content; + + err = cbs_h265_write_slice_segment_header(ctx, pbc, &slice->header); + if(err < 0) + return err; + + if(slice->data) { + err = cbs_h2645_write_slice_data(ctx, pbc, slice->data, + slice->data_size, + slice->data_bit_start); + if(err < 0) + return err; + } + else { + // No slice data - that was just the header. + } + } break; + + case HEVC_NAL_AUD: { + err = cbs_h265_write_aud(ctx, pbc, unit->content); + if(err < 0) + return err; + } break; + + case HEVC_NAL_SEI_PREFIX: + case HEVC_NAL_SEI_SUFFIX: { + err = cbs_h265_write_sei(ctx, pbc, unit->content, + unit->type == HEVC_NAL_SEI_PREFIX); + + if(err < 0) + return err; + } break; + + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " + "NAL unit type %" PRIu32 ".\n", + unit->type); + return AVERROR_PATCHWELCOME; + } + + return 0; +} + +static int cbs_h2645_unit_requires_zero_byte(enum AVCodecID codec_id, + CodedBitstreamUnitType type, + int nal_unit_index) { + // Section B.1.2 in H.264, section B.2.2 in H.265. + if(nal_unit_index == 0) { + // Assume that this is the first NAL unit in an access unit. + return 1; + } + if(codec_id == AV_CODEC_ID_H264) + return type == H264_NAL_SPS || type == H264_NAL_PPS; + if(codec_id == AV_CODEC_ID_HEVC) + return type == HEVC_NAL_VPS || type == HEVC_NAL_SPS || type == HEVC_NAL_PPS; + return 0; +} + +static int cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) { + uint8_t *data; + size_t max_size, dp, sp; + int err, i, zero_run; + + for(i = 0; i < frag->nb_units; i++) { + // Data should already all have been written when we get here. + av_assert0(frag->units[i].data); + } + + max_size = 0; + for(i = 0; i < frag->nb_units; i++) { + // Start code + content with worst-case emulation prevention. + max_size += 4 + frag->units[i].data_size * 3 / 2; + } + + data = av_realloc(NULL, max_size + AV_INPUT_BUFFER_PADDING_SIZE); + if(!data) + return AVERROR(ENOMEM); + + dp = 0; + for(i = 0; i < frag->nb_units; i++) { + CodedBitstreamUnit *unit = &frag->units[i]; + + if(unit->data_bit_padding > 0) { + if(i < frag->nb_units - 1) + av_log(ctx->log_ctx, AV_LOG_WARNING, "Probably invalid " + "unaligned padding on non-final NAL unit.\n"); + else + frag->data_bit_padding = unit->data_bit_padding; + } + + if(cbs_h2645_unit_requires_zero_byte(ctx->codec->codec_id, unit->type, i)) { + // zero_byte + data[dp++] = 0; + } + // start_code_prefix_one_3bytes + data[dp++] = 0; + data[dp++] = 0; + data[dp++] = 1; + + zero_run = 0; + for(sp = 0; sp < unit->data_size; sp++) { + if(zero_run < 2) { + if(unit->data[sp] == 0) + ++zero_run; + else + zero_run = 0; + } + else { + if((unit->data[sp] & ~3) == 0) { + // emulation_prevention_three_byte + data[dp++] = 3; + } + zero_run = unit->data[sp] == 0; + } + data[dp++] = unit->data[sp]; + } + } + + av_assert0(dp <= max_size); + err = av_reallocp(&data, dp + AV_INPUT_BUFFER_PADDING_SIZE); + if(err) + return err; + memset(data + dp, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + frag->data_ref = av_buffer_create(data, dp + AV_INPUT_BUFFER_PADDING_SIZE, + NULL, NULL, 0); + if(!frag->data_ref) { + av_freep(&data); + return AVERROR(ENOMEM); + } + + frag->data = data; + frag->data_size = dp; + + return 0; +} + +static void cbs_h264_flush(CodedBitstreamContext *ctx) { + CodedBitstreamH264Context *h264 = ctx->priv_data; + + for(int i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) { + av_buffer_unref(&h264->sps_ref[i]); + h264->sps[i] = NULL; + } + for(int i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) { + av_buffer_unref(&h264->pps_ref[i]); + h264->pps[i] = NULL; + } + + h264->active_sps = NULL; + h264->active_pps = NULL; + h264->last_slice_nal_unit_type = 0; +} + +static void cbs_h264_close(CodedBitstreamContext *ctx) { + CodedBitstreamH264Context *h264 = ctx->priv_data; + int i; + + ff_h2645_packet_uninit(&h264->common.read_packet); + + for(i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) + av_buffer_unref(&h264->sps_ref[i]); + for(i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) + av_buffer_unref(&h264->pps_ref[i]); +} + +static void cbs_h265_flush(CodedBitstreamContext *ctx) { + CodedBitstreamH265Context *h265 = ctx->priv_data; + + for(int i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) { + av_buffer_unref(&h265->vps_ref[i]); + h265->vps[i] = NULL; + } + for(int i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) { + av_buffer_unref(&h265->sps_ref[i]); + h265->sps[i] = NULL; + } + for(int i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++) { + av_buffer_unref(&h265->pps_ref[i]); + h265->pps[i] = NULL; + } + + h265->active_vps = NULL; + h265->active_sps = NULL; + h265->active_pps = NULL; +} + +static void cbs_h265_close(CodedBitstreamContext *ctx) { + CodedBitstreamH265Context *h265 = ctx->priv_data; + int i; + + ff_h2645_packet_uninit(&h265->common.read_packet); + + for(i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) + av_buffer_unref(&h265->vps_ref[i]); + for(i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) + av_buffer_unref(&h265->sps_ref[i]); + for(i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++) + av_buffer_unref(&h265->pps_ref[i]); +} + +static void cbs_h264_free_sei(void *opaque, uint8_t *content) { + H264RawSEI *sei = (H264RawSEI *)content; + ff_cbs_sei_free_message_list(&sei->message_list); + av_free(content); +} + +static const CodedBitstreamUnitTypeDescriptor cbs_h264_unit_types[] = { + CBS_UNIT_TYPE_POD(H264_NAL_SPS, H264RawSPS), + CBS_UNIT_TYPE_POD(H264_NAL_SPS_EXT, H264RawSPSExtension), + + CBS_UNIT_TYPE_INTERNAL_REF(H264_NAL_PPS, H264RawPPS, slice_group_id), + + { + .nb_unit_types = 3, + .unit_types = { + H264_NAL_IDR_SLICE, + H264_NAL_SLICE, + H264_NAL_AUXILIARY_SLICE, + }, + .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS, + .content_size = sizeof(H264RawSlice), + .nb_ref_offsets = 1, + .ref_offsets = { offsetof(H264RawSlice, data) }, + }, + + CBS_UNIT_TYPE_POD(H264_NAL_AUD, H264RawAUD), CBS_UNIT_TYPE_POD(H264_NAL_FILLER_DATA, H264RawFiller), CBS_UNIT_TYPE_POD(H264_NAL_END_SEQUENCE, H264RawNALUnitHeader), CBS_UNIT_TYPE_POD(H264_NAL_END_STREAM, H264RawNALUnitHeader), + + CBS_UNIT_TYPE_COMPLEX(H264_NAL_SEI, H264RawSEI, &cbs_h264_free_sei), + + CBS_UNIT_TYPE_END_OF_LIST +}; + +static void cbs_h265_free_sei(void *opaque, uint8_t *content) { + H265RawSEI *sei = (H265RawSEI *)content; + ff_cbs_sei_free_message_list(&sei->message_list); + av_free(content); +} + +static const CodedBitstreamUnitTypeDescriptor cbs_h265_unit_types[] = { + CBS_UNIT_TYPE_INTERNAL_REF(HEVC_NAL_VPS, H265RawVPS, extension_data.data), + CBS_UNIT_TYPE_INTERNAL_REF(HEVC_NAL_SPS, H265RawSPS, extension_data.data), + CBS_UNIT_TYPE_INTERNAL_REF(HEVC_NAL_PPS, H265RawPPS, extension_data.data), + + CBS_UNIT_TYPE_POD(HEVC_NAL_AUD, H265RawAUD), + + { + // Slices of non-IRAP pictures. + .nb_unit_types = CBS_UNIT_TYPE_RANGE, + .unit_type_range_start = HEVC_NAL_TRAIL_N, + .unit_type_range_end = HEVC_NAL_RASL_R, + + .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS, + .content_size = sizeof(H265RawSlice), + .nb_ref_offsets = 1, + .ref_offsets = { offsetof(H265RawSlice, data) }, + }, + + { + // Slices of IRAP pictures. + .nb_unit_types = CBS_UNIT_TYPE_RANGE, + .unit_type_range_start = HEVC_NAL_BLA_W_LP, + .unit_type_range_end = HEVC_NAL_CRA_NUT, + + .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS, + .content_size = sizeof(H265RawSlice), + .nb_ref_offsets = 1, + .ref_offsets = { offsetof(H265RawSlice, data) }, + }, + + { + .nb_unit_types = 2, + .unit_types = { + HEVC_NAL_SEI_PREFIX, + HEVC_NAL_SEI_SUFFIX }, + .content_type = CBS_CONTENT_TYPE_COMPLEX, + .content_size = sizeof(H265RawSEI), + .content_free = &cbs_h265_free_sei, + }, + + CBS_UNIT_TYPE_END_OF_LIST +}; + +const CodedBitstreamType ff_cbs_type_h264 = { + .codec_id = AV_CODEC_ID_H264, + + .priv_data_size = sizeof(CodedBitstreamH264Context), + + .unit_types = cbs_h264_unit_types, + + .split_fragment = &cbs_h2645_split_fragment, + .read_unit = &cbs_h264_read_nal_unit, + .write_unit = &cbs_h264_write_nal_unit, + .assemble_fragment = &cbs_h2645_assemble_fragment, + + .flush = &cbs_h264_flush, + .close = &cbs_h264_close, +}; + +const CodedBitstreamType ff_cbs_type_h265 = { + .codec_id = AV_CODEC_ID_HEVC, + + .priv_data_size = sizeof(CodedBitstreamH265Context), + + .unit_types = cbs_h265_unit_types, + + .split_fragment = &cbs_h2645_split_fragment, + .read_unit = &cbs_h265_read_nal_unit, + .write_unit = &cbs_h265_write_nal_unit, + .assemble_fragment = &cbs_h2645_assemble_fragment, + + .flush = &cbs_h265_flush, + .close = &cbs_h265_close, +}; + +static const SEIMessageTypeDescriptor cbs_sei_common_types[] = { + { + SEI_TYPE_FILLER_PAYLOAD, + 1, + 1, + sizeof(SEIRawFillerPayload), + SEI_MESSAGE_RW(sei, filler_payload), + }, + { + SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35, + 1, + 1, + sizeof(SEIRawUserDataRegistered), + SEI_MESSAGE_RW(sei, user_data_registered), + }, + { + SEI_TYPE_USER_DATA_UNREGISTERED, + 1, + 1, + sizeof(SEIRawUserDataUnregistered), + SEI_MESSAGE_RW(sei, user_data_unregistered), + }, + { + SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME, + 1, + 0, + sizeof(SEIRawMasteringDisplayColourVolume), + SEI_MESSAGE_RW(sei, mastering_display_colour_volume), + }, + { + SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO, + 1, + 0, + sizeof(SEIRawContentLightLevelInfo), + SEI_MESSAGE_RW(sei, content_light_level_info), + }, + { + SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS, + 1, + 0, + sizeof(SEIRawAlternativeTransferCharacteristics), + SEI_MESSAGE_RW(sei, alternative_transfer_characteristics), + }, + SEI_MESSAGE_TYPE_END, +}; + +static const SEIMessageTypeDescriptor cbs_sei_h264_types[] = { + { + SEI_TYPE_BUFFERING_PERIOD, + 1, + 0, + sizeof(H264RawSEIBufferingPeriod), + SEI_MESSAGE_RW(h264, sei_buffering_period), + }, + { + SEI_TYPE_PIC_TIMING, + 1, + 0, + sizeof(H264RawSEIPicTiming), + SEI_MESSAGE_RW(h264, sei_pic_timing), + }, + { + SEI_TYPE_PAN_SCAN_RECT, + 1, + 0, + sizeof(H264RawSEIPanScanRect), + SEI_MESSAGE_RW(h264, sei_pan_scan_rect), + }, + { + SEI_TYPE_RECOVERY_POINT, + 1, + 0, + sizeof(H264RawSEIRecoveryPoint), + SEI_MESSAGE_RW(h264, sei_recovery_point), + }, + { + SEI_TYPE_DISPLAY_ORIENTATION, + 1, + 0, + sizeof(H264RawSEIDisplayOrientation), + SEI_MESSAGE_RW(h264, sei_display_orientation), + }, + SEI_MESSAGE_TYPE_END +}; + +static const SEIMessageTypeDescriptor cbs_sei_h265_types[] = { + { + SEI_TYPE_BUFFERING_PERIOD, + 1, + 0, + sizeof(H265RawSEIBufferingPeriod), + SEI_MESSAGE_RW(h265, sei_buffering_period), + }, + { + SEI_TYPE_PIC_TIMING, + 1, + 0, + sizeof(H265RawSEIPicTiming), + SEI_MESSAGE_RW(h265, sei_pic_timing), + }, + { + SEI_TYPE_PAN_SCAN_RECT, + 1, + 0, + sizeof(H265RawSEIPanScanRect), + SEI_MESSAGE_RW(h265, sei_pan_scan_rect), + }, + { + SEI_TYPE_RECOVERY_POINT, + 1, + 0, + sizeof(H265RawSEIRecoveryPoint), + SEI_MESSAGE_RW(h265, sei_recovery_point), + }, + { + SEI_TYPE_DISPLAY_ORIENTATION, + 1, + 0, + sizeof(H265RawSEIDisplayOrientation), + SEI_MESSAGE_RW(h265, sei_display_orientation), + }, + { + SEI_TYPE_ACTIVE_PARAMETER_SETS, + 1, + 0, + sizeof(H265RawSEIActiveParameterSets), + SEI_MESSAGE_RW(h265, sei_active_parameter_sets), + }, + { + SEI_TYPE_DECODED_PICTURE_HASH, + 0, + 1, + sizeof(H265RawSEIDecodedPictureHash), + SEI_MESSAGE_RW(h265, sei_decoded_picture_hash), + }, + { + SEI_TYPE_TIME_CODE, + 1, + 0, + sizeof(H265RawSEITimeCode), + SEI_MESSAGE_RW(h265, sei_time_code), + }, + { + SEI_TYPE_ALPHA_CHANNEL_INFO, + 1, + 0, + sizeof(H265RawSEIAlphaChannelInfo), + SEI_MESSAGE_RW(h265, sei_alpha_channel_info), + }, + SEI_MESSAGE_TYPE_END +}; + +const SEIMessageTypeDescriptor *ff_cbs_sei_find_type(CodedBitstreamContext *ctx, + int payload_type) { + const SEIMessageTypeDescriptor *codec_list; + int i; + + for(i = 0; cbs_sei_common_types[i].type >= 0; i++) { + if(cbs_sei_common_types[i].type == payload_type) + return &cbs_sei_common_types[i]; + } + + switch(ctx->codec->codec_id) { + case AV_CODEC_ID_H264: + codec_list = cbs_sei_h264_types; + break; + case AV_CODEC_ID_H265: + codec_list = cbs_sei_h265_types; + break; + default: + return NULL; + } + + for(i = 0; codec_list[i].type >= 0; i++) { + if(codec_list[i].type == payload_type) + return &codec_list[i]; + } + + return NULL; +} diff --git a/third-party/cbs/cbs_h264_syntax_template.c b/third-party/cbs/cbs_h264_syntax_template.c new file mode 100644 index 00000000..a2d3735b --- /dev/null +++ b/third-party/cbs/cbs_h264_syntax_template.c @@ -0,0 +1,1175 @@ +/* + * 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, + H264RawNALUnitHeader *current, + uint32_t valid_type_mask) { + int err; + + fixed(1, forbidden_zero_bit, 0); + ub(2, nal_ref_idc); + ub(5, nal_unit_type); + + if(!(1 << current->nal_unit_type & valid_type_mask)) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid NAL unit type %d.\n", + current->nal_unit_type); + return AVERROR_INVALIDDATA; + } + + if(current->nal_unit_type == 14 || + current->nal_unit_type == 20 || + current->nal_unit_type == 21) { + if(current->nal_unit_type != 21) + flag(svc_extension_flag); + else + flag(avc_3d_extension_flag); + + if(current->svc_extension_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SVC not supported.\n"); + return AVERROR_PATCHWELCOME; + } + else if(current->avc_3d_extension_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "3DAVC not supported.\n"); + return AVERROR_PATCHWELCOME; + } + else { + av_log(ctx->log_ctx, AV_LOG_ERROR, "MVC not supported.\n"); + return AVERROR_PATCHWELCOME; + } + } + + return 0; +} + +static int FUNC(scaling_list)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawScalingList *current, + int size_of_scaling_list) { + int err, i, scale; + + scale = 8; + for(i = 0; i < size_of_scaling_list; i++) { + ses(delta_scale[i], -128, +127, 1, i); + scale = (scale + current->delta_scale[i] + 256) % 256; + if(scale == 0) + break; + } + + return 0; +} + +static int FUNC(hrd_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawHRD *current) { + int err, i; + + ue(cpb_cnt_minus1, 0, 31); + ub(4, bit_rate_scale); + ub(4, cpb_size_scale); + + for(i = 0; i <= current->cpb_cnt_minus1; i++) { + ues(bit_rate_value_minus1[i], 0, UINT32_MAX - 1, 1, i); + ues(cpb_size_value_minus1[i], 0, UINT32_MAX - 1, 1, i); + flags(cbr_flag[i], 1, i); + } + + ub(5, initial_cpb_removal_delay_length_minus1); + ub(5, cpb_removal_delay_length_minus1); + ub(5, dpb_output_delay_length_minus1); + ub(5, time_offset_length); + + return 0; +} + +static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawVUI *current, H264RawSPS *sps) { + int err; + + flag(aspect_ratio_info_present_flag); + if(current->aspect_ratio_info_present_flag) { + ub(8, aspect_ratio_idc); + if(current->aspect_ratio_idc == 255) { + ub(16, sar_width); + ub(16, sar_height); + } + } + else { + infer(aspect_ratio_idc, 0); + } + + flag(overscan_info_present_flag); + if(current->overscan_info_present_flag) + flag(overscan_appropriate_flag); + + flag(video_signal_type_present_flag); + if(current->video_signal_type_present_flag) { + ub(3, video_format); + flag(video_full_range_flag); + flag(colour_description_present_flag); + if(current->colour_description_present_flag) { + ub(8, colour_primaries); + ub(8, transfer_characteristics); + ub(8, matrix_coefficients); + } + else { + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + } + } + else { + infer(video_format, 5); + infer(video_full_range_flag, 0); + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + } + + flag(chroma_loc_info_present_flag); + if(current->chroma_loc_info_present_flag) { + ue(chroma_sample_loc_type_top_field, 0, 5); + ue(chroma_sample_loc_type_bottom_field, 0, 5); + } + else { + infer(chroma_sample_loc_type_top_field, 0); + infer(chroma_sample_loc_type_bottom_field, 0); + } + + flag(timing_info_present_flag); + if(current->timing_info_present_flag) { + u(32, num_units_in_tick, 1, UINT32_MAX); + u(32, time_scale, 1, UINT32_MAX); + flag(fixed_frame_rate_flag); + } + else { + infer(fixed_frame_rate_flag, 0); + } + + flag(nal_hrd_parameters_present_flag); + if(current->nal_hrd_parameters_present_flag) + CHECK(FUNC(hrd_parameters)(ctx, rw, ¤t->nal_hrd_parameters)); + + flag(vcl_hrd_parameters_present_flag); + if(current->vcl_hrd_parameters_present_flag) + CHECK(FUNC(hrd_parameters)(ctx, rw, ¤t->vcl_hrd_parameters)); + + if(current->nal_hrd_parameters_present_flag || + current->vcl_hrd_parameters_present_flag) + flag(low_delay_hrd_flag); + else + infer(low_delay_hrd_flag, 1 - current->fixed_frame_rate_flag); + + flag(pic_struct_present_flag); + + flag(bitstream_restriction_flag); + if(current->bitstream_restriction_flag) { + flag(motion_vectors_over_pic_boundaries_flag); + ue(max_bytes_per_pic_denom, 0, 16); + ue(max_bits_per_mb_denom, 0, 16); + // The current version of the standard constrains this to be in + // [0,15], but older versions allow 16. + ue(log2_max_mv_length_horizontal, 0, 16); + ue(log2_max_mv_length_vertical, 0, 16); + ue(max_num_reorder_frames, 0, H264_MAX_DPB_FRAMES); + ue(max_dec_frame_buffering, 0, H264_MAX_DPB_FRAMES); + } + else { + infer(motion_vectors_over_pic_boundaries_flag, 1); + infer(max_bytes_per_pic_denom, 2); + infer(max_bits_per_mb_denom, 1); + infer(log2_max_mv_length_horizontal, 15); + infer(log2_max_mv_length_vertical, 15); + + if((sps->profile_idc == 44 || sps->profile_idc == 86 || + sps->profile_idc == 100 || sps->profile_idc == 110 || + sps->profile_idc == 122 || sps->profile_idc == 244) && + sps->constraint_set3_flag) { + infer(max_num_reorder_frames, 0); + infer(max_dec_frame_buffering, 0); + } + else { + infer(max_num_reorder_frames, H264_MAX_DPB_FRAMES); + infer(max_dec_frame_buffering, H264_MAX_DPB_FRAMES); + } + } + + return 0; +} + +static int FUNC(vui_parameters_default)(CodedBitstreamContext *ctx, + RWContext *rw, H264RawVUI *current, + H264RawSPS *sps) { + infer(aspect_ratio_idc, 0); + + infer(video_format, 5); + infer(video_full_range_flag, 0); + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + + infer(chroma_sample_loc_type_top_field, 0); + infer(chroma_sample_loc_type_bottom_field, 0); + + infer(fixed_frame_rate_flag, 0); + infer(low_delay_hrd_flag, 1); + + infer(pic_struct_present_flag, 0); + + infer(motion_vectors_over_pic_boundaries_flag, 1); + infer(max_bytes_per_pic_denom, 2); + infer(max_bits_per_mb_denom, 1); + infer(log2_max_mv_length_horizontal, 15); + infer(log2_max_mv_length_vertical, 15); + + if((sps->profile_idc == 44 || sps->profile_idc == 86 || + sps->profile_idc == 100 || sps->profile_idc == 110 || + sps->profile_idc == 122 || sps->profile_idc == 244) && + sps->constraint_set3_flag) { + infer(max_num_reorder_frames, 0); + infer(max_dec_frame_buffering, 0); + } + else { + infer(max_num_reorder_frames, H264_MAX_DPB_FRAMES); + infer(max_dec_frame_buffering, H264_MAX_DPB_FRAMES); + } + + return 0; +} + +static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSPS *current) { + int err, i; + + HEADER("Sequence Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_SPS)); + + ub(8, profile_idc); + + flag(constraint_set0_flag); + flag(constraint_set1_flag); + flag(constraint_set2_flag); + flag(constraint_set3_flag); + flag(constraint_set4_flag); + flag(constraint_set5_flag); + + u(2, reserved_zero_2bits, 0, 0); + + ub(8, level_idc); + + ue(seq_parameter_set_id, 0, 31); + + if(current->profile_idc == 100 || current->profile_idc == 110 || + current->profile_idc == 122 || current->profile_idc == 244 || + current->profile_idc == 44 || current->profile_idc == 83 || + current->profile_idc == 86 || current->profile_idc == 118 || + current->profile_idc == 128 || current->profile_idc == 138) { + ue(chroma_format_idc, 0, 3); + + if(current->chroma_format_idc == 3) + flag(separate_colour_plane_flag); + else + infer(separate_colour_plane_flag, 0); + + ue(bit_depth_luma_minus8, 0, 6); + ue(bit_depth_chroma_minus8, 0, 6); + + flag(qpprime_y_zero_transform_bypass_flag); + + flag(seq_scaling_matrix_present_flag); + if(current->seq_scaling_matrix_present_flag) { + for(i = 0; i < ((current->chroma_format_idc != 3) ? 8 : 12); i++) { + flags(seq_scaling_list_present_flag[i], 1, i); + if(current->seq_scaling_list_present_flag[i]) { + if(i < 6) + CHECK(FUNC(scaling_list)(ctx, rw, + ¤t->scaling_list_4x4[i], + 16)); + else + CHECK(FUNC(scaling_list)(ctx, rw, + ¤t->scaling_list_8x8[i - 6], + 64)); + } + } + } + } + else { + infer(chroma_format_idc, current->profile_idc == 183 ? 0 : 1); + + infer(separate_colour_plane_flag, 0); + infer(bit_depth_luma_minus8, 0); + infer(bit_depth_chroma_minus8, 0); + } + + ue(log2_max_frame_num_minus4, 0, 12); + ue(pic_order_cnt_type, 0, 2); + + if(current->pic_order_cnt_type == 0) { + ue(log2_max_pic_order_cnt_lsb_minus4, 0, 12); + } + else if(current->pic_order_cnt_type == 1) { + flag(delta_pic_order_always_zero_flag); + se(offset_for_non_ref_pic, INT32_MIN + 1, INT32_MAX); + se(offset_for_top_to_bottom_field, INT32_MIN + 1, INT32_MAX); + ue(num_ref_frames_in_pic_order_cnt_cycle, 0, 255); + + for(i = 0; i < current->num_ref_frames_in_pic_order_cnt_cycle; i++) + ses(offset_for_ref_frame[i], INT32_MIN + 1, INT32_MAX, 1, i); + } + + ue(max_num_ref_frames, 0, H264_MAX_DPB_FRAMES); + flag(gaps_in_frame_num_allowed_flag); + + ue(pic_width_in_mbs_minus1, 0, H264_MAX_MB_WIDTH); + ue(pic_height_in_map_units_minus1, 0, H264_MAX_MB_HEIGHT); + + flag(frame_mbs_only_flag); + if(!current->frame_mbs_only_flag) + flag(mb_adaptive_frame_field_flag); + + flag(direct_8x8_inference_flag); + + flag(frame_cropping_flag); + if(current->frame_cropping_flag) { + ue(frame_crop_left_offset, 0, H264_MAX_WIDTH); + ue(frame_crop_right_offset, 0, H264_MAX_WIDTH); + ue(frame_crop_top_offset, 0, H264_MAX_HEIGHT); + ue(frame_crop_bottom_offset, 0, H264_MAX_HEIGHT); + } + + flag(vui_parameters_present_flag); + if(current->vui_parameters_present_flag) + CHECK(FUNC(vui_parameters)(ctx, rw, ¤t->vui, current)); + else + CHECK(FUNC(vui_parameters_default)(ctx, rw, ¤t->vui, current)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(sps_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSPSExtension *current) { + int err; + + HEADER("Sequence Parameter Set Extension"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_SPS_EXT)); + + ue(seq_parameter_set_id, 0, 31); + + ue(aux_format_idc, 0, 3); + + if(current->aux_format_idc != 0) { + int bits; + + ue(bit_depth_aux_minus8, 0, 4); + flag(alpha_incr_flag); + + bits = current->bit_depth_aux_minus8 + 9; + ub(bits, alpha_opaque_value); + ub(bits, alpha_transparent_value); + } + + flag(additional_extension_flag); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawPPS *current) { + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps; + int err, i; + + HEADER("Picture Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_PPS)); + + ue(pic_parameter_set_id, 0, 255); + ue(seq_parameter_set_id, 0, 31); + + sps = h264->sps[current->seq_parameter_set_id]; + if(!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + current->seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + + flag(entropy_coding_mode_flag); + flag(bottom_field_pic_order_in_frame_present_flag); + + ue(num_slice_groups_minus1, 0, 7); + if(current->num_slice_groups_minus1 > 0) { + unsigned int pic_size; + int iGroup; + + pic_size = (sps->pic_width_in_mbs_minus1 + 1) * + (sps->pic_height_in_map_units_minus1 + 1); + + ue(slice_group_map_type, 0, 6); + + if(current->slice_group_map_type == 0) { + for(iGroup = 0; iGroup <= current->num_slice_groups_minus1; iGroup++) + ues(run_length_minus1[iGroup], 0, pic_size - 1, 1, iGroup); + } + else if(current->slice_group_map_type == 2) { + for(iGroup = 0; iGroup < current->num_slice_groups_minus1; iGroup++) { + ues(top_left[iGroup], 0, pic_size - 1, 1, iGroup); + ues(bottom_right[iGroup], + current->top_left[iGroup], pic_size - 1, 1, iGroup); + } + } + else if(current->slice_group_map_type == 3 || + current->slice_group_map_type == 4 || + current->slice_group_map_type == 5) { + flag(slice_group_change_direction_flag); + ue(slice_group_change_rate_minus1, 0, pic_size - 1); + } + else if(current->slice_group_map_type == 6) { + ue(pic_size_in_map_units_minus1, pic_size - 1, pic_size - 1); + + allocate(current->slice_group_id, + current->pic_size_in_map_units_minus1 + 1); + for(i = 0; i <= current->pic_size_in_map_units_minus1; i++) + us(av_log2(2 * current->num_slice_groups_minus1 + 1), + slice_group_id[i], 0, current->num_slice_groups_minus1, 1, i); + } + } + + ue(num_ref_idx_l0_default_active_minus1, 0, 31); + ue(num_ref_idx_l1_default_active_minus1, 0, 31); + + flag(weighted_pred_flag); + u(2, weighted_bipred_idc, 0, 2); + + se(pic_init_qp_minus26, -26 - 6 * sps->bit_depth_luma_minus8, +25); + se(pic_init_qs_minus26, -26, +25); + se(chroma_qp_index_offset, -12, +12); + + flag(deblocking_filter_control_present_flag); + flag(constrained_intra_pred_flag); + flag(redundant_pic_cnt_present_flag); + + if(more_rbsp_data(current->more_rbsp_data)) { + flag(transform_8x8_mode_flag); + + flag(pic_scaling_matrix_present_flag); + if(current->pic_scaling_matrix_present_flag) { + for(i = 0; i < 6 + (((sps->chroma_format_idc != 3) ? 2 : 6) * + current->transform_8x8_mode_flag); + i++) { + flags(pic_scaling_list_present_flag[i], 1, i); + if(current->pic_scaling_list_present_flag[i]) { + if(i < 6) + CHECK(FUNC(scaling_list)(ctx, rw, + ¤t->scaling_list_4x4[i], + 16)); + else + CHECK(FUNC(scaling_list)(ctx, rw, + ¤t->scaling_list_8x8[i - 6], + 64)); + } + } + } + + se(second_chroma_qp_index_offset, -12, +12); + } + else { + infer(transform_8x8_mode_flag, 0); + infer(pic_scaling_matrix_present_flag, 0); + infer(second_chroma_qp_index_offset, current->chroma_qp_index_offset); + } + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(sei_buffering_period)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIBufferingPeriod *current, + SEIMessageState *sei) { + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps; + int err, i, length; + + HEADER("Buffering Period"); + + ue(seq_parameter_set_id, 0, 31); + + sps = h264->sps[current->seq_parameter_set_id]; + if(!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + current->seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h264->active_sps = sps; + + if(sps->vui.nal_hrd_parameters_present_flag) { + for(i = 0; i <= sps->vui.nal_hrd_parameters.cpb_cnt_minus1; i++) { + length = sps->vui.nal_hrd_parameters.initial_cpb_removal_delay_length_minus1 + 1; + xu(length, initial_cpb_removal_delay[SchedSelIdx], + current->nal.initial_cpb_removal_delay[i], + 1, MAX_UINT_BITS(length), 1, i); + xu(length, initial_cpb_removal_delay_offset[SchedSelIdx], + current->nal.initial_cpb_removal_delay_offset[i], + 0, MAX_UINT_BITS(length), 1, i); + } + } + + if(sps->vui.vcl_hrd_parameters_present_flag) { + for(i = 0; i <= sps->vui.vcl_hrd_parameters.cpb_cnt_minus1; i++) { + length = sps->vui.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1 + 1; + xu(length, initial_cpb_removal_delay[SchedSelIdx], + current->vcl.initial_cpb_removal_delay[i], + 1, MAX_UINT_BITS(length), 1, i); + xu(length, initial_cpb_removal_delay_offset[SchedSelIdx], + current->vcl.initial_cpb_removal_delay_offset[i], + 0, MAX_UINT_BITS(length), 1, i); + } + } + + return 0; +} + +static int FUNC(sei_pic_timestamp)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIPicTimestamp *current, + const H264RawSPS *sps) { + uint8_t time_offset_length; + int err; + + u(2, ct_type, 0, 2); + flag(nuit_field_based_flag); + u(5, counting_type, 0, 6); + flag(full_timestamp_flag); + flag(discontinuity_flag); + flag(cnt_dropped_flag); + ub(8, n_frames); + if(current->full_timestamp_flag) { + u(6, seconds_value, 0, 59); + u(6, minutes_value, 0, 59); + u(5, hours_value, 0, 23); + } + else { + flag(seconds_flag); + if(current->seconds_flag) { + u(6, seconds_value, 0, 59); + flag(minutes_flag); + if(current->minutes_flag) { + u(6, minutes_value, 0, 59); + flag(hours_flag); + if(current->hours_flag) + u(5, hours_value, 0, 23); + } + } + } + + if(sps->vui.nal_hrd_parameters_present_flag) + time_offset_length = sps->vui.nal_hrd_parameters.time_offset_length; + else if(sps->vui.vcl_hrd_parameters_present_flag) + time_offset_length = sps->vui.vcl_hrd_parameters.time_offset_length; + else + time_offset_length = 24; + + if(time_offset_length > 0) + ib(time_offset_length, time_offset); + else + infer(time_offset, 0); + + return 0; +} + +static int FUNC(sei_pic_timing)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIPicTiming *current, + SEIMessageState *sei) { + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps; + int err; + + HEADER("Picture Timing"); + + sps = h264->active_sps; + if(!sps) { + // If there is exactly one possible SPS but it is not yet active + // then just assume that it should be the active one. + int i, k = -1; + for(i = 0; i < H264_MAX_SPS_COUNT; i++) { + if(h264->sps[i]) { + if(k >= 0) { + k = -1; + break; + } + k = i; + } + } + if(k >= 0) + sps = h264->sps[k]; + } + if(!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "No active SPS for pic_timing.\n"); + return AVERROR_INVALIDDATA; + } + + if(sps->vui.nal_hrd_parameters_present_flag || + sps->vui.vcl_hrd_parameters_present_flag) { + const H264RawHRD *hrd; + + if(sps->vui.nal_hrd_parameters_present_flag) + hrd = &sps->vui.nal_hrd_parameters; + else if(sps->vui.vcl_hrd_parameters_present_flag) + hrd = &sps->vui.vcl_hrd_parameters; + else { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "No HRD parameters for pic_timing.\n"); + return AVERROR_INVALIDDATA; + } + + ub(hrd->cpb_removal_delay_length_minus1 + 1, cpb_removal_delay); + ub(hrd->dpb_output_delay_length_minus1 + 1, dpb_output_delay); + } + + if(sps->vui.pic_struct_present_flag) { + static const uint8_t num_clock_ts[9] = { + 1, 1, 1, 2, 2, 3, 3, 2, 3 + }; + int i; + + u(4, pic_struct, 0, 8); + if(current->pic_struct > 8) + return AVERROR_INVALIDDATA; + + for(i = 0; i < num_clock_ts[current->pic_struct]; i++) { + flags(clock_timestamp_flag[i], 1, i); + if(current->clock_timestamp_flag[i]) + CHECK(FUNC(sei_pic_timestamp)(ctx, rw, + ¤t->timestamp[i], sps)); + } + } + + return 0; +} + +static int FUNC(sei_pan_scan_rect)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIPanScanRect *current, + SEIMessageState *sei) { + int err, i; + + HEADER("Pan-Scan Rectangle"); + + ue(pan_scan_rect_id, 0, UINT32_MAX - 1); + flag(pan_scan_rect_cancel_flag); + + if(!current->pan_scan_rect_cancel_flag) { + ue(pan_scan_cnt_minus1, 0, 2); + + for(i = 0; i <= current->pan_scan_cnt_minus1; i++) { + ses(pan_scan_rect_left_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + ses(pan_scan_rect_right_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + ses(pan_scan_rect_top_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + ses(pan_scan_rect_bottom_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + } + + ue(pan_scan_rect_repetition_period, 0, 16384); + } + + return 0; +} + +static int FUNC(sei_recovery_point)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIRecoveryPoint *current, + SEIMessageState *sei) { + int err; + + HEADER("Recovery Point"); + + ue(recovery_frame_cnt, 0, 65535); + flag(exact_match_flag); + flag(broken_link_flag); + u(2, changing_slice_group_idc, 0, 2); + + return 0; +} + +static int FUNC(sei_display_orientation)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIDisplayOrientation *current, + SEIMessageState *sei) { + int err; + + HEADER("Display Orientation"); + + flag(display_orientation_cancel_flag); + if(!current->display_orientation_cancel_flag) { + flag(hor_flip); + flag(ver_flip); + ub(16, anticlockwise_rotation); + ue(display_orientation_repetition_period, 0, 16384); + flag(display_orientation_extension_flag); + } + + return 0; +} + +static int FUNC(sei)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEI *current) { + int err; + + HEADER("Supplemental Enhancement Information"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_SEI)); + + CHECK(FUNC_SEI(message_list)(ctx, rw, ¤t->message_list, 1)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(aud)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawAUD *current) { + int err; + + HEADER("Access Unit Delimiter"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_AUD)); + + ub(3, primary_pic_type); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(ref_pic_list_modification)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSliceHeader *current) { + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps = h264->active_sps; + int err, i, mopn; + + if(current->slice_type % 5 != 2 && + current->slice_type % 5 != 4) { + flag(ref_pic_list_modification_flag_l0); + if(current->ref_pic_list_modification_flag_l0) { + for(i = 0; i < H264_MAX_RPLM_COUNT; i++) { + xue(modification_of_pic_nums_idc, + current->rplm_l0[i].modification_of_pic_nums_idc, 0, 3, 0); + + mopn = current->rplm_l0[i].modification_of_pic_nums_idc; + if(mopn == 3) + break; + + if(mopn == 0 || mopn == 1) + xue(abs_diff_pic_num_minus1, + current->rplm_l0[i].abs_diff_pic_num_minus1, + 0, (1 + current->field_pic_flag) * (1 << (sps->log2_max_frame_num_minus4 + 4)), 0); + else if(mopn == 2) + xue(long_term_pic_num, + current->rplm_l0[i].long_term_pic_num, + 0, sps->max_num_ref_frames - 1, 0); + } + } + } + + if(current->slice_type % 5 == 1) { + flag(ref_pic_list_modification_flag_l1); + if(current->ref_pic_list_modification_flag_l1) { + for(i = 0; i < H264_MAX_RPLM_COUNT; i++) { + xue(modification_of_pic_nums_idc, + current->rplm_l1[i].modification_of_pic_nums_idc, 0, 3, 0); + + mopn = current->rplm_l1[i].modification_of_pic_nums_idc; + if(mopn == 3) + break; + + if(mopn == 0 || mopn == 1) + xue(abs_diff_pic_num_minus1, + current->rplm_l1[i].abs_diff_pic_num_minus1, + 0, (1 + current->field_pic_flag) * (1 << (sps->log2_max_frame_num_minus4 + 4)), 0); + else if(mopn == 2) + xue(long_term_pic_num, + current->rplm_l1[i].long_term_pic_num, + 0, sps->max_num_ref_frames - 1, 0); + } + } + } + + return 0; +} + +static int FUNC(pred_weight_table)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSliceHeader *current) { + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps = h264->active_sps; + int chroma; + int err, i, j; + + ue(luma_log2_weight_denom, 0, 7); + + chroma = !sps->separate_colour_plane_flag && sps->chroma_format_idc != 0; + if(chroma) + ue(chroma_log2_weight_denom, 0, 7); + + for(i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { + flags(luma_weight_l0_flag[i], 1, i); + if(current->luma_weight_l0_flag[i]) { + ses(luma_weight_l0[i], -128, +127, 1, i); + ses(luma_offset_l0[i], -128, +127, 1, i); + } + if(chroma) { + flags(chroma_weight_l0_flag[i], 1, i); + if(current->chroma_weight_l0_flag[i]) { + for(j = 0; j < 2; j++) { + ses(chroma_weight_l0[i][j], -128, +127, 2, i, j); + ses(chroma_offset_l0[i][j], -128, +127, 2, i, j); + } + } + } + } + + if(current->slice_type % 5 == 1) { + for(i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { + flags(luma_weight_l1_flag[i], 1, i); + if(current->luma_weight_l1_flag[i]) { + ses(luma_weight_l1[i], -128, +127, 1, i); + ses(luma_offset_l1[i], -128, +127, 1, i); + } + if(chroma) { + flags(chroma_weight_l1_flag[i], 1, i); + if(current->chroma_weight_l1_flag[i]) { + for(j = 0; j < 2; j++) { + ses(chroma_weight_l1[i][j], -128, +127, 2, i, j); + ses(chroma_offset_l1[i][j], -128, +127, 2, i, j); + } + } + } + } + } + + return 0; +} + +static int FUNC(dec_ref_pic_marking)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSliceHeader *current, int idr_pic_flag) { + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps = h264->active_sps; + int err, i; + uint32_t mmco; + + if(idr_pic_flag) { + flag(no_output_of_prior_pics_flag); + flag(long_term_reference_flag); + } + else { + flag(adaptive_ref_pic_marking_mode_flag); + if(current->adaptive_ref_pic_marking_mode_flag) { + for(i = 0; i < H264_MAX_MMCO_COUNT; i++) { + xue(memory_management_control_operation, + current->mmco[i].memory_management_control_operation, + 0, 6, 0); + + mmco = current->mmco[i].memory_management_control_operation; + if(mmco == 0) + break; + + if(mmco == 1 || mmco == 3) + xue(difference_of_pic_nums_minus1, + current->mmco[i].difference_of_pic_nums_minus1, + 0, INT32_MAX, 0); + if(mmco == 2) + xue(long_term_pic_num, + current->mmco[i].long_term_pic_num, + 0, sps->max_num_ref_frames - 1, 0); + if(mmco == 3 || mmco == 6) + xue(long_term_frame_idx, + current->mmco[i].long_term_frame_idx, + 0, sps->max_num_ref_frames - 1, 0); + if(mmco == 4) + xue(max_long_term_frame_idx_plus1, + current->mmco[i].max_long_term_frame_idx_plus1, + 0, sps->max_num_ref_frames, 0); + } + if(i == H264_MAX_MMCO_COUNT) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many " + "memory management control operations.\n"); + return AVERROR_INVALIDDATA; + } + } + } + + return 0; +} + +static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSliceHeader *current) { + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps; + const H264RawPPS *pps; + int err; + int idr_pic_flag; + int slice_type_i, slice_type_p, slice_type_b; + int slice_type_si, slice_type_sp; + + HEADER("Slice Header"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_SLICE | + 1 << H264_NAL_IDR_SLICE | + 1 << H264_NAL_AUXILIARY_SLICE)); + + if(current->nal_unit_header.nal_unit_type == H264_NAL_AUXILIARY_SLICE) { + if(!h264->last_slice_nal_unit_type) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Auxiliary slice " + "is not decodable without the main picture " + "in the same access unit.\n"); + return AVERROR_INVALIDDATA; + } + idr_pic_flag = h264->last_slice_nal_unit_type == H264_NAL_IDR_SLICE; + } + else { + idr_pic_flag = current->nal_unit_header.nal_unit_type == H264_NAL_IDR_SLICE; + } + + ue(first_mb_in_slice, 0, H264_MAX_MB_PIC_SIZE - 1); + ue(slice_type, 0, 9); + + slice_type_i = current->slice_type % 5 == 2; + slice_type_p = current->slice_type % 5 == 0; + slice_type_b = current->slice_type % 5 == 1; + slice_type_si = current->slice_type % 5 == 4; + slice_type_sp = current->slice_type % 5 == 3; + + if(idr_pic_flag && !(slice_type_i || slice_type_si)) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid slice type %d " + "for IDR picture.\n", + current->slice_type); + return AVERROR_INVALIDDATA; + } + + ue(pic_parameter_set_id, 0, 255); + + pps = h264->pps[current->pic_parameter_set_id]; + if(!pps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "PPS id %d not available.\n", + current->pic_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h264->active_pps = pps; + + sps = h264->sps[pps->seq_parameter_set_id]; + if(!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + pps->seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h264->active_sps = sps; + + if(sps->separate_colour_plane_flag) + u(2, colour_plane_id, 0, 2); + + ub(sps->log2_max_frame_num_minus4 + 4, frame_num); + + if(!sps->frame_mbs_only_flag) { + flag(field_pic_flag); + if(current->field_pic_flag) + flag(bottom_field_flag); + else + infer(bottom_field_flag, 0); + } + else { + infer(field_pic_flag, 0); + infer(bottom_field_flag, 0); + } + + if(idr_pic_flag) + ue(idr_pic_id, 0, 65535); + + if(sps->pic_order_cnt_type == 0) { + ub(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, pic_order_cnt_lsb); + if(pps->bottom_field_pic_order_in_frame_present_flag && + !current->field_pic_flag) + se(delta_pic_order_cnt_bottom, INT32_MIN + 1, INT32_MAX); + } + else if(sps->pic_order_cnt_type == 1) { + if(!sps->delta_pic_order_always_zero_flag) { + se(delta_pic_order_cnt[0], INT32_MIN + 1, INT32_MAX); + if(pps->bottom_field_pic_order_in_frame_present_flag && + !current->field_pic_flag) + se(delta_pic_order_cnt[1], INT32_MIN + 1, INT32_MAX); + else + infer(delta_pic_order_cnt[1], 0); + } + else { + infer(delta_pic_order_cnt[0], 0); + infer(delta_pic_order_cnt[1], 0); + } + } + + if(pps->redundant_pic_cnt_present_flag) + ue(redundant_pic_cnt, 0, 127); + else + infer(redundant_pic_cnt, 0); + + if(current->nal_unit_header.nal_unit_type != H264_NAL_AUXILIARY_SLICE && !current->redundant_pic_cnt) + h264->last_slice_nal_unit_type = + current->nal_unit_header.nal_unit_type; + + if(slice_type_b) + flag(direct_spatial_mv_pred_flag); + + if(slice_type_p || slice_type_sp || slice_type_b) { + flag(num_ref_idx_active_override_flag); + if(current->num_ref_idx_active_override_flag) { + ue(num_ref_idx_l0_active_minus1, 0, 31); + if(slice_type_b) + ue(num_ref_idx_l1_active_minus1, 0, 31); + } + else { + infer(num_ref_idx_l0_active_minus1, + pps->num_ref_idx_l0_default_active_minus1); + infer(num_ref_idx_l1_active_minus1, + pps->num_ref_idx_l1_default_active_minus1); + } + } + + if(current->nal_unit_header.nal_unit_type == 20 || + current->nal_unit_header.nal_unit_type == 21) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "MVC / 3DAVC not supported.\n"); + return AVERROR_PATCHWELCOME; + } + else { + CHECK(FUNC(ref_pic_list_modification)(ctx, rw, current)); + } + + if((pps->weighted_pred_flag && (slice_type_p || slice_type_sp)) || + (pps->weighted_bipred_idc == 1 && slice_type_b)) { + CHECK(FUNC(pred_weight_table)(ctx, rw, current)); + } + + if(current->nal_unit_header.nal_ref_idc != 0) { + CHECK(FUNC(dec_ref_pic_marking)(ctx, rw, current, idr_pic_flag)); + } + + if(pps->entropy_coding_mode_flag && + !slice_type_i && !slice_type_si) { + ue(cabac_init_idc, 0, 2); + } + + se(slice_qp_delta, -51 - 6 * sps->bit_depth_luma_minus8, + +51 + 6 * sps->bit_depth_luma_minus8); + if(slice_type_sp || slice_type_si) { + if(slice_type_sp) + flag(sp_for_switch_flag); + se(slice_qs_delta, -51, +51); + } + + if(pps->deblocking_filter_control_present_flag) { + ue(disable_deblocking_filter_idc, 0, 2); + if(current->disable_deblocking_filter_idc != 1) { + se(slice_alpha_c0_offset_div2, -6, +6); + se(slice_beta_offset_div2, -6, +6); + } + else { + infer(slice_alpha_c0_offset_div2, 0); + infer(slice_beta_offset_div2, 0); + } + } + else { + infer(disable_deblocking_filter_idc, 0); + infer(slice_alpha_c0_offset_div2, 0); + infer(slice_beta_offset_div2, 0); + } + + if(pps->num_slice_groups_minus1 > 0 && + pps->slice_group_map_type >= 3 && + pps->slice_group_map_type <= 5) { + unsigned int pic_size, max, bits; + + pic_size = (sps->pic_width_in_mbs_minus1 + 1) * + (sps->pic_height_in_map_units_minus1 + 1); + max = (pic_size + pps->slice_group_change_rate_minus1) / + (pps->slice_group_change_rate_minus1 + 1); + bits = av_ceil_log2(max + 1); + + u(bits, slice_group_change_cycle, 0, max); + } + + if(pps->entropy_coding_mode_flag) { + while(byte_alignment(rw)) + fixed(1, cabac_alignment_one_bit, 1); + } + + return 0; +} + +static int FUNC(filler)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawFiller *current) { + int err; + + HEADER("Filler Data"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_FILLER_DATA)); + +#ifdef READ + while(show_bits(rw, 8) == 0xff) { + fixed(8, ff_byte, 0xff); + ++current->filler_size; + } +#else + { + uint32_t i; + for(i = 0; i < current->filler_size; i++) + fixed(8, ff_byte, 0xff); + } +#endif + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(end_of_sequence)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawNALUnitHeader *current) { + HEADER("End of Sequence"); + + return FUNC(nal_unit_header)(ctx, rw, current, + 1 << H264_NAL_END_SEQUENCE); +} + +static int FUNC(end_of_stream)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawNALUnitHeader *current) { + HEADER("End of Stream"); + + return FUNC(nal_unit_header)(ctx, rw, current, + 1 << H264_NAL_END_STREAM); +} diff --git a/third-party/cbs/cbs_h265_syntax_template.c b/third-party/cbs/cbs_h265_syntax_template.c new file mode 100644 index 00000000..7ceefc6f --- /dev/null +++ b/third-party/cbs/cbs_h265_syntax_template.c @@ -0,0 +1,2038 @@ +/* + * 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, + H265RawNALUnitHeader *current, + int expected_nal_unit_type) { + int err; + + fixed(1, forbidden_zero_bit, 0); + + if(expected_nal_unit_type >= 0) + u(6, nal_unit_type, expected_nal_unit_type, + expected_nal_unit_type); + else + ub(6, nal_unit_type); + + u(6, nuh_layer_id, 0, 62); + u(3, nuh_temporal_id_plus1, 1, 7); + + return 0; +} + +static int FUNC(byte_alignment)(CodedBitstreamContext *ctx, RWContext *rw) { + int err; + + fixed(1, alignment_bit_equal_to_one, 1); + while(byte_alignment(rw) != 0) + fixed(1, alignment_bit_equal_to_zero, 0); + + return 0; +} + +static int FUNC(extension_data)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawExtensionData *current) { + int err; + size_t k; +#ifdef READ + GetBitContext start; + uint8_t bit; + start = *rw; + for(k = 0; cbs_h2645_read_more_rbsp_data(rw); k++) + skip_bits(rw, 1); + current->bit_length = k; + if(k > 0) { + *rw = start; + allocate(current->data, (current->bit_length + 7) / 8); + for(k = 0; k < current->bit_length; k++) { + xu(1, extension_data, bit, 0, 1, 0); + current->data[k / 8] |= bit << (7 - k % 8); + } + } +#else + for(k = 0; k < current->bit_length; k++) + xu(1, extension_data, current->data[k / 8] >> (7 - k % 8) & 1, 0, 1, 0); +#endif + return 0; +} + +static int FUNC(profile_tier_level)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawProfileTierLevel *current, + int profile_present_flag, + int max_num_sub_layers_minus1) { + int err, i, j; + + if(profile_present_flag) { + u(2, general_profile_space, 0, 0); + flag(general_tier_flag); + ub(5, general_profile_idc); + + for(j = 0; j < 32; j++) + flags(general_profile_compatibility_flag[j], 1, j); + + flag(general_progressive_source_flag); + flag(general_interlaced_source_flag); + flag(general_non_packed_constraint_flag); + flag(general_frame_only_constraint_flag); + +#define profile_compatible(x) (current->general_profile_idc == (x) || \ + current->general_profile_compatibility_flag[x]) + if(profile_compatible(4) || profile_compatible(5) || + profile_compatible(6) || profile_compatible(7) || + profile_compatible(8) || profile_compatible(9) || + profile_compatible(10)) { + flag(general_max_12bit_constraint_flag); + flag(general_max_10bit_constraint_flag); + flag(general_max_8bit_constraint_flag); + flag(general_max_422chroma_constraint_flag); + flag(general_max_420chroma_constraint_flag); + flag(general_max_monochrome_constraint_flag); + flag(general_intra_constraint_flag); + flag(general_one_picture_only_constraint_flag); + flag(general_lower_bit_rate_constraint_flag); + + if(profile_compatible(5) || profile_compatible(9) || + profile_compatible(10)) { + flag(general_max_14bit_constraint_flag); + fixed(24, general_reserved_zero_33bits, 0); + fixed(9, general_reserved_zero_33bits, 0); + } + else { + fixed(24, general_reserved_zero_34bits, 0); + fixed(10, general_reserved_zero_34bits, 0); + } + } + else if(profile_compatible(2)) { + fixed(7, general_reserved_zero_7bits, 0); + flag(general_one_picture_only_constraint_flag); + fixed(24, general_reserved_zero_35bits, 0); + fixed(11, general_reserved_zero_35bits, 0); + } + else { + fixed(24, general_reserved_zero_43bits, 0); + fixed(19, general_reserved_zero_43bits, 0); + } + + if(profile_compatible(1) || profile_compatible(2) || + profile_compatible(3) || profile_compatible(4) || + profile_compatible(5) || profile_compatible(9)) { + flag(general_inbld_flag); + } + else { + fixed(1, general_reserved_zero_bit, 0); + } +#undef profile_compatible + } + + ub(8, general_level_idc); + + for(i = 0; i < max_num_sub_layers_minus1; i++) { + flags(sub_layer_profile_present_flag[i], 1, i); + flags(sub_layer_level_present_flag[i], 1, i); + } + + if(max_num_sub_layers_minus1 > 0) { + for(i = max_num_sub_layers_minus1; i < 8; i++) + fixed(2, reserved_zero_2bits, 0); + } + + for(i = 0; i < max_num_sub_layers_minus1; i++) { + if(current->sub_layer_profile_present_flag[i]) { + us(2, sub_layer_profile_space[i], 0, 0, 1, i); + flags(sub_layer_tier_flag[i], 1, i); + ubs(5, sub_layer_profile_idc[i], 1, i); + + for(j = 0; j < 32; j++) + flags(sub_layer_profile_compatibility_flag[i][j], 2, i, j); + + flags(sub_layer_progressive_source_flag[i], 1, i); + flags(sub_layer_interlaced_source_flag[i], 1, i); + flags(sub_layer_non_packed_constraint_flag[i], 1, i); + flags(sub_layer_frame_only_constraint_flag[i], 1, i); + +#define profile_compatible(x) (current->sub_layer_profile_idc[i] == (x) || \ + current->sub_layer_profile_compatibility_flag[i][x]) + if(profile_compatible(4) || profile_compatible(5) || + profile_compatible(6) || profile_compatible(7) || + profile_compatible(8) || profile_compatible(9) || + profile_compatible(10)) { + flags(sub_layer_max_12bit_constraint_flag[i], 1, i); + flags(sub_layer_max_10bit_constraint_flag[i], 1, i); + flags(sub_layer_max_8bit_constraint_flag[i], 1, i); + flags(sub_layer_max_422chroma_constraint_flag[i], 1, i); + flags(sub_layer_max_420chroma_constraint_flag[i], 1, i); + flags(sub_layer_max_monochrome_constraint_flag[i], 1, i); + flags(sub_layer_intra_constraint_flag[i], 1, i); + flags(sub_layer_one_picture_only_constraint_flag[i], 1, i); + flags(sub_layer_lower_bit_rate_constraint_flag[i], 1, i); + + if(profile_compatible(5)) { + flags(sub_layer_max_14bit_constraint_flag[i], 1, i); + fixed(24, sub_layer_reserved_zero_33bits, 0); + fixed(9, sub_layer_reserved_zero_33bits, 0); + } + else { + fixed(24, sub_layer_reserved_zero_34bits, 0); + fixed(10, sub_layer_reserved_zero_34bits, 0); + } + } + else if(profile_compatible(2)) { + fixed(7, sub_layer_reserved_zero_7bits, 0); + flags(sub_layer_one_picture_only_constraint_flag[i], 1, i); + fixed(24, sub_layer_reserved_zero_43bits, 0); + fixed(11, sub_layer_reserved_zero_43bits, 0); + } + else { + fixed(24, sub_layer_reserved_zero_43bits, 0); + fixed(19, sub_layer_reserved_zero_43bits, 0); + } + + if(profile_compatible(1) || profile_compatible(2) || + profile_compatible(3) || profile_compatible(4) || + profile_compatible(5) || profile_compatible(9)) { + flags(sub_layer_inbld_flag[i], 1, i); + } + else { + fixed(1, sub_layer_reserved_zero_bit, 0); + } +#undef profile_compatible + } + if(current->sub_layer_level_present_flag[i]) + ubs(8, sub_layer_level_idc[i], 1, i); + } + + return 0; +} + +static int FUNC(sub_layer_hrd_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawHRDParameters *hrd, + int nal, int sub_layer_id) { + H265RawSubLayerHRDParameters *current; + int err, i; + + if(nal) + current = &hrd->nal_sub_layer_hrd_parameters[sub_layer_id]; + else + current = &hrd->vcl_sub_layer_hrd_parameters[sub_layer_id]; + + for(i = 0; i <= hrd->cpb_cnt_minus1[sub_layer_id]; i++) { + ues(bit_rate_value_minus1[i], 0, UINT32_MAX - 1, 1, i); + ues(cpb_size_value_minus1[i], 0, UINT32_MAX - 1, 1, i); + if(hrd->sub_pic_hrd_params_present_flag) { + ues(cpb_size_du_value_minus1[i], 0, UINT32_MAX - 1, 1, i); + ues(bit_rate_du_value_minus1[i], 0, UINT32_MAX - 1, 1, i); + } + flags(cbr_flag[i], 1, i); + } + + return 0; +} + +static int FUNC(hrd_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawHRDParameters *current, int common_inf_present_flag, + int max_num_sub_layers_minus1) { + int err, i; + + if(common_inf_present_flag) { + flag(nal_hrd_parameters_present_flag); + flag(vcl_hrd_parameters_present_flag); + + if(current->nal_hrd_parameters_present_flag || + current->vcl_hrd_parameters_present_flag) { + flag(sub_pic_hrd_params_present_flag); + if(current->sub_pic_hrd_params_present_flag) { + ub(8, tick_divisor_minus2); + ub(5, du_cpb_removal_delay_increment_length_minus1); + flag(sub_pic_cpb_params_in_pic_timing_sei_flag); + ub(5, dpb_output_delay_du_length_minus1); + } + + ub(4, bit_rate_scale); + ub(4, cpb_size_scale); + if(current->sub_pic_hrd_params_present_flag) + ub(4, cpb_size_du_scale); + + ub(5, initial_cpb_removal_delay_length_minus1); + ub(5, au_cpb_removal_delay_length_minus1); + ub(5, dpb_output_delay_length_minus1); + } + else { + infer(sub_pic_hrd_params_present_flag, 0); + + infer(initial_cpb_removal_delay_length_minus1, 23); + infer(au_cpb_removal_delay_length_minus1, 23); + infer(dpb_output_delay_length_minus1, 23); + } + } + + for(i = 0; i <= max_num_sub_layers_minus1; i++) { + flags(fixed_pic_rate_general_flag[i], 1, i); + + if(!current->fixed_pic_rate_general_flag[i]) + flags(fixed_pic_rate_within_cvs_flag[i], 1, i); + else + infer(fixed_pic_rate_within_cvs_flag[i], 1); + + if(current->fixed_pic_rate_within_cvs_flag[i]) { + ues(elemental_duration_in_tc_minus1[i], 0, 2047, 1, i); + infer(low_delay_hrd_flag[i], 0); + } + else + flags(low_delay_hrd_flag[i], 1, i); + + if(!current->low_delay_hrd_flag[i]) + ues(cpb_cnt_minus1[i], 0, 31, 1, i); + else + infer(cpb_cnt_minus1[i], 0); + + if(current->nal_hrd_parameters_present_flag) + CHECK(FUNC(sub_layer_hrd_parameters)(ctx, rw, current, 0, i)); + if(current->vcl_hrd_parameters_present_flag) + CHECK(FUNC(sub_layer_hrd_parameters)(ctx, rw, current, 1, i)); + } + + return 0; +} + +static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawVUI *current, const H265RawSPS *sps) { + int err; + + flag(aspect_ratio_info_present_flag); + if(current->aspect_ratio_info_present_flag) { + ub(8, aspect_ratio_idc); + if(current->aspect_ratio_idc == 255) { + ub(16, sar_width); + ub(16, sar_height); + } + } + else { + infer(aspect_ratio_idc, 0); + } + + flag(overscan_info_present_flag); + if(current->overscan_info_present_flag) + flag(overscan_appropriate_flag); + + flag(video_signal_type_present_flag); + if(current->video_signal_type_present_flag) { + ub(3, video_format); + flag(video_full_range_flag); + flag(colour_description_present_flag); + if(current->colour_description_present_flag) { + ub(8, colour_primaries); + ub(8, transfer_characteristics); + ub(8, matrix_coefficients); + } + else { + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + } + } + else { + infer(video_format, 5); + infer(video_full_range_flag, 0); + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + } + + flag(chroma_loc_info_present_flag); + if(current->chroma_loc_info_present_flag) { + ue(chroma_sample_loc_type_top_field, 0, 5); + ue(chroma_sample_loc_type_bottom_field, 0, 5); + } + else { + infer(chroma_sample_loc_type_top_field, 0); + infer(chroma_sample_loc_type_bottom_field, 0); + } + + flag(neutral_chroma_indication_flag); + flag(field_seq_flag); + flag(frame_field_info_present_flag); + + flag(default_display_window_flag); + if(current->default_display_window_flag) { + ue(def_disp_win_left_offset, 0, 16384); + ue(def_disp_win_right_offset, 0, 16384); + ue(def_disp_win_top_offset, 0, 16384); + ue(def_disp_win_bottom_offset, 0, 16384); + } + + flag(vui_timing_info_present_flag); + if(current->vui_timing_info_present_flag) { + u(32, vui_num_units_in_tick, 1, UINT32_MAX); + u(32, vui_time_scale, 1, UINT32_MAX); + flag(vui_poc_proportional_to_timing_flag); + if(current->vui_poc_proportional_to_timing_flag) + ue(vui_num_ticks_poc_diff_one_minus1, 0, UINT32_MAX - 1); + + flag(vui_hrd_parameters_present_flag); + if(current->vui_hrd_parameters_present_flag) { + CHECK(FUNC(hrd_parameters)(ctx, rw, ¤t->hrd_parameters, + 1, sps->sps_max_sub_layers_minus1)); + } + } + + flag(bitstream_restriction_flag); + if(current->bitstream_restriction_flag) { + flag(tiles_fixed_structure_flag); + flag(motion_vectors_over_pic_boundaries_flag); + flag(restricted_ref_pic_lists_flag); + ue(min_spatial_segmentation_idc, 0, 4095); + ue(max_bytes_per_pic_denom, 0, 16); + ue(max_bits_per_min_cu_denom, 0, 16); + ue(log2_max_mv_length_horizontal, 0, 16); + ue(log2_max_mv_length_vertical, 0, 16); + } + else { + infer(tiles_fixed_structure_flag, 0); + infer(motion_vectors_over_pic_boundaries_flag, 1); + infer(min_spatial_segmentation_idc, 0); + infer(max_bytes_per_pic_denom, 2); + infer(max_bits_per_min_cu_denom, 1); + infer(log2_max_mv_length_horizontal, 15); + infer(log2_max_mv_length_vertical, 15); + } + + return 0; +} + +static int FUNC(vps)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawVPS *current) { + int err, i, j; + + HEADER("Video Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, HEVC_NAL_VPS)); + + ub(4, vps_video_parameter_set_id); + + flag(vps_base_layer_internal_flag); + flag(vps_base_layer_available_flag); + u(6, vps_max_layers_minus1, 0, HEVC_MAX_LAYERS - 1); + u(3, vps_max_sub_layers_minus1, 0, HEVC_MAX_SUB_LAYERS - 1); + flag(vps_temporal_id_nesting_flag); + + if(current->vps_max_sub_layers_minus1 == 0 && + current->vps_temporal_id_nesting_flag != 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid stream: " + "vps_temporal_id_nesting_flag must be 1 if " + "vps_max_sub_layers_minus1 is 0.\n"); + return AVERROR_INVALIDDATA; + } + + fixed(16, vps_reserved_0xffff_16bits, 0xffff); + + CHECK(FUNC(profile_tier_level)(ctx, rw, ¤t->profile_tier_level, + 1, current->vps_max_sub_layers_minus1)); + + flag(vps_sub_layer_ordering_info_present_flag); + for(i = (current->vps_sub_layer_ordering_info_present_flag ? + 0 : + current->vps_max_sub_layers_minus1); + i <= current->vps_max_sub_layers_minus1; i++) { + ues(vps_max_dec_pic_buffering_minus1[i], + 0, HEVC_MAX_DPB_SIZE - 1, 1, i); + ues(vps_max_num_reorder_pics[i], + 0, current->vps_max_dec_pic_buffering_minus1[i], 1, i); + ues(vps_max_latency_increase_plus1[i], + 0, UINT32_MAX - 1, 1, i); + } + if(!current->vps_sub_layer_ordering_info_present_flag) { + for(i = 0; i < current->vps_max_sub_layers_minus1; i++) { + infer(vps_max_dec_pic_buffering_minus1[i], + current->vps_max_dec_pic_buffering_minus1[current->vps_max_sub_layers_minus1]); + infer(vps_max_num_reorder_pics[i], + current->vps_max_num_reorder_pics[current->vps_max_sub_layers_minus1]); + infer(vps_max_latency_increase_plus1[i], + current->vps_max_latency_increase_plus1[current->vps_max_sub_layers_minus1]); + } + } + + u(6, vps_max_layer_id, 0, HEVC_MAX_LAYERS - 1); + ue(vps_num_layer_sets_minus1, 0, HEVC_MAX_LAYER_SETS - 1); + for(i = 1; i <= current->vps_num_layer_sets_minus1; i++) { + for(j = 0; j <= current->vps_max_layer_id; j++) + flags(layer_id_included_flag[i][j], 2, i, j); + } + for(j = 0; j <= current->vps_max_layer_id; j++) + infer(layer_id_included_flag[0][j], j == 0); + + flag(vps_timing_info_present_flag); + if(current->vps_timing_info_present_flag) { + u(32, vps_num_units_in_tick, 1, UINT32_MAX); + u(32, vps_time_scale, 1, UINT32_MAX); + flag(vps_poc_proportional_to_timing_flag); + if(current->vps_poc_proportional_to_timing_flag) + ue(vps_num_ticks_poc_diff_one_minus1, 0, UINT32_MAX - 1); + ue(vps_num_hrd_parameters, 0, current->vps_num_layer_sets_minus1 + 1); + for(i = 0; i < current->vps_num_hrd_parameters; i++) { + ues(hrd_layer_set_idx[i], + current->vps_base_layer_internal_flag ? 0 : 1, + current->vps_num_layer_sets_minus1, 1, i); + if(i > 0) + flags(cprms_present_flag[i], 1, i); + else + infer(cprms_present_flag[0], 1); + + CHECK(FUNC(hrd_parameters)(ctx, rw, ¤t->hrd_parameters[i], + current->cprms_present_flag[i], + current->vps_max_sub_layers_minus1)); + } + } + + flag(vps_extension_flag); + if(current->vps_extension_flag) + CHECK(FUNC(extension_data)(ctx, rw, ¤t->extension_data)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(st_ref_pic_set)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSTRefPicSet *current, int st_rps_idx, + const H265RawSPS *sps) { + int err, i, j; + + if(st_rps_idx != 0) + flag(inter_ref_pic_set_prediction_flag); + else + infer(inter_ref_pic_set_prediction_flag, 0); + + if(current->inter_ref_pic_set_prediction_flag) { + unsigned int ref_rps_idx, num_delta_pocs, num_ref_pics; + const H265RawSTRefPicSet *ref; + int delta_rps, d_poc; + int ref_delta_poc_s0[HEVC_MAX_REFS], ref_delta_poc_s1[HEVC_MAX_REFS]; + int delta_poc_s0[HEVC_MAX_REFS], delta_poc_s1[HEVC_MAX_REFS]; + uint8_t used_by_curr_pic_s0[HEVC_MAX_REFS], + used_by_curr_pic_s1[HEVC_MAX_REFS]; + + if(st_rps_idx == sps->num_short_term_ref_pic_sets) + ue(delta_idx_minus1, 0, st_rps_idx - 1); + else + infer(delta_idx_minus1, 0); + + ref_rps_idx = st_rps_idx - (current->delta_idx_minus1 + 1); + ref = &sps->st_ref_pic_set[ref_rps_idx]; + num_delta_pocs = ref->num_negative_pics + ref->num_positive_pics; + av_assert0(num_delta_pocs < HEVC_MAX_DPB_SIZE); + + flag(delta_rps_sign); + ue(abs_delta_rps_minus1, 0, INT16_MAX); + delta_rps = (1 - 2 * current->delta_rps_sign) * + (current->abs_delta_rps_minus1 + 1); + + num_ref_pics = 0; + for(j = 0; j <= num_delta_pocs; j++) { + flags(used_by_curr_pic_flag[j], 1, j); + if(!current->used_by_curr_pic_flag[j]) + flags(use_delta_flag[j], 1, j); + else + infer(use_delta_flag[j], 1); + if(current->use_delta_flag[j]) + ++num_ref_pics; + } + if(num_ref_pics >= HEVC_MAX_DPB_SIZE) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid stream: " + "short-term ref pic set %d " + "contains too many pictures.\n", + st_rps_idx); + return AVERROR_INVALIDDATA; + } + + // Since the stored form of an RPS here is actually the delta-step + // form used when inter_ref_pic_set_prediction_flag is not set, we + // need to reconstruct that here in order to be able to refer to + // the RPS later (which is required for parsing, because we don't + // even know what syntax elements appear without it). Therefore, + // this code takes the delta-step form of the reference set, turns + // it into the delta-array form, applies the prediction process of + // 7.4.8, converts the result back to the delta-step form, and + // stores that as the current set for future use. Note that the + // inferences here mean that writers using prediction will need + // to fill in the delta-step values correctly as well - since the + // whole RPS prediction process is somewhat overly sophisticated, + // this hopefully forms a useful check for them to ensure their + // predicted form actually matches what was intended rather than + // an onerous additional requirement. + + d_poc = 0; + for(i = 0; i < ref->num_negative_pics; i++) { + d_poc -= ref->delta_poc_s0_minus1[i] + 1; + ref_delta_poc_s0[i] = d_poc; + } + d_poc = 0; + for(i = 0; i < ref->num_positive_pics; i++) { + d_poc += ref->delta_poc_s1_minus1[i] + 1; + ref_delta_poc_s1[i] = d_poc; + } + + i = 0; + for(j = ref->num_positive_pics - 1; j >= 0; j--) { + d_poc = ref_delta_poc_s1[j] + delta_rps; + if(d_poc < 0 && current->use_delta_flag[ref->num_negative_pics + j]) { + delta_poc_s0[i] = d_poc; + used_by_curr_pic_s0[i++] = + current->used_by_curr_pic_flag[ref->num_negative_pics + j]; + } + } + if(delta_rps < 0 && current->use_delta_flag[num_delta_pocs]) { + delta_poc_s0[i] = delta_rps; + used_by_curr_pic_s0[i++] = + current->used_by_curr_pic_flag[num_delta_pocs]; + } + for(j = 0; j < ref->num_negative_pics; j++) { + d_poc = ref_delta_poc_s0[j] + delta_rps; + if(d_poc < 0 && current->use_delta_flag[j]) { + delta_poc_s0[i] = d_poc; + used_by_curr_pic_s0[i++] = current->used_by_curr_pic_flag[j]; + } + } + + infer(num_negative_pics, i); + for(i = 0; i < current->num_negative_pics; i++) { + infer(delta_poc_s0_minus1[i], + -(delta_poc_s0[i] - (i == 0 ? 0 : delta_poc_s0[i - 1])) - 1); + infer(used_by_curr_pic_s0_flag[i], used_by_curr_pic_s0[i]); + } + + i = 0; + for(j = ref->num_negative_pics - 1; j >= 0; j--) { + d_poc = ref_delta_poc_s0[j] + delta_rps; + if(d_poc > 0 && current->use_delta_flag[j]) { + delta_poc_s1[i] = d_poc; + used_by_curr_pic_s1[i++] = current->used_by_curr_pic_flag[j]; + } + } + if(delta_rps > 0 && current->use_delta_flag[num_delta_pocs]) { + delta_poc_s1[i] = delta_rps; + used_by_curr_pic_s1[i++] = + current->used_by_curr_pic_flag[num_delta_pocs]; + } + for(j = 0; j < ref->num_positive_pics; j++) { + d_poc = ref_delta_poc_s1[j] + delta_rps; + if(d_poc > 0 && current->use_delta_flag[ref->num_negative_pics + j]) { + delta_poc_s1[i] = d_poc; + used_by_curr_pic_s1[i++] = + current->used_by_curr_pic_flag[ref->num_negative_pics + j]; + } + } + + infer(num_positive_pics, i); + for(i = 0; i < current->num_positive_pics; i++) { + infer(delta_poc_s1_minus1[i], + delta_poc_s1[i] - (i == 0 ? 0 : delta_poc_s1[i - 1]) - 1); + infer(used_by_curr_pic_s1_flag[i], used_by_curr_pic_s1[i]); + } + } + else { + ue(num_negative_pics, 0, 15); + ue(num_positive_pics, 0, 15 - current->num_negative_pics); + + for(i = 0; i < current->num_negative_pics; i++) { + ues(delta_poc_s0_minus1[i], 0, INT16_MAX, 1, i); + flags(used_by_curr_pic_s0_flag[i], 1, i); + } + + for(i = 0; i < current->num_positive_pics; i++) { + ues(delta_poc_s1_minus1[i], 0, INT16_MAX, 1, i); + flags(used_by_curr_pic_s1_flag[i], 1, i); + } + } + + return 0; +} + +static int FUNC(scaling_list_data)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawScalingList *current) { + int sizeId, matrixId; + int err, n, i; + + for(sizeId = 0; sizeId < 4; sizeId++) { + for(matrixId = 0; matrixId < 6; matrixId += (sizeId == 3 ? 3 : 1)) { + flags(scaling_list_pred_mode_flag[sizeId][matrixId], + 2, sizeId, matrixId); + if(!current->scaling_list_pred_mode_flag[sizeId][matrixId]) { + ues(scaling_list_pred_matrix_id_delta[sizeId][matrixId], + 0, sizeId == 3 ? matrixId / 3 : matrixId, + 2, sizeId, matrixId); + } + else { + n = FFMIN(64, 1 << (4 + (sizeId << 1))); + if(sizeId > 1) { + ses(scaling_list_dc_coef_minus8[sizeId - 2][matrixId], -7, +247, + 2, sizeId - 2, matrixId); + } + for(i = 0; i < n; i++) { + ses(scaling_list_delta_coeff[sizeId][matrixId][i], + -128, +127, 3, sizeId, matrixId, i); + } + } + } + } + + return 0; +} + +static int FUNC(sps_range_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSPS *current) { + int err; + + flag(transform_skip_rotation_enabled_flag); + flag(transform_skip_context_enabled_flag); + flag(implicit_rdpcm_enabled_flag); + flag(explicit_rdpcm_enabled_flag); + flag(extended_precision_processing_flag); + flag(intra_smoothing_disabled_flag); + flag(high_precision_offsets_enabled_flag); + flag(persistent_rice_adaptation_enabled_flag); + flag(cabac_bypass_alignment_enabled_flag); + + return 0; +} + +static int FUNC(sps_scc_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSPS *current) { + int err, comp, i; + + flag(sps_curr_pic_ref_enabled_flag); + + flag(palette_mode_enabled_flag); + if(current->palette_mode_enabled_flag) { + ue(palette_max_size, 0, 64); + ue(delta_palette_max_predictor_size, 0, 128); + + flag(sps_palette_predictor_initializer_present_flag); + if(current->sps_palette_predictor_initializer_present_flag) { + ue(sps_num_palette_predictor_initializer_minus1, 0, 128); + for(comp = 0; comp < (current->chroma_format_idc ? 3 : 1); comp++) { + int bit_depth = comp == 0 ? current->bit_depth_luma_minus8 + 8 : current->bit_depth_chroma_minus8 + 8; + for(i = 0; i <= current->sps_num_palette_predictor_initializer_minus1; i++) + ubs(bit_depth, sps_palette_predictor_initializers[comp][i], 2, comp, i); + } + } + } + + u(2, motion_vector_resolution_control_idc, 0, 2); + flag(intra_boundary_filtering_disable_flag); + + return 0; +} + +static int FUNC(vui_parameters_default)(CodedBitstreamContext *ctx, + RWContext *rw, H265RawVUI *current, + H265RawSPS *sps) { + infer(aspect_ratio_idc, 0); + + infer(video_format, 5); + infer(video_full_range_flag, 0); + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + + infer(chroma_sample_loc_type_top_field, 0); + infer(chroma_sample_loc_type_bottom_field, 0); + + infer(tiles_fixed_structure_flag, 0); + infer(motion_vectors_over_pic_boundaries_flag, 1); + infer(min_spatial_segmentation_idc, 0); + infer(max_bytes_per_pic_denom, 2); + infer(max_bits_per_min_cu_denom, 1); + infer(log2_max_mv_length_horizontal, 15); + infer(log2_max_mv_length_vertical, 15); + + return 0; +} + +static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSPS *current) { + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawVPS *vps; + int err, i; + unsigned int min_cb_log2_size_y, ctb_log2_size_y, + min_cb_size_y, min_tb_log2_size_y; + + HEADER("Sequence Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, HEVC_NAL_SPS)); + + ub(4, sps_video_parameter_set_id); + h265->active_vps = vps = h265->vps[current->sps_video_parameter_set_id]; + + u(3, sps_max_sub_layers_minus1, 0, HEVC_MAX_SUB_LAYERS - 1); + flag(sps_temporal_id_nesting_flag); + if(vps) { + if(vps->vps_max_sub_layers_minus1 > current->sps_max_sub_layers_minus1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid stream: " + "sps_max_sub_layers_minus1 (%d) must be less than or equal to " + "vps_max_sub_layers_minus1 (%d).\n", + vps->vps_max_sub_layers_minus1, + current->sps_max_sub_layers_minus1); + return AVERROR_INVALIDDATA; + } + if(vps->vps_temporal_id_nesting_flag && + !current->sps_temporal_id_nesting_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid stream: " + "sps_temporal_id_nesting_flag must be 1 if " + "vps_temporal_id_nesting_flag is 1.\n"); + return AVERROR_INVALIDDATA; + } + } + + CHECK(FUNC(profile_tier_level)(ctx, rw, ¤t->profile_tier_level, + 1, current->sps_max_sub_layers_minus1)); + + ue(sps_seq_parameter_set_id, 0, 15); + + ue(chroma_format_idc, 0, 3); + if(current->chroma_format_idc == 3) + flag(separate_colour_plane_flag); + else + infer(separate_colour_plane_flag, 0); + + ue(pic_width_in_luma_samples, 1, HEVC_MAX_WIDTH); + ue(pic_height_in_luma_samples, 1, HEVC_MAX_HEIGHT); + + flag(conformance_window_flag); + if(current->conformance_window_flag) { + ue(conf_win_left_offset, 0, current->pic_width_in_luma_samples); + ue(conf_win_right_offset, 0, current->pic_width_in_luma_samples); + ue(conf_win_top_offset, 0, current->pic_height_in_luma_samples); + ue(conf_win_bottom_offset, 0, current->pic_height_in_luma_samples); + } + else { + infer(conf_win_left_offset, 0); + infer(conf_win_right_offset, 0); + infer(conf_win_top_offset, 0); + infer(conf_win_bottom_offset, 0); + } + + ue(bit_depth_luma_minus8, 0, 8); + ue(bit_depth_chroma_minus8, 0, 8); + + ue(log2_max_pic_order_cnt_lsb_minus4, 0, 12); + + flag(sps_sub_layer_ordering_info_present_flag); + for(i = (current->sps_sub_layer_ordering_info_present_flag ? + 0 : + current->sps_max_sub_layers_minus1); + i <= current->sps_max_sub_layers_minus1; i++) { + ues(sps_max_dec_pic_buffering_minus1[i], + 0, HEVC_MAX_DPB_SIZE - 1, 1, i); + ues(sps_max_num_reorder_pics[i], + 0, current->sps_max_dec_pic_buffering_minus1[i], 1, i); + ues(sps_max_latency_increase_plus1[i], + 0, UINT32_MAX - 1, 1, i); + } + if(!current->sps_sub_layer_ordering_info_present_flag) { + for(i = 0; i < current->sps_max_sub_layers_minus1; i++) { + infer(sps_max_dec_pic_buffering_minus1[i], + current->sps_max_dec_pic_buffering_minus1[current->sps_max_sub_layers_minus1]); + infer(sps_max_num_reorder_pics[i], + current->sps_max_num_reorder_pics[current->sps_max_sub_layers_minus1]); + infer(sps_max_latency_increase_plus1[i], + current->sps_max_latency_increase_plus1[current->sps_max_sub_layers_minus1]); + } + } + + ue(log2_min_luma_coding_block_size_minus3, 0, 3); + min_cb_log2_size_y = current->log2_min_luma_coding_block_size_minus3 + 3; + + ue(log2_diff_max_min_luma_coding_block_size, 0, 3); + ctb_log2_size_y = min_cb_log2_size_y + + current->log2_diff_max_min_luma_coding_block_size; + + min_cb_size_y = 1 << min_cb_log2_size_y; + if(current->pic_width_in_luma_samples % min_cb_size_y || + current->pic_height_in_luma_samples % min_cb_size_y) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid dimensions: %ux%u not divisible " + "by MinCbSizeY = %u.\n", + current->pic_width_in_luma_samples, + current->pic_height_in_luma_samples, min_cb_size_y); + return AVERROR_INVALIDDATA; + } + + ue(log2_min_luma_transform_block_size_minus2, 0, min_cb_log2_size_y - 3); + min_tb_log2_size_y = current->log2_min_luma_transform_block_size_minus2 + 2; + + ue(log2_diff_max_min_luma_transform_block_size, + 0, FFMIN(ctb_log2_size_y, 5) - min_tb_log2_size_y); + + ue(max_transform_hierarchy_depth_inter, + 0, ctb_log2_size_y - min_tb_log2_size_y); + ue(max_transform_hierarchy_depth_intra, + 0, ctb_log2_size_y - min_tb_log2_size_y); + + flag(scaling_list_enabled_flag); + if(current->scaling_list_enabled_flag) { + flag(sps_scaling_list_data_present_flag); + if(current->sps_scaling_list_data_present_flag) + CHECK(FUNC(scaling_list_data)(ctx, rw, ¤t->scaling_list)); + } + else { + infer(sps_scaling_list_data_present_flag, 0); + } + + flag(amp_enabled_flag); + flag(sample_adaptive_offset_enabled_flag); + + flag(pcm_enabled_flag); + if(current->pcm_enabled_flag) { + u(4, pcm_sample_bit_depth_luma_minus1, + 0, current->bit_depth_luma_minus8 + 8 - 1); + u(4, pcm_sample_bit_depth_chroma_minus1, + 0, current->bit_depth_chroma_minus8 + 8 - 1); + + ue(log2_min_pcm_luma_coding_block_size_minus3, + FFMIN(min_cb_log2_size_y, 5) - 3, FFMIN(ctb_log2_size_y, 5) - 3); + ue(log2_diff_max_min_pcm_luma_coding_block_size, + 0, FFMIN(ctb_log2_size_y, 5) - (current->log2_min_pcm_luma_coding_block_size_minus3 + 3)); + + flag(pcm_loop_filter_disabled_flag); + } + + ue(num_short_term_ref_pic_sets, 0, HEVC_MAX_SHORT_TERM_REF_PIC_SETS); + for(i = 0; i < current->num_short_term_ref_pic_sets; i++) + CHECK(FUNC(st_ref_pic_set)(ctx, rw, ¤t->st_ref_pic_set[i], i, current)); + + flag(long_term_ref_pics_present_flag); + if(current->long_term_ref_pics_present_flag) { + ue(num_long_term_ref_pics_sps, 0, HEVC_MAX_LONG_TERM_REF_PICS); + for(i = 0; i < current->num_long_term_ref_pics_sps; i++) { + ubs(current->log2_max_pic_order_cnt_lsb_minus4 + 4, + lt_ref_pic_poc_lsb_sps[i], 1, i); + flags(used_by_curr_pic_lt_sps_flag[i], 1, i); + } + } + + flag(sps_temporal_mvp_enabled_flag); + flag(strong_intra_smoothing_enabled_flag); + + flag(vui_parameters_present_flag); + if(current->vui_parameters_present_flag) + CHECK(FUNC(vui_parameters)(ctx, rw, ¤t->vui, current)); + else + CHECK(FUNC(vui_parameters_default)(ctx, rw, ¤t->vui, current)); + + flag(sps_extension_present_flag); + if(current->sps_extension_present_flag) { + flag(sps_range_extension_flag); + flag(sps_multilayer_extension_flag); + flag(sps_3d_extension_flag); + flag(sps_scc_extension_flag); + ub(4, sps_extension_4bits); + } + + if(current->sps_range_extension_flag) + CHECK(FUNC(sps_range_extension)(ctx, rw, current)); + if(current->sps_multilayer_extension_flag) + return AVERROR_PATCHWELCOME; + if(current->sps_3d_extension_flag) + return AVERROR_PATCHWELCOME; + if(current->sps_scc_extension_flag) + CHECK(FUNC(sps_scc_extension)(ctx, rw, current)); + if(current->sps_extension_4bits) + CHECK(FUNC(extension_data)(ctx, rw, ¤t->extension_data)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(pps_range_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawPPS *current) { + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps = h265->active_sps; + int err, i; + + if(current->transform_skip_enabled_flag) + ue(log2_max_transform_skip_block_size_minus2, 0, 3); + flag(cross_component_prediction_enabled_flag); + + flag(chroma_qp_offset_list_enabled_flag); + if(current->chroma_qp_offset_list_enabled_flag) { + ue(diff_cu_chroma_qp_offset_depth, + 0, sps->log2_diff_max_min_luma_coding_block_size); + ue(chroma_qp_offset_list_len_minus1, 0, 5); + for(i = 0; i <= current->chroma_qp_offset_list_len_minus1; i++) { + ses(cb_qp_offset_list[i], -12, +12, 1, i); + ses(cr_qp_offset_list[i], -12, +12, 1, i); + } + } + + ue(log2_sao_offset_scale_luma, 0, FFMAX(0, sps->bit_depth_luma_minus8 - 2)); + ue(log2_sao_offset_scale_chroma, 0, FFMAX(0, sps->bit_depth_chroma_minus8 - 2)); + + return 0; +} + +static int FUNC(pps_scc_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawPPS *current) { + int err, comp, i; + + flag(pps_curr_pic_ref_enabled_flag); + + flag(residual_adaptive_colour_transform_enabled_flag); + if(current->residual_adaptive_colour_transform_enabled_flag) { + flag(pps_slice_act_qp_offsets_present_flag); + se(pps_act_y_qp_offset_plus5, -7, +17); + se(pps_act_cb_qp_offset_plus5, -7, +17); + se(pps_act_cr_qp_offset_plus3, -9, +15); + } + else { + infer(pps_slice_act_qp_offsets_present_flag, 0); + infer(pps_act_y_qp_offset_plus5, 0); + infer(pps_act_cb_qp_offset_plus5, 0); + infer(pps_act_cr_qp_offset_plus3, 0); + } + + flag(pps_palette_predictor_initializer_present_flag); + if(current->pps_palette_predictor_initializer_present_flag) { + ue(pps_num_palette_predictor_initializer, 0, 128); + if(current->pps_num_palette_predictor_initializer > 0) { + flag(monochrome_palette_flag); + ue(luma_bit_depth_entry_minus8, 0, 8); + if(!current->monochrome_palette_flag) + ue(chroma_bit_depth_entry_minus8, 0, 8); + for(comp = 0; comp < (current->monochrome_palette_flag ? 1 : 3); comp++) { + int bit_depth = comp == 0 ? current->luma_bit_depth_entry_minus8 + 8 : current->chroma_bit_depth_entry_minus8 + 8; + for(i = 0; i < current->pps_num_palette_predictor_initializer; i++) + ubs(bit_depth, pps_palette_predictor_initializers[comp][i], 2, comp, i); + } + } + } + + return 0; +} + +static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawPPS *current) { + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps; + int err, i; + + HEADER("Picture Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, HEVC_NAL_PPS)); + + ue(pps_pic_parameter_set_id, 0, 63); + ue(pps_seq_parameter_set_id, 0, 15); + sps = h265->sps[current->pps_seq_parameter_set_id]; + if(!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + current->pps_seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h265->active_sps = sps; + + flag(dependent_slice_segments_enabled_flag); + flag(output_flag_present_flag); + ub(3, num_extra_slice_header_bits); + flag(sign_data_hiding_enabled_flag); + flag(cabac_init_present_flag); + + ue(num_ref_idx_l0_default_active_minus1, 0, 14); + ue(num_ref_idx_l1_default_active_minus1, 0, 14); + + se(init_qp_minus26, -(26 + 6 * sps->bit_depth_luma_minus8), +25); + + flag(constrained_intra_pred_flag); + flag(transform_skip_enabled_flag); + flag(cu_qp_delta_enabled_flag); + if(current->cu_qp_delta_enabled_flag) + ue(diff_cu_qp_delta_depth, + 0, sps->log2_diff_max_min_luma_coding_block_size); + else + infer(diff_cu_qp_delta_depth, 0); + + se(pps_cb_qp_offset, -12, +12); + se(pps_cr_qp_offset, -12, +12); + flag(pps_slice_chroma_qp_offsets_present_flag); + + flag(weighted_pred_flag); + flag(weighted_bipred_flag); + + flag(transquant_bypass_enabled_flag); + flag(tiles_enabled_flag); + flag(entropy_coding_sync_enabled_flag); + + if(current->tiles_enabled_flag) { + ue(num_tile_columns_minus1, 0, HEVC_MAX_TILE_COLUMNS); + ue(num_tile_rows_minus1, 0, HEVC_MAX_TILE_ROWS); + flag(uniform_spacing_flag); + if(!current->uniform_spacing_flag) { + for(i = 0; i < current->num_tile_columns_minus1; i++) + ues(column_width_minus1[i], 0, sps->pic_width_in_luma_samples, 1, i); + for(i = 0; i < current->num_tile_rows_minus1; i++) + ues(row_height_minus1[i], 0, sps->pic_height_in_luma_samples, 1, i); + } + flag(loop_filter_across_tiles_enabled_flag); + } + else { + infer(num_tile_columns_minus1, 0); + infer(num_tile_rows_minus1, 0); + } + + flag(pps_loop_filter_across_slices_enabled_flag); + flag(deblocking_filter_control_present_flag); + if(current->deblocking_filter_control_present_flag) { + flag(deblocking_filter_override_enabled_flag); + flag(pps_deblocking_filter_disabled_flag); + if(!current->pps_deblocking_filter_disabled_flag) { + se(pps_beta_offset_div2, -6, +6); + se(pps_tc_offset_div2, -6, +6); + } + else { + infer(pps_beta_offset_div2, 0); + infer(pps_tc_offset_div2, 0); + } + } + else { + infer(deblocking_filter_override_enabled_flag, 0); + infer(pps_deblocking_filter_disabled_flag, 0); + infer(pps_beta_offset_div2, 0); + infer(pps_tc_offset_div2, 0); + } + + flag(pps_scaling_list_data_present_flag); + if(current->pps_scaling_list_data_present_flag) + CHECK(FUNC(scaling_list_data)(ctx, rw, ¤t->scaling_list)); + + flag(lists_modification_present_flag); + + ue(log2_parallel_merge_level_minus2, + 0, (sps->log2_min_luma_coding_block_size_minus3 + 3 + sps->log2_diff_max_min_luma_coding_block_size - 2)); + + flag(slice_segment_header_extension_present_flag); + + flag(pps_extension_present_flag); + if(current->pps_extension_present_flag) { + flag(pps_range_extension_flag); + flag(pps_multilayer_extension_flag); + flag(pps_3d_extension_flag); + flag(pps_scc_extension_flag); + ub(4, pps_extension_4bits); + } + if(current->pps_range_extension_flag) + CHECK(FUNC(pps_range_extension)(ctx, rw, current)); + if(current->pps_multilayer_extension_flag) + return AVERROR_PATCHWELCOME; + if(current->pps_3d_extension_flag) + return AVERROR_PATCHWELCOME; + if(current->pps_scc_extension_flag) + CHECK(FUNC(pps_scc_extension)(ctx, rw, current)); + if(current->pps_extension_4bits) + CHECK(FUNC(extension_data)(ctx, rw, ¤t->extension_data)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(aud)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawAUD *current) { + int err; + + HEADER("Access Unit Delimiter"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, HEVC_NAL_AUD)); + + u(3, pic_type, 0, 2); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(ref_pic_lists_modification)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSliceHeader *current, + unsigned int num_pic_total_curr) { + unsigned int entry_size; + int err, i; + + entry_size = av_log2(num_pic_total_curr - 1) + 1; + + flag(ref_pic_list_modification_flag_l0); + if(current->ref_pic_list_modification_flag_l0) { + for(i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) + us(entry_size, list_entry_l0[i], 0, num_pic_total_curr - 1, 1, i); + } + + if(current->slice_type == HEVC_SLICE_B) { + flag(ref_pic_list_modification_flag_l1); + if(current->ref_pic_list_modification_flag_l1) { + for(i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) + us(entry_size, list_entry_l1[i], 0, num_pic_total_curr - 1, 1, i); + } + } + + return 0; +} + +static int FUNC(pred_weight_table)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSliceHeader *current) { + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps = h265->active_sps; + int err, i, j; + int chroma = !sps->separate_colour_plane_flag && + sps->chroma_format_idc != 0; + + ue(luma_log2_weight_denom, 0, 7); + if(chroma) + se(delta_chroma_log2_weight_denom, -7, 7); + else + infer(delta_chroma_log2_weight_denom, 0); + + for(i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { + if(1 /* is not same POC and same layer_id */) + flags(luma_weight_l0_flag[i], 1, i); + else + infer(luma_weight_l0_flag[i], 0); + } + if(chroma) { + for(i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { + if(1 /* is not same POC and same layer_id */) + flags(chroma_weight_l0_flag[i], 1, i); + else + infer(chroma_weight_l0_flag[i], 0); + } + } + + for(i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { + if(current->luma_weight_l0_flag[i]) { + ses(delta_luma_weight_l0[i], -128, +127, 1, i); + ses(luma_offset_l0[i], + -(1 << (sps->bit_depth_luma_minus8 + 8 - 1)), + ((1 << (sps->bit_depth_luma_minus8 + 8 - 1)) - 1), 1, i); + } + else { + infer(delta_luma_weight_l0[i], 0); + infer(luma_offset_l0[i], 0); + } + if(current->chroma_weight_l0_flag[i]) { + for(j = 0; j < 2; j++) { + ses(delta_chroma_weight_l0[i][j], -128, +127, 2, i, j); + ses(chroma_offset_l0[i][j], + -(4 << (sps->bit_depth_chroma_minus8 + 8 - 1)), + ((4 << (sps->bit_depth_chroma_minus8 + 8 - 1)) - 1), 2, i, j); + } + } + else { + for(j = 0; j < 2; j++) { + infer(delta_chroma_weight_l0[i][j], 0); + infer(chroma_offset_l0[i][j], 0); + } + } + } + + if(current->slice_type == HEVC_SLICE_B) { + for(i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { + if(1 /* RefPicList1[i] is not CurrPic, nor is it in a different layer */) + flags(luma_weight_l1_flag[i], 1, i); + else + infer(luma_weight_l1_flag[i], 0); + } + if(chroma) { + for(i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { + if(1 /* RefPicList1[i] is not CurrPic, nor is it in a different layer */) + flags(chroma_weight_l1_flag[i], 1, i); + else + infer(chroma_weight_l1_flag[i], 0); + } + } + + for(i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { + if(current->luma_weight_l1_flag[i]) { + ses(delta_luma_weight_l1[i], -128, +127, 1, i); + ses(luma_offset_l1[i], + -(1 << (sps->bit_depth_luma_minus8 + 8 - 1)), + ((1 << (sps->bit_depth_luma_minus8 + 8 - 1)) - 1), 1, i); + } + else { + infer(delta_luma_weight_l1[i], 0); + infer(luma_offset_l1[i], 0); + } + if(current->chroma_weight_l1_flag[i]) { + for(j = 0; j < 2; j++) { + ses(delta_chroma_weight_l1[i][j], -128, +127, 2, i, j); + ses(chroma_offset_l1[i][j], + -(4 << (sps->bit_depth_chroma_minus8 + 8 - 1)), + ((4 << (sps->bit_depth_chroma_minus8 + 8 - 1)) - 1), 2, i, j); + } + } + else { + for(j = 0; j < 2; j++) { + infer(delta_chroma_weight_l1[i][j], 0); + infer(chroma_offset_l1[i][j], 0); + } + } + } + } + + return 0; +} + +static int FUNC(slice_segment_header)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSliceHeader *current) { + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps; + const H265RawPPS *pps; + unsigned int min_cb_log2_size_y, ctb_log2_size_y, ctb_size_y; + unsigned int pic_width_in_ctbs_y, pic_height_in_ctbs_y, pic_size_in_ctbs_y; + unsigned int num_pic_total_curr = 0; + int err, i; + + HEADER("Slice Segment Header"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, -1)); + + flag(first_slice_segment_in_pic_flag); + + if(current->nal_unit_header.nal_unit_type >= HEVC_NAL_BLA_W_LP && + current->nal_unit_header.nal_unit_type <= HEVC_NAL_RSV_IRAP_VCL23) + flag(no_output_of_prior_pics_flag); + + ue(slice_pic_parameter_set_id, 0, 63); + + pps = h265->pps[current->slice_pic_parameter_set_id]; + if(!pps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "PPS id %d not available.\n", + current->slice_pic_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h265->active_pps = pps; + + sps = h265->sps[pps->pps_seq_parameter_set_id]; + if(!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + pps->pps_seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h265->active_sps = sps; + + min_cb_log2_size_y = sps->log2_min_luma_coding_block_size_minus3 + 3; + ctb_log2_size_y = min_cb_log2_size_y + sps->log2_diff_max_min_luma_coding_block_size; + ctb_size_y = 1 << ctb_log2_size_y; + pic_width_in_ctbs_y = + (sps->pic_width_in_luma_samples + ctb_size_y - 1) / ctb_size_y; + pic_height_in_ctbs_y = + (sps->pic_height_in_luma_samples + ctb_size_y - 1) / ctb_size_y; + pic_size_in_ctbs_y = pic_width_in_ctbs_y * pic_height_in_ctbs_y; + + if(!current->first_slice_segment_in_pic_flag) { + unsigned int address_size = av_log2(pic_size_in_ctbs_y - 1) + 1; + if(pps->dependent_slice_segments_enabled_flag) + flag(dependent_slice_segment_flag); + else + infer(dependent_slice_segment_flag, 0); + u(address_size, slice_segment_address, 0, pic_size_in_ctbs_y - 1); + } + else { + infer(dependent_slice_segment_flag, 0); + } + + if(!current->dependent_slice_segment_flag) { + for(i = 0; i < pps->num_extra_slice_header_bits; i++) + flags(slice_reserved_flag[i], 1, i); + + ue(slice_type, 0, 2); + + if(pps->output_flag_present_flag) + flag(pic_output_flag); + + if(sps->separate_colour_plane_flag) + u(2, colour_plane_id, 0, 2); + + if(current->nal_unit_header.nal_unit_type != HEVC_NAL_IDR_W_RADL && + current->nal_unit_header.nal_unit_type != HEVC_NAL_IDR_N_LP) { + const H265RawSTRefPicSet *rps; + int dpb_slots_remaining; + + ub(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, slice_pic_order_cnt_lsb); + + flag(short_term_ref_pic_set_sps_flag); + if(!current->short_term_ref_pic_set_sps_flag) { + CHECK(FUNC(st_ref_pic_set)(ctx, rw, ¤t->short_term_ref_pic_set, + sps->num_short_term_ref_pic_sets, sps)); + rps = ¤t->short_term_ref_pic_set; + } + else if(sps->num_short_term_ref_pic_sets > 1) { + unsigned int idx_size = av_log2(sps->num_short_term_ref_pic_sets - 1) + 1; + u(idx_size, short_term_ref_pic_set_idx, + 0, sps->num_short_term_ref_pic_sets - 1); + rps = &sps->st_ref_pic_set[current->short_term_ref_pic_set_idx]; + } + else { + infer(short_term_ref_pic_set_idx, 0); + rps = &sps->st_ref_pic_set[0]; + } + + dpb_slots_remaining = HEVC_MAX_DPB_SIZE - 1 - + rps->num_negative_pics - rps->num_positive_pics; + if(pps->pps_curr_pic_ref_enabled_flag && + (sps->sample_adaptive_offset_enabled_flag || + !pps->pps_deblocking_filter_disabled_flag || + pps->deblocking_filter_override_enabled_flag)) { + // This picture will occupy two DPB slots. + if(dpb_slots_remaining == 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid stream: " + "short-term ref pic set contains too many pictures " + "to use with current picture reference enabled.\n"); + return AVERROR_INVALIDDATA; + } + --dpb_slots_remaining; + } + + num_pic_total_curr = 0; + for(i = 0; i < rps->num_negative_pics; i++) + if(rps->used_by_curr_pic_s0_flag[i]) + ++num_pic_total_curr; + for(i = 0; i < rps->num_positive_pics; i++) + if(rps->used_by_curr_pic_s1_flag[i]) + ++num_pic_total_curr; + + if(sps->long_term_ref_pics_present_flag) { + unsigned int idx_size; + + if(sps->num_long_term_ref_pics_sps > 0) { + ue(num_long_term_sps, 0, FFMIN(sps->num_long_term_ref_pics_sps, dpb_slots_remaining)); + idx_size = av_log2(sps->num_long_term_ref_pics_sps - 1) + 1; + dpb_slots_remaining -= current->num_long_term_sps; + } + else { + infer(num_long_term_sps, 0); + idx_size = 0; + } + ue(num_long_term_pics, 0, dpb_slots_remaining); + + for(i = 0; i < current->num_long_term_sps + + current->num_long_term_pics; + i++) { + if(i < current->num_long_term_sps) { + if(sps->num_long_term_ref_pics_sps > 1) + us(idx_size, lt_idx_sps[i], + 0, sps->num_long_term_ref_pics_sps - 1, 1, i); + if(sps->used_by_curr_pic_lt_sps_flag[current->lt_idx_sps[i]]) + ++num_pic_total_curr; + } + else { + ubs(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, poc_lsb_lt[i], 1, i); + flags(used_by_curr_pic_lt_flag[i], 1, i); + if(current->used_by_curr_pic_lt_flag[i]) + ++num_pic_total_curr; + } + flags(delta_poc_msb_present_flag[i], 1, i); + if(current->delta_poc_msb_present_flag[i]) + ues(delta_poc_msb_cycle_lt[i], 0, UINT32_MAX - 1, 1, i); + else + infer(delta_poc_msb_cycle_lt[i], 0); + } + } + + if(sps->sps_temporal_mvp_enabled_flag) + flag(slice_temporal_mvp_enabled_flag); + else + infer(slice_temporal_mvp_enabled_flag, 0); + + if(pps->pps_curr_pic_ref_enabled_flag) + ++num_pic_total_curr; + } + + if(sps->sample_adaptive_offset_enabled_flag) { + flag(slice_sao_luma_flag); + if(!sps->separate_colour_plane_flag && sps->chroma_format_idc != 0) + flag(slice_sao_chroma_flag); + else + infer(slice_sao_chroma_flag, 0); + } + else { + infer(slice_sao_luma_flag, 0); + infer(slice_sao_chroma_flag, 0); + } + + if(current->slice_type == HEVC_SLICE_P || + current->slice_type == HEVC_SLICE_B) { + flag(num_ref_idx_active_override_flag); + if(current->num_ref_idx_active_override_flag) { + ue(num_ref_idx_l0_active_minus1, 0, 14); + if(current->slice_type == HEVC_SLICE_B) + ue(num_ref_idx_l1_active_minus1, 0, 14); + else + infer(num_ref_idx_l1_active_minus1, pps->num_ref_idx_l1_default_active_minus1); + } + else { + infer(num_ref_idx_l0_active_minus1, pps->num_ref_idx_l0_default_active_minus1); + infer(num_ref_idx_l1_active_minus1, pps->num_ref_idx_l1_default_active_minus1); + } + + if(pps->lists_modification_present_flag && num_pic_total_curr > 1) + CHECK(FUNC(ref_pic_lists_modification)(ctx, rw, current, + num_pic_total_curr)); + + if(current->slice_type == HEVC_SLICE_B) + flag(mvd_l1_zero_flag); + if(pps->cabac_init_present_flag) + flag(cabac_init_flag); + else + infer(cabac_init_flag, 0); + if(current->slice_temporal_mvp_enabled_flag) { + if(current->slice_type == HEVC_SLICE_B) + flag(collocated_from_l0_flag); + else + infer(collocated_from_l0_flag, 1); + if(current->collocated_from_l0_flag) { + if(current->num_ref_idx_l0_active_minus1 > 0) + ue(collocated_ref_idx, 0, current->num_ref_idx_l0_active_minus1); + else + infer(collocated_ref_idx, 0); + } + else { + if(current->num_ref_idx_l1_active_minus1 > 0) + ue(collocated_ref_idx, 0, current->num_ref_idx_l1_active_minus1); + else + infer(collocated_ref_idx, 0); + } + } + + if((pps->weighted_pred_flag && current->slice_type == HEVC_SLICE_P) || + (pps->weighted_bipred_flag && current->slice_type == HEVC_SLICE_B)) + CHECK(FUNC(pred_weight_table)(ctx, rw, current)); + + ue(five_minus_max_num_merge_cand, 0, 4); + if(sps->motion_vector_resolution_control_idc == 2) + flag(use_integer_mv_flag); + else + infer(use_integer_mv_flag, sps->motion_vector_resolution_control_idc); + } + + se(slice_qp_delta, + -6 * sps->bit_depth_luma_minus8 - (pps->init_qp_minus26 + 26), + +51 - (pps->init_qp_minus26 + 26)); + if(pps->pps_slice_chroma_qp_offsets_present_flag) { + se(slice_cb_qp_offset, -12, +12); + se(slice_cr_qp_offset, -12, +12); + } + else { + infer(slice_cb_qp_offset, 0); + infer(slice_cr_qp_offset, 0); + } + if(pps->pps_slice_act_qp_offsets_present_flag) { + se(slice_act_y_qp_offset, + -12 - (pps->pps_act_y_qp_offset_plus5 - 5), + +12 - (pps->pps_act_y_qp_offset_plus5 - 5)); + se(slice_act_cb_qp_offset, + -12 - (pps->pps_act_cb_qp_offset_plus5 - 5), + +12 - (pps->pps_act_cb_qp_offset_plus5 - 5)); + se(slice_act_cr_qp_offset, + -12 - (pps->pps_act_cr_qp_offset_plus3 - 3), + +12 - (pps->pps_act_cr_qp_offset_plus3 - 3)); + } + else { + infer(slice_act_y_qp_offset, 0); + infer(slice_act_cb_qp_offset, 0); + infer(slice_act_cr_qp_offset, 0); + } + if(pps->chroma_qp_offset_list_enabled_flag) + flag(cu_chroma_qp_offset_enabled_flag); + else + infer(cu_chroma_qp_offset_enabled_flag, 0); + + if(pps->deblocking_filter_override_enabled_flag) + flag(deblocking_filter_override_flag); + else + infer(deblocking_filter_override_flag, 0); + if(current->deblocking_filter_override_flag) { + flag(slice_deblocking_filter_disabled_flag); + if(!current->slice_deblocking_filter_disabled_flag) { + se(slice_beta_offset_div2, -6, +6); + se(slice_tc_offset_div2, -6, +6); + } + else { + infer(slice_beta_offset_div2, pps->pps_beta_offset_div2); + infer(slice_tc_offset_div2, pps->pps_tc_offset_div2); + } + } + else { + infer(slice_deblocking_filter_disabled_flag, + pps->pps_deblocking_filter_disabled_flag); + infer(slice_beta_offset_div2, pps->pps_beta_offset_div2); + infer(slice_tc_offset_div2, pps->pps_tc_offset_div2); + } + if(pps->pps_loop_filter_across_slices_enabled_flag && + (current->slice_sao_luma_flag || current->slice_sao_chroma_flag || + !current->slice_deblocking_filter_disabled_flag)) + flag(slice_loop_filter_across_slices_enabled_flag); + else + infer(slice_loop_filter_across_slices_enabled_flag, + pps->pps_loop_filter_across_slices_enabled_flag); + } + + if(pps->tiles_enabled_flag || pps->entropy_coding_sync_enabled_flag) { + unsigned int num_entry_point_offsets_limit; + if(!pps->tiles_enabled_flag && pps->entropy_coding_sync_enabled_flag) + num_entry_point_offsets_limit = pic_height_in_ctbs_y - 1; + else if(pps->tiles_enabled_flag && !pps->entropy_coding_sync_enabled_flag) + num_entry_point_offsets_limit = + (pps->num_tile_columns_minus1 + 1) * (pps->num_tile_rows_minus1 + 1); + else + num_entry_point_offsets_limit = + (pps->num_tile_columns_minus1 + 1) * pic_height_in_ctbs_y - 1; + ue(num_entry_point_offsets, 0, num_entry_point_offsets_limit); + + if(current->num_entry_point_offsets > HEVC_MAX_ENTRY_POINT_OFFSETS) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many entry points: " + "%" PRIu16 ".\n", + current->num_entry_point_offsets); + return AVERROR_PATCHWELCOME; + } + + if(current->num_entry_point_offsets > 0) { + ue(offset_len_minus1, 0, 31); + for(i = 0; i < current->num_entry_point_offsets; i++) + ubs(current->offset_len_minus1 + 1, entry_point_offset_minus1[i], 1, i); + } + } + + if(pps->slice_segment_header_extension_present_flag) { + ue(slice_segment_header_extension_length, 0, 256); + for(i = 0; i < current->slice_segment_header_extension_length; i++) + us(8, slice_segment_header_extension_data_byte[i], 0x00, 0xff, 1, i); + } + + CHECK(FUNC(byte_alignment)(ctx, rw)); + + return 0; +} + +static int FUNC(sei_buffering_period)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIBufferingPeriod *current, SEIMessageState *sei) { + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps; + const H265RawHRDParameters *hrd; + int err, i, length; + +#ifdef READ + int start_pos, end_pos; + start_pos = get_bits_count(rw); +#endif + + HEADER("Buffering Period"); + + ue(bp_seq_parameter_set_id, 0, HEVC_MAX_SPS_COUNT - 1); + + sps = h265->sps[current->bp_seq_parameter_set_id]; + if(!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + current->bp_seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h265->active_sps = sps; + + if(!sps->vui_parameters_present_flag || + !sps->vui.vui_hrd_parameters_present_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Buffering period SEI requires " + "HRD parameters to be present in SPS.\n"); + return AVERROR_INVALIDDATA; + } + hrd = &sps->vui.hrd_parameters; + if(!hrd->nal_hrd_parameters_present_flag && + !hrd->vcl_hrd_parameters_present_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Buffering period SEI requires " + "NAL or VCL HRD parameters to be present.\n"); + return AVERROR_INVALIDDATA; + } + + if(!hrd->sub_pic_hrd_params_present_flag) + flag(irap_cpb_params_present_flag); + else + infer(irap_cpb_params_present_flag, 0); + if(current->irap_cpb_params_present_flag) { + length = hrd->au_cpb_removal_delay_length_minus1 + 1; + ub(length, cpb_delay_offset); + length = hrd->dpb_output_delay_length_minus1 + 1; + ub(length, dpb_delay_offset); + } + else { + infer(cpb_delay_offset, 0); + infer(dpb_delay_offset, 0); + } + + flag(concatenation_flag); + + length = hrd->au_cpb_removal_delay_length_minus1 + 1; + ub(length, au_cpb_removal_delay_delta_minus1); + + if(hrd->nal_hrd_parameters_present_flag) { + for(i = 0; i <= hrd->cpb_cnt_minus1[0]; i++) { + length = hrd->initial_cpb_removal_delay_length_minus1 + 1; + + ubs(length, nal_initial_cpb_removal_delay[i], 1, i); + ubs(length, nal_initial_cpb_removal_offset[i], 1, i); + + if(hrd->sub_pic_hrd_params_present_flag || + current->irap_cpb_params_present_flag) { + ubs(length, nal_initial_alt_cpb_removal_delay[i], 1, i); + ubs(length, nal_initial_alt_cpb_removal_offset[i], 1, i); + } + } + } + if(hrd->vcl_hrd_parameters_present_flag) { + for(i = 0; i <= hrd->cpb_cnt_minus1[0]; i++) { + length = hrd->initial_cpb_removal_delay_length_minus1 + 1; + + ubs(length, vcl_initial_cpb_removal_delay[i], 1, i); + ubs(length, vcl_initial_cpb_removal_offset[i], 1, i); + + if(hrd->sub_pic_hrd_params_present_flag || + current->irap_cpb_params_present_flag) { + ubs(length, vcl_initial_alt_cpb_removal_delay[i], 1, i); + ubs(length, vcl_initial_alt_cpb_removal_offset[i], 1, i); + } + } + } + +#ifdef READ + end_pos = get_bits_count(rw); + if(cbs_h265_payload_extension_present(rw, sei->payload_size, + end_pos - start_pos)) + flag(use_alt_cpb_params_flag); + else + infer(use_alt_cpb_params_flag, 0); +#else + // If unknown extension data exists, then use_alt_cpb_params_flag is + // coded in the bitstream and must be written even if it's 0. + if(current->use_alt_cpb_params_flag || sei->extension_present) { + flag(use_alt_cpb_params_flag); + // Ensure this bit is not the last in the payload by making the + // more_data_in_payload() check evaluate to true, so it may not + // be mistaken as something else by decoders. + sei->extension_present = 1; + } +#endif + + return 0; +} + +static int FUNC(sei_pic_timing)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIPicTiming *current, SEIMessageState *sei) { + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps; + const H265RawHRDParameters *hrd; + int err, expected_source_scan_type, i, length; + + HEADER("Picture Timing"); + + sps = h265->active_sps; + if(!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "No active SPS for pic_timing.\n"); + return AVERROR_INVALIDDATA; + } + + expected_source_scan_type = 2 - + 2 * sps->profile_tier_level.general_interlaced_source_flag - + sps->profile_tier_level.general_progressive_source_flag; + + if(sps->vui.frame_field_info_present_flag) { + u(4, pic_struct, 0, 12); + u(2, source_scan_type, + expected_source_scan_type >= 0 ? expected_source_scan_type : 0, + expected_source_scan_type >= 0 ? expected_source_scan_type : 2); + flag(duplicate_flag); + } + else { + infer(pic_struct, 0); + infer(source_scan_type, + expected_source_scan_type >= 0 ? expected_source_scan_type : 2); + infer(duplicate_flag, 0); + } + + if(sps->vui_parameters_present_flag && + sps->vui.vui_hrd_parameters_present_flag) + hrd = &sps->vui.hrd_parameters; + else + hrd = NULL; + if(hrd && (hrd->nal_hrd_parameters_present_flag || + hrd->vcl_hrd_parameters_present_flag)) { + length = hrd->au_cpb_removal_delay_length_minus1 + 1; + ub(length, au_cpb_removal_delay_minus1); + + length = hrd->dpb_output_delay_length_minus1 + 1; + ub(length, pic_dpb_output_delay); + + if(hrd->sub_pic_hrd_params_present_flag) { + length = hrd->dpb_output_delay_du_length_minus1 + 1; + ub(length, pic_dpb_output_du_delay); + } + + if(hrd->sub_pic_hrd_params_present_flag && + hrd->sub_pic_cpb_params_in_pic_timing_sei_flag) { + // Each decoding unit must contain at least one slice segment. + ue(num_decoding_units_minus1, 0, HEVC_MAX_SLICE_SEGMENTS); + flag(du_common_cpb_removal_delay_flag); + + length = hrd->du_cpb_removal_delay_increment_length_minus1 + 1; + if(current->du_common_cpb_removal_delay_flag) + ub(length, du_common_cpb_removal_delay_increment_minus1); + + for(i = 0; i <= current->num_decoding_units_minus1; i++) { + ues(num_nalus_in_du_minus1[i], + 0, HEVC_MAX_SLICE_SEGMENTS, 1, i); + if(!current->du_common_cpb_removal_delay_flag && + i < current->num_decoding_units_minus1) + ubs(length, du_cpb_removal_delay_increment_minus1[i], 1, i); + } + } + } + + return 0; +} + +static int FUNC(sei_pan_scan_rect)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIPanScanRect *current, SEIMessageState *sei) { + int err, i; + + HEADER("Pan-Scan Rectangle"); + + ue(pan_scan_rect_id, 0, UINT32_MAX - 1); + flag(pan_scan_rect_cancel_flag); + + if(!current->pan_scan_rect_cancel_flag) { + ue(pan_scan_cnt_minus1, 0, 2); + + for(i = 0; i <= current->pan_scan_cnt_minus1; i++) { + ses(pan_scan_rect_left_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + ses(pan_scan_rect_right_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + ses(pan_scan_rect_top_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + ses(pan_scan_rect_bottom_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + } + + flag(pan_scan_rect_persistence_flag); + } + + return 0; +} + +static int FUNC(sei_recovery_point)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIRecoveryPoint *current, SEIMessageState *sei) { + int err; + + HEADER("Recovery Point"); + + se(recovery_poc_cnt, -32768, 32767); + + flag(exact_match_flag); + flag(broken_link_flag); + + return 0; +} + +static int FUNC(sei_display_orientation)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIDisplayOrientation *current, SEIMessageState *sei) { + int err; + + HEADER("Display Orientation"); + + flag(display_orientation_cancel_flag); + if(!current->display_orientation_cancel_flag) { + flag(hor_flip); + flag(ver_flip); + ub(16, anticlockwise_rotation); + flag(display_orientation_persistence_flag); + } + + return 0; +} + +static int FUNC(sei_active_parameter_sets)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIActiveParameterSets *current, SEIMessageState *sei) { + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawVPS *vps; + int err, i; + + HEADER("Active Parameter Sets"); + + u(4, active_video_parameter_set_id, 0, HEVC_MAX_VPS_COUNT); + vps = h265->vps[current->active_video_parameter_set_id]; + if(!vps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "VPS id %d not available for active " + "parameter sets.\n", + current->active_video_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h265->active_vps = vps; + + flag(self_contained_cvs_flag); + flag(no_parameter_set_update_flag); + + ue(num_sps_ids_minus1, 0, HEVC_MAX_SPS_COUNT - 1); + for(i = 0; i <= current->num_sps_ids_minus1; i++) + ues(active_seq_parameter_set_id[i], 0, HEVC_MAX_SPS_COUNT - 1, 1, i); + + for(i = vps->vps_base_layer_internal_flag; + i <= FFMIN(62, vps->vps_max_layers_minus1); i++) { + ues(layer_sps_idx[i], 0, current->num_sps_ids_minus1, 1, i); + + if(i == 0) + h265->active_sps = h265->sps[current->active_seq_parameter_set_id[current->layer_sps_idx[0]]]; + } + + return 0; +} + +static int FUNC(sei_decoded_picture_hash)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIDecodedPictureHash *current, SEIMessageState *sei) { + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps = h265->active_sps; + int err, c, i; + + HEADER("Decoded Picture Hash"); + + if(!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "No active SPS for decoded picture hash.\n"); + return AVERROR_INVALIDDATA; + } + + u(8, hash_type, 0, 2); + + for(c = 0; c < (sps->chroma_format_idc == 0 ? 1 : 3); c++) { + if(current->hash_type == 0) { + for(i = 0; i < 16; i++) + us(8, picture_md5[c][i], 0x00, 0xff, 2, c, i); + } + else if(current->hash_type == 1) { + us(16, picture_crc[c], 0x0000, 0xffff, 1, c); + } + else if(current->hash_type == 2) { + us(32, picture_checksum[c], 0x00000000, 0xffffffff, 1, c); + } + } + + return 0; +} + +static int FUNC(sei_time_code)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEITimeCode *current, SEIMessageState *sei) { + int err, i; + + HEADER("Time Code"); + + u(2, num_clock_ts, 1, 3); + + for(i = 0; i < current->num_clock_ts; i++) { + flags(clock_timestamp_flag[i], 1, i); + + if(current->clock_timestamp_flag[i]) { + flags(units_field_based_flag[i], 1, i); + us(5, counting_type[i], 0, 6, 1, i); + flags(full_timestamp_flag[i], 1, i); + flags(discontinuity_flag[i], 1, i); + flags(cnt_dropped_flag[i], 1, i); + + ubs(9, n_frames[i], 1, i); + + if(current->full_timestamp_flag[i]) { + us(6, seconds_value[i], 0, 59, 1, i); + us(6, minutes_value[i], 0, 59, 1, i); + us(5, hours_value[i], 0, 23, 1, i); + } + else { + flags(seconds_flag[i], 1, i); + if(current->seconds_flag[i]) { + us(6, seconds_value[i], 0, 59, 1, i); + flags(minutes_flag[i], 1, i); + if(current->minutes_flag[i]) { + us(6, minutes_value[i], 0, 59, 1, i); + flags(hours_flag[i], 1, i); + if(current->hours_flag[i]) + us(5, hours_value[i], 0, 23, 1, i); + } + } + } + + ubs(5, time_offset_length[i], 1, i); + if(current->time_offset_length[i] > 0) + ibs(current->time_offset_length[i], time_offset_value[i], 1, i); + else + infer(time_offset_value[i], 0); + } + } + + return 0; +} + +static int FUNC(sei_alpha_channel_info)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIAlphaChannelInfo *current, SEIMessageState *sei) { + int err, length; + + HEADER("Alpha Channel Information"); + + flag(alpha_channel_cancel_flag); + if(!current->alpha_channel_cancel_flag) { + ub(3, alpha_channel_use_idc); + ub(3, alpha_channel_bit_depth_minus8); + length = current->alpha_channel_bit_depth_minus8 + 9; + ub(length, alpha_transparent_value); + ub(length, alpha_opaque_value); + flag(alpha_channel_incr_flag); + flag(alpha_channel_clip_flag); + if(current->alpha_channel_clip_flag) + flag(alpha_channel_clip_type_flag); + } + else { + infer(alpha_channel_use_idc, 2); + infer(alpha_channel_incr_flag, 0); + infer(alpha_channel_clip_flag, 0); + } + + return 0; +} + +static int FUNC(sei)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEI *current, int prefix) { + int err; + + if(prefix) + HEADER("Prefix Supplemental Enhancement Information"); + else + HEADER("Suffix Supplemental Enhancement Information"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + prefix ? HEVC_NAL_SEI_PREFIX : HEVC_NAL_SEI_SUFFIX)); + + CHECK(FUNC_SEI(message_list)(ctx, rw, ¤t->message_list, prefix)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} diff --git a/third-party/cbs/cbs_internal.h b/third-party/cbs/cbs_internal.h new file mode 100644 index 00000000..529bd55f --- /dev/null +++ b/third-party/cbs/cbs_internal.h @@ -0,0 +1,221 @@ +/* + * 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 + +#include +#include + +#include "cbs/cbs.h" +#include "codec_id.h" +#include "get_bits.h" +#include "put_bits.h" + + +enum CBSContentType { + // Unit content is a simple structure. + CBS_CONTENT_TYPE_POD, + // Unit content contains some references to other structures, but all + // managed via buffer reference counting. The descriptor defines the + // structure offsets of every buffer reference. + CBS_CONTENT_TYPE_INTERNAL_REFS, + // Unit content is something more complex. The descriptor defines + // special functions to manage the content. + CBS_CONTENT_TYPE_COMPLEX, +}; + +enum { + // Maximum number of unit types described by the same unit type + // descriptor. + CBS_MAX_UNIT_TYPES = 3, + // Maximum number of reference buffer offsets in any one unit. + CBS_MAX_REF_OFFSETS = 2, + // Special value used in a unit type descriptor to indicate that it + // applies to a large range of types rather than a set of discrete + // values. + CBS_UNIT_TYPE_RANGE = -1, +}; + +typedef const struct CodedBitstreamUnitTypeDescriptor { + // Number of entries in the unit_types array, or the special value + // CBS_UNIT_TYPE_RANGE to indicate that the range fields should be + // used instead. + int nb_unit_types; + + // Array of unit types that this entry describes. + const CodedBitstreamUnitType unit_types[CBS_MAX_UNIT_TYPES]; + + // Start and end of unit type range, used if nb_unit_types is + // CBS_UNIT_TYPE_RANGE. + const CodedBitstreamUnitType unit_type_range_start; + const CodedBitstreamUnitType unit_type_range_end; + + // The type of content described. + enum CBSContentType content_type; + // The size of the structure which should be allocated to contain + // the decomposed content of this type of unit. + size_t content_size; + + // Number of entries in the ref_offsets array. Only used if the + // content_type is CBS_CONTENT_TYPE_INTERNAL_REFS. + int nb_ref_offsets; + // The structure must contain two adjacent elements: + // type *field; + // AVBufferRef *field_ref; + // where field points to something in the buffer referred to by + // field_ref. This offset is then set to offsetof(struct, field). + size_t ref_offsets[CBS_MAX_REF_OFFSETS]; + + void (*content_free)(void *opaque, uint8_t *data); + int (*content_clone)(AVBufferRef **ref, CodedBitstreamUnit *unit); +} CodedBitstreamUnitTypeDescriptor; + +typedef struct CodedBitstreamType { + enum AVCodecID codec_id; + + // A class for the private data, used to declare private AVOptions. + // This field is NULL for types that do not declare any options. + // If this field is non-NULL, the first member of the filter private data + // must be a pointer to AVClass. + const AVClass *priv_class; + + size_t priv_data_size; + + // List of unit type descriptors for this codec. + // Terminated by a descriptor with nb_unit_types equal to zero. + const CodedBitstreamUnitTypeDescriptor *unit_types; + + // Split frag->data into coded bitstream units, creating the + // frag->units array. Fill data but not content on each unit. + // The header argument should be 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 data bitstream from unit->content into pbc. + // Return value AVERROR(ENOSPC) indicates that pbc was too small. + int (*write_unit)(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc); + + // 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); + + // Reset the codec internal state. + void (*flush)(CodedBitstreamContext *ctx); + + // 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 int *subscripts, + 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, + const int *subscripts, 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, + const int *subscripts, uint32_t value, + uint32_t range_min, uint32_t range_max); + +int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc, + int width, const char *name, + const int *subscripts, int32_t *write_to, + int32_t range_min, int32_t range_max); + +int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, + const int *subscripts, int32_t value, + int32_t range_min, int32_t range_max); + +// The largest unsigned value representable in N bits, suitable for use as +// range_max in the above functions. +#define MAX_UINT_BITS(length) ((UINT64_C(1) << (length)) - 1) + +// The largest signed value representable in N bits, suitable for use as +// range_max in the above functions. +#define MAX_INT_BITS(length) ((INT64_C(1) << ((length)-1)) - 1) + +// The smallest signed value representable in N bits, suitable for use as +// range_min in the above functions. +#define MIN_INT_BITS(length) (-(INT64_C(1) << ((length)-1))) + + +#define CBS_UNIT_TYPE_POD(type, structure) \ + { \ + .nb_unit_types = 1, \ + .unit_types = { type }, \ + .content_type = CBS_CONTENT_TYPE_POD, \ + .content_size = sizeof(structure), \ + } +#define CBS_UNIT_TYPE_INTERNAL_REF(type, structure, ref_field) \ + { \ + .nb_unit_types = 1, \ + .unit_types = { type }, \ + .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS, \ + .content_size = sizeof(structure), \ + .nb_ref_offsets = 1, \ + .ref_offsets = { offsetof(structure, ref_field) }, \ + } +#define CBS_UNIT_TYPE_COMPLEX(type, structure, free_func) \ + { \ + .nb_unit_types = 1, \ + .unit_types = { type }, \ + .content_type = CBS_CONTENT_TYPE_COMPLEX, \ + .content_size = sizeof(structure), \ + .content_free = free_func, \ + } +#define CBS_UNIT_TYPE_END_OF_LIST \ + { .nb_unit_types = 0 } + + +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_jpeg; +extern const CodedBitstreamType ff_cbs_type_mpeg2; +extern const CodedBitstreamType ff_cbs_type_vp9; + + +#endif /* AVCODEC_CBS_INTERNAL_H */ diff --git a/third-party/cbs/cbs_jpeg.c b/third-party/cbs/cbs_jpeg.c new file mode 100644 index 00000000..bb4f08a1 --- /dev/null +++ b/third-party/cbs/cbs_jpeg.c @@ -0,0 +1,482 @@ +/* + * 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 "cbs/cbs_jpeg.h" +#include "cbs/cbs.h" + +#include "cbs_internal.h" + + +#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 SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]) { subs, __VA_ARGS__ }) : NULL) + +#define u(width, name, range_min, range_max) \ + xu(width, name, range_min, range_max, 0, ) +#define us(width, name, sub, range_min, range_max) \ + xu(width, name, range_min, range_max, 1, sub) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext +#define FUNC(name) cbs_jpeg_read_##name + +#define xu(width, name, 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)); \ + current->name = value; \ + } while(0) + +#include "cbs_jpeg_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef FUNC +#undef xu + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext +#define FUNC(name) cbs_jpeg_write_##name + +#define xu(width, name, range_min, range_max, subs, ...) \ + do { \ + uint32_t value = current->name; \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while(0) + + +#include "cbs_jpeg_syntax_template.c" + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef FUNC +#undef xu + + +static void cbs_jpeg_free_application_data(void *opaque, uint8_t *content) { + JPEGRawApplicationData *ad = (JPEGRawApplicationData *)content; + av_buffer_unref(&ad->Ap_ref); + av_freep(&content); +} + +static void cbs_jpeg_free_comment(void *opaque, uint8_t *content) { + JPEGRawComment *comment = (JPEGRawComment *)content; + av_buffer_unref(&comment->Cm_ref); + av_freep(&content); +} + +static void cbs_jpeg_free_scan(void *opaque, uint8_t *content) { + JPEGRawScan *scan = (JPEGRawScan *)content; + av_buffer_unref(&scan->data_ref); + av_freep(&content); +} + +static int cbs_jpeg_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) { + AVBufferRef *data_ref; + uint8_t *data; + size_t data_size; + int unit, start, end, marker, next_start, next_marker; + int err, i, j, length; + + if(frag->data_size < 4) { + // Definitely too short to be meaningful. + return AVERROR_INVALIDDATA; + } + + for(i = 0; i + 1 < frag->data_size && frag->data[i] != 0xff; i++) + ; + if(i > 0) { + av_log(ctx->log_ctx, AV_LOG_WARNING, "Discarding %d bytes at " + "beginning of image.\n", + i); + } + for(++i; i + 1 < frag->data_size && frag->data[i] == 0xff; i++) + ; + if(i + 1 >= frag->data_size && frag->data[i]) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: " + "no SOI marker found.\n"); + return AVERROR_INVALIDDATA; + } + marker = frag->data[i]; + if(marker != JPEG_MARKER_SOI) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: first " + "marker is %02x, should be SOI.\n", + marker); + return AVERROR_INVALIDDATA; + } + for(++i; i + 1 < frag->data_size && frag->data[i] == 0xff; i++) + ; + if(i + 1 >= frag->data_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: " + "no image content found.\n"); + return AVERROR_INVALIDDATA; + } + marker = frag->data[i]; + start = i + 1; + + for(unit = 0;; unit++) { + if(marker == JPEG_MARKER_EOI) { + break; + } + else if(marker == JPEG_MARKER_SOS) { + next_marker = -1; + end = start; + for(i = start; i + 1 < frag->data_size; i++) { + if(frag->data[i] != 0xff) + continue; + end = i; + for(++i; i + 1 < frag->data_size && + frag->data[i] == 0xff; + i++) + ; + if(i + 1 < frag->data_size) { + if(frag->data[i] == 0x00) + continue; + next_marker = frag->data[i]; + next_start = i + 1; + } + break; + } + } + else { + i = start; + if(i + 2 > frag->data_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: " + "truncated at %02x marker.\n", + marker); + return AVERROR_INVALIDDATA; + } + length = AV_RB16(frag->data + i); + if(i + length > frag->data_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: " + "truncated at %02x marker segment.\n", + marker); + return AVERROR_INVALIDDATA; + } + end = start + length; + + i = end; + if(frag->data[i] != 0xff) { + next_marker = -1; + } + else { + for(++i; i + 1 < frag->data_size && + frag->data[i] == 0xff; + i++) + ; + if(i + 1 >= frag->data_size) { + next_marker = -1; + } + else { + next_marker = frag->data[i]; + next_start = i + 1; + } + } + } + + if(marker == JPEG_MARKER_SOS) { + length = AV_RB16(frag->data + start); + + if(length > end - start) + return AVERROR_INVALIDDATA; + + data_ref = NULL; + data = av_malloc(end - start + + AV_INPUT_BUFFER_PADDING_SIZE); + if(!data) + return AVERROR(ENOMEM); + + memcpy(data, frag->data + start, length); + for(i = start + length, j = length; i < end; i++, j++) { + if(frag->data[i] == 0xff) { + while(frag->data[i] == 0xff) + ++i; + data[j] = 0xff; + } + else { + data[j] = frag->data[i]; + } + } + data_size = j; + + memset(data + data_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + } + else { + data = frag->data + start; + data_size = end - start; + data_ref = frag->data_ref; + } + + err = ff_cbs_insert_unit_data(frag, unit, marker, + data, data_size, data_ref); + if(err < 0) + return err; + + if(next_marker == -1) + break; + marker = next_marker; + start = next_start; + } + + return 0; +} + +static int cbs_jpeg_read_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) { + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if(err < 0) + return err; + + if(unit->type >= JPEG_MARKER_SOF0 && + unit->type <= JPEG_MARKER_SOF3) { + err = ff_cbs_alloc_unit_content(unit, + sizeof(JPEGRawFrameHeader), + NULL); + if(err < 0) + return err; + + err = cbs_jpeg_read_frame_header(ctx, &gbc, unit->content); + if(err < 0) + return err; + } + else if(unit->type >= JPEG_MARKER_APPN && + unit->type <= JPEG_MARKER_APPN + 15) { + err = ff_cbs_alloc_unit_content(unit, + sizeof(JPEGRawApplicationData), + &cbs_jpeg_free_application_data); + if(err < 0) + return err; + + err = cbs_jpeg_read_application_data(ctx, &gbc, unit->content); + if(err < 0) + return err; + } + else if(unit->type == JPEG_MARKER_SOS) { + JPEGRawScan *scan; + int pos; + + err = ff_cbs_alloc_unit_content(unit, + sizeof(JPEGRawScan), + &cbs_jpeg_free_scan); + if(err < 0) + return err; + scan = unit->content; + + err = cbs_jpeg_read_scan_header(ctx, &gbc, &scan->header); + if(err < 0) + return err; + + pos = get_bits_count(&gbc); + av_assert0(pos % 8 == 0); + if(pos > 0) { + scan->data_size = unit->data_size - pos / 8; + scan->data_ref = av_buffer_ref(unit->data_ref); + if(!scan->data_ref) + return AVERROR(ENOMEM); + scan->data = unit->data + pos / 8; + } + } + else { + switch(unit->type) { +#define SEGMENT(marker, type, func, free) \ + case JPEG_MARKER_##marker: { \ + err = ff_cbs_alloc_unit_content(unit, \ + sizeof(type), free); \ + if(err < 0) \ + return err; \ + err = cbs_jpeg_read_##func(ctx, &gbc, unit->content); \ + if(err < 0) \ + return err; \ + } break + SEGMENT(DQT, JPEGRawQuantisationTableSpecification, dqt, NULL); + SEGMENT(DHT, JPEGRawHuffmanTableSpecification, dht, NULL); + SEGMENT(COM, JPEGRawComment, comment, &cbs_jpeg_free_comment); +#undef SEGMENT + default: + return AVERROR(ENOSYS); + } + } + + return 0; +} + +static int cbs_jpeg_write_scan(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) { + JPEGRawScan *scan = unit->content; + int err; + + err = cbs_jpeg_write_scan_header(ctx, pbc, &scan->header); + if(err < 0) + return err; + + if(scan->data) { + if(scan->data_size * 8 > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + av_assert0(put_bits_count(pbc) % 8 == 0); + + flush_put_bits(pbc); + + memcpy(put_bits_ptr(pbc), scan->data, scan->data_size); + skip_put_bytes(pbc, scan->data_size); + } + + return 0; +} + +static int cbs_jpeg_write_segment(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) { + int err; + + if(unit->type >= JPEG_MARKER_SOF0 && + unit->type <= JPEG_MARKER_SOF3) { + err = cbs_jpeg_write_frame_header(ctx, pbc, unit->content); + } + else if(unit->type >= JPEG_MARKER_APPN && + unit->type <= JPEG_MARKER_APPN + 15) { + err = cbs_jpeg_write_application_data(ctx, pbc, unit->content); + } + else { + switch(unit->type) { +#define SEGMENT(marker, func) \ + case JPEG_MARKER_##marker: \ + err = cbs_jpeg_write_##func(ctx, pbc, unit->content); \ + break; + SEGMENT(DQT, dqt); + SEGMENT(DHT, dht); + SEGMENT(COM, comment); + default: + return AVERROR_PATCHWELCOME; + } + } + + return err; +} + +static int cbs_jpeg_write_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) { + if(unit->type == JPEG_MARKER_SOS) + return cbs_jpeg_write_scan(ctx, unit, pbc); + else + return cbs_jpeg_write_segment(ctx, unit, pbc); +} + +static int cbs_jpeg_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) { + const CodedBitstreamUnit *unit; + uint8_t *data; + size_t size, dp, sp; + int i; + + size = 4; // SOI + EOI. + for(i = 0; i < frag->nb_units; i++) { + unit = &frag->units[i]; + size += 2 + unit->data_size; + if(unit->type == JPEG_MARKER_SOS) { + for(sp = 0; sp < unit->data_size; sp++) { + if(unit->data[sp] == 0xff) + ++size; + } + } + } + + frag->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if(!frag->data_ref) + return AVERROR(ENOMEM); + data = frag->data_ref->data; + + dp = 0; + + data[dp++] = 0xff; + data[dp++] = JPEG_MARKER_SOI; + + for(i = 0; i < frag->nb_units; i++) { + unit = &frag->units[i]; + + data[dp++] = 0xff; + data[dp++] = unit->type; + + if(unit->type != JPEG_MARKER_SOS) { + memcpy(data + dp, unit->data, unit->data_size); + dp += unit->data_size; + } + else { + sp = AV_RB16(unit->data); + av_assert0(sp <= unit->data_size); + memcpy(data + dp, unit->data, sp); + dp += sp; + + for(; sp < unit->data_size; sp++) { + if(unit->data[sp] == 0xff) { + data[dp++] = 0xff; + data[dp++] = 0x00; + } + else { + data[dp++] = unit->data[sp]; + } + } + } + } + + data[dp++] = 0xff; + data[dp++] = JPEG_MARKER_EOI; + + av_assert0(dp == size); + + memset(data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + frag->data = data; + frag->data_size = size; + + return 0; +} + +const CodedBitstreamType ff_cbs_type_jpeg = { + .codec_id = AV_CODEC_ID_MJPEG, + + .split_fragment = &cbs_jpeg_split_fragment, + .read_unit = &cbs_jpeg_read_unit, + .write_unit = &cbs_jpeg_write_unit, + .assemble_fragment = &cbs_jpeg_assemble_fragment, +}; diff --git a/third-party/cbs/cbs_jpeg_syntax_template.c b/third-party/cbs/cbs_jpeg_syntax_template.c new file mode 100644 index 00000000..613a6835 --- /dev/null +++ b/third-party/cbs/cbs_jpeg_syntax_template.c @@ -0,0 +1,189 @@ +/* + * 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(frame_header)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawFrameHeader *current) { + int err, i; + + HEADER("Frame Header"); + + u(16, Lf, 8, 8 + 3 * JPEG_MAX_COMPONENTS); + + u(8, P, 2, 16); + u(16, Y, 0, JPEG_MAX_HEIGHT); + u(16, X, 1, JPEG_MAX_WIDTH); + u(8, Nf, 1, JPEG_MAX_COMPONENTS); + + for(i = 0; i < current->Nf; i++) { + us(8, C[i], i, 0, JPEG_MAX_COMPONENTS); + us(4, H[i], i, 1, 4); + us(4, V[i], i, 1, 4); + us(8, Tq[i], i, 0, 3); + } + + return 0; +} + +static int FUNC(quantisation_table)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawQuantisationTable *current) { + int err, i; + + u(4, Pq, 0, 1); + u(4, Tq, 0, 3); + + if(current->Pq) { + for(i = 0; i < 64; i++) + us(16, Q[i], i, 1, 255); + } + else { + for(i = 0; i < 64; i++) + us(8, Q[i], i, 1, 255); + } + + return 0; +} + +static int FUNC(dqt)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawQuantisationTableSpecification *current) { + int err, i, n; + + HEADER("Quantisation Tables"); + + u(16, Lq, 2, 2 + 4 * 65); + n = current->Lq / 65; + + for(i = 0; i < n; i++) + CHECK(FUNC(quantisation_table)(ctx, rw, ¤t->table[i])); + + return 0; +} + +static int FUNC(huffman_table)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawHuffmanTable *current) { + int err, i, j, ij; + + u(4, Tc, 0, 1); + u(4, Th, 0, 3); + + for(i = 0; i < 16; i++) + us(8, L[i], i, 0, 224); + + ij = 0; + for(i = 0; i < 16; i++) { + for(j = 0; j < current->L[i]; j++) { + if(ij >= 224) + return AVERROR_INVALIDDATA; + us(8, V[ij], ij, 0, 255); + ++ij; + } + } + + return 0; +} + +static int FUNC(dht)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawHuffmanTableSpecification *current) { + int err, i, j, n; + + HEADER("Huffman Tables"); + + u(16, Lh, 2, 2 + 8 * (1 + 16 + 256)); + + n = 2; + for(i = 0; n < current->Lh; i++) { + if(i >= 8) + return AVERROR_INVALIDDATA; + + CHECK(FUNC(huffman_table)(ctx, rw, ¤t->table[i])); + + ++n; + for(j = 0; j < 16; j++) + n += 1 + current->table[i].L[j]; + } + + return 0; +} + +static int FUNC(scan_header)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawScanHeader *current) { + int err, j; + + HEADER("Scan"); + + u(16, Ls, 6, 6 + 2 * JPEG_MAX_COMPONENTS); + + u(8, Ns, 1, 4); + for(j = 0; j < current->Ns; j++) { + us(8, Cs[j], j, 0, JPEG_MAX_COMPONENTS); + us(4, Td[j], j, 0, 3); + us(4, Ta[j], j, 0, 3); + } + + u(8, Ss, 0, 63); + u(8, Se, 0, 63); + u(4, Ah, 0, 13); + u(4, Al, 0, 15); + + return 0; +} + +static int FUNC(application_data)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawApplicationData *current) { + int err, i; + + HEADER("Application Data"); + + u(16, Lp, 2, 65535); + + if(current->Lp > 2) { +#ifdef READ + current->Ap_ref = av_buffer_alloc(current->Lp - 2); + if(!current->Ap_ref) + return AVERROR(ENOMEM); + current->Ap = current->Ap_ref->data; +#endif + + for(i = 0; i < current->Lp - 2; i++) + us(8, Ap[i], i, 0, 255); + } + + return 0; +} + +static int FUNC(comment)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawComment *current) { + int err, i; + + HEADER("Comment"); + + u(16, Lc, 2, 65535); + + if(current->Lc > 2) { +#ifdef READ + current->Cm_ref = av_buffer_alloc(current->Lc - 2); + if(!current->Cm_ref) + return AVERROR(ENOMEM); + current->Cm = current->Cm_ref->data; +#endif + + for(i = 0; i < current->Lc - 2; i++) + us(8, Cm[i], i, 0, 255); + } + + return 0; +} diff --git a/third-party/cbs/cbs_mpeg2.c b/third-party/cbs/cbs_mpeg2.c new file mode 100644 index 00000000..98a975f8 --- /dev/null +++ b/third-party/cbs/cbs_mpeg2.c @@ -0,0 +1,469 @@ +/* + * 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 "cbs/cbs.h" +#include "cbs/cbs_mpeg2.h" + +#include "cbs_internal.h" + + +#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_MPEG2(rw, name) FUNC_NAME(rw, mpeg2, name) +#define FUNC(name) FUNC_MPEG2(READWRITE, name) + +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]) { subs, __VA_ARGS__ }) : NULL) + +#define ui(width, name) \ + xui(width, name, current->name, 0, MAX_UINT_BITS(width), 0, ) +#define uir(width, name) \ + xui(width, name, current->name, 1, MAX_UINT_BITS(width), 0, ) +#define uis(width, name, subs, ...) \ + xui(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__) +#define uirs(width, name, subs, ...) \ + xui(width, name, current->name, 1, MAX_UINT_BITS(width), subs, __VA_ARGS__) +#define xui(width, name, var, range_min, range_max, subs, ...) \ + xuia(width, #name, var, range_min, range_max, subs, __VA_ARGS__) +#define sis(width, name, subs, ...) \ + xsi(width, name, current->name, subs, __VA_ARGS__) + +#define marker_bit() \ + bit("marker_bit", 1) +#define bit(string, value) \ + do { \ + av_unused uint32_t bit = value; \ + xuia(1, string, bit, value, value, 0, ); \ + } while(0) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define xuia(width, string, var, range_min, range_max, subs, ...) \ + do { \ + uint32_t value; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, string, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while(0) + +#define xsi(width, name, var, subs, ...) \ + do { \ + int32_t value; \ + CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), &value, \ + MIN_INT_BITS(width), \ + MAX_INT_BITS(width))); \ + var = value; \ + } while(0) + +#define nextbits(width, compare, var) \ + (get_bits_left(rw) >= width && \ + (var = show_bits(rw, width)) == (compare)) + +#define infer(name, value) \ + do { \ + current->name = value; \ + } while(0) + +#include "cbs_mpeg2_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef xuia +#undef xsi +#undef nextbits +#undef infer + + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define xuia(width, string, var, range_min, range_max, subs, ...) \ + do { \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, string, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + var, range_min, range_max)); \ + } while(0) + +#define xsi(width, name, var, subs, ...) \ + do { \ + CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), var, \ + MIN_INT_BITS(width), \ + MAX_INT_BITS(width))); \ + } while(0) + +#define nextbits(width, compare, var) (var) + +#define infer(name, value) \ + do { \ + if(current->name != (value)) { \ + av_log(ctx->log_ctx, AV_LOG_WARNING, "Warning: " \ + "%s does not match inferred value: " \ + "%" PRId64 ", but should be %" PRId64 ".\n", \ + #name, (int64_t)current->name, (int64_t)(value)); \ + } \ + } while(0) + +#include "cbs_mpeg2_syntax_template.c" + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef xuia +#undef xsi +#undef nextbits +#undef infer + +static const uint8_t *avpriv_find_start_code(const uint8_t *restrict p, + const uint8_t *end, + uint32_t *restrict state) { + int i; + + av_assert0(p <= end); + if(p >= end) + return end; + + for(i = 0; i < 3; i++) { + uint32_t tmp = *state << 8; + *state = tmp + *(p++); + if(tmp == 0x100 || p == end) + return p; + } + + while(p < end) { + if(p[-1] > 1) p += 3; + else if(p[-2]) + p += 2; + else if(p[-3] | (p[-1] - 1)) + p++; + else { + p++; + break; + } + } + + p = FFMIN(p, end) - 4; + *state = AV_RB32(p); + + return p + 4; +} + +static int cbs_mpeg2_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) { + const uint8_t *start, *end; + CodedBitstreamUnitType unit_type; + uint32_t start_code = -1; + size_t unit_size; + int err, i, final = 0; + + start = avpriv_find_start_code(frag->data, frag->data + frag->data_size, + &start_code); + if(start_code >> 8 != 0x000001) { + // No start code found. + return AVERROR_INVALIDDATA; + } + + for(i = 0;; i++) { + unit_type = start_code & 0xff; + + if(start == frag->data + frag->data_size) { + // The last four bytes form a start code which constitutes + // a unit of its own. In this situation avpriv_find_start_code + // won't modify start_code at all so modify start_code so that + // the next unit will be treated as the last unit. + start_code = 0; + } + + end = avpriv_find_start_code(start--, frag->data + frag->data_size, + &start_code); + + // start points to the byte containing the start_code_identifier + // (may be the last byte of fragment->data); end points to the byte + // following the byte containing the start code identifier (or to + // the end of fragment->data). + if(start_code >> 8 == 0x000001) { + // Unit runs from start to the beginning of the start code + // pointed to by end (including any padding zeroes). + unit_size = (end - 4) - start; + } + else { + // We didn't find a start code, so this is the final unit. + unit_size = end - start; + final = 1; + } + + err = ff_cbs_insert_unit_data(frag, i, unit_type, (uint8_t *)start, + unit_size, frag->data_ref); + if(err < 0) + return err; + + if(final) + break; + + start = end; + } + + return 0; +} + +static int cbs_mpeg2_read_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) { + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if(err < 0) + return err; + + err = ff_cbs_alloc_unit_content2(ctx, unit); + if(err < 0) + return err; + + if(MPEG2_START_IS_SLICE(unit->type)) { + MPEG2RawSlice *slice = unit->content; + int pos, len; + + err = cbs_mpeg2_read_slice_header(ctx, &gbc, &slice->header); + if(err < 0) + return err; + + if(!get_bits_left(&gbc)) + return AVERROR_INVALIDDATA; + + pos = get_bits_count(&gbc); + len = unit->data_size; + + slice->data_size = len - pos / 8; + slice->data_ref = av_buffer_ref(unit->data_ref); + if(!slice->data_ref) + return AVERROR(ENOMEM); + slice->data = unit->data + pos / 8; + + slice->data_bit_start = pos % 8; + } + else { + switch(unit->type) { +#define START(start_code, type, read_func, free_func) \ + case start_code: { \ + type *header = unit->content; \ + err = cbs_mpeg2_read_##read_func(ctx, &gbc, header); \ + if(err < 0) \ + return err; \ + } break; + START(MPEG2_START_PICTURE, MPEG2RawPictureHeader, + picture_header, &cbs_mpeg2_free_picture_header); + START(MPEG2_START_USER_DATA, MPEG2RawUserData, + user_data, &cbs_mpeg2_free_user_data); + START(MPEG2_START_SEQUENCE_HEADER, MPEG2RawSequenceHeader, + sequence_header, NULL); + START(MPEG2_START_EXTENSION, MPEG2RawExtensionData, + extension_data, NULL); + START(MPEG2_START_GROUP, MPEG2RawGroupOfPicturesHeader, + group_of_pictures_header, NULL); + START(MPEG2_START_SEQUENCE_END, MPEG2RawSequenceEnd, + sequence_end, NULL); +#undef START + default: + return AVERROR(ENOSYS); + } + } + + return 0; +} + +static int cbs_mpeg2_write_header(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) { + int err; + + switch(unit->type) { +#define START(start_code, type, func) \ + case start_code: \ + err = cbs_mpeg2_write_##func(ctx, pbc, unit->content); \ + break; + START(MPEG2_START_PICTURE, MPEG2RawPictureHeader, picture_header); + START(MPEG2_START_USER_DATA, MPEG2RawUserData, user_data); + START(MPEG2_START_SEQUENCE_HEADER, MPEG2RawSequenceHeader, sequence_header); + START(MPEG2_START_EXTENSION, MPEG2RawExtensionData, extension_data); + START(MPEG2_START_GROUP, MPEG2RawGroupOfPicturesHeader, + group_of_pictures_header); + START(MPEG2_START_SEQUENCE_END, MPEG2RawSequenceEnd, sequence_end); +#undef START + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for start " + "code %02" PRIx32 ".\n", + unit->type); + return AVERROR_PATCHWELCOME; + } + + return err; +} + +static int cbs_mpeg2_write_slice(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) { + MPEG2RawSlice *slice = unit->content; + int err; + + err = cbs_mpeg2_write_slice_header(ctx, pbc, &slice->header); + if(err < 0) + return err; + + if(slice->data) { + size_t rest = slice->data_size - (slice->data_bit_start + 7) / 8; + uint8_t *pos = slice->data + slice->data_bit_start / 8; + + av_assert0(slice->data_bit_start >= 0 && + slice->data_size > slice->data_bit_start / 8); + + if(slice->data_size * 8 + 8 > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + // First copy the remaining bits of the first byte + if(slice->data_bit_start % 8) + put_bits(pbc, 8 - slice->data_bit_start % 8, + *pos++ & MAX_UINT_BITS(8 - slice->data_bit_start % 8)); + + if(put_bits_count(pbc) % 8 == 0) { + // If the writer is aligned at this point, + // memcpy can be used to improve performance. + // This is the normal case. + flush_put_bits(pbc); + memcpy(put_bits_ptr(pbc), pos, rest); + skip_put_bytes(pbc, rest); + } + else { + // If not, we have to copy manually: + for(; rest > 3; rest -= 4, pos += 4) + put_bits32(pbc, AV_RB32(pos)); + + for(; rest; rest--, pos++) + put_bits(pbc, 8, *pos); + + // Align with zeros + put_bits(pbc, 8 - put_bits_count(pbc) % 8, 0); + } + } + + return 0; +} + +static int cbs_mpeg2_write_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) { + if(MPEG2_START_IS_SLICE(unit->type)) + return cbs_mpeg2_write_slice(ctx, unit, pbc); + else + return cbs_mpeg2_write_header(ctx, unit, pbc); +} + +static int cbs_mpeg2_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) { + uint8_t *data; + size_t size, dp; + int i; + + size = 0; + for(i = 0; i < frag->nb_units; i++) + size += 3 + frag->units[i].data_size; + + frag->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if(!frag->data_ref) + return AVERROR(ENOMEM); + data = frag->data_ref->data; + + dp = 0; + for(i = 0; i < frag->nb_units; i++) { + CodedBitstreamUnit *unit = &frag->units[i]; + + data[dp++] = 0; + data[dp++] = 0; + data[dp++] = 1; + + memcpy(data + dp, unit->data, unit->data_size); + dp += unit->data_size; + } + + av_assert0(dp == size); + + memset(data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + frag->data = data; + frag->data_size = size; + + return 0; +} + +static const CodedBitstreamUnitTypeDescriptor cbs_mpeg2_unit_types[] = { + CBS_UNIT_TYPE_INTERNAL_REF(MPEG2_START_PICTURE, MPEG2RawPictureHeader, + extra_information_picture.extra_information), + + { + .nb_unit_types = CBS_UNIT_TYPE_RANGE, + .unit_type_range_start = 0x01, + .unit_type_range_end = 0xaf, + + .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS, + .content_size = sizeof(MPEG2RawSlice), + .nb_ref_offsets = 2, + .ref_offsets = { offsetof(MPEG2RawSlice, header.extra_information_slice.extra_information), + offsetof(MPEG2RawSlice, data) }, + }, + + CBS_UNIT_TYPE_INTERNAL_REF(MPEG2_START_USER_DATA, MPEG2RawUserData, + user_data), + + CBS_UNIT_TYPE_POD(MPEG2_START_SEQUENCE_HEADER, MPEG2RawSequenceHeader), + CBS_UNIT_TYPE_POD(MPEG2_START_EXTENSION, MPEG2RawExtensionData), + CBS_UNIT_TYPE_POD(MPEG2_START_SEQUENCE_END, MPEG2RawSequenceEnd), + CBS_UNIT_TYPE_POD(MPEG2_START_GROUP, MPEG2RawGroupOfPicturesHeader), + + CBS_UNIT_TYPE_END_OF_LIST +}; + +const CodedBitstreamType ff_cbs_type_mpeg2 = { + .codec_id = AV_CODEC_ID_MPEG2VIDEO, + + .priv_data_size = sizeof(CodedBitstreamMPEG2Context), + + .unit_types = cbs_mpeg2_unit_types, + + .split_fragment = &cbs_mpeg2_split_fragment, + .read_unit = &cbs_mpeg2_read_unit, + .write_unit = &cbs_mpeg2_write_unit, + .assemble_fragment = &cbs_mpeg2_assemble_fragment, +}; diff --git a/third-party/cbs/cbs_mpeg2_syntax_template.c b/third-party/cbs/cbs_mpeg2_syntax_template.c new file mode 100644 index 00000000..7fc1e80a --- /dev/null +++ b/third-party/cbs/cbs_mpeg2_syntax_template.c @@ -0,0 +1,413 @@ +/* + * 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(sequence_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSequenceHeader *current) { + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err, i; + + HEADER("Sequence Header"); + + ui(8, sequence_header_code); + + uir(12, horizontal_size_value); + uir(12, vertical_size_value); + + mpeg2->horizontal_size = current->horizontal_size_value; + mpeg2->vertical_size = current->vertical_size_value; + + uir(4, aspect_ratio_information); + uir(4, frame_rate_code); + ui(18, bit_rate_value); + + marker_bit(); + + ui(10, vbv_buffer_size_value); + ui(1, constrained_parameters_flag); + + ui(1, load_intra_quantiser_matrix); + if(current->load_intra_quantiser_matrix) { + for(i = 0; i < 64; i++) + uirs(8, intra_quantiser_matrix[i], 1, i); + } + + ui(1, load_non_intra_quantiser_matrix); + if(current->load_non_intra_quantiser_matrix) { + for(i = 0; i < 64; i++) + uirs(8, non_intra_quantiser_matrix[i], 1, i); + } + + return 0; +} + +static int FUNC(user_data)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawUserData *current) { + size_t k; + int err; + + HEADER("User Data"); + + ui(8, user_data_start_code); + +#ifdef READ + k = get_bits_left(rw); + av_assert0(k % 8 == 0); + current->user_data_length = k /= 8; + if(k > 0) { + current->user_data_ref = av_buffer_allocz(k + AV_INPUT_BUFFER_PADDING_SIZE); + if(!current->user_data_ref) + return AVERROR(ENOMEM); + current->user_data = current->user_data_ref->data; + } +#endif + + for(k = 0; k < current->user_data_length; k++) + uis(8, user_data[k], 1, k); + + return 0; +} + +static int FUNC(sequence_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSequenceExtension *current) { + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err; + + HEADER("Sequence Extension"); + + ui(8, profile_and_level_indication); + ui(1, progressive_sequence); + ui(2, chroma_format); + ui(2, horizontal_size_extension); + ui(2, vertical_size_extension); + + mpeg2->horizontal_size = (mpeg2->horizontal_size & 0xfff) | + current->horizontal_size_extension << 12; + mpeg2->vertical_size = (mpeg2->vertical_size & 0xfff) | + current->vertical_size_extension << 12; + mpeg2->progressive_sequence = current->progressive_sequence; + + ui(12, bit_rate_extension); + marker_bit(); + ui(8, vbv_buffer_size_extension); + ui(1, low_delay); + ui(2, frame_rate_extension_n); + ui(5, frame_rate_extension_d); + + return 0; +} + +static int FUNC(sequence_display_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSequenceDisplayExtension *current) { + int err; + + HEADER("Sequence Display Extension"); + + ui(3, video_format); + + ui(1, colour_description); + if(current->colour_description) { +#ifdef READ +#define READ_AND_PATCH(name) \ + do { \ + ui(8, name); \ + if(current->name == 0) { \ + current->name = 2; \ + av_log(ctx->log_ctx, AV_LOG_WARNING, "%s in a sequence display " \ + "extension had the invalid value 0. Setting it to 2 " \ + "(meaning unknown) instead.\n", \ + #name); \ + } \ + } while(0) + READ_AND_PATCH(colour_primaries); + READ_AND_PATCH(transfer_characteristics); + READ_AND_PATCH(matrix_coefficients); +#undef READ_AND_PATCH +#else + uir(8, colour_primaries); + uir(8, transfer_characteristics); + uir(8, matrix_coefficients); +#endif + } + else { + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + } + + ui(14, display_horizontal_size); + marker_bit(); + ui(14, display_vertical_size); + + return 0; +} + +static int FUNC(group_of_pictures_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawGroupOfPicturesHeader *current) { + int err; + + HEADER("Group of Pictures Header"); + + ui(8, group_start_code); + + ui(25, time_code); + ui(1, closed_gop); + ui(1, broken_link); + + return 0; +} + +static int FUNC(extra_information)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawExtraInformation *current, + const char *element_name, const char *marker_name) { + int err; + size_t k; +#ifdef READ + GetBitContext start = *rw; + uint8_t bit; + + for(k = 0; nextbits(1, 1, bit); k++) + skip_bits(rw, 1 + 8); + current->extra_information_length = k; + if(k > 0) { + *rw = start; + current->extra_information_ref = + av_buffer_allocz(k + AV_INPUT_BUFFER_PADDING_SIZE); + if(!current->extra_information_ref) + return AVERROR(ENOMEM); + current->extra_information = current->extra_information_ref->data; + } +#endif + + for(k = 0; k < current->extra_information_length; k++) { + bit(marker_name, 1); + xuia(8, element_name, + current->extra_information[k], 0, 255, 1, k); + } + + bit(marker_name, 0); + + return 0; +} + +static int FUNC(picture_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawPictureHeader *current) { + int err; + + HEADER("Picture Header"); + + ui(8, picture_start_code); + + ui(10, temporal_reference); + uir(3, picture_coding_type); + ui(16, vbv_delay); + + if(current->picture_coding_type == 2 || + current->picture_coding_type == 3) { + ui(1, full_pel_forward_vector); + ui(3, forward_f_code); + } + + if(current->picture_coding_type == 3) { + ui(1, full_pel_backward_vector); + ui(3, backward_f_code); + } + + CHECK(FUNC(extra_information)(ctx, rw, ¤t->extra_information_picture, + "extra_information_picture[k]", "extra_bit_picture")); + + return 0; +} + +static int FUNC(picture_coding_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawPictureCodingExtension *current) { + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err; + + HEADER("Picture Coding Extension"); + + uir(4, f_code[0][0]); + uir(4, f_code[0][1]); + uir(4, f_code[1][0]); + uir(4, f_code[1][1]); + + ui(2, intra_dc_precision); + ui(2, picture_structure); + ui(1, top_field_first); + ui(1, frame_pred_frame_dct); + ui(1, concealment_motion_vectors); + ui(1, q_scale_type); + ui(1, intra_vlc_format); + ui(1, alternate_scan); + ui(1, repeat_first_field); + ui(1, chroma_420_type); + ui(1, progressive_frame); + + if(mpeg2->progressive_sequence) { + if(current->repeat_first_field) { + if(current->top_field_first) + mpeg2->number_of_frame_centre_offsets = 3; + else + mpeg2->number_of_frame_centre_offsets = 2; + } + else { + mpeg2->number_of_frame_centre_offsets = 1; + } + } + else { + if(current->picture_structure == 1 || // Top field. + current->picture_structure == 2) { // Bottom field. + mpeg2->number_of_frame_centre_offsets = 1; + } + else { + if(current->repeat_first_field) + mpeg2->number_of_frame_centre_offsets = 3; + else + mpeg2->number_of_frame_centre_offsets = 2; + } + } + + ui(1, composite_display_flag); + if(current->composite_display_flag) { + ui(1, v_axis); + ui(3, field_sequence); + ui(1, sub_carrier); + ui(7, burst_amplitude); + ui(8, sub_carrier_phase); + } + + return 0; +} + +static int FUNC(quant_matrix_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawQuantMatrixExtension *current) { + int err, i; + + HEADER("Quant Matrix Extension"); + + ui(1, load_intra_quantiser_matrix); + if(current->load_intra_quantiser_matrix) { + for(i = 0; i < 64; i++) + uirs(8, intra_quantiser_matrix[i], 1, i); + } + + ui(1, load_non_intra_quantiser_matrix); + if(current->load_non_intra_quantiser_matrix) { + for(i = 0; i < 64; i++) + uirs(8, non_intra_quantiser_matrix[i], 1, i); + } + + ui(1, load_chroma_intra_quantiser_matrix); + if(current->load_chroma_intra_quantiser_matrix) { + for(i = 0; i < 64; i++) + uirs(8, intra_quantiser_matrix[i], 1, i); + } + + ui(1, load_chroma_non_intra_quantiser_matrix); + if(current->load_chroma_non_intra_quantiser_matrix) { + for(i = 0; i < 64; i++) + uirs(8, chroma_non_intra_quantiser_matrix[i], 1, i); + } + + return 0; +} + +static int FUNC(picture_display_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawPictureDisplayExtension *current) { + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err, i; + + HEADER("Picture Display Extension"); + + for(i = 0; i < mpeg2->number_of_frame_centre_offsets; i++) { + sis(16, frame_centre_horizontal_offset[i], 1, i); + marker_bit(); + sis(16, frame_centre_vertical_offset[i], 1, i); + marker_bit(); + } + + return 0; +} + +static int FUNC(extension_data)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawExtensionData *current) { + int err; + + HEADER("Extension Data"); + + ui(8, extension_start_code); + ui(4, extension_start_code_identifier); + + switch(current->extension_start_code_identifier) { + case MPEG2_EXTENSION_SEQUENCE: + return FUNC(sequence_extension)(ctx, rw, ¤t->data.sequence); + case MPEG2_EXTENSION_SEQUENCE_DISPLAY: + return FUNC(sequence_display_extension)(ctx, rw, ¤t->data.sequence_display); + case MPEG2_EXTENSION_QUANT_MATRIX: + return FUNC(quant_matrix_extension)(ctx, rw, ¤t->data.quant_matrix); + case MPEG2_EXTENSION_PICTURE_DISPLAY: + return FUNC(picture_display_extension)(ctx, rw, ¤t->data.picture_display); + case MPEG2_EXTENSION_PICTURE_CODING: + return FUNC(picture_coding_extension)(ctx, rw, ¤t->data.picture_coding); + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Extension ID %d not supported.\n", + current->extension_start_code_identifier); + return AVERROR_PATCHWELCOME; + } +} + +static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSliceHeader *current) { + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err; + + HEADER("Slice Header"); + + ui(8, slice_vertical_position); + + if(mpeg2->vertical_size > 2800) + ui(3, slice_vertical_position_extension); + if(mpeg2->scalable) { + if(mpeg2->scalable_mode == 0) + ui(7, priority_breakpoint); + } + + uir(5, quantiser_scale_code); + + if(nextbits(1, 1, current->slice_extension_flag)) { + ui(1, slice_extension_flag); + ui(1, intra_slice); + ui(1, slice_picture_id_enable); + ui(6, slice_picture_id); + } + + CHECK(FUNC(extra_information)(ctx, rw, ¤t->extra_information_slice, + "extra_information_slice[k]", "extra_bit_slice")); + + return 0; +} + +static int FUNC(sequence_end)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSequenceEnd *current) { + int err; + + HEADER("Sequence End"); + + ui(8, sequence_end_code); + + return 0; +} diff --git a/third-party/cbs/cbs_sei.c b/third-party/cbs/cbs_sei.c new file mode 100644 index 00000000..c184d67d --- /dev/null +++ b/third-party/cbs/cbs_sei.c @@ -0,0 +1,355 @@ +/* + * 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 "cbs/cbs_sei.h" +#include "cbs/cbs.h" +#include "cbs/cbs_h264.h" +#include "cbs/cbs_h265.h" + +#include "cbs_internal.h" + +static void cbs_free_user_data_registered(void *opaque, uint8_t *data) { + SEIRawUserDataRegistered *udr = (SEIRawUserDataRegistered *)data; + av_buffer_unref(&udr->data_ref); + av_free(udr); +} + +static void cbs_free_user_data_unregistered(void *opaque, uint8_t *data) { + SEIRawUserDataUnregistered *udu = (SEIRawUserDataUnregistered *)data; + av_buffer_unref(&udu->data_ref); + av_free(udu); +} + +int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message, + const SEIMessageTypeDescriptor *desc) { + void (*free_func)(void *, uint8_t *); + + av_assert0(message->payload == NULL && + message->payload_ref == NULL); + message->payload_type = desc->type; + + if(desc->type == SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35) + free_func = &cbs_free_user_data_registered; + else if(desc->type == SEI_TYPE_USER_DATA_UNREGISTERED) + free_func = &cbs_free_user_data_unregistered; + else + free_func = NULL; + + if(free_func) { + message->payload = av_mallocz(desc->size); + if(!message->payload) + return AVERROR(ENOMEM); + message->payload_ref = + av_buffer_create(message->payload, desc->size, + free_func, NULL, 0); + } + else { + message->payload_ref = av_buffer_alloc(desc->size); + } + if(!message->payload_ref) { + av_freep(&message->payload); + return AVERROR(ENOMEM); + } + message->payload = message->payload_ref->data; + + return 0; +} + +int ff_cbs_sei_list_add(SEIRawMessageList *list) { + void *ptr; + int old_count = list->nb_messages_allocated; + + av_assert0(list->nb_messages <= old_count); + if(list->nb_messages + 1 > old_count) { + int new_count = 2 * old_count + 1; + + ptr = av_realloc_array(list->messages, + new_count, sizeof(*list->messages)); + if(!ptr) + return AVERROR(ENOMEM); + + list->messages = ptr; + list->nb_messages_allocated = new_count; + + // Zero the newly-added entries. + memset(list->messages + old_count, 0, + (new_count - old_count) * sizeof(*list->messages)); + } + ++list->nb_messages; + return 0; +} + +void ff_cbs_sei_free_message_list(SEIRawMessageList *list) { + for(int i = 0; i < list->nb_messages; i++) { + SEIRawMessage *message = &list->messages[i]; + av_buffer_unref(&message->payload_ref); + av_buffer_unref(&message->extension_data_ref); + } + av_free(list->messages); +} + +static int cbs_sei_get_unit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + int prefix, + CodedBitstreamUnit **sei_unit) { + CodedBitstreamUnit *unit; + int sei_type, highest_vcl_type, err, i, position; + + switch(ctx->codec->codec_id) { + case AV_CODEC_ID_H264: + // (We can ignore auxiliary slices because we only have prefix + // SEI in H.264 and an auxiliary picture must always follow a + // primary picture.) + highest_vcl_type = H264_NAL_IDR_SLICE; + if(prefix) + sei_type = H264_NAL_SEI; + else + return AVERROR(EINVAL); + break; + case AV_CODEC_ID_H265: + highest_vcl_type = HEVC_NAL_RSV_VCL31; + if(prefix) + sei_type = HEVC_NAL_SEI_PREFIX; + else + sei_type = HEVC_NAL_SEI_SUFFIX; + break; + default: + return AVERROR(EINVAL); + } + + // Find an existing SEI NAL unit of the right type. + unit = NULL; + for(i = 0; i < au->nb_units; i++) { + if(au->units[i].type == sei_type) { + unit = &au->units[i]; + break; + } + } + + if(unit) { + *sei_unit = unit; + return 0; + } + + // Need to add a new SEI NAL unit ... + if(prefix) { + // ... before the first VCL NAL unit. + for(i = 0; i < au->nb_units; i++) { + if(au->units[i].type < highest_vcl_type) + break; + } + position = i; + } + else { + // ... after the last VCL NAL unit. + for(i = au->nb_units - 1; i >= 0; i--) { + if(au->units[i].type < highest_vcl_type) + break; + } + if(i < 0) { + // No VCL units; just put it at the end. + position = au->nb_units; + } + else { + position = i + 1; + } + } + + err = ff_cbs_insert_unit_content(au, position, sei_type, + NULL, NULL); + if(err < 0) + return err; + unit = &au->units[position]; + unit->type = sei_type; + + err = ff_cbs_alloc_unit_content2(ctx, unit); + if(err < 0) + return err; + + switch(ctx->codec->codec_id) { + case AV_CODEC_ID_H264: { + H264RawSEI sei = { + .nal_unit_header = { + .nal_ref_idc = 0, + .nal_unit_type = sei_type, + }, + }; + memcpy(unit->content, &sei, sizeof(sei)); + } break; + case AV_CODEC_ID_H265: { + H265RawSEI sei = { + .nal_unit_header = { + .nal_unit_type = sei_type, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }, + }; + memcpy(unit->content, &sei, sizeof(sei)); + } break; + default: + av_assert0(0); + } + + *sei_unit = unit; + return 0; +} + +static int cbs_sei_get_message_list(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + SEIRawMessageList **list) { + switch(ctx->codec->codec_id) { + case AV_CODEC_ID_H264: { + H264RawSEI *sei = unit->content; + if(unit->type != H264_NAL_SEI) + return AVERROR(EINVAL); + *list = &sei->message_list; + } break; + case AV_CODEC_ID_H265: { + H265RawSEI *sei = unit->content; + if(unit->type != HEVC_NAL_SEI_PREFIX && + unit->type != HEVC_NAL_SEI_SUFFIX) + return AVERROR(EINVAL); + *list = &sei->message_list; + } break; + default: + return AVERROR(EINVAL); + } + + return 0; +} + +int ff_cbs_sei_add_message(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + int prefix, + uint32_t payload_type, + void *payload_data, + AVBufferRef *payload_buf) { + const SEIMessageTypeDescriptor *desc; + CodedBitstreamUnit *unit; + SEIRawMessageList *list; + SEIRawMessage *message; + AVBufferRef *payload_ref; + int err; + + desc = ff_cbs_sei_find_type(ctx, payload_type); + if(!desc) + return AVERROR(EINVAL); + + // Find an existing SEI unit or make a new one to add to. + err = cbs_sei_get_unit(ctx, au, prefix, &unit); + if(err < 0) + return err; + + // Find the message list inside the codec-dependent unit. + err = cbs_sei_get_message_list(ctx, unit, &list); + if(err < 0) + return err; + + // Add a new message to the message list. + err = ff_cbs_sei_list_add(list); + if(err < 0) + return err; + + if(payload_buf) { + payload_ref = av_buffer_ref(payload_buf); + if(!payload_ref) + return AVERROR(ENOMEM); + } + else { + payload_ref = NULL; + } + + message = &list->messages[list->nb_messages - 1]; + + message->payload_type = payload_type; + message->payload = payload_data; + message->payload_ref = payload_ref; + + return 0; +} + +int ff_cbs_sei_find_message(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + uint32_t payload_type, + SEIRawMessage **iter) { + int err, i, j, found; + + found = 0; + for(i = 0; i < au->nb_units; i++) { + CodedBitstreamUnit *unit = &au->units[i]; + SEIRawMessageList *list; + + err = cbs_sei_get_message_list(ctx, unit, &list); + if(err < 0) + continue; + + for(j = 0; j < list->nb_messages; j++) { + SEIRawMessage *message = &list->messages[j]; + + if(message->payload_type == payload_type) { + if(!*iter || found) { + *iter = message; + return 0; + } + if(message == *iter) + found = 1; + } + } + } + + return AVERROR(ENOENT); +} + +static void cbs_sei_delete_message(SEIRawMessageList *list, + int position) { + SEIRawMessage *message; + + av_assert0(0 <= position && position < list->nb_messages); + + message = &list->messages[position]; + av_buffer_unref(&message->payload_ref); + av_buffer_unref(&message->extension_data_ref); + + --list->nb_messages; + + if(list->nb_messages > 0) { + memmove(list->messages + position, + list->messages + position + 1, + (list->nb_messages - position) * sizeof(*list->messages)); + } +} + +void ff_cbs_sei_delete_message_type(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + uint32_t payload_type) { + int err, i, j; + + for(i = 0; i < au->nb_units; i++) { + CodedBitstreamUnit *unit = &au->units[i]; + SEIRawMessageList *list; + + err = cbs_sei_get_message_list(ctx, unit, &list); + if(err < 0) + continue; + + for(j = list->nb_messages - 1; j >= 0; j--) { + if(list->messages[j].payload_type == payload_type) + cbs_sei_delete_message(list, j); + } + } +} diff --git a/third-party/cbs/cbs_sei_syntax_template.c b/third-party/cbs/cbs_sei_syntax_template.c new file mode 100644 index 00000000..e9688013 --- /dev/null +++ b/third-party/cbs/cbs_sei_syntax_template.c @@ -0,0 +1,310 @@ +/* + * 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(filler_payload)(CodedBitstreamContext *ctx, RWContext *rw, + SEIRawFillerPayload *current, SEIMessageState *state) { + int err, i; + + HEADER("Filler Payload"); + +#ifdef READ + current->payload_size = state->payload_size; +#endif + + for(i = 0; i < current->payload_size; i++) + fixed(8, ff_byte, 0xff); + + return 0; +} + +static int FUNC(user_data_registered)(CodedBitstreamContext *ctx, RWContext *rw, + SEIRawUserDataRegistered *current, SEIMessageState *state) { + int err, i, j; + + HEADER("User Data Registered ITU-T T.35"); + + u(8, itu_t_t35_country_code, 0x00, 0xff); + if(current->itu_t_t35_country_code != 0xff) + i = 1; + else { + u(8, itu_t_t35_country_code_extension_byte, 0x00, 0xff); + i = 2; + } + +#ifdef READ + if(state->payload_size < i) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Invalid SEI user data registered payload.\n"); + return AVERROR_INVALIDDATA; + } + current->data_length = state->payload_size - i; +#endif + + allocate(current->data, current->data_length); + for(j = 0; j < current->data_length; j++) + xu(8, itu_t_t35_payload_byte[], current->data[j], 0x00, 0xff, 1, i + j); + + return 0; +} + +static int FUNC(user_data_unregistered)(CodedBitstreamContext *ctx, RWContext *rw, + SEIRawUserDataUnregistered *current, SEIMessageState *state) { + int err, i; + + HEADER("User Data Unregistered"); + +#ifdef READ + if(state->payload_size < 16) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Invalid SEI user data unregistered payload.\n"); + return AVERROR_INVALIDDATA; + } + current->data_length = state->payload_size - 16; +#endif + + for(i = 0; i < 16; i++) + us(8, uuid_iso_iec_11578[i], 0x00, 0xff, 1, i); + + allocate(current->data, current->data_length); + + for(i = 0; i < current->data_length; i++) + xu(8, user_data_payload_byte[i], current->data[i], 0x00, 0xff, 1, i); + + return 0; +} + +static int FUNC(mastering_display_colour_volume)(CodedBitstreamContext *ctx, RWContext *rw, + SEIRawMasteringDisplayColourVolume *current, SEIMessageState *state) { + int err, c; + + HEADER("Mastering Display Colour Volume"); + + for(c = 0; c < 3; c++) { + ubs(16, display_primaries_x[c], 1, c); + ubs(16, display_primaries_y[c], 1, c); + } + + ub(16, white_point_x); + ub(16, white_point_y); + + ub(32, max_display_mastering_luminance); + ub(32, min_display_mastering_luminance); + + return 0; +} + +static int FUNC(content_light_level_info)(CodedBitstreamContext *ctx, RWContext *rw, + SEIRawContentLightLevelInfo *current, SEIMessageState *state) { + int err; + + HEADER("Content Light Level Information"); + + ub(16, max_content_light_level); + ub(16, max_pic_average_light_level); + + return 0; +} + +static int FUNC(alternative_transfer_characteristics)(CodedBitstreamContext *ctx, RWContext *rw, + SEIRawAlternativeTransferCharacteristics *current, + SEIMessageState *state) { + int err; + + HEADER("Alternative Transfer Characteristics"); + + ub(8, preferred_transfer_characteristics); + + return 0; +} + +static int FUNC(message)(CodedBitstreamContext *ctx, RWContext *rw, + SEIRawMessage *current) { + const SEIMessageTypeDescriptor *desc; + int err, i; + + desc = ff_cbs_sei_find_type(ctx, current->payload_type); + if(desc) { + SEIMessageState state = { + .payload_type = current->payload_type, + .payload_size = current->payload_size, + .extension_present = current->extension_bit_length > 0, + }; + int start_position, current_position, bits_written; + +#ifdef READ + CHECK(ff_cbs_sei_alloc_message_payload(current, desc)); +#endif + + start_position = bit_position(rw); + + CHECK(desc->READWRITE(ctx, rw, current->payload, &state)); + + current_position = bit_position(rw); + bits_written = current_position - start_position; + + if(byte_alignment(rw) || state.extension_present || + bits_written < 8 * current->payload_size) { + size_t bits_left; + +#ifdef READ + GetBitContext tmp = *rw; + int trailing_bits, trailing_zero_bits; + + bits_left = 8 * current->payload_size - bits_written; + if(bits_left > 8) + skip_bits_long(&tmp, bits_left - 8); + trailing_bits = get_bits(&tmp, FFMIN(bits_left, 8)); + if(trailing_bits == 0) { + // The trailing bits must contain a bit_equal_to_one, so + // they can't all be zero. + return AVERROR_INVALIDDATA; + } + trailing_zero_bits = ff_ctz(trailing_bits); + current->extension_bit_length = + bits_left - 1 - trailing_zero_bits; +#endif + + if(current->extension_bit_length > 0) { + allocate(current->extension_data, + (current->extension_bit_length + 7) / 8); + + bits_left = current->extension_bit_length; + for(i = 0; bits_left > 0; i++) { + int length = FFMIN(bits_left, 8); + xu(length, reserved_payload_extension_data, + current->extension_data[i], + 0, MAX_UINT_BITS(length), 0); + bits_left -= length; + } + } + + fixed(1, bit_equal_to_one, 1); + while(byte_alignment(rw)) + fixed(1, bit_equal_to_zero, 0); + } + +#ifdef WRITE + current->payload_size = (put_bits_count(rw) - start_position) / 8; +#endif + } + else { + uint8_t *data; + + allocate(current->payload, current->payload_size); + data = current->payload; + + for(i = 0; i < current->payload_size; i++) + xu(8, payload_byte[i], data[i], 0, 255, 1, i); + } + + return 0; +} + +static int FUNC(message_list)(CodedBitstreamContext *ctx, RWContext *rw, + SEIRawMessageList *current, int prefix) { + SEIRawMessage *message; + int err, k; + +#ifdef READ + for(k = 0;; k++) { + uint32_t payload_type = 0; + uint32_t payload_size = 0; + uint32_t tmp; + GetBitContext payload_gbc; + + while(show_bits(rw, 8) == 0xff) { + fixed(8, ff_byte, 0xff); + payload_type += 255; + } + xu(8, last_payload_type_byte, tmp, 0, 254, 0); + payload_type += tmp; + + while(show_bits(rw, 8) == 0xff) { + fixed(8, ff_byte, 0xff); + payload_size += 255; + } + xu(8, last_payload_size_byte, tmp, 0, 254, 0); + payload_size += tmp; + + // There must be space remaining for both the payload and + // the trailing bits on the SEI NAL unit. + if(payload_size + 1 > get_bits_left(rw) / 8) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Invalid SEI message: payload_size too large " + "(%" PRIu32 " bytes).\n", + payload_size); + return AVERROR_INVALIDDATA; + } + CHECK(init_get_bits(&payload_gbc, rw->buffer, + get_bits_count(rw) + 8 * payload_size)); + skip_bits_long(&payload_gbc, get_bits_count(rw)); + + CHECK(ff_cbs_sei_list_add(current)); + message = ¤t->messages[k]; + + message->payload_type = payload_type; + message->payload_size = payload_size; + + CHECK(FUNC(message)(ctx, &payload_gbc, message)); + + skip_bits_long(rw, 8 * payload_size); + + if(!cbs_h2645_read_more_rbsp_data(rw)) + break; + } +#else + for(k = 0; k < current->nb_messages; k++) { + PutBitContext start_state; + uint32_t tmp; + int trace, i; + + message = ¤t->messages[k]; + + // We write the payload twice in order to find the size. Trace + // output is switched off for the first write. + trace = ctx->trace_enable; + ctx->trace_enable = 0; + + start_state = *rw; + for(i = 0; i < 2; i++) { + *rw = start_state; + + tmp = message->payload_type; + while(tmp >= 255) { + fixed(8, ff_byte, 0xff); + tmp -= 255; + } + xu(8, last_payload_type_byte, tmp, 0, 254, 0); + + tmp = message->payload_size; + while(tmp >= 255) { + fixed(8, ff_byte, 0xff); + tmp -= 255; + } + xu(8, last_payload_size_byte, tmp, 0, 254, 0); + + err = FUNC(message)(ctx, rw, message); + ctx->trace_enable = trace; + if(err < 0) + return err; + } + } +#endif + + return 0; +} diff --git a/third-party/cbs/cbs_vp9.c b/third-party/cbs/cbs_vp9.c new file mode 100644 index 00000000..74da5b03 --- /dev/null +++ b/third-party/cbs/cbs_vp9.c @@ -0,0 +1,675 @@ +/* + * 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 "cbs/cbs.h" +#include "cbs/cbs_vp9.h" +#include "cbs_internal.h" + + +static int cbs_vp9_read_s(CodedBitstreamContext *ctx, GetBitContext *gbc, + int width, const char *name, + const int *subscripts, int32_t *write_to) { + uint32_t magnitude; + int position, sign; + int32_t value; + + if(ctx->trace_enable) + position = get_bits_count(gbc); + + if(get_bits_left(gbc) < width + 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid signed value at " + "%s: bitstream ended.\n", + name); + return AVERROR_INVALIDDATA; + } + + magnitude = get_bits(gbc, width); + sign = get_bits1(gbc); + value = sign ? -(int32_t)magnitude : magnitude; + + if(ctx->trace_enable) { + char bits[33]; + int i; + for(i = 0; i < width; i++) + bits[i] = magnitude >> (width - i - 1) & 1 ? '1' : '0'; + bits[i] = sign ? '1' : '0'; + bits[i + 1] = 0; + + ff_cbs_trace_syntax_element(ctx, position, name, subscripts, + bits, value); + } + + *write_to = value; + return 0; +} + +static int cbs_vp9_write_s(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, + const int *subscripts, int32_t value) { + uint32_t magnitude; + int sign; + + if(put_bits_left(pbc) < width + 1) + return AVERROR(ENOSPC); + + sign = value < 0; + magnitude = sign ? -value : value; + + if(ctx->trace_enable) { + char bits[33]; + int i; + for(i = 0; i < width; i++) + bits[i] = magnitude >> (width - i - 1) & 1 ? '1' : '0'; + bits[i] = sign ? '1' : '0'; + bits[i + 1] = 0; + + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, subscripts, bits, value); + } + + put_bits(pbc, width, magnitude); + put_bits(pbc, 1, sign); + + return 0; +} + +static int cbs_vp9_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc, + uint32_t range_min, uint32_t range_max, + const char *name, uint32_t *write_to) { + uint32_t value; + int position, i; + char bits[8]; + + av_assert0(range_min <= range_max && range_max - range_min < sizeof(bits) - 1); + if(ctx->trace_enable) + position = get_bits_count(gbc); + + for(i = 0, value = range_min; value < range_max;) { + if(get_bits_left(gbc) < 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid increment value at " + "%s: bitstream ended.\n", + name); + return AVERROR_INVALIDDATA; + } + if(get_bits1(gbc)) { + bits[i++] = '1'; + ++value; + } + else { + bits[i++] = '0'; + break; + } + } + + if(ctx->trace_enable) { + bits[i] = 0; + ff_cbs_trace_syntax_element(ctx, position, name, NULL, bits, value); + } + + *write_to = value; + return 0; +} + +static int cbs_vp9_write_increment(CodedBitstreamContext *ctx, PutBitContext *pbc, + uint32_t range_min, uint32_t range_max, + const char *name, uint32_t value) { + int len; + + av_assert0(range_min <= range_max && range_max - range_min < 8); + 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(value == range_max) + len = range_max - range_min; + else + len = value - range_min + 1; + if(put_bits_left(pbc) < len) + return AVERROR(ENOSPC); + + if(ctx->trace_enable) { + char bits[8]; + int i; + for(i = 0; i < len; i++) { + if(range_min + i == value) + bits[i] = '0'; + else + bits[i] = '1'; + } + bits[i] = 0; + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, NULL, bits, value); + } + + if(len > 0) + put_bits(pbc, len, (1 << len) - 1 - (value != range_max)); + + return 0; +} + +static int cbs_vp9_read_le(CodedBitstreamContext *ctx, GetBitContext *gbc, + int width, const char *name, + const int *subscripts, uint32_t *write_to) { + uint32_t value; + int position, b; + + av_assert0(width % 8 == 0); + + if(ctx->trace_enable) + position = get_bits_count(gbc); + + if(get_bits_left(gbc) < width) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid le value at " + "%s: bitstream ended.\n", + name); + return AVERROR_INVALIDDATA; + } + + value = 0; + for(b = 0; b < width; b += 8) + value |= get_bits(gbc, 8) << b; + + if(ctx->trace_enable) { + char bits[33]; + int i; + for(b = 0; b < width; b += 8) + for(i = 0; i < 8; i++) + bits[b + i] = value >> (b + i) & 1 ? '1' : '0'; + bits[b] = 0; + + ff_cbs_trace_syntax_element(ctx, position, name, subscripts, + bits, value); + } + + *write_to = value; + return 0; +} + +static int cbs_vp9_write_le(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, + const int *subscripts, uint32_t value) { + int b; + + av_assert0(width % 8 == 0); + + if(put_bits_left(pbc) < width) + return AVERROR(ENOSPC); + + if(ctx->trace_enable) { + char bits[33]; + int i; + for(b = 0; b < width; b += 8) + for(i = 0; i < 8; i++) + bits[b + i] = value >> (b + i) & 1 ? '1' : '0'; + bits[b] = 0; + + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, subscripts, bits, value); + } + + for(b = 0; b < width; b += 8) + put_bits(pbc, 8, value >> b & 0xff); + + 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_VP9(rw, name) FUNC_NAME(rw, vp9, name) +#define FUNC(name) FUNC_VP9(READWRITE, name) + +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]) { subs, __VA_ARGS__ }) : NULL) + +#define f(width, name) \ + xf(width, name, current->name, 0, ) +#define s(width, name) \ + xs(width, name, current->name, 0, ) +#define fs(width, name, subs, ...) \ + xf(width, name, current->name, subs, __VA_ARGS__) +#define ss(width, name, subs, ...) \ + xs(width, name, current->name, subs, __VA_ARGS__) + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define xf(width, name, var, subs, ...) \ + do { \ + uint32_t value; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, 0, (1 << width) - 1)); \ + var = value; \ + } while(0) +#define xs(width, name, var, subs, ...) \ + do { \ + int32_t value; \ + CHECK(cbs_vp9_read_s(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), &value)); \ + var = value; \ + } while(0) + + +#define increment(name, min, max) \ + do { \ + uint32_t value; \ + CHECK(cbs_vp9_read_increment(ctx, rw, min, max, #name, &value)); \ + current->name = value; \ + } while(0) + +#define fle(width, name, subs, ...) \ + do { \ + CHECK(cbs_vp9_read_le(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), ¤t->name)); \ + } while(0) + +#define delta_q(name) \ + do { \ + uint8_t delta_coded; \ + int8_t delta_q; \ + xf(1, name.delta_coded, delta_coded, 0, ); \ + if(delta_coded) \ + xs(4, name.delta_q, delta_q, 0, ); \ + else \ + delta_q = 0; \ + current->name = delta_q; \ + } while(0) + +#define prob(name, subs, ...) \ + do { \ + uint8_t prob_coded; \ + uint8_t prob; \ + xf(1, name.prob_coded, prob_coded, subs, __VA_ARGS__); \ + if(prob_coded) \ + xf(8, name.prob, prob, subs, __VA_ARGS__); \ + else \ + prob = 255; \ + current->name = prob; \ + } while(0) + +#define fixed(width, name, value) \ + do { \ + av_unused uint32_t fixed_value; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + 0, &fixed_value, value, value)); \ + } while(0) + +#define infer(name, value) \ + do { \ + current->name = value; \ + } while(0) + +#define byte_alignment(rw) (get_bits_count(rw) % 8) + +#include "cbs_vp9_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef xf +#undef xs +#undef increment +#undef fle +#undef delta_q +#undef prob +#undef fixed +#undef infer +#undef byte_alignment + + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define xf(width, name, var, subs, ...) \ + do { \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + var, 0, (1 << width) - 1)); \ + } while(0) +#define xs(width, name, var, subs, ...) \ + do { \ + CHECK(cbs_vp9_write_s(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), var)); \ + } while(0) + +#define increment(name, min, max) \ + do { \ + CHECK(cbs_vp9_write_increment(ctx, rw, min, max, #name, current->name)); \ + } while(0) + +#define fle(width, name, subs, ...) \ + do { \ + CHECK(cbs_vp9_write_le(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), current->name)); \ + } while(0) + +#define delta_q(name) \ + do { \ + xf(1, name.delta_coded, !!current->name, 0, ); \ + if(current->name) \ + xs(4, name.delta_q, current->name, 0, ); \ + } while(0) + +#define prob(name, subs, ...) \ + do { \ + xf(1, name.prob_coded, current->name != 255, subs, __VA_ARGS__); \ + if(current->name != 255) \ + xf(8, name.prob, current->name, subs, __VA_ARGS__); \ + } while(0) + +#define fixed(width, name, value) \ + do { \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + 0, value, value, value)); \ + } while(0) + +#define infer(name, value) \ + do { \ + if(current->name != (value)) { \ + av_log(ctx->log_ctx, AV_LOG_WARNING, "Warning: " \ + "%s does not match inferred value: " \ + "%" PRId64 ", but should be %" PRId64 ".\n", \ + #name, (int64_t)current->name, (int64_t)(value)); \ + } \ + } while(0) + +#define byte_alignment(rw) (put_bits_count(rw) % 8) + +#include "cbs_vp9_syntax_template.c" + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef xf +#undef xs +#undef increment +#undef fle +#undef delta_q +#undef prob +#undef fixed +#undef infer +#undef byte_alignment + + +static int cbs_vp9_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) { + uint8_t superframe_header; + int err; + + if(frag->data_size == 0) + return AVERROR_INVALIDDATA; + + // Last byte in the packet. + superframe_header = frag->data[frag->data_size - 1]; + + if((superframe_header & 0xe0) == 0xc0) { + VP9RawSuperframeIndex sfi; + GetBitContext gbc; + size_t index_size, pos; + int i; + + index_size = 2 + (((superframe_header & 0x18) >> 3) + 1) * + ((superframe_header & 0x07) + 1); + + if(index_size > frag->data_size) + return AVERROR_INVALIDDATA; + + err = init_get_bits(&gbc, frag->data + frag->data_size - index_size, + 8 * index_size); + if(err < 0) + return err; + + err = cbs_vp9_read_superframe_index(ctx, &gbc, &sfi); + if(err < 0) + return err; + + pos = 0; + for(i = 0; i <= sfi.frames_in_superframe_minus_1; i++) { + if(pos + sfi.frame_sizes[i] + index_size > frag->data_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Frame %d too large " + "in superframe: %" PRIu32 " bytes.\n", + i, sfi.frame_sizes[i]); + return AVERROR_INVALIDDATA; + } + + err = ff_cbs_insert_unit_data(frag, -1, 0, + frag->data + pos, + sfi.frame_sizes[i], + frag->data_ref); + if(err < 0) + return err; + + pos += sfi.frame_sizes[i]; + } + if(pos + index_size != frag->data_size) { + av_log(ctx->log_ctx, AV_LOG_WARNING, "Extra padding at " + "end of superframe: %zu bytes.\n", + frag->data_size - (pos + index_size)); + } + + return 0; + } + else { + err = ff_cbs_insert_unit_data(frag, -1, 0, + frag->data, frag->data_size, + frag->data_ref); + if(err < 0) + return err; + } + + return 0; +} + +static int cbs_vp9_read_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) { + VP9RawFrame *frame; + GetBitContext gbc; + int err, pos; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if(err < 0) + return err; + + err = ff_cbs_alloc_unit_content2(ctx, unit); + if(err < 0) + return err; + frame = unit->content; + + err = cbs_vp9_read_frame(ctx, &gbc, frame); + if(err < 0) + return err; + + pos = get_bits_count(&gbc); + av_assert0(pos % 8 == 0); + pos /= 8; + av_assert0(pos <= unit->data_size); + + if(pos == unit->data_size) { + // No data (e.g. a show-existing-frame frame). + } + else { + frame->data_ref = av_buffer_ref(unit->data_ref); + if(!frame->data_ref) + return AVERROR(ENOMEM); + + frame->data = unit->data + pos; + frame->data_size = unit->data_size - pos; + } + + return 0; +} + +static int cbs_vp9_write_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) { + VP9RawFrame *frame = unit->content; + int err; + + err = cbs_vp9_write_frame(ctx, pbc, frame); + if(err < 0) + return err; + + // Frame must be byte-aligned. + av_assert0(put_bits_count(pbc) % 8 == 0); + + if(frame->data) { + if(frame->data_size > put_bits_left(pbc) / 8) + return AVERROR(ENOSPC); + + flush_put_bits(pbc); + memcpy(put_bits_ptr(pbc), frame->data, frame->data_size); + skip_put_bytes(pbc, frame->data_size); + } + + return 0; +} + +static int cbs_vp9_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) { + int err; + + if(frag->nb_units == 1) { + // Output is just the content of the single frame. + + CodedBitstreamUnit *frame = &frag->units[0]; + + frag->data_ref = av_buffer_ref(frame->data_ref); + if(!frag->data_ref) + return AVERROR(ENOMEM); + + frag->data = frame->data; + frag->data_size = frame->data_size; + } + else { + // Build superframe out of frames. + + VP9RawSuperframeIndex sfi; + PutBitContext pbc; + AVBufferRef *ref; + uint8_t *data; + size_t size, max, pos; + int i, size_len; + + if(frag->nb_units > 8) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many frames to " + "make superframe: %d.\n", + frag->nb_units); + return AVERROR(EINVAL); + } + + max = 0; + for(i = 0; i < frag->nb_units; i++) + if(max < frag->units[i].data_size) + max = frag->units[i].data_size; + + if(max < 2) + size_len = 1; + else + size_len = av_log2(max) / 8 + 1; + av_assert0(size_len <= 4); + + sfi.superframe_marker = VP9_SUPERFRAME_MARKER; + sfi.bytes_per_framesize_minus_1 = size_len - 1; + sfi.frames_in_superframe_minus_1 = frag->nb_units - 1; + + size = 2; + for(i = 0; i < frag->nb_units; i++) { + size += size_len + frag->units[i].data_size; + sfi.frame_sizes[i] = frag->units[i].data_size; + } + + ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if(!ref) + return AVERROR(ENOMEM); + data = ref->data; + memset(data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + pos = 0; + for(i = 0; i < frag->nb_units; i++) { + av_assert0(size - pos > frag->units[i].data_size); + memcpy(data + pos, frag->units[i].data, + frag->units[i].data_size); + pos += frag->units[i].data_size; + } + av_assert0(size - pos == 2 + frag->nb_units * size_len); + + init_put_bits(&pbc, data + pos, size - pos); + + err = cbs_vp9_write_superframe_index(ctx, &pbc, &sfi); + if(err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write " + "superframe index.\n"); + av_buffer_unref(&ref); + return err; + } + + av_assert0(put_bits_left(&pbc) == 0); + flush_put_bits(&pbc); + + frag->data_ref = ref; + frag->data = data; + frag->data_size = size; + } + + return 0; +} + +static void cbs_vp9_flush(CodedBitstreamContext *ctx) { + CodedBitstreamVP9Context *vp9 = ctx->priv_data; + + memset(vp9->ref, 0, sizeof(vp9->ref)); +} + +static const CodedBitstreamUnitTypeDescriptor cbs_vp9_unit_types[] = { + CBS_UNIT_TYPE_INTERNAL_REF(0, VP9RawFrame, data), + CBS_UNIT_TYPE_END_OF_LIST +}; + +const CodedBitstreamType ff_cbs_type_vp9 = { + .codec_id = AV_CODEC_ID_VP9, + + .priv_data_size = sizeof(CodedBitstreamVP9Context), + + .unit_types = cbs_vp9_unit_types, + + .split_fragment = &cbs_vp9_split_fragment, + .read_unit = &cbs_vp9_read_unit, + .write_unit = &cbs_vp9_write_unit, + + .flush = &cbs_vp9_flush, + + .assemble_fragment = &cbs_vp9_assemble_fragment, +}; diff --git a/third-party/cbs/cbs_vp9_syntax_template.c b/third-party/cbs/cbs_vp9_syntax_template.c new file mode 100644 index 00000000..a0e15c53 --- /dev/null +++ b/third-party/cbs/cbs_vp9_syntax_template.c @@ -0,0 +1,422 @@ +/* + * 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(frame_sync_code)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) { + int err; + + fixed(8, frame_sync_byte_0, VP9_FRAME_SYNC_0); + fixed(8, frame_sync_byte_1, VP9_FRAME_SYNC_1); + fixed(8, frame_sync_byte_2, VP9_FRAME_SYNC_2); + + return 0; +} + +static int FUNC(color_config)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current, int profile) { + CodedBitstreamVP9Context *vp9 = ctx->priv_data; + int err; + + if(profile >= 2) { + f(1, ten_or_twelve_bit); + vp9->bit_depth = current->ten_or_twelve_bit ? 12 : 10; + } + else + vp9->bit_depth = 8; + + f(3, color_space); + + if(current->color_space != VP9_CS_RGB) { + f(1, color_range); + if(profile == 1 || profile == 3) { + f(1, subsampling_x); + f(1, subsampling_y); + fixed(1, reserved_zero, 0); + } + else { + infer(subsampling_x, 1); + infer(subsampling_y, 1); + } + } + else { + infer(color_range, 1); + if(profile == 1 || profile == 3) { + infer(subsampling_x, 0); + infer(subsampling_y, 0); + fixed(1, reserved_zero, 0); + } + } + + vp9->subsampling_x = current->subsampling_x; + vp9->subsampling_y = current->subsampling_y; + + return 0; +} + +static int FUNC(frame_size)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) { + CodedBitstreamVP9Context *vp9 = ctx->priv_data; + int err; + + f(16, frame_width_minus_1); + f(16, frame_height_minus_1); + + vp9->frame_width = current->frame_width_minus_1 + 1; + vp9->frame_height = current->frame_height_minus_1 + 1; + + vp9->mi_cols = (vp9->frame_width + 7) >> 3; + vp9->mi_rows = (vp9->frame_height + 7) >> 3; + vp9->sb64_cols = (vp9->mi_cols + 7) >> 3; + vp9->sb64_rows = (vp9->mi_rows + 7) >> 3; + + return 0; +} + +static int FUNC(render_size)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) { + int err; + + f(1, render_and_frame_size_different); + + if(current->render_and_frame_size_different) { + f(16, render_width_minus_1); + f(16, render_height_minus_1); + } + + return 0; +} + +static int FUNC(frame_size_with_refs)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) { + CodedBitstreamVP9Context *vp9 = ctx->priv_data; + int err, i; + + for(i = 0; i < VP9_REFS_PER_FRAME; i++) { + fs(1, found_ref[i], 1, i); + if(current->found_ref[i]) { + VP9ReferenceFrameState *ref = + &vp9->ref[current->ref_frame_idx[i]]; + + vp9->frame_width = ref->frame_width; + vp9->frame_height = ref->frame_height; + + vp9->subsampling_x = ref->subsampling_x; + vp9->subsampling_y = ref->subsampling_y; + vp9->bit_depth = ref->bit_depth; + + break; + } + } + if(i >= VP9_REFS_PER_FRAME) + CHECK(FUNC(frame_size)(ctx, rw, current)); + else { + vp9->mi_cols = (vp9->frame_width + 7) >> 3; + vp9->mi_rows = (vp9->frame_height + 7) >> 3; + vp9->sb64_cols = (vp9->mi_cols + 7) >> 3; + vp9->sb64_rows = (vp9->mi_rows + 7) >> 3; + } + CHECK(FUNC(render_size)(ctx, rw, current)); + + return 0; +} + +static int FUNC(interpolation_filter)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) { + int err; + + f(1, is_filter_switchable); + if(!current->is_filter_switchable) + f(2, raw_interpolation_filter_type); + + return 0; +} + +static int FUNC(loop_filter_params)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) { + int err, i; + + f(6, loop_filter_level); + f(3, loop_filter_sharpness); + + f(1, loop_filter_delta_enabled); + if(current->loop_filter_delta_enabled) { + f(1, loop_filter_delta_update); + if(current->loop_filter_delta_update) { + for(i = 0; i < VP9_MAX_REF_FRAMES; i++) { + fs(1, update_ref_delta[i], 1, i); + if(current->update_ref_delta[i]) + ss(6, loop_filter_ref_deltas[i], 1, i); + } + for(i = 0; i < 2; i++) { + fs(1, update_mode_delta[i], 1, i); + if(current->update_mode_delta[i]) + ss(6, loop_filter_mode_deltas[i], 1, i); + } + } + } + + return 0; +} + +static int FUNC(quantization_params)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) { + int err; + + f(8, base_q_idx); + + delta_q(delta_q_y_dc); + delta_q(delta_q_uv_dc); + delta_q(delta_q_uv_ac); + + return 0; +} + +static int FUNC(segmentation_params)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) { + static const uint8_t segmentation_feature_bits[VP9_SEG_LVL_MAX] = { 8, 6, 2, 0 }; + static const uint8_t segmentation_feature_signed[VP9_SEG_LVL_MAX] = { 1, 1, 0, 0 }; + + int err, i, j; + + f(1, segmentation_enabled); + + if(current->segmentation_enabled) { + f(1, segmentation_update_map); + if(current->segmentation_update_map) { + for(i = 0; i < 7; i++) + prob(segmentation_tree_probs[i], 1, i); + f(1, segmentation_temporal_update); + for(i = 0; i < 3; i++) { + if(current->segmentation_temporal_update) + prob(segmentation_pred_prob[i], 1, i); + else + infer(segmentation_pred_prob[i], 255); + } + } + + f(1, segmentation_update_data); + if(current->segmentation_update_data) { + f(1, segmentation_abs_or_delta_update); + for(i = 0; i < VP9_MAX_SEGMENTS; i++) { + for(j = 0; j < VP9_SEG_LVL_MAX; j++) { + fs(1, feature_enabled[i][j], 2, i, j); + if(current->feature_enabled[i][j] && + segmentation_feature_bits[j]) { + fs(segmentation_feature_bits[j], + feature_value[i][j], 2, i, j); + if(segmentation_feature_signed[j]) + fs(1, feature_sign[i][j], 2, i, j); + else + infer(feature_sign[i][j], 0); + } + else { + infer(feature_value[i][j], 0); + infer(feature_sign[i][j], 0); + } + } + } + } + } + + return 0; +} + +static int FUNC(tile_info)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) { + CodedBitstreamVP9Context *vp9 = ctx->priv_data; + int min_log2_tile_cols, max_log2_tile_cols; + int err; + + min_log2_tile_cols = 0; + while((VP9_MAX_TILE_WIDTH_B64 << min_log2_tile_cols) < vp9->sb64_cols) + ++min_log2_tile_cols; + max_log2_tile_cols = 0; + while((vp9->sb64_cols >> (max_log2_tile_cols + 1)) >= VP9_MIN_TILE_WIDTH_B64) + ++max_log2_tile_cols; + + increment(tile_cols_log2, min_log2_tile_cols, max_log2_tile_cols); + + increment(tile_rows_log2, 0, 2); + + return 0; +} + +static int FUNC(uncompressed_header)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) { + CodedBitstreamVP9Context *vp9 = ctx->priv_data; + int err, i; + + f(2, frame_marker); + + f(1, profile_low_bit); + f(1, profile_high_bit); + vp9->profile = (current->profile_high_bit << 1) + current->profile_low_bit; + if(vp9->profile == 3) + fixed(1, reserved_zero, 0); + + f(1, show_existing_frame); + if(current->show_existing_frame) { + f(3, frame_to_show_map_idx); + infer(header_size_in_bytes, 0); + infer(refresh_frame_flags, 0x00); + infer(loop_filter_level, 0); + return 0; + } + + f(1, frame_type); + f(1, show_frame); + f(1, error_resilient_mode); + + if(current->frame_type == VP9_KEY_FRAME) { + CHECK(FUNC(frame_sync_code)(ctx, rw, current)); + CHECK(FUNC(color_config)(ctx, rw, current, vp9->profile)); + CHECK(FUNC(frame_size)(ctx, rw, current)); + CHECK(FUNC(render_size)(ctx, rw, current)); + + infer(refresh_frame_flags, 0xff); + } + else { + if(current->show_frame == 0) + f(1, intra_only); + else + infer(intra_only, 0); + + if(current->error_resilient_mode == 0) + f(2, reset_frame_context); + else + infer(reset_frame_context, 0); + + if(current->intra_only == 1) { + CHECK(FUNC(frame_sync_code)(ctx, rw, current)); + + if(vp9->profile > 0) { + CHECK(FUNC(color_config)(ctx, rw, current, vp9->profile)); + } + else { + infer(color_space, 1); + infer(subsampling_x, 1); + infer(subsampling_y, 1); + vp9->bit_depth = 8; + + vp9->subsampling_x = current->subsampling_x; + vp9->subsampling_y = current->subsampling_y; + } + + f(8, refresh_frame_flags); + + CHECK(FUNC(frame_size)(ctx, rw, current)); + CHECK(FUNC(render_size)(ctx, rw, current)); + } + else { + f(8, refresh_frame_flags); + + for(i = 0; i < VP9_REFS_PER_FRAME; i++) { + fs(3, ref_frame_idx[i], 1, i); + fs(1, ref_frame_sign_bias[VP9_LAST_FRAME + i], + 1, VP9_LAST_FRAME + i); + } + + CHECK(FUNC(frame_size_with_refs)(ctx, rw, current)); + f(1, allow_high_precision_mv); + CHECK(FUNC(interpolation_filter)(ctx, rw, current)); + } + } + + if(current->error_resilient_mode == 0) { + f(1, refresh_frame_context); + f(1, frame_parallel_decoding_mode); + } + else { + infer(refresh_frame_context, 0); + infer(frame_parallel_decoding_mode, 1); + } + + f(2, frame_context_idx); + + CHECK(FUNC(loop_filter_params)(ctx, rw, current)); + CHECK(FUNC(quantization_params)(ctx, rw, current)); + CHECK(FUNC(segmentation_params)(ctx, rw, current)); + CHECK(FUNC(tile_info)(ctx, rw, current)); + + f(16, header_size_in_bytes); + + for(i = 0; i < VP9_NUM_REF_FRAMES; i++) { + if(current->refresh_frame_flags & (1 << i)) { + vp9->ref[i] = (VP9ReferenceFrameState) { + .frame_width = vp9->frame_width, + .frame_height = vp9->frame_height, + .subsampling_x = vp9->subsampling_x, + .subsampling_y = vp9->subsampling_y, + .bit_depth = vp9->bit_depth, + }; + } + } + + av_log(ctx->log_ctx, AV_LOG_DEBUG, "Frame: size %dx%d " + "subsample %dx%d bit_depth %d tiles %dx%d.\n", + vp9->frame_width, vp9->frame_height, + vp9->subsampling_x, vp9->subsampling_y, + vp9->bit_depth, 1 << current->tile_cols_log2, + 1 << current->tile_rows_log2); + + return 0; +} + +static int FUNC(trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw) { + int err; + while(byte_alignment(rw) != 0) + fixed(1, zero_bit, 0); + + return 0; +} + +static int FUNC(frame)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrame *current) { + int err; + + HEADER("Frame"); + + CHECK(FUNC(uncompressed_header)(ctx, rw, ¤t->header)); + + CHECK(FUNC(trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(superframe_index)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawSuperframeIndex *current) { + int err, i; + + HEADER("Superframe Index"); + + f(3, superframe_marker); + f(2, bytes_per_framesize_minus_1); + f(3, frames_in_superframe_minus_1); + + for(i = 0; i <= current->frames_in_superframe_minus_1; i++) { + // Surprise little-endian! + fle(8 * (current->bytes_per_framesize_minus_1 + 1), + frame_sizes[i], 1, i); + } + + f(3, superframe_marker); + f(2, bytes_per_framesize_minus_1); + f(3, frames_in_superframe_minus_1); + + return 0; +} diff --git a/third-party/cbs/codec_id.h b/third-party/cbs/codec_id.h new file mode 100644 index 00000000..a4fe0407 --- /dev/null +++ b/third-party/cbs/codec_id.h @@ -0,0 +1,627 @@ +/* + * Codec IDs + * + * 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_CODEC_ID_H +#define AVCODEC_CODEC_ID_H + +#include "libavutil/avutil.h" +#include "libavutil/samplefmt.h" + +/** + * @addtogroup lavc_core + * @{ + */ + +/** + * Identify the syntax and semantics of the bitstream. + * The principle is roughly: + * Two decoders with the same ID can decode the same streams. + * Two encoders with the same ID can encode compatible streams. + * There may be slight deviations from the principle due to implementation + * details. + * + * If you add a codec ID to this list, add it so that + * 1. no value of an existing codec ID changes (that would break ABI), + * 2. it is as close as possible to similar codecs + * + * After adding new codec IDs, do not forget to add an entry to the codec + * descriptor list and bump libavcodec minor version. + */ +enum AVCodecID { + AV_CODEC_ID_NONE, + + /* video codecs */ + AV_CODEC_ID_MPEG1VIDEO, + AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding + AV_CODEC_ID_H261, + AV_CODEC_ID_H263, + AV_CODEC_ID_RV10, + AV_CODEC_ID_RV20, + AV_CODEC_ID_MJPEG, + AV_CODEC_ID_MJPEGB, + AV_CODEC_ID_LJPEG, + AV_CODEC_ID_SP5X, + AV_CODEC_ID_JPEGLS, + AV_CODEC_ID_MPEG4, + AV_CODEC_ID_RAWVIDEO, + AV_CODEC_ID_MSMPEG4V1, + AV_CODEC_ID_MSMPEG4V2, + AV_CODEC_ID_MSMPEG4V3, + AV_CODEC_ID_WMV1, + AV_CODEC_ID_WMV2, + AV_CODEC_ID_H263P, + AV_CODEC_ID_H263I, + AV_CODEC_ID_FLV1, + AV_CODEC_ID_SVQ1, + AV_CODEC_ID_SVQ3, + AV_CODEC_ID_DVVIDEO, + AV_CODEC_ID_HUFFYUV, + AV_CODEC_ID_CYUV, + AV_CODEC_ID_H264, + AV_CODEC_ID_INDEO3, + AV_CODEC_ID_VP3, + AV_CODEC_ID_THEORA, + AV_CODEC_ID_ASV1, + AV_CODEC_ID_ASV2, + AV_CODEC_ID_FFV1, + AV_CODEC_ID_4XM, + AV_CODEC_ID_VCR1, + AV_CODEC_ID_CLJR, + AV_CODEC_ID_MDEC, + AV_CODEC_ID_ROQ, + AV_CODEC_ID_INTERPLAY_VIDEO, + AV_CODEC_ID_XAN_WC3, + AV_CODEC_ID_XAN_WC4, + AV_CODEC_ID_RPZA, + AV_CODEC_ID_CINEPAK, + AV_CODEC_ID_WS_VQA, + AV_CODEC_ID_MSRLE, + AV_CODEC_ID_MSVIDEO1, + AV_CODEC_ID_IDCIN, + AV_CODEC_ID_8BPS, + AV_CODEC_ID_SMC, + AV_CODEC_ID_FLIC, + AV_CODEC_ID_TRUEMOTION1, + AV_CODEC_ID_VMDVIDEO, + AV_CODEC_ID_MSZH, + AV_CODEC_ID_ZLIB, + AV_CODEC_ID_QTRLE, + AV_CODEC_ID_TSCC, + AV_CODEC_ID_ULTI, + AV_CODEC_ID_QDRAW, + AV_CODEC_ID_VIXL, + AV_CODEC_ID_QPEG, + AV_CODEC_ID_PNG, + AV_CODEC_ID_PPM, + AV_CODEC_ID_PBM, + AV_CODEC_ID_PGM, + AV_CODEC_ID_PGMYUV, + AV_CODEC_ID_PAM, + AV_CODEC_ID_FFVHUFF, + AV_CODEC_ID_RV30, + AV_CODEC_ID_RV40, + AV_CODEC_ID_VC1, + AV_CODEC_ID_WMV3, + AV_CODEC_ID_LOCO, + AV_CODEC_ID_WNV1, + AV_CODEC_ID_AASC, + AV_CODEC_ID_INDEO2, + AV_CODEC_ID_FRAPS, + AV_CODEC_ID_TRUEMOTION2, + AV_CODEC_ID_BMP, + AV_CODEC_ID_CSCD, + AV_CODEC_ID_MMVIDEO, + AV_CODEC_ID_ZMBV, + AV_CODEC_ID_AVS, + AV_CODEC_ID_SMACKVIDEO, + AV_CODEC_ID_NUV, + AV_CODEC_ID_KMVC, + AV_CODEC_ID_FLASHSV, + AV_CODEC_ID_CAVS, + AV_CODEC_ID_JPEG2000, + AV_CODEC_ID_VMNC, + AV_CODEC_ID_VP5, + AV_CODEC_ID_VP6, + AV_CODEC_ID_VP6F, + AV_CODEC_ID_TARGA, + AV_CODEC_ID_DSICINVIDEO, + AV_CODEC_ID_TIERTEXSEQVIDEO, + AV_CODEC_ID_TIFF, + AV_CODEC_ID_GIF, + AV_CODEC_ID_DXA, + AV_CODEC_ID_DNXHD, + AV_CODEC_ID_THP, + AV_CODEC_ID_SGI, + AV_CODEC_ID_C93, + AV_CODEC_ID_BETHSOFTVID, + AV_CODEC_ID_PTX, + AV_CODEC_ID_TXD, + AV_CODEC_ID_VP6A, + AV_CODEC_ID_AMV, + AV_CODEC_ID_VB, + AV_CODEC_ID_PCX, + AV_CODEC_ID_SUNRAST, + AV_CODEC_ID_INDEO4, + AV_CODEC_ID_INDEO5, + AV_CODEC_ID_MIMIC, + AV_CODEC_ID_RL2, + AV_CODEC_ID_ESCAPE124, + AV_CODEC_ID_DIRAC, + AV_CODEC_ID_BFI, + AV_CODEC_ID_CMV, + AV_CODEC_ID_MOTIONPIXELS, + AV_CODEC_ID_TGV, + AV_CODEC_ID_TGQ, + AV_CODEC_ID_TQI, + AV_CODEC_ID_AURA, + AV_CODEC_ID_AURA2, + AV_CODEC_ID_V210X, + AV_CODEC_ID_TMV, + AV_CODEC_ID_V210, + AV_CODEC_ID_DPX, + AV_CODEC_ID_MAD, + AV_CODEC_ID_FRWU, + AV_CODEC_ID_FLASHSV2, + AV_CODEC_ID_CDGRAPHICS, + AV_CODEC_ID_R210, + AV_CODEC_ID_ANM, + AV_CODEC_ID_BINKVIDEO, + AV_CODEC_ID_IFF_ILBM, +#define AV_CODEC_ID_IFF_BYTERUN1 AV_CODEC_ID_IFF_ILBM + AV_CODEC_ID_KGV1, + AV_CODEC_ID_YOP, + AV_CODEC_ID_VP8, + AV_CODEC_ID_PICTOR, + AV_CODEC_ID_ANSI, + AV_CODEC_ID_A64_MULTI, + AV_CODEC_ID_A64_MULTI5, + AV_CODEC_ID_R10K, + AV_CODEC_ID_MXPEG, + AV_CODEC_ID_LAGARITH, + AV_CODEC_ID_PRORES, + AV_CODEC_ID_JV, + AV_CODEC_ID_DFA, + AV_CODEC_ID_WMV3IMAGE, + AV_CODEC_ID_VC1IMAGE, + AV_CODEC_ID_UTVIDEO, + AV_CODEC_ID_BMV_VIDEO, + AV_CODEC_ID_VBLE, + AV_CODEC_ID_DXTORY, + AV_CODEC_ID_V410, + AV_CODEC_ID_XWD, + AV_CODEC_ID_CDXL, + AV_CODEC_ID_XBM, + AV_CODEC_ID_ZEROCODEC, + AV_CODEC_ID_MSS1, + AV_CODEC_ID_MSA1, + AV_CODEC_ID_TSCC2, + AV_CODEC_ID_MTS2, + AV_CODEC_ID_CLLC, + AV_CODEC_ID_MSS2, + AV_CODEC_ID_VP9, + AV_CODEC_ID_AIC, + AV_CODEC_ID_ESCAPE130, + AV_CODEC_ID_G2M, + AV_CODEC_ID_WEBP, + AV_CODEC_ID_HNM4_VIDEO, + AV_CODEC_ID_HEVC, +#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC + AV_CODEC_ID_FIC, + AV_CODEC_ID_ALIAS_PIX, + AV_CODEC_ID_BRENDER_PIX, + AV_CODEC_ID_PAF_VIDEO, + AV_CODEC_ID_EXR, + AV_CODEC_ID_VP7, + AV_CODEC_ID_SANM, + AV_CODEC_ID_SGIRLE, + AV_CODEC_ID_MVC1, + AV_CODEC_ID_MVC2, + AV_CODEC_ID_HQX, + AV_CODEC_ID_TDSC, + AV_CODEC_ID_HQ_HQA, + AV_CODEC_ID_HAP, + AV_CODEC_ID_DDS, + AV_CODEC_ID_DXV, + AV_CODEC_ID_SCREENPRESSO, + AV_CODEC_ID_RSCC, + AV_CODEC_ID_AVS2, + AV_CODEC_ID_PGX, + AV_CODEC_ID_AVS3, + AV_CODEC_ID_MSP2, + AV_CODEC_ID_VVC, +#define AV_CODEC_ID_H266 AV_CODEC_ID_VVC + AV_CODEC_ID_Y41P, + AV_CODEC_ID_AVRP, + AV_CODEC_ID_012V, + AV_CODEC_ID_AVUI, + AV_CODEC_ID_AYUV, + AV_CODEC_ID_TARGA_Y216, + AV_CODEC_ID_V308, + AV_CODEC_ID_V408, + AV_CODEC_ID_YUV4, + AV_CODEC_ID_AVRN, + AV_CODEC_ID_CPIA, + AV_CODEC_ID_XFACE, + AV_CODEC_ID_SNOW, + AV_CODEC_ID_SMVJPEG, + AV_CODEC_ID_APNG, + AV_CODEC_ID_DAALA, + AV_CODEC_ID_CFHD, + AV_CODEC_ID_TRUEMOTION2RT, + AV_CODEC_ID_M101, + AV_CODEC_ID_MAGICYUV, + AV_CODEC_ID_SHEERVIDEO, + AV_CODEC_ID_YLC, + AV_CODEC_ID_PSD, + AV_CODEC_ID_PIXLET, + AV_CODEC_ID_SPEEDHQ, + AV_CODEC_ID_FMVC, + AV_CODEC_ID_SCPR, + AV_CODEC_ID_CLEARVIDEO, + AV_CODEC_ID_XPM, + AV_CODEC_ID_AV1, + AV_CODEC_ID_BITPACKED, + AV_CODEC_ID_MSCC, + AV_CODEC_ID_SRGC, + AV_CODEC_ID_SVG, + AV_CODEC_ID_GDV, + AV_CODEC_ID_FITS, + AV_CODEC_ID_IMM4, + AV_CODEC_ID_PROSUMER, + AV_CODEC_ID_MWSC, + AV_CODEC_ID_WCMV, + AV_CODEC_ID_RASC, + AV_CODEC_ID_HYMT, + AV_CODEC_ID_ARBC, + AV_CODEC_ID_AGM, + AV_CODEC_ID_LSCR, + AV_CODEC_ID_VP4, + AV_CODEC_ID_IMM5, + AV_CODEC_ID_MVDV, + AV_CODEC_ID_MVHA, + AV_CODEC_ID_CDTOONS, + AV_CODEC_ID_MV30, + AV_CODEC_ID_NOTCHLC, + AV_CODEC_ID_PFM, + AV_CODEC_ID_MOBICLIP, + AV_CODEC_ID_PHOTOCD, + AV_CODEC_ID_IPU, + AV_CODEC_ID_ARGO, + AV_CODEC_ID_CRI, + AV_CODEC_ID_SIMBIOSIS_IMX, + AV_CODEC_ID_SGA_VIDEO, + + /* various PCM "codecs" */ + AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs + AV_CODEC_ID_PCM_S16LE = 0x10000, + AV_CODEC_ID_PCM_S16BE, + AV_CODEC_ID_PCM_U16LE, + AV_CODEC_ID_PCM_U16BE, + AV_CODEC_ID_PCM_S8, + AV_CODEC_ID_PCM_U8, + AV_CODEC_ID_PCM_MULAW, + AV_CODEC_ID_PCM_ALAW, + AV_CODEC_ID_PCM_S32LE, + AV_CODEC_ID_PCM_S32BE, + AV_CODEC_ID_PCM_U32LE, + AV_CODEC_ID_PCM_U32BE, + AV_CODEC_ID_PCM_S24LE, + AV_CODEC_ID_PCM_S24BE, + AV_CODEC_ID_PCM_U24LE, + AV_CODEC_ID_PCM_U24BE, + AV_CODEC_ID_PCM_S24DAUD, + AV_CODEC_ID_PCM_ZORK, + AV_CODEC_ID_PCM_S16LE_PLANAR, + AV_CODEC_ID_PCM_DVD, + AV_CODEC_ID_PCM_F32BE, + AV_CODEC_ID_PCM_F32LE, + AV_CODEC_ID_PCM_F64BE, + AV_CODEC_ID_PCM_F64LE, + AV_CODEC_ID_PCM_BLURAY, + AV_CODEC_ID_PCM_LXF, + AV_CODEC_ID_S302M, + AV_CODEC_ID_PCM_S8_PLANAR, + AV_CODEC_ID_PCM_S24LE_PLANAR, + AV_CODEC_ID_PCM_S32LE_PLANAR, + AV_CODEC_ID_PCM_S16BE_PLANAR, + AV_CODEC_ID_PCM_S64LE, + AV_CODEC_ID_PCM_S64BE, + AV_CODEC_ID_PCM_F16LE, + AV_CODEC_ID_PCM_F24LE, + AV_CODEC_ID_PCM_VIDC, + AV_CODEC_ID_PCM_SGA, + + /* various ADPCM codecs */ + AV_CODEC_ID_ADPCM_IMA_QT = 0x11000, + AV_CODEC_ID_ADPCM_IMA_WAV, + AV_CODEC_ID_ADPCM_IMA_DK3, + AV_CODEC_ID_ADPCM_IMA_DK4, + AV_CODEC_ID_ADPCM_IMA_WS, + AV_CODEC_ID_ADPCM_IMA_SMJPEG, + AV_CODEC_ID_ADPCM_MS, + AV_CODEC_ID_ADPCM_4XM, + AV_CODEC_ID_ADPCM_XA, + AV_CODEC_ID_ADPCM_ADX, + AV_CODEC_ID_ADPCM_EA, + AV_CODEC_ID_ADPCM_G726, + AV_CODEC_ID_ADPCM_CT, + AV_CODEC_ID_ADPCM_SWF, + AV_CODEC_ID_ADPCM_YAMAHA, + AV_CODEC_ID_ADPCM_SBPRO_4, + AV_CODEC_ID_ADPCM_SBPRO_3, + AV_CODEC_ID_ADPCM_SBPRO_2, + AV_CODEC_ID_ADPCM_THP, + AV_CODEC_ID_ADPCM_IMA_AMV, + AV_CODEC_ID_ADPCM_EA_R1, + AV_CODEC_ID_ADPCM_EA_R3, + AV_CODEC_ID_ADPCM_EA_R2, + AV_CODEC_ID_ADPCM_IMA_EA_SEAD, + AV_CODEC_ID_ADPCM_IMA_EA_EACS, + AV_CODEC_ID_ADPCM_EA_XAS, + AV_CODEC_ID_ADPCM_EA_MAXIS_XA, + AV_CODEC_ID_ADPCM_IMA_ISS, + AV_CODEC_ID_ADPCM_G722, + AV_CODEC_ID_ADPCM_IMA_APC, + AV_CODEC_ID_ADPCM_VIMA, + AV_CODEC_ID_ADPCM_AFC, + AV_CODEC_ID_ADPCM_IMA_OKI, + AV_CODEC_ID_ADPCM_DTK, + AV_CODEC_ID_ADPCM_IMA_RAD, + AV_CODEC_ID_ADPCM_G726LE, + AV_CODEC_ID_ADPCM_THP_LE, + AV_CODEC_ID_ADPCM_PSX, + AV_CODEC_ID_ADPCM_AICA, + AV_CODEC_ID_ADPCM_IMA_DAT4, + AV_CODEC_ID_ADPCM_MTAF, + AV_CODEC_ID_ADPCM_AGM, + AV_CODEC_ID_ADPCM_ARGO, + AV_CODEC_ID_ADPCM_IMA_SSI, + AV_CODEC_ID_ADPCM_ZORK, + AV_CODEC_ID_ADPCM_IMA_APM, + AV_CODEC_ID_ADPCM_IMA_ALP, + AV_CODEC_ID_ADPCM_IMA_MTF, + AV_CODEC_ID_ADPCM_IMA_CUNNING, + AV_CODEC_ID_ADPCM_IMA_MOFLEX, + AV_CODEC_ID_ADPCM_IMA_ACORN, + + /* AMR */ + AV_CODEC_ID_AMR_NB = 0x12000, + AV_CODEC_ID_AMR_WB, + + /* RealAudio codecs*/ + AV_CODEC_ID_RA_144 = 0x13000, + AV_CODEC_ID_RA_288, + + /* various DPCM codecs */ + AV_CODEC_ID_ROQ_DPCM = 0x14000, + AV_CODEC_ID_INTERPLAY_DPCM, + AV_CODEC_ID_XAN_DPCM, + AV_CODEC_ID_SOL_DPCM, + AV_CODEC_ID_SDX2_DPCM, + AV_CODEC_ID_GREMLIN_DPCM, + AV_CODEC_ID_DERF_DPCM, + + /* audio codecs */ + AV_CODEC_ID_MP2 = 0x15000, + AV_CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3 + AV_CODEC_ID_AAC, + AV_CODEC_ID_AC3, + AV_CODEC_ID_DTS, + AV_CODEC_ID_VORBIS, + AV_CODEC_ID_DVAUDIO, + AV_CODEC_ID_WMAV1, + AV_CODEC_ID_WMAV2, + AV_CODEC_ID_MACE3, + AV_CODEC_ID_MACE6, + AV_CODEC_ID_VMDAUDIO, + AV_CODEC_ID_FLAC, + AV_CODEC_ID_MP3ADU, + AV_CODEC_ID_MP3ON4, + AV_CODEC_ID_SHORTEN, + AV_CODEC_ID_ALAC, + AV_CODEC_ID_WESTWOOD_SND1, + AV_CODEC_ID_GSM, ///< as in Berlin toast format + AV_CODEC_ID_QDM2, + AV_CODEC_ID_COOK, + AV_CODEC_ID_TRUESPEECH, + AV_CODEC_ID_TTA, + AV_CODEC_ID_SMACKAUDIO, + AV_CODEC_ID_QCELP, + AV_CODEC_ID_WAVPACK, + AV_CODEC_ID_DSICINAUDIO, + AV_CODEC_ID_IMC, + AV_CODEC_ID_MUSEPACK7, + AV_CODEC_ID_MLP, + AV_CODEC_ID_GSM_MS, /* as found in WAV */ + AV_CODEC_ID_ATRAC3, + AV_CODEC_ID_APE, + AV_CODEC_ID_NELLYMOSER, + AV_CODEC_ID_MUSEPACK8, + AV_CODEC_ID_SPEEX, + AV_CODEC_ID_WMAVOICE, + AV_CODEC_ID_WMAPRO, + AV_CODEC_ID_WMALOSSLESS, + AV_CODEC_ID_ATRAC3P, + AV_CODEC_ID_EAC3, + AV_CODEC_ID_SIPR, + AV_CODEC_ID_MP1, + AV_CODEC_ID_TWINVQ, + AV_CODEC_ID_TRUEHD, + AV_CODEC_ID_MP4ALS, + AV_CODEC_ID_ATRAC1, + AV_CODEC_ID_BINKAUDIO_RDFT, + AV_CODEC_ID_BINKAUDIO_DCT, + AV_CODEC_ID_AAC_LATM, + AV_CODEC_ID_QDMC, + AV_CODEC_ID_CELT, + AV_CODEC_ID_G723_1, + AV_CODEC_ID_G729, + AV_CODEC_ID_8SVX_EXP, + AV_CODEC_ID_8SVX_FIB, + AV_CODEC_ID_BMV_AUDIO, + AV_CODEC_ID_RALF, + AV_CODEC_ID_IAC, + AV_CODEC_ID_ILBC, + AV_CODEC_ID_OPUS, + AV_CODEC_ID_COMFORT_NOISE, + AV_CODEC_ID_TAK, + AV_CODEC_ID_METASOUND, + AV_CODEC_ID_PAF_AUDIO, + AV_CODEC_ID_ON2AVC, + AV_CODEC_ID_DSS_SP, + AV_CODEC_ID_CODEC2, + AV_CODEC_ID_FFWAVESYNTH, + AV_CODEC_ID_SONIC, + AV_CODEC_ID_SONIC_LS, + AV_CODEC_ID_EVRC, + AV_CODEC_ID_SMV, + AV_CODEC_ID_DSD_LSBF, + AV_CODEC_ID_DSD_MSBF, + AV_CODEC_ID_DSD_LSBF_PLANAR, + AV_CODEC_ID_DSD_MSBF_PLANAR, + AV_CODEC_ID_4GV, + AV_CODEC_ID_INTERPLAY_ACM, + AV_CODEC_ID_XMA1, + AV_CODEC_ID_XMA2, + AV_CODEC_ID_DST, + AV_CODEC_ID_ATRAC3AL, + AV_CODEC_ID_ATRAC3PAL, + AV_CODEC_ID_DOLBY_E, + AV_CODEC_ID_APTX, + AV_CODEC_ID_APTX_HD, + AV_CODEC_ID_SBC, + AV_CODEC_ID_ATRAC9, + AV_CODEC_ID_HCOM, + AV_CODEC_ID_ACELP_KELVIN, + AV_CODEC_ID_MPEGH_3D_AUDIO, + AV_CODEC_ID_SIREN, + AV_CODEC_ID_HCA, + AV_CODEC_ID_FASTAUDIO, + + /* subtitle codecs */ + AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. + AV_CODEC_ID_DVD_SUBTITLE = 0x17000, + AV_CODEC_ID_DVB_SUBTITLE, + AV_CODEC_ID_TEXT, ///< raw UTF-8 text + AV_CODEC_ID_XSUB, + AV_CODEC_ID_SSA, + AV_CODEC_ID_MOV_TEXT, + AV_CODEC_ID_HDMV_PGS_SUBTITLE, + AV_CODEC_ID_DVB_TELETEXT, + AV_CODEC_ID_SRT, + AV_CODEC_ID_MICRODVD, + AV_CODEC_ID_EIA_608, + AV_CODEC_ID_JACOSUB, + AV_CODEC_ID_SAMI, + AV_CODEC_ID_REALTEXT, + AV_CODEC_ID_STL, + AV_CODEC_ID_SUBVIEWER1, + AV_CODEC_ID_SUBVIEWER, + AV_CODEC_ID_SUBRIP, + AV_CODEC_ID_WEBVTT, + AV_CODEC_ID_MPL2, + AV_CODEC_ID_VPLAYER, + AV_CODEC_ID_PJS, + AV_CODEC_ID_ASS, + AV_CODEC_ID_HDMV_TEXT_SUBTITLE, + AV_CODEC_ID_TTML, + AV_CODEC_ID_ARIB_CAPTION, + + /* other specific kind of codecs (generally used for attachments) */ + AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. + AV_CODEC_ID_TTF = 0x18000, + + AV_CODEC_ID_SCTE_35, ///< Contain timestamp estimated through PCR of program stream. + AV_CODEC_ID_EPG, + AV_CODEC_ID_BINTEXT, + AV_CODEC_ID_XBIN, + AV_CODEC_ID_IDF, + AV_CODEC_ID_OTF, + AV_CODEC_ID_SMPTE_KLV, + AV_CODEC_ID_DVD_NAV, + AV_CODEC_ID_TIMED_ID3, + AV_CODEC_ID_BIN_DATA, + + + AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it + + AV_CODEC_ID_MPEG2TS = 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS + * stream (only used by libavformat) */ + AV_CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems + * stream (only used by libavformat) */ + AV_CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information. + AV_CODEC_ID_WRAPPED_AVFRAME = 0x21001, ///< Passthrough codec, AVFrames wrapped in AVPacket +}; + +/** + * Get the type of the given codec. + */ +enum AVMediaType avcodec_get_type(enum AVCodecID codec_id); + +/** + * Get the name of a codec. + * @return a static string identifying the codec; never NULL + */ +const char *avcodec_get_name(enum AVCodecID id); + +/** + * Return codec bits per sample. + * + * @param[in] codec_id the codec + * @return Number of bits per sample or zero if unknown for the given codec. + */ +int av_get_bits_per_sample(enum AVCodecID codec_id); + +/** + * Return codec bits per sample. + * Only return non-zero if the bits per sample is exactly correct, not an + * approximation. + * + * @param[in] codec_id the codec + * @return Number of bits per sample or zero if unknown for the given codec. + */ +int av_get_exact_bits_per_sample(enum AVCodecID codec_id); + +/** + * Return a name for the specified profile, if available. + * + * @param codec_id the ID of the codec to which the requested profile belongs + * @param profile the profile value for which a name is requested + * @return A name for the profile if found, NULL otherwise. + * + * @note unlike av_get_profile_name(), which searches a list of profiles + * supported by a specific decoder or encoder implementation, this + * function searches the list of profiles from the AVCodecDescriptor + */ +const char *avcodec_profile_name(enum AVCodecID codec_id, int profile); + +/** + * Return the PCM codec associated with a sample format. + * @param be endianness, 0 for little, 1 for big, + * -1 (or anything else) for native + * @return AV_CODEC_ID_PCM_* or AV_CODEC_ID_NONE + */ +enum AVCodecID av_get_pcm_codec(enum AVSampleFormat fmt, int be); + +/** + * @} + */ + +#endif // AVCODEC_CODEC_ID_H diff --git a/third-party/cbs/defs.h b/third-party/cbs/defs.h new file mode 100644 index 00000000..1c5f0ce8 --- /dev/null +++ b/third-party/cbs/defs.h @@ -0,0 +1,51 @@ +/* + * + * 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_DEFS_H +#define AVCODEC_DEFS_H + +/** + * @file + * @ingroup libavc + * Misc types and constants that do not belong anywhere else. + */ + +#include +#include + +/** + * @ingroup lavc_decoding + * Required number of additionally allocated bytes at the end of the input bitstream for decoding. + * This is mainly needed because some optimized bitstream readers read + * 32 or 64 bit at once and could read over the end.
+ * Note: If the first 23 bits of the additional bytes are not 0, then damaged + * MPEG bitstreams could cause overread and segfault. + */ +#define AV_INPUT_BUFFER_PADDING_SIZE 64 + +/** + * Encode extradata length to a buffer. Used by xiph codecs. + * + * @param s buffer to write to; must be at least (v/255+1) bytes long + * @param v size of extradata in bytes + * @return number of bytes written to the buffer. + */ +unsigned int av_xiphlacing(unsigned char *s, unsigned int v); + +#endif // AVCODEC_DEFS_H diff --git a/third-party/cbs/get_bits.h b/third-party/cbs/get_bits.h new file mode 100644 index 00000000..3c34b040 --- /dev/null +++ b/third-party/cbs/get_bits.h @@ -0,0 +1,831 @@ +/* + * Copyright (c) 2004 Michael Niedermayer + * Copyright (c) 2016 Alexandra Hájková + * + * 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 + */ + +/** + * @file + * bitstream reader API header. + */ + +#ifndef AVCODEC_GET_BITS_H +#define AVCODEC_GET_BITS_H + +#include + +#include +#include +#include +#include + +#include "defs.h" +#include "mathops.h" +#include "vlc.h" + +/* + * Safe bitstream reading: + * optionally, the get_bits API can check to ensure that we + * don't read past input buffer boundaries. This is protected + * with CONFIG_SAFE_BITSTREAM_READER at the global level, and + * then below that with UNCHECKED_BITSTREAM_READER at the per- + * decoder level. This means that decoders that check internally + * can "#define UNCHECKED_BITSTREAM_READER 1" to disable + * overread checks. + * Boundary checking causes a minor performance penalty so for + * applications that won't want/need this, it can be disabled + * globally using "#define CONFIG_SAFE_BITSTREAM_READER 0". + */ +#ifndef UNCHECKED_BITSTREAM_READER +#define UNCHECKED_BITSTREAM_READER 0 +#endif + +#ifndef CACHED_BITSTREAM_READER +#define CACHED_BITSTREAM_READER 0 +#endif + +#include "cbs/h2645_parse.h" + +static inline unsigned int get_bits(GetBitContext *s, int n); +static inline void skip_bits(GetBitContext *s, int n); +static inline unsigned int show_bits(GetBitContext *s, int n); + +/* Bitstream reader API docs: + * name + * arbitrary name which is used as prefix for the internal variables + * + * gb + * getbitcontext + * + * OPEN_READER(name, gb) + * load gb into local variables + * + * CLOSE_READER(name, gb) + * store local vars in gb + * + * UPDATE_CACHE(name, gb) + * Refill the internal cache from the bitstream. + * After this call at least MIN_CACHE_BITS will be available. + * + * GET_CACHE(name, gb) + * Will output the contents of the internal cache, + * next bit is MSB of 32 or 64 bits (FIXME 64 bits). + * + * SHOW_UBITS(name, gb, num) + * Will return the next num bits. + * + * SHOW_SBITS(name, gb, num) + * Will return the next num bits and do sign extension. + * + * SKIP_BITS(name, gb, num) + * Will skip over the next num bits. + * Note, this is equivalent to SKIP_CACHE; SKIP_COUNTER. + * + * SKIP_CACHE(name, gb, num) + * Will remove the next num bits from the cache (note SKIP_COUNTER + * MUST be called before UPDATE_CACHE / CLOSE_READER). + * + * SKIP_COUNTER(name, gb, num) + * Will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS). + * + * LAST_SKIP_BITS(name, gb, num) + * Like SKIP_BITS, to be used if next call is UPDATE_CACHE or CLOSE_READER. + * + * BITS_LEFT(name, gb) + * Return the number of bits left + * + * For examples see get_bits, show_bits, skip_bits, get_vlc. + */ + +#if CACHED_BITSTREAM_READER +#define MIN_CACHE_BITS 64 +#elif defined LONG_BITSTREAM_READER +#define MIN_CACHE_BITS 32 +#else +#define MIN_CACHE_BITS 25 +#endif + +#if !CACHED_BITSTREAM_READER + +#define OPEN_READER_NOSIZE(name, gb) \ + unsigned int name##_index = (gb)->index; \ + unsigned int av_unused name##_cache + +#if UNCHECKED_BITSTREAM_READER +#define OPEN_READER(name, gb) OPEN_READER_NOSIZE(name, gb) + +#define BITS_AVAILABLE(name, gb) 1 +#else +#define OPEN_READER(name, gb) \ + OPEN_READER_NOSIZE(name, gb); \ + unsigned int name##_size_plus8 = (gb)->size_in_bits_plus8 + +#define BITS_AVAILABLE(name, gb) name##_index < name##_size_plus8 +#endif + +#define CLOSE_READER(name, gb) (gb)->index = name##_index + +#ifdef LONG_BITSTREAM_READER + +#define UPDATE_CACHE_LE(name, gb) name##_cache = \ + AV_RL64((gb)->buffer + (name##_index >> 3)) >> (name##_index & 7) + +#define UPDATE_CACHE_BE(name, gb) name##_cache = \ + AV_RB64((gb)->buffer + (name##_index >> 3)) >> (32 - (name##_index & 7)) + +#else + +#define UPDATE_CACHE_LE(name, gb) name##_cache = \ + AV_RL32((gb)->buffer + (name##_index >> 3)) >> (name##_index & 7) + +#define UPDATE_CACHE_BE(name, gb) name##_cache = \ + AV_RB32((gb)->buffer + (name##_index >> 3)) << (name##_index & 7) + +#endif + + +#ifdef BITSTREAM_READER_LE + +#define UPDATE_CACHE(name, gb) UPDATE_CACHE_LE(name, gb) + +#define SKIP_CACHE(name, gb, num) name##_cache >>= (num) + +#else + +#define UPDATE_CACHE(name, gb) UPDATE_CACHE_BE(name, gb) + +#define SKIP_CACHE(name, gb, num) name##_cache <<= (num) + +#endif + +#if UNCHECKED_BITSTREAM_READER +#define SKIP_COUNTER(name, gb, num) name##_index += (num) +#else +#define SKIP_COUNTER(name, gb, num) \ + name##_index = FFMIN(name##_size_plus8, name##_index + (num)) +#endif + +#define BITS_LEFT(name, gb) ((int)((gb)->size_in_bits - name##_index)) + +#define SKIP_BITS(name, gb, num) \ + do { \ + SKIP_CACHE(name, gb, num); \ + SKIP_COUNTER(name, gb, num); \ + } while(0) + +#define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) + +#define SHOW_UBITS_LE(name, gb, num) zero_extend(name##_cache, num) +#define SHOW_SBITS_LE(name, gb, num) sign_extend(name##_cache, num) + +#define SHOW_UBITS_BE(name, gb, num) NEG_USR32(name##_cache, num) +#define SHOW_SBITS_BE(name, gb, num) NEG_SSR32(name##_cache, num) + +#ifdef BITSTREAM_READER_LE +#define SHOW_UBITS(name, gb, num) SHOW_UBITS_LE(name, gb, num) +#define SHOW_SBITS(name, gb, num) SHOW_SBITS_LE(name, gb, num) +#else +#define SHOW_UBITS(name, gb, num) SHOW_UBITS_BE(name, gb, num) +#define SHOW_SBITS(name, gb, num) SHOW_SBITS_BE(name, gb, num) +#endif + +#define GET_CACHE(name, gb) ((uint32_t)name##_cache) + +#endif + +static inline int get_bits_count(const GetBitContext *s) { +#if CACHED_BITSTREAM_READER + return s->index - s->bits_left; +#else + return s->index; +#endif +} + +#if CACHED_BITSTREAM_READER +static inline void refill_32(GetBitContext *s, int is_le) { +#if !UNCHECKED_BITSTREAM_READER + if(s->index >> 3 >= s->buffer_end - s->buffer) + return; +#endif + + if(is_le) + s->cache = (uint64_t)AV_RL32(s->buffer + (s->index >> 3)) << s->bits_left | s->cache; + else + s->cache = s->cache | (uint64_t)AV_RB32(s->buffer + (s->index >> 3)) << (32 - s->bits_left); + s->index += 32; + s->bits_left += 32; +} + +static inline void refill_64(GetBitContext *s, int is_le) { +#if !UNCHECKED_BITSTREAM_READER + if(s->index >> 3 >= s->buffer_end - s->buffer) + return; +#endif + + if(is_le) + s->cache = AV_RL64(s->buffer + (s->index >> 3)); + else + s->cache = AV_RB64(s->buffer + (s->index >> 3)); + s->index += 64; + s->bits_left = 64; +} + +static inline uint64_t get_val(GetBitContext *s, unsigned n, int is_le) { + uint64_t ret; + av_assert2(n > 0 && n <= 63); + if(is_le) { + ret = s->cache & ((UINT64_C(1) << n) - 1); + s->cache >>= n; + } + else { + ret = s->cache >> (64 - n); + s->cache <<= n; + } + s->bits_left -= n; + return ret; +} + +static inline unsigned show_val(const GetBitContext *s, unsigned n) { +#ifdef BITSTREAM_READER_LE + return s->cache & ((UINT64_C(1) << n) - 1); +#else + return s->cache >> (64 - n); +#endif +} +#endif + +/** + * Skips the specified number of bits. + * @param n the number of bits to skip, + * For the UNCHECKED_BITSTREAM_READER this must not cause the distance + * from the start to overflow int32_t. Staying within the bitstream + padding + * is sufficient, too. + */ +static inline void skip_bits_long(GetBitContext *s, int n) { +#if CACHED_BITSTREAM_READER + skip_bits(s, n); +#else +#if UNCHECKED_BITSTREAM_READER + s->index += n; +#else + s->index += av_clip(n, -s->index, s->size_in_bits_plus8 - s->index); +#endif +#endif +} + +#if CACHED_BITSTREAM_READER +static inline void skip_remaining(GetBitContext *s, unsigned n) { +#ifdef BITSTREAM_READER_LE + s->cache >>= n; +#else + s->cache <<= n; +#endif + s->bits_left -= n; +} +#endif + +/** + * Read MPEG-1 dc-style VLC (sign bit + mantissa with no MSB). + * if MSB not set it is negative + * @param n length in bits + */ +static inline int get_xbits(GetBitContext *s, int n) { +#if CACHED_BITSTREAM_READER + int32_t cache = show_bits(s, 32); + int sign = ~cache >> 31; + skip_remaining(s, n); + + return ((((uint32_t)(sign ^ cache)) >> (32 - n)) ^ sign) - sign; +#else + register int sign; + register int32_t cache; + OPEN_READER(re, s); + av_assert2(n > 0 && n <= 25); + UPDATE_CACHE(re, s); + cache = GET_CACHE(re, s); + sign = ~cache >> 31; + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return (NEG_USR32(sign ^ cache, n) ^ sign) - sign; +#endif +} + +#if !CACHED_BITSTREAM_READER +static inline int get_xbits_le(GetBitContext *s, int n) { + register int sign; + register int32_t cache; + OPEN_READER(re, s); + av_assert2(n > 0 && n <= 25); + UPDATE_CACHE_LE(re, s); + cache = GET_CACHE(re, s); + sign = sign_extend(~cache, n) >> 31; + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return (zero_extend(sign ^ cache, n) ^ sign) - sign; +} +#endif + +static inline int get_sbits(GetBitContext *s, int n) { + register int tmp; +#if CACHED_BITSTREAM_READER + av_assert2(n > 0 && n <= 25); + tmp = sign_extend(get_bits(s, n), n); +#else + OPEN_READER(re, s); + av_assert2(n > 0 && n <= 25); + UPDATE_CACHE(re, s); + tmp = SHOW_SBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); +#endif + return tmp; +} + +/** + * Read 1-25 bits. + */ +static inline unsigned int get_bits(GetBitContext *s, int n) { + register unsigned int tmp; +#if CACHED_BITSTREAM_READER + + av_assert2(n > 0 && n <= 32); + if(n > s->bits_left) { +#ifdef BITSTREAM_READER_LE + refill_32(s, 1); +#else + refill_32(s, 0); +#endif + if(s->bits_left < 32) + s->bits_left = n; + } + +#ifdef BITSTREAM_READER_LE + tmp = get_val(s, n, 1); +#else + tmp = get_val(s, n, 0); +#endif +#else + OPEN_READER(re, s); + av_assert2(n > 0 && n <= 25); + UPDATE_CACHE(re, s); + tmp = SHOW_UBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); +#endif + av_assert2(tmp < UINT64_C(1) << n); + return tmp; +} + +/** + * Read 0-25 bits. + */ +static av_always_inline int get_bitsz(GetBitContext *s, int n) { + return n ? get_bits(s, n) : 0; +} + +static inline unsigned int get_bits_le(GetBitContext *s, int n) { +#if CACHED_BITSTREAM_READER + av_assert2(n > 0 && n <= 32); + if(n > s->bits_left) { + refill_32(s, 1); + if(s->bits_left < 32) + s->bits_left = n; + } + + return get_val(s, n, 1); +#else + register int tmp; + OPEN_READER(re, s); + av_assert2(n > 0 && n <= 25); + UPDATE_CACHE_LE(re, s); + tmp = SHOW_UBITS_LE(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return tmp; +#endif +} + +/** + * Show 1-25 bits. + */ +static inline unsigned int show_bits(GetBitContext *s, int n) { + register unsigned int tmp; +#if CACHED_BITSTREAM_READER + if(n > s->bits_left) +#ifdef BITSTREAM_READER_LE + refill_32(s, 1); +#else + refill_32(s, 0); +#endif + + tmp = show_val(s, n); +#else + OPEN_READER_NOSIZE(re, s); + av_assert2(n > 0 && n <= 25); + UPDATE_CACHE(re, s); + tmp = SHOW_UBITS(re, s, n); +#endif + return tmp; +} + +static inline void skip_bits(GetBitContext *s, int n) { +#if CACHED_BITSTREAM_READER + if(n < s->bits_left) + skip_remaining(s, n); + else { + n -= s->bits_left; + s->cache = 0; + s->bits_left = 0; + + if(n >= 64) { + unsigned skip = (n / 8) * 8; + + n -= skip; + s->index += skip; + } +#ifdef BITSTREAM_READER_LE + refill_64(s, 1); +#else + refill_64(s, 0); +#endif + if(n) + skip_remaining(s, n); + } +#else + OPEN_READER(re, s); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); +#endif +} + +static inline unsigned int get_bits1(GetBitContext *s) { +#if CACHED_BITSTREAM_READER + if(!s->bits_left) +#ifdef BITSTREAM_READER_LE + refill_64(s, 1); +#else + refill_64(s, 0); +#endif + +#ifdef BITSTREAM_READER_LE + return get_val(s, 1, 1); +#else + return get_val(s, 1, 0); +#endif +#else + unsigned int index = s->index; + uint8_t result = s->buffer[index >> 3]; +#ifdef BITSTREAM_READER_LE + result >>= index & 7; + result &= 1; +#else + result <<= index & 7; + result >>= 8 - 1; +#endif +#if !UNCHECKED_BITSTREAM_READER + if(s->index < s->size_in_bits_plus8) +#endif + index++; + s->index = index; + + return result; +#endif +} + +static inline unsigned int show_bits1(GetBitContext *s) { + return show_bits(s, 1); +} + +static inline void skip_bits1(GetBitContext *s) { + skip_bits(s, 1); +} + +/** + * Read 0-32 bits. + */ +static inline unsigned int get_bits_long(GetBitContext *s, int n) { + av_assert2(n >= 0 && n <= 32); + if(!n) { + return 0; +#if CACHED_BITSTREAM_READER + } + return get_bits(s, n); +#else + } + else if(n <= MIN_CACHE_BITS) { + return get_bits(s, n); + } + else { +#ifdef BITSTREAM_READER_LE + unsigned ret = get_bits(s, 16); + return ret | (get_bits(s, n - 16) << 16); +#else + unsigned ret = get_bits(s, 16) << (n - 16); + return ret | get_bits(s, n - 16); +#endif + } +#endif +} + +/** + * Read 0-64 bits. + */ +static inline uint64_t get_bits64(GetBitContext *s, int n) { + if(n <= 32) { + return get_bits_long(s, n); + } + else { +#ifdef BITSTREAM_READER_LE + uint64_t ret = get_bits_long(s, 32); + return ret | (uint64_t)get_bits_long(s, n - 32) << 32; +#else + uint64_t ret = (uint64_t)get_bits_long(s, n - 32) << 32; + return ret | get_bits_long(s, 32); +#endif + } +} + +/** + * Read 0-32 bits as a signed integer. + */ +static inline int get_sbits_long(GetBitContext *s, int n) { + // sign_extend(x, 0) is undefined + if(!n) + return 0; + + return sign_extend(get_bits_long(s, n), n); +} + +/** + * Show 0-32 bits. + */ +static inline unsigned int show_bits_long(GetBitContext *s, int n) { + if(n <= MIN_CACHE_BITS) { + return show_bits(s, n); + } + else { + GetBitContext gb = *s; + return get_bits_long(&gb, n); + } +} + +static inline int check_marker(void *logctx, GetBitContext *s, const char *msg) { + int bit = get_bits1(s); + if(!bit) + av_log(logctx, AV_LOG_INFO, "Marker bit missing at %d of %d %s\n", + get_bits_count(s) - 1, s->size_in_bits, msg); + + return bit; +} + +static inline int init_get_bits_xe(GetBitContext *s, const uint8_t *buffer, + int bit_size, int is_le) { + int buffer_size; + int ret = 0; + + if(bit_size >= INT_MAX - FFMAX(7, AV_INPUT_BUFFER_PADDING_SIZE * 8) || bit_size < 0 || !buffer) { + bit_size = 0; + buffer = NULL; + ret = AVERROR_INVALIDDATA; + } + + buffer_size = (bit_size + 7) >> 3; + + s->buffer = buffer; + s->size_in_bits = bit_size; + s->size_in_bits_plus8 = bit_size + 8; + s->buffer_end = buffer + buffer_size; + s->index = 0; + +#if CACHED_BITSTREAM_READER + s->cache = 0; + s->bits_left = 0; + refill_64(s, is_le); +#endif + + return ret; +} + +/** + * Initialize GetBitContext. + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param bit_size the size of the buffer in bits + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. + */ +static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, + int bit_size) { +#ifdef BITSTREAM_READER_LE + return init_get_bits_xe(s, buffer, bit_size, 1); +#else + return init_get_bits_xe(s, buffer, bit_size, 0); +#endif +} + +/** + * Initialize GetBitContext. + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param byte_size the size of the buffer in bytes + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. + */ +static inline int init_get_bits8(GetBitContext *s, const uint8_t *buffer, + int byte_size) { + if(byte_size > INT_MAX / 8 || byte_size < 0) + byte_size = -1; + return init_get_bits(s, buffer, byte_size * 8); +} + +static inline int init_get_bits8_le(GetBitContext *s, const uint8_t *buffer, + int byte_size) { + if(byte_size > INT_MAX / 8 || byte_size < 0) + byte_size = -1; + return init_get_bits_xe(s, buffer, byte_size * 8, 1); +} + +static inline const uint8_t *align_get_bits(GetBitContext *s) { + int n = -get_bits_count(s) & 7; + if(n) + skip_bits(s, n); + return s->buffer + (s->index >> 3); +} + +/** + * If the vlc code is invalid and max_depth=1, then no bits will be removed. + * If the vlc code is invalid and max_depth>1, then the number of bits removed + * is undefined. + */ +#define GET_VLC(code, name, gb, table, bits, max_depth) \ + do { \ + int n, nb_bits; \ + unsigned int index; \ + \ + index = SHOW_UBITS(name, gb, bits); \ + code = table[index][0]; \ + n = table[index][1]; \ + \ + if(max_depth > 1 && n < 0) { \ + LAST_SKIP_BITS(name, gb, bits); \ + UPDATE_CACHE(name, gb); \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + code; \ + code = table[index][0]; \ + n = table[index][1]; \ + if(max_depth > 2 && n < 0) { \ + LAST_SKIP_BITS(name, gb, nb_bits); \ + UPDATE_CACHE(name, gb); \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + code; \ + code = table[index][0]; \ + n = table[index][1]; \ + } \ + } \ + SKIP_BITS(name, gb, n); \ + } while(0) + +#define GET_RL_VLC(level, run, name, gb, table, bits, \ + max_depth, need_update) \ + do { \ + int n, nb_bits; \ + unsigned int index; \ + \ + index = SHOW_UBITS(name, gb, bits); \ + level = table[index].level; \ + n = table[index].len; \ + \ + if(max_depth > 1 && n < 0) { \ + SKIP_BITS(name, gb, bits); \ + if(need_update) { \ + UPDATE_CACHE(name, gb); \ + } \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + level; \ + level = table[index].level; \ + n = table[index].len; \ + if(max_depth > 2 && n < 0) { \ + LAST_SKIP_BITS(name, gb, nb_bits); \ + if(need_update) { \ + UPDATE_CACHE(name, gb); \ + } \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + level; \ + level = table[index].level; \ + n = table[index].len; \ + } \ + } \ + run = table[index].run; \ + SKIP_BITS(name, gb, n); \ + } while(0) + +/* Return the LUT element for the given bitstream configuration. */ +static inline int set_idx(GetBitContext *s, int code, int *n, int *nb_bits, + VLC_TYPE (*table)[2]) { + unsigned idx; + + *nb_bits = -*n; + idx = show_bits(s, *nb_bits) + code; + *n = table[idx][1]; + + return table[idx][0]; +} + +/** + * Parse a vlc code. + * @param bits is the number of bits which will be read at once, must be + * identical to nb_bits in init_vlc() + * @param max_depth is the number of times bits bits must be read to completely + * read the longest vlc code + * = (max_vlc_length + bits - 1) / bits + * @returns the code parsed or -1 if no vlc matches + */ +static av_always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], + int bits, int max_depth) { +#if CACHED_BITSTREAM_READER + int nb_bits; + unsigned idx = show_bits(s, bits); + int code = table[idx][0]; + int n = table[idx][1]; + + if(max_depth > 1 && n < 0) { + skip_remaining(s, bits); + code = set_idx(s, code, &n, &nb_bits, table); + if(max_depth > 2 && n < 0) { + skip_remaining(s, nb_bits); + code = set_idx(s, code, &n, &nb_bits, table); + } + } + skip_remaining(s, n); + + return code; +#else + int code; + + OPEN_READER(re, s); + UPDATE_CACHE(re, s); + + GET_VLC(code, re, s, table, bits, max_depth); + + CLOSE_READER(re, s); + + return code; +#endif +} + +static inline int decode012(GetBitContext *gb) { + int n; + n = get_bits1(gb); + if(n == 0) + return 0; + else + return get_bits1(gb) + 1; +} + +static inline int decode210(GetBitContext *gb) { + if(get_bits1(gb)) + return 0; + else + return 2 - get_bits1(gb); +} + +static inline int get_bits_left(GetBitContext *gb) { + return gb->size_in_bits - get_bits_count(gb); +} + +static inline int skip_1stop_8data_bits(GetBitContext *gb) { + if(get_bits_left(gb) <= 0) + return AVERROR_INVALIDDATA; + + while(get_bits1(gb)) { + skip_bits(gb, 8); + if(get_bits_left(gb) <= 0) + return AVERROR_INVALIDDATA; + } + + return 0; +} + +#endif /* AVCODEC_GET_BITS_H */ diff --git a/third-party/cbs/h2645_parse.c b/third-party/cbs/h2645_parse.c new file mode 100644 index 00000000..9b2cfbc8 --- /dev/null +++ b/third-party/cbs/h2645_parse.c @@ -0,0 +1,534 @@ +/* + * H.264/HEVC common parsing code + * + * 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 +#include + +#include "cbs/h264.h" +#include "cbs/h2645_parse.h" +#include "cbs/hevc.h" + +#include "bytestream.h" +#include "get_bits.h" +#include "intmath.h" + +int ff_h2645_extract_rbsp(const uint8_t *src, int length, + H2645RBSP *rbsp, H2645NAL *nal, int small_padding) { + int i, si, di; + uint8_t *dst; + + nal->skipped_bytes = 0; +#define STARTCODE_TEST \ + if(i + 2 < length && src[i + 1] == 0 && src[i + 2] <= 3) { \ + if(src[i + 2] != 3 && src[i + 2] != 0) { \ + /* startcode, so we must be past the end */ \ + length = i; \ + } \ + break; \ + } +#if HAVE_FAST_UNALIGNED +#define FIND_FIRST_ZERO \ + if(i > 0 && !src[i]) \ + i--; \ + while(src[i]) \ + i++ +#if HAVE_FAST_64BIT + for(i = 0; i + 1 < length; i += 9) { + if(!((~AV_RN64(src + i) & + (AV_RN64(src + i) - 0x0100010001000101ULL)) & + 0x8000800080008080ULL)) + continue; + FIND_FIRST_ZERO; + STARTCODE_TEST; + i -= 7; + } +#else + for(i = 0; i + 1 < length; i += 5) { + if(!((~AV_RN32(src + i) & + (AV_RN32(src + i) - 0x01000101U)) & + 0x80008080U)) + continue; + FIND_FIRST_ZERO; + STARTCODE_TEST; + i -= 3; + } +#endif /* HAVE_FAST_64BIT */ +#else + for(i = 0; i + 1 < length; i += 2) { + if(src[i]) + continue; + if(i > 0 && src[i - 1] == 0) + i--; + STARTCODE_TEST; + } +#endif /* HAVE_FAST_UNALIGNED */ + + if(i >= length - 1 && small_padding) { // no escaped 0 + nal->data = + nal->raw_data = src; + nal->size = + nal->raw_size = length; + return length; + } + else if(i > length) + i = length; + + nal->rbsp_buffer = &rbsp->rbsp_buffer[rbsp->rbsp_buffer_size]; + dst = nal->rbsp_buffer; + + memcpy(dst, src, i); + si = di = i; + while(si + 2 < length) { + // remove escapes (very rare 1:2^22) + if(src[si + 2] > 3) { + dst[di++] = src[si++]; + dst[di++] = src[si++]; + } + else if(src[si] == 0 && src[si + 1] == 0 && src[si + 2] != 0) { + if(src[si + 2] == 3) { // escape + dst[di++] = 0; + dst[di++] = 0; + si += 3; + + if(nal->skipped_bytes_pos) { + nal->skipped_bytes++; + if(nal->skipped_bytes_pos_size < nal->skipped_bytes) { + nal->skipped_bytes_pos_size *= 2; + av_assert0(nal->skipped_bytes_pos_size >= nal->skipped_bytes); + av_reallocp_array(&nal->skipped_bytes_pos, + nal->skipped_bytes_pos_size, + sizeof(*nal->skipped_bytes_pos)); + if(!nal->skipped_bytes_pos) { + nal->skipped_bytes_pos_size = 0; + return AVERROR(ENOMEM); + } + } + if(nal->skipped_bytes_pos) + nal->skipped_bytes_pos[nal->skipped_bytes - 1] = di - 1; + } + continue; + } + else // next start code + goto nsc; + } + + dst[di++] = src[si++]; + } + while(si < length) + dst[di++] = src[si++]; + +nsc: + memset(dst + di, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + nal->data = dst; + nal->size = di; + nal->raw_data = src; + nal->raw_size = si; + rbsp->rbsp_buffer_size += si; + + return si; +} + +static const char *const hevc_nal_type_name[64] = { + "TRAIL_N", // HEVC_NAL_TRAIL_N + "TRAIL_R", // HEVC_NAL_TRAIL_R + "TSA_N", // HEVC_NAL_TSA_N + "TSA_R", // HEVC_NAL_TSA_R + "STSA_N", // HEVC_NAL_STSA_N + "STSA_R", // HEVC_NAL_STSA_R + "RADL_N", // HEVC_NAL_RADL_N + "RADL_R", // HEVC_NAL_RADL_R + "RASL_N", // HEVC_NAL_RASL_N + "RASL_R", // HEVC_NAL_RASL_R + "RSV_VCL_N10", // HEVC_NAL_VCL_N10 + "RSV_VCL_R11", // HEVC_NAL_VCL_R11 + "RSV_VCL_N12", // HEVC_NAL_VCL_N12 + "RSV_VLC_R13", // HEVC_NAL_VCL_R13 + "RSV_VCL_N14", // HEVC_NAL_VCL_N14 + "RSV_VCL_R15", // HEVC_NAL_VCL_R15 + "BLA_W_LP", // HEVC_NAL_BLA_W_LP + "BLA_W_RADL", // HEVC_NAL_BLA_W_RADL + "BLA_N_LP", // HEVC_NAL_BLA_N_LP + "IDR_W_RADL", // HEVC_NAL_IDR_W_RADL + "IDR_N_LP", // HEVC_NAL_IDR_N_LP + "CRA_NUT", // HEVC_NAL_CRA_NUT + "RSV_IRAP_VCL22", // HEVC_NAL_RSV_IRAP_VCL22 + "RSV_IRAP_VCL23", // HEVC_NAL_RSV_IRAP_VCL23 + "RSV_VCL24", // HEVC_NAL_RSV_VCL24 + "RSV_VCL25", // HEVC_NAL_RSV_VCL25 + "RSV_VCL26", // HEVC_NAL_RSV_VCL26 + "RSV_VCL27", // HEVC_NAL_RSV_VCL27 + "RSV_VCL28", // HEVC_NAL_RSV_VCL28 + "RSV_VCL29", // HEVC_NAL_RSV_VCL29 + "RSV_VCL30", // HEVC_NAL_RSV_VCL30 + "RSV_VCL31", // HEVC_NAL_RSV_VCL31 + "VPS", // HEVC_NAL_VPS + "SPS", // HEVC_NAL_SPS + "PPS", // HEVC_NAL_PPS + "AUD", // HEVC_NAL_AUD + "EOS_NUT", // HEVC_NAL_EOS_NUT + "EOB_NUT", // HEVC_NAL_EOB_NUT + "FD_NUT", // HEVC_NAL_FD_NUT + "SEI_PREFIX", // HEVC_NAL_SEI_PREFIX + "SEI_SUFFIX", // HEVC_NAL_SEI_SUFFIX + "RSV_NVCL41", // HEVC_NAL_RSV_NVCL41 + "RSV_NVCL42", // HEVC_NAL_RSV_NVCL42 + "RSV_NVCL43", // HEVC_NAL_RSV_NVCL43 + "RSV_NVCL44", // HEVC_NAL_RSV_NVCL44 + "RSV_NVCL45", // HEVC_NAL_RSV_NVCL45 + "RSV_NVCL46", // HEVC_NAL_RSV_NVCL46 + "RSV_NVCL47", // HEVC_NAL_RSV_NVCL47 + "UNSPEC48", // HEVC_NAL_UNSPEC48 + "UNSPEC49", // HEVC_NAL_UNSPEC49 + "UNSPEC50", // HEVC_NAL_UNSPEC50 + "UNSPEC51", // HEVC_NAL_UNSPEC51 + "UNSPEC52", // HEVC_NAL_UNSPEC52 + "UNSPEC53", // HEVC_NAL_UNSPEC53 + "UNSPEC54", // HEVC_NAL_UNSPEC54 + "UNSPEC55", // HEVC_NAL_UNSPEC55 + "UNSPEC56", // HEVC_NAL_UNSPEC56 + "UNSPEC57", // HEVC_NAL_UNSPEC57 + "UNSPEC58", // HEVC_NAL_UNSPEC58 + "UNSPEC59", // HEVC_NAL_UNSPEC59 + "UNSPEC60", // HEVC_NAL_UNSPEC60 + "UNSPEC61", // HEVC_NAL_UNSPEC61 + "UNSPEC62", // HEVC_NAL_UNSPEC62 + "UNSPEC63", // HEVC_NAL_UNSPEC63 +}; + +static const char *hevc_nal_unit_name(int nal_type) { + av_assert0(nal_type >= 0 && nal_type < 64); + return hevc_nal_type_name[nal_type]; +} + +static const char *const h264_nal_type_name[32] = { + "Unspecified 0", //H264_NAL_UNSPECIFIED + "Coded slice of a non-IDR picture", // H264_NAL_SLICE + "Coded slice data partition A", // H264_NAL_DPA + "Coded slice data partition B", // H264_NAL_DPB + "Coded slice data partition C", // H264_NAL_DPC + "IDR", // H264_NAL_IDR_SLICE + "SEI", // H264_NAL_SEI + "SPS", // H264_NAL_SPS + "PPS", // H264_NAL_PPS + "AUD", // H264_NAL_AUD + "End of sequence", // H264_NAL_END_SEQUENCE + "End of stream", // H264_NAL_END_STREAM + "Filler data", // H264_NAL_FILLER_DATA + "SPS extension", // H264_NAL_SPS_EXT + "Prefix", // H264_NAL_PREFIX + "Subset SPS", // H264_NAL_SUB_SPS + "Depth parameter set", // H264_NAL_DPS + "Reserved 17", // H264_NAL_RESERVED17 + "Reserved 18", // H264_NAL_RESERVED18 + "Auxiliary coded picture without partitioning", // H264_NAL_AUXILIARY_SLICE + "Slice extension", // H264_NAL_EXTEN_SLICE + "Slice extension for a depth view or a 3D-AVC texture view", // H264_NAL_DEPTH_EXTEN_SLICE + "Reserved 22", // H264_NAL_RESERVED22 + "Reserved 23", // H264_NAL_RESERVED23 + "Unspecified 24", // H264_NAL_UNSPECIFIED24 + "Unspecified 25", // H264_NAL_UNSPECIFIED25 + "Unspecified 26", // H264_NAL_UNSPECIFIED26 + "Unspecified 27", // H264_NAL_UNSPECIFIED27 + "Unspecified 28", // H264_NAL_UNSPECIFIED28 + "Unspecified 29", // H264_NAL_UNSPECIFIED29 + "Unspecified 30", // H264_NAL_UNSPECIFIED30 + "Unspecified 31", // H264_NAL_UNSPECIFIED31 +}; + +static const char *h264_nal_unit_name(int nal_type) { + av_assert0(nal_type >= 0 && nal_type < 32); + return h264_nal_type_name[nal_type]; +} + +static int get_bit_length(H2645NAL *nal, int skip_trailing_zeros) { + int size = nal->size; + int v; + + while(skip_trailing_zeros && size > 0 && nal->data[size - 1] == 0) + size--; + + if(!size) + return 0; + + v = nal->data[size - 1]; + + if(size > INT_MAX / 8) + return AVERROR(ERANGE); + size *= 8; + + /* remove the stop bit and following trailing zeros, + * or nothing for damaged bitstreams */ + if(v) + size -= ff_ctz(v) + 1; + + return size; +} + +/** + * @return AVERROR_INVALIDDATA if the packet is not a valid NAL unit, + * 0 otherwise + */ +static int hevc_parse_nal_header(H2645NAL *nal, void *logctx) { + GetBitContext *gb = &nal->gb; + + if(get_bits1(gb) != 0) + return AVERROR_INVALIDDATA; + + nal->type = get_bits(gb, 6); + + nal->nuh_layer_id = get_bits(gb, 6); + nal->temporal_id = get_bits(gb, 3) - 1; + if(nal->temporal_id < 0) + return AVERROR_INVALIDDATA; + + av_log(logctx, AV_LOG_DEBUG, + "nal_unit_type: %d(%s), nuh_layer_id: %d, temporal_id: %d\n", + nal->type, hevc_nal_unit_name(nal->type), nal->nuh_layer_id, nal->temporal_id); + + return 0; +} + +static int h264_parse_nal_header(H2645NAL *nal, void *logctx) { + GetBitContext *gb = &nal->gb; + + if(get_bits1(gb) != 0) + return AVERROR_INVALIDDATA; + + nal->ref_idc = get_bits(gb, 2); + nal->type = get_bits(gb, 5); + + av_log(logctx, AV_LOG_DEBUG, + "nal_unit_type: %d(%s), nal_ref_idc: %d\n", + nal->type, h264_nal_unit_name(nal->type), nal->ref_idc); + + return 0; +} + +static int find_next_start_code(const uint8_t *buf, const uint8_t *next_avc) { + int i = 0; + + if(buf + 3 >= next_avc) + return next_avc - buf; + + while(buf + i + 3 < next_avc) { + if(buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1) + break; + i++; + } + return i + 3; +} + +static void alloc_rbsp_buffer(H2645RBSP *rbsp, unsigned int size, int use_ref) { + int min_size = size; + + if(size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) + goto fail; + size += AV_INPUT_BUFFER_PADDING_SIZE; + + if(rbsp->rbsp_buffer_alloc_size >= size && + (!rbsp->rbsp_buffer_ref || av_buffer_is_writable(rbsp->rbsp_buffer_ref))) { + av_assert0(rbsp->rbsp_buffer); + memset(rbsp->rbsp_buffer + min_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + return; + } + + size = FFMIN(size + size / 16 + 32, INT_MAX); + + if(rbsp->rbsp_buffer_ref) + av_buffer_unref(&rbsp->rbsp_buffer_ref); + else + av_free(rbsp->rbsp_buffer); + + rbsp->rbsp_buffer = av_mallocz(size); + if(!rbsp->rbsp_buffer) + goto fail; + rbsp->rbsp_buffer_alloc_size = size; + + if(use_ref) { + rbsp->rbsp_buffer_ref = av_buffer_create(rbsp->rbsp_buffer, size, + NULL, NULL, 0); + if(!rbsp->rbsp_buffer_ref) + goto fail; + } + + return; + +fail: + rbsp->rbsp_buffer_alloc_size = 0; + if(rbsp->rbsp_buffer_ref) { + av_buffer_unref(&rbsp->rbsp_buffer_ref); + rbsp->rbsp_buffer = NULL; + } + else + av_freep(&rbsp->rbsp_buffer); + + return; +} + +int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, + void *logctx, int is_nalff, int nal_length_size, + enum AVCodecID codec_id, int small_padding, int use_ref) { + GetByteContext bc; + int consumed, ret = 0; + int next_avc = is_nalff ? 0 : length; + int64_t padding = small_padding ? 0 : MAX_MBPAIR_SIZE; + + bytestream2_init(&bc, buf, length); + alloc_rbsp_buffer(&pkt->rbsp, length + padding, use_ref); + + if(!pkt->rbsp.rbsp_buffer) + return AVERROR(ENOMEM); + + pkt->rbsp.rbsp_buffer_size = 0; + pkt->nb_nals = 0; + while(bytestream2_get_bytes_left(&bc) >= 4) { + H2645NAL *nal; + int extract_length = 0; + int skip_trailing_zeros = 1; + + if(bytestream2_tell(&bc) == next_avc) { + int i = 0; + extract_length = get_nalsize(nal_length_size, + bc.buffer, bytestream2_get_bytes_left(&bc), &i, logctx); + if(extract_length < 0) + return extract_length; + + bytestream2_skip(&bc, nal_length_size); + + next_avc = bytestream2_tell(&bc) + extract_length; + } + else { + int buf_index; + + if(bytestream2_tell(&bc) > next_avc) + av_log(logctx, AV_LOG_WARNING, "Exceeded next NALFF position, re-syncing.\n"); + + /* search start code */ + buf_index = find_next_start_code(bc.buffer, buf + next_avc); + + bytestream2_skip(&bc, buf_index); + + if(!bytestream2_get_bytes_left(&bc)) { + if(pkt->nb_nals > 0) { + // No more start codes: we discarded some irrelevant + // bytes at the end of the packet. + return 0; + } + else { + av_log(logctx, AV_LOG_ERROR, "No start code is found.\n"); + return AVERROR_INVALIDDATA; + } + } + + extract_length = FFMIN(bytestream2_get_bytes_left(&bc), next_avc - bytestream2_tell(&bc)); + + if(bytestream2_tell(&bc) >= next_avc) { + /* skip to the start of the next NAL */ + bytestream2_skip(&bc, next_avc - bytestream2_tell(&bc)); + continue; + } + } + + if(pkt->nals_allocated < pkt->nb_nals + 1) { + int new_size = pkt->nals_allocated + 1; + void *tmp; + + if(new_size >= INT_MAX / sizeof(*pkt->nals)) + return AVERROR(ENOMEM); + + tmp = av_fast_realloc(pkt->nals, &pkt->nal_buffer_size, new_size * sizeof(*pkt->nals)); + if(!tmp) + return AVERROR(ENOMEM); + + pkt->nals = tmp; + memset(pkt->nals + pkt->nals_allocated, 0, sizeof(*pkt->nals)); + + nal = &pkt->nals[pkt->nb_nals]; + nal->skipped_bytes_pos_size = FFMIN(1024, extract_length / 3 + 1); // initial buffer size + nal->skipped_bytes_pos = av_malloc_array(nal->skipped_bytes_pos_size, sizeof(*nal->skipped_bytes_pos)); + if(!nal->skipped_bytes_pos) + return AVERROR(ENOMEM); + + pkt->nals_allocated = new_size; + } + nal = &pkt->nals[pkt->nb_nals]; + + consumed = ff_h2645_extract_rbsp(bc.buffer, extract_length, &pkt->rbsp, nal, small_padding); + if(consumed < 0) + return consumed; + + if(is_nalff && (extract_length != consumed) && extract_length) + av_log(logctx, AV_LOG_DEBUG, + "NALFF: Consumed only %d bytes instead of %d\n", + consumed, extract_length); + + bytestream2_skip(&bc, consumed); + + /* see commit 3566042a0 */ + if(bytestream2_get_bytes_left(&bc) >= 4 && + bytestream2_peek_be32(&bc) == 0x000001E0) + skip_trailing_zeros = 0; + + nal->size_bits = get_bit_length(nal, skip_trailing_zeros); + + if(nal->size <= 0 || nal->size_bits <= 0) + continue; + + ret = init_get_bits(&nal->gb, nal->data, nal->size_bits); + if(ret < 0) + return ret; + + /* Reset type in case it contains a stale value from a previously parsed NAL */ + nal->type = 0; + + if(codec_id == AV_CODEC_ID_HEVC) + ret = hevc_parse_nal_header(nal, logctx); + else + ret = h264_parse_nal_header(nal, logctx); + if(ret < 0) { + av_log(logctx, AV_LOG_WARNING, "Invalid NAL unit %d, skipping.\n", + nal->type); + continue; + } + + pkt->nb_nals++; + } + + return 0; +} + +void ff_h2645_packet_uninit(H2645Packet *pkt) { + int i; + for(i = 0; i < pkt->nals_allocated; i++) { + av_freep(&pkt->nals[i].skipped_bytes_pos); + } + av_freep(&pkt->nals); + pkt->nals_allocated = pkt->nal_buffer_size = 0; + if(pkt->rbsp.rbsp_buffer_ref) { + av_buffer_unref(&pkt->rbsp.rbsp_buffer_ref); + pkt->rbsp.rbsp_buffer = NULL; + } + else + av_freep(&pkt->rbsp.rbsp_buffer); + pkt->rbsp.rbsp_buffer_alloc_size = pkt->rbsp.rbsp_buffer_size = 0; +} diff --git a/third-party/cbs/h264_ps.h b/third-party/cbs/h264_ps.h new file mode 100644 index 00000000..fbd0cb7a --- /dev/null +++ b/third-party/cbs/h264_ps.h @@ -0,0 +1,173 @@ +/* + * 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 + */ + +/** + * @file + * H.264 parameter set handling + */ + +#ifndef AVCODEC_H264_PS_H +#define AVCODEC_H264_PS_H + +#include + +#include +#include +#include +#include + +#include "cbs/h264.h" + +#include "get_bits.h" + +#define MAX_SPS_COUNT 32 +#define MAX_PPS_COUNT 256 +#define MAX_LOG2_MAX_FRAME_NUM (12 + 4) + +/** + * Sequence parameter set + */ +typedef struct SPS { + unsigned int sps_id; + int profile_idc; + int level_idc; + int chroma_format_idc; + int transform_bypass; ///< qpprime_y_zero_transform_bypass_flag + int log2_max_frame_num; ///< log2_max_frame_num_minus4 + 4 + int poc_type; ///< pic_order_cnt_type + int log2_max_poc_lsb; ///< log2_max_pic_order_cnt_lsb_minus4 + int delta_pic_order_always_zero_flag; + int offset_for_non_ref_pic; + int offset_for_top_to_bottom_field; + int poc_cycle_length; ///< num_ref_frames_in_pic_order_cnt_cycle + int ref_frame_count; ///< num_ref_frames + int gaps_in_frame_num_allowed_flag; + int mb_width; ///< pic_width_in_mbs_minus1 + 1 + ///< (pic_height_in_map_units_minus1 + 1) * (2 - frame_mbs_only_flag) + int mb_height; + int frame_mbs_only_flag; + int mb_aff; ///< mb_adaptive_frame_field_flag + int direct_8x8_inference_flag; + int crop; ///< frame_cropping_flag + + /* those 4 are already in luma samples */ + unsigned int crop_left; ///< frame_cropping_rect_left_offset + unsigned int crop_right; ///< frame_cropping_rect_right_offset + unsigned int crop_top; ///< frame_cropping_rect_top_offset + unsigned int crop_bottom; ///< frame_cropping_rect_bottom_offset + int vui_parameters_present_flag; + AVRational sar; + int video_signal_type_present_flag; + int full_range; + int colour_description_present_flag; + enum AVColorPrimaries color_primaries; + enum AVColorTransferCharacteristic color_trc; + enum AVColorSpace colorspace; + enum AVChromaLocation chroma_location; + + int timing_info_present_flag; + uint32_t num_units_in_tick; + uint32_t time_scale; + int fixed_frame_rate_flag; + int32_t offset_for_ref_frame[256]; + int bitstream_restriction_flag; + int num_reorder_frames; + int scaling_matrix_present; + uint8_t scaling_matrix4[6][16]; + uint8_t scaling_matrix8[6][64]; + int nal_hrd_parameters_present_flag; + int vcl_hrd_parameters_present_flag; + int pic_struct_present_flag; + int time_offset_length; + int cpb_cnt; ///< See H.264 E.1.2 + int initial_cpb_removal_delay_length; ///< initial_cpb_removal_delay_length_minus1 + 1 + int cpb_removal_delay_length; ///< cpb_removal_delay_length_minus1 + 1 + int dpb_output_delay_length; ///< dpb_output_delay_length_minus1 + 1 + int bit_depth_luma; ///< bit_depth_luma_minus8 + 8 + int bit_depth_chroma; ///< bit_depth_chroma_minus8 + 8 + int residual_color_transform_flag; ///< residual_colour_transform_flag + int constraint_set_flags; ///< constraint_set[0-3]_flag + uint8_t data[4096]; + size_t data_size; +} SPS; + +/** + * Picture parameter set + */ +typedef struct PPS { + unsigned int sps_id; + int cabac; ///< entropy_coding_mode_flag + int pic_order_present; ///< pic_order_present_flag + int slice_group_count; ///< num_slice_groups_minus1 + 1 + int mb_slice_group_map_type; + unsigned int ref_count[2]; ///< num_ref_idx_l0/1_active_minus1 + 1 + int weighted_pred; ///< weighted_pred_flag + int weighted_bipred_idc; + int init_qp; ///< pic_init_qp_minus26 + 26 + int init_qs; ///< pic_init_qs_minus26 + 26 + int chroma_qp_index_offset[2]; + int deblocking_filter_parameters_present; ///< deblocking_filter_parameters_present_flag + int constrained_intra_pred; ///< constrained_intra_pred_flag + int redundant_pic_cnt_present; ///< redundant_pic_cnt_present_flag + int transform_8x8_mode; ///< transform_8x8_mode_flag + uint8_t scaling_matrix4[6][16]; + uint8_t scaling_matrix8[6][64]; + uint8_t chroma_qp_table[2][QP_MAX_NUM + 1]; ///< pre-scaled (with chroma_qp_index_offset) version of qp_table + int chroma_qp_diff; + uint8_t data[4096]; + size_t data_size; + + uint32_t dequant4_buffer[6][QP_MAX_NUM + 1][16]; + uint32_t dequant8_buffer[6][QP_MAX_NUM + 1][64]; + uint32_t (*dequant4_coeff[6])[16]; + uint32_t (*dequant8_coeff[6])[64]; + + AVBufferRef *sps_ref; + const SPS *sps; +} PPS; + +typedef struct H264ParamSets { + AVBufferRef *sps_list[MAX_SPS_COUNT]; + AVBufferRef *pps_list[MAX_PPS_COUNT]; + + AVBufferRef *pps_ref; + /* currently active parameters sets */ + const PPS *pps; + const SPS *sps; + + int overread_warning_printed[2]; +} H264ParamSets; + +/** + * Decode SPS + */ +int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, + H264ParamSets *ps, int ignore_truncation); + +/** + * Decode PPS + */ +int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avctx, + H264ParamSets *ps, int bit_length); + +/** + * Uninit H264 param sets structure. + */ +void ff_h264_ps_uninit(H264ParamSets *ps); + +#endif /* AVCODEC_H264_PS_H */ diff --git a/third-party/cbs/h264_sei.h b/third-party/cbs/h264_sei.h new file mode 100644 index 00000000..64dbb86e --- /dev/null +++ b/third-party/cbs/h264_sei.h @@ -0,0 +1,202 @@ +/* + * 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_H264_SEI_H +#define AVCODEC_H264_SEI_H + +#include "cbs/sei.h" +#include "get_bits.h" +#include "h264_ps.h" + + +/** + * pic_struct in picture timing SEI message + */ +typedef enum { + H264_SEI_PIC_STRUCT_FRAME = 0, ///< 0: %frame + H264_SEI_PIC_STRUCT_TOP_FIELD = 1, ///< 1: top field + H264_SEI_PIC_STRUCT_BOTTOM_FIELD = 2, ///< 2: bottom field + H264_SEI_PIC_STRUCT_TOP_BOTTOM = 3, ///< 3: top field, bottom field, in that order + H264_SEI_PIC_STRUCT_BOTTOM_TOP = 4, ///< 4: bottom field, top field, in that order + H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP = 5, ///< 5: top field, bottom field, top field repeated, in that order + H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM = 6, ///< 6: bottom field, top field, bottom field repeated, in that order + H264_SEI_PIC_STRUCT_FRAME_DOUBLING = 7, ///< 7: %frame doubling + H264_SEI_PIC_STRUCT_FRAME_TRIPLING = 8 ///< 8: %frame tripling +} H264_SEI_PicStructType; + +/** + * frame_packing_arrangement types + */ +typedef enum { + H264_SEI_FPA_TYPE_CHECKERBOARD = 0, + H264_SEI_FPA_TYPE_INTERLEAVE_COLUMN = 1, + H264_SEI_FPA_TYPE_INTERLEAVE_ROW = 2, + H264_SEI_FPA_TYPE_SIDE_BY_SIDE = 3, + H264_SEI_FPA_TYPE_TOP_BOTTOM = 4, + H264_SEI_FPA_TYPE_INTERLEAVE_TEMPORAL = 5, + H264_SEI_FPA_TYPE_2D = 6, +} H264_SEI_FpaType; + +typedef struct H264SEITimeCode { + /* When not continuously receiving full timecodes, we have to reference + the previous timecode received */ + int full; + int frame; + int seconds; + int minutes; + int hours; + int dropframe; +} H264SEITimeCode; + +typedef struct H264SEIPictureTiming { + // maximum size of pic_timing according to the spec should be 274 bits + uint8_t payload[40]; + int payload_size_bits; + + int present; + H264_SEI_PicStructType pic_struct; + + /** + * Bit set of clock types for fields/frames in picture timing SEI message. + * For each found ct_type, appropriate bit is set (e.g., bit 1 for + * interlaced). + */ + int ct_type; + + /** + * dpb_output_delay in picture timing SEI message, see H.264 C.2.2 + */ + int dpb_output_delay; + + /** + * cpb_removal_delay in picture timing SEI message, see H.264 C.1.2 + */ + int cpb_removal_delay; + + /** + * Maximum three timecodes in a pic_timing SEI. + */ + H264SEITimeCode timecode[3]; + + /** + * Number of timecode in use + */ + int timecode_cnt; +} H264SEIPictureTiming; + +typedef struct H264SEIAFD { + int present; + uint8_t active_format_description; +} H264SEIAFD; + +typedef struct H264SEIA53Caption { + AVBufferRef *buf_ref; +} H264SEIA53Caption; + +typedef struct H264SEIUnregistered { + int x264_build; + AVBufferRef **buf_ref; + int nb_buf_ref; +} H264SEIUnregistered; + +typedef struct H264SEIRecoveryPoint { + /** + * recovery_frame_cnt + * + * Set to -1 if no recovery point SEI message found or to number of frames + * before playback synchronizes. Frames having recovery point are key + * frames. + */ + int recovery_frame_cnt; +} H264SEIRecoveryPoint; + +typedef struct H264SEIBufferingPeriod { + int present; ///< Buffering period SEI flag + int initial_cpb_removal_delay[32]; ///< Initial timestamps for CPBs +} H264SEIBufferingPeriod; + +typedef struct H264SEIFramePacking { + int present; + int arrangement_id; + int arrangement_cancel_flag; ///< is previous arrangement canceled, -1 if never received + H264_SEI_FpaType arrangement_type; + int arrangement_repetition_period; + int content_interpretation_type; + int quincunx_sampling_flag; + int current_frame_is_frame0_flag; +} H264SEIFramePacking; + +typedef struct H264SEIDisplayOrientation { + int present; + int anticlockwise_rotation; + int hflip, vflip; +} H264SEIDisplayOrientation; + +typedef struct H264SEIGreenMetaData { + uint8_t green_metadata_type; + uint8_t period_type; + uint16_t num_seconds; + uint16_t num_pictures; + uint8_t percent_non_zero_macroblocks; + uint8_t percent_intra_coded_macroblocks; + uint8_t percent_six_tap_filtering; + uint8_t percent_alpha_point_deblocking_instance; + uint8_t xsd_metric_type; + uint16_t xsd_metric_value; +} H264SEIGreenMetaData; + +typedef struct H264SEIAlternativeTransfer { + int present; + int preferred_transfer_characteristics; +} H264SEIAlternativeTransfer; + +typedef struct H264SEIContext { + H264SEIPictureTiming picture_timing; + H264SEIAFD afd; + H264SEIA53Caption a53_caption; + H264SEIUnregistered unregistered; + H264SEIRecoveryPoint recovery_point; + H264SEIBufferingPeriod buffering_period; + H264SEIFramePacking frame_packing; + H264SEIDisplayOrientation display_orientation; + H264SEIGreenMetaData green_metadata; + H264SEIAlternativeTransfer alternative_transfer; +} H264SEIContext; + +struct H264ParamSets; + +int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb, + const struct H264ParamSets *ps, void *logctx); + +/** + * Reset SEI values at the beginning of the frame. + */ +void ff_h264_sei_uninit(H264SEIContext *h); + +/** + * Get stereo_mode string from the h264 frame_packing_arrangement + */ +const char *ff_h264_sei_stereo_mode(const H264SEIFramePacking *h); + +/** + * Parse the contents of a picture timing message given an active SPS. + */ +int ff_h264_sei_process_picture_timing(H264SEIPictureTiming *h, const SPS *sps, + void *logctx); + +#endif /* AVCODEC_H264_SEI_H */ diff --git a/third-party/cbs/hevc_sei.h b/third-party/cbs/hevc_sei.h new file mode 100644 index 00000000..8dfffcc4 --- /dev/null +++ b/third-party/cbs/hevc_sei.h @@ -0,0 +1,142 @@ +/* + * HEVC Supplementary Enhancement Information messages + * + * 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_HEVC_SEI_H +#define AVCODEC_HEVC_SEI_H + +#include + +#include + +#include "cbs/sei.h" + +#include "get_bits.h" + + +typedef enum { + HEVC_SEI_PIC_STRUCT_FRAME_DOUBLING = 7, + HEVC_SEI_PIC_STRUCT_FRAME_TRIPLING = 8 +} HEVC_SEI_PicStructType; + +typedef struct HEVCSEIPictureHash { + uint8_t md5[3][16]; + uint8_t is_md5; +} HEVCSEIPictureHash; + +typedef struct HEVCSEIFramePacking { + int present; + int arrangement_type; + int content_interpretation_type; + int quincunx_subsampling; + int current_frame_is_frame0_flag; +} HEVCSEIFramePacking; + +typedef struct HEVCSEIDisplayOrientation { + int present; + int anticlockwise_rotation; + int hflip, vflip; +} HEVCSEIDisplayOrientation; + +typedef struct HEVCSEIPictureTiming { + int picture_struct; +} HEVCSEIPictureTiming; + +typedef struct HEVCSEIA53Caption { + AVBufferRef *buf_ref; +} HEVCSEIA53Caption; + +typedef struct HEVCSEIUnregistered { + AVBufferRef **buf_ref; + int nb_buf_ref; +} HEVCSEIUnregistered; + +typedef struct HEVCSEIMasteringDisplay { + int present; + uint16_t display_primaries[3][2]; + uint16_t white_point[2]; + uint32_t max_luminance; + uint32_t min_luminance; +} HEVCSEIMasteringDisplay; + +typedef struct HEVCSEIDynamicHDRPlus { + AVBufferRef *info; +} HEVCSEIDynamicHDRPlus; + +typedef struct HEVCSEIContentLight { + int present; + uint16_t max_content_light_level; + uint16_t max_pic_average_light_level; +} HEVCSEIContentLight; + +typedef struct HEVCSEIAlternativeTransfer { + int present; + int preferred_transfer_characteristics; +} HEVCSEIAlternativeTransfer; + +typedef struct HEVCSEITimeCode { + int present; + uint8_t num_clock_ts; + uint8_t clock_timestamp_flag[3]; + uint8_t units_field_based_flag[3]; + uint8_t counting_type[3]; + uint8_t full_timestamp_flag[3]; + uint8_t discontinuity_flag[3]; + uint8_t cnt_dropped_flag[3]; + uint16_t n_frames[3]; + uint8_t seconds_value[3]; + uint8_t minutes_value[3]; + uint8_t hours_value[3]; + uint8_t seconds_flag[3]; + uint8_t minutes_flag[3]; + uint8_t hours_flag[3]; + uint8_t time_offset_length[3]; + int32_t time_offset_value[3]; +} HEVCSEITimeCode; + +typedef struct HEVCSEI { + HEVCSEIPictureHash picture_hash; + HEVCSEIFramePacking frame_packing; + HEVCSEIDisplayOrientation display_orientation; + HEVCSEIPictureTiming picture_timing; + HEVCSEIA53Caption a53_caption; + HEVCSEIUnregistered unregistered; + HEVCSEIMasteringDisplay mastering_display; + HEVCSEIDynamicHDRPlus dynamic_hdr_plus; + HEVCSEIContentLight content_light; + int active_seq_parameter_set_id; + HEVCSEIAlternativeTransfer alternative_transfer; + HEVCSEITimeCode timecode; +} HEVCSEI; + +struct HEVCParamSets; + +int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEI *s, + const struct HEVCParamSets *ps, int type); + +/** + * Reset SEI values that are stored on the Context. + * e.g. Caption data that was extracted during NAL + * parsing. + * + * @param s HEVCContext. + */ +void ff_hevc_reset_sei(HEVCSEI *s); + +#endif /* AVCODEC_HEVC_SEI_H */ diff --git a/third-party/cbs/include/cbs/av1.h b/third-party/cbs/include/cbs/av1.h new file mode 100644 index 00000000..d8c2b9e7 --- /dev/null +++ b/third-party/cbs/include/cbs/av1.h @@ -0,0 +1,171 @@ +/* + * 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 + */ + +/** + * @file + * AV1 common definitions + */ + +#ifndef AVCODEC_AV1_H +#define AVCODEC_AV1_H + +// OBU types (section 6.2.2). +typedef enum { + // 0 reserved. + AV1_OBU_SEQUENCE_HEADER = 1, + AV1_OBU_TEMPORAL_DELIMITER = 2, + AV1_OBU_FRAME_HEADER = 3, + AV1_OBU_TILE_GROUP = 4, + AV1_OBU_METADATA = 5, + AV1_OBU_FRAME = 6, + AV1_OBU_REDUNDANT_FRAME_HEADER = 7, + AV1_OBU_TILE_LIST = 8, + // 9-14 reserved. + AV1_OBU_PADDING = 15, +} AV1_OBU_Type; + +// Metadata types (section 6.7.1). +enum { + AV1_METADATA_TYPE_HDR_CLL = 1, + AV1_METADATA_TYPE_HDR_MDCV = 2, + AV1_METADATA_TYPE_SCALABILITY = 3, + AV1_METADATA_TYPE_ITUT_T35 = 4, + AV1_METADATA_TYPE_TIMECODE = 5, +}; + +// Frame types (section 6.8.2). +enum { + AV1_FRAME_KEY = 0, + AV1_FRAME_INTER = 1, + AV1_FRAME_INTRA_ONLY = 2, + AV1_FRAME_SWITCH = 3, +}; + +// Reference frames (section 6.10.24). +enum { + AV1_REF_FRAME_INTRA = 0, + AV1_REF_FRAME_LAST = 1, + AV1_REF_FRAME_LAST2 = 2, + AV1_REF_FRAME_LAST3 = 3, + AV1_REF_FRAME_GOLDEN = 4, + AV1_REF_FRAME_BWDREF = 5, + AV1_REF_FRAME_ALTREF2 = 6, + AV1_REF_FRAME_ALTREF = 7, +}; + +// Constants (section 3). +enum { + AV1_MAX_OPERATING_POINTS = 32, + + AV1_MAX_SB_SIZE = 128, + AV1_MI_SIZE = 4, + + AV1_MAX_TILE_WIDTH = 4096, + AV1_MAX_TILE_AREA = 4096 * 2304, + AV1_MAX_TILE_ROWS = 64, + AV1_MAX_TILE_COLS = 64, + + AV1_NUM_REF_FRAMES = 8, + AV1_REFS_PER_FRAME = 7, + AV1_TOTAL_REFS_PER_FRAME = 8, + AV1_PRIMARY_REF_NONE = 7, + + AV1_MAX_SEGMENTS = 8, + AV1_SEG_LVL_MAX = 8, + + AV1_SEG_LVL_ALT_Q = 0, + AV1_SEG_LVL_ALT_LF_Y_V = 1, + AV1_SEG_LVL_REF_FRAME = 5, + AV1_SEG_LVL_SKIP = 6, + AV1_SEG_LVL_GLOBAL_MV = 7, + + AV1_SELECT_SCREEN_CONTENT_TOOLS = 2, + AV1_SELECT_INTEGER_MV = 2, + + AV1_SUPERRES_NUM = 8, + AV1_SUPERRES_DENOM_MIN = 9, + + AV1_INTERPOLATION_FILTER_SWITCHABLE = 4, + + AV1_GM_ABS_ALPHA_BITS = 12, + AV1_GM_ALPHA_PREC_BITS = 15, + AV1_GM_ABS_TRANS_ONLY_BITS = 9, + AV1_GM_TRANS_ONLY_PREC_BITS = 3, + AV1_GM_ABS_TRANS_BITS = 12, + AV1_GM_TRANS_PREC_BITS = 6, + AV1_WARPEDMODEL_PREC_BITS = 16, + + AV1_WARP_MODEL_IDENTITY = 0, + AV1_WARP_MODEL_TRANSLATION = 1, + AV1_WARP_MODEL_ROTZOOM = 2, + AV1_WARP_MODEL_AFFINE = 3, +}; + + +// The main colour configuration information uses the same ISO/IEC 23001-8 +// (H.273) enums as FFmpeg does, so separate definitions are not required. + +// Chroma sample position. +enum { + AV1_CSP_UNKNOWN = 0, + AV1_CSP_VERTICAL = 1, // -> AVCHROMA_LOC_LEFT. + AV1_CSP_COLOCATED = 2, // -> AVCHROMA_LOC_TOPLEFT. +}; + +// Scalability modes (section 6.7.5) +enum { + AV1_SCALABILITY_L1T2 = 0, + AV1_SCALABILITY_L1T3 = 1, + AV1_SCALABILITY_L2T1 = 2, + AV1_SCALABILITY_L2T2 = 3, + AV1_SCALABILITY_L2T3 = 4, + AV1_SCALABILITY_S2T1 = 5, + AV1_SCALABILITY_S2T2 = 6, + AV1_SCALABILITY_S2T3 = 7, + AV1_SCALABILITY_L2T1h = 8, + AV1_SCALABILITY_L2T2h = 9, + AV1_SCALABILITY_L2T3h = 10, + AV1_SCALABILITY_S2T1h = 11, + AV1_SCALABILITY_S2T2h = 12, + AV1_SCALABILITY_S2T3h = 13, + AV1_SCALABILITY_SS = 14, + AV1_SCALABILITY_L3T1 = 15, + AV1_SCALABILITY_L3T2 = 16, + AV1_SCALABILITY_L3T3 = 17, + AV1_SCALABILITY_S3T1 = 18, + AV1_SCALABILITY_S3T2 = 19, + AV1_SCALABILITY_S3T3 = 20, + AV1_SCALABILITY_L3T2_KEY = 21, + AV1_SCALABILITY_L3T3_KEY = 22, + AV1_SCALABILITY_L4T5_KEY = 23, + AV1_SCALABILITY_L4T7_KEY = 24, + AV1_SCALABILITY_L3T2_KEY_SHIFT = 25, + AV1_SCALABILITY_L3T3_KEY_SHIFT = 26, + AV1_SCALABILITY_L4T5_KEY_SHIFT = 27, + AV1_SCALABILITY_L4T7_KEY_SHIFT = 28, +}; + +// Frame Restoration types (section 6.10.15) +enum { + AV1_RESTORE_NONE = 0, + AV1_RESTORE_WIENER = 1, + AV1_RESTORE_SGRPROJ = 2, + AV1_RESTORE_SWITCHABLE = 3, +}; + +#endif /* AVCODEC_AV1_H */ diff --git a/third-party/cbs/include/cbs/cbs.h b/third-party/cbs/include/cbs/cbs.h new file mode 100644 index 00000000..5502a166 --- /dev/null +++ b/third-party/cbs/include/cbs/cbs.h @@ -0,0 +1,448 @@ +/* + * 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 + +#include + + +/* + * This defines a framework for converting between a coded bitstream + * and structures defining all individual syntax elements found in + * such a stream. + * + * Conversion in both directions is possible. Given a coded bitstream + * (any meaningful fragment), it can be parsed and decomposed into + * syntax elements stored in a set of codec-specific structures. + * Similarly, given a set of those same codec-specific structures the + * syntax elements can be serialised and combined to create a coded + * bitstream. + */ + +struct CodedBitstreamType; + +/** + * The codec-specific type of a bitstream unit. + * + * AV1: obu_type + * H.264 / AVC: nal_unit_type + * H.265 / HEVC: nal_unit_type + * JPEG: marker value (without 0xff prefix) + * MPEG-2: start code value (without prefix) + * VP9: unused, set to zero (every unit is a frame) + */ +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 directly-parsable 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; + /** + * A reference to the buffer containing data. + * + * Must be set if data is not NULL. + */ + AVBufferRef *data_ref; + + /** + * 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; + /** + * If content is reference counted, a reference to the buffer containing + * content. Null if content is not reference counted. + */ + AVBufferRef *content_ref; +} 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; + /** + * A reference to the buffer containing data. + * + * Must be set if data is not NULL. + */ + AVBufferRef *data_ref; + + /** + * 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; + + /** + * Number of allocated units. + * + * Must always be >= nb_units; designed for internal use by cbs. + */ + int nb_units_allocated; + + /** + * Pointer to an array of units of length nb_units_allocated. + * Only the first nb_units are valid. + * + * Must be NULL if nb_units_allocated 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. + */ + const 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; + + /** + * Write buffer. Used as intermediate buffer when writing units. + * For internal use of cbs only. + */ + uint8_t *write_buffer; + size_t write_buffer_size; +} CodedBitstreamContext; + + +/** + * Table of all supported codec IDs. + * + * Terminated by AV_CODEC_ID_NONE. + */ +extern const enum AVCodecID ff_cbs_all_codec_ids[]; + + +/** + * Create and initialise a new context for the given codec. + */ +int ff_cbs_init(CodedBitstreamContext **ctx, + enum AVCodecID codec_id, void *log_ctx); + +/** + * Reset all internal state in a context. + */ +void ff_cbs_flush(CodedBitstreamContext *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. + * + * The fragment must have been zeroed or reset via ff_cbs_fragment_reset + * before use. + */ +int ff_cbs_read_extradata(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVCodecParameters *par); + +/** + * Read the extradata bitstream found in a codec context into a + * fragment, then split into units and decompose. + * + * This acts identical to ff_cbs_read_extradata() for the case where + * you already have a codec context. + */ +int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVCodecContext *avctx); + +/** + * Read the data bitstream from a packet into a fragment, then + * split into units and decompose. + * + * This also updates the internal state of the coded bitstream context + * with any persistent data from the fragment which may be required to + * read following fragments (e.g. parameter sets). + * + * The fragment must have been zeroed or reset via ff_cbs_fragment_reset + * before use. + */ +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. + * + * This also updates the internal state of the coded bitstream context + * with any persistent data from the fragment which may be required to + * read following fragments (e.g. parameter sets). + * + * The fragment must have been zeroed or reset via ff_cbs_fragment_reset + * before use. + */ +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. + * + * This also updates the internal state of the coded bitstream context + * with any persistent data from the fragment which may be required to + * write following fragments (e.g. parameter sets). + */ +int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag); + +/** + * Write the bitstream of a fragment to the extradata in codec parameters. + * + * Modifies context and fragment as ff_cbs_write_fragment_data does and + * 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. + * + * Modifies context and fragment as ff_cbs_write_fragment_data does. + * + * On success, the packet's buf is unreferenced and its buf, data and + * size fields are set to the corresponding values from the newly updated + * fragment; other fields are not touched. On failure, the packet is not + * touched at all. + */ +int ff_cbs_write_packet(CodedBitstreamContext *ctx, + AVPacket *pkt, + CodedBitstreamFragment *frag); + + +/** + * Free the units contained in a fragment as well as the fragment's + * own data buffer, but not the units array itself. + */ +void ff_cbs_fragment_reset(CodedBitstreamFragment *frag); + +/** + * Free the units array of a fragment in addition to what + * ff_cbs_fragment_reset does. + */ +void ff_cbs_fragment_free(CodedBitstreamFragment *frag); + +/** + * Allocate a new internal content buffer of the given size in the unit. + * + * The content will be zeroed. + */ +int ff_cbs_alloc_unit_content(CodedBitstreamUnit *unit, + size_t size, + void (*free)(void *opaque, uint8_t *content)); + +/** + * Allocate a new internal content buffer matching the type of the unit. + * + * The content will be zeroed. + */ +int ff_cbs_alloc_unit_content2(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit); + + +/** + * Allocate a new internal data buffer of the given size in the unit. + * + * The data buffer will have input padding. + */ +int ff_cbs_alloc_unit_data(CodedBitstreamUnit *unit, + size_t size); + +/** + * Insert a new unit into a fragment with the given content. + * + * The content structure continues to be owned by the caller if + * content_buf is not supplied. + */ +int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + void *content, + AVBufferRef *content_buf); + +/** + * Insert a new unit into a fragment with the given data bitstream. + * + * If data_buf is not supplied then data must have been allocated with + * av_malloc() and will on success become owned by the unit after this + * call or freed on error. + */ +int ff_cbs_insert_unit_data(CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + uint8_t *data, size_t data_size, + AVBufferRef *data_buf); + +/** + * Delete a unit from a fragment and free all memory it uses. + * + * Requires position to be >= 0 and < frag->nb_units. + */ +void ff_cbs_delete_unit(CodedBitstreamFragment *frag, + int position); + + +/** + * Make the content of a unit refcounted. + * + * If the unit is not refcounted, this will do a deep copy of the unit + * content to new refcounted buffers. + * + * It is not valid to call this function on a unit which does not have + * decomposed content. + */ +int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit); + +/** + * Make the content of a unit writable so that internal fields can be + * modified. + * + * If it is known that there are no other references to the content of + * the unit, does nothing and returns success. Otherwise (including the + * case where the unit content is not refcounted), it does a full clone + * of the content (including any internal buffers) to make a new copy, + * and replaces the existing references inside the unit with that. + * + * It is not valid to call this function on a unit which does not have + * decomposed content. + */ +int ff_cbs_make_unit_writable(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit); + + +#endif /* AVCODEC_CBS_H */ diff --git a/third-party/cbs/include/cbs/cbs_av1.h b/third-party/cbs/include/cbs/cbs_av1.h new file mode 100644 index 00000000..760f9a5d --- /dev/null +++ b/third-party/cbs/include/cbs/cbs_av1.h @@ -0,0 +1,464 @@ +/* + * 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_AV1_H +#define AVCODEC_CBS_AV1_H + +#include +#include + +#include "av1.h" +#include "cbs.h" + + +typedef struct AV1RawOBUHeader { + uint8_t obu_forbidden_bit; + uint8_t obu_type; + uint8_t obu_extension_flag; + uint8_t obu_has_size_field; + uint8_t obu_reserved_1bit; + + uint8_t temporal_id; + uint8_t spatial_id; + uint8_t extension_header_reserved_3bits; +} AV1RawOBUHeader; + +typedef struct AV1RawColorConfig { + uint8_t high_bitdepth; + uint8_t twelve_bit; + uint8_t mono_chrome; + + uint8_t color_description_present_flag; + uint8_t color_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + + uint8_t color_range; + uint8_t subsampling_x; + uint8_t subsampling_y; + uint8_t chroma_sample_position; + uint8_t separate_uv_delta_q; +} AV1RawColorConfig; + +typedef struct AV1RawTimingInfo { + uint32_t num_units_in_display_tick; + uint32_t time_scale; + + uint8_t equal_picture_interval; + uint32_t num_ticks_per_picture_minus_1; +} AV1RawTimingInfo; + +typedef struct AV1RawDecoderModelInfo { + uint8_t buffer_delay_length_minus_1; + uint32_t num_units_in_decoding_tick; + uint8_t buffer_removal_time_length_minus_1; + uint8_t frame_presentation_time_length_minus_1; +} AV1RawDecoderModelInfo; + +typedef struct AV1RawSequenceHeader { + uint8_t seq_profile; + uint8_t still_picture; + uint8_t reduced_still_picture_header; + + uint8_t timing_info_present_flag; + uint8_t decoder_model_info_present_flag; + uint8_t initial_display_delay_present_flag; + uint8_t operating_points_cnt_minus_1; + + AV1RawTimingInfo timing_info; + AV1RawDecoderModelInfo decoder_model_info; + + uint16_t operating_point_idc[AV1_MAX_OPERATING_POINTS]; + uint8_t seq_level_idx[AV1_MAX_OPERATING_POINTS]; + uint8_t seq_tier[AV1_MAX_OPERATING_POINTS]; + uint8_t decoder_model_present_for_this_op[AV1_MAX_OPERATING_POINTS]; + uint32_t decoder_buffer_delay[AV1_MAX_OPERATING_POINTS]; + uint32_t encoder_buffer_delay[AV1_MAX_OPERATING_POINTS]; + uint8_t low_delay_mode_flag[AV1_MAX_OPERATING_POINTS]; + uint8_t initial_display_delay_present_for_this_op[AV1_MAX_OPERATING_POINTS]; + uint8_t initial_display_delay_minus_1[AV1_MAX_OPERATING_POINTS]; + + uint8_t frame_width_bits_minus_1; + uint8_t frame_height_bits_minus_1; + uint16_t max_frame_width_minus_1; + uint16_t max_frame_height_minus_1; + + uint8_t frame_id_numbers_present_flag; + uint8_t delta_frame_id_length_minus_2; + uint8_t additional_frame_id_length_minus_1; + + uint8_t use_128x128_superblock; + uint8_t enable_filter_intra; + uint8_t enable_intra_edge_filter; + uint8_t enable_interintra_compound; + uint8_t enable_masked_compound; + uint8_t enable_warped_motion; + uint8_t enable_dual_filter; + + uint8_t enable_order_hint; + uint8_t enable_jnt_comp; + uint8_t enable_ref_frame_mvs; + + uint8_t seq_choose_screen_content_tools; + uint8_t seq_force_screen_content_tools; + uint8_t seq_choose_integer_mv; + uint8_t seq_force_integer_mv; + + uint8_t order_hint_bits_minus_1; + + uint8_t enable_superres; + uint8_t enable_cdef; + uint8_t enable_restoration; + + AV1RawColorConfig color_config; + + uint8_t film_grain_params_present; +} AV1RawSequenceHeader; + +typedef struct AV1RawFilmGrainParams { + uint8_t apply_grain; + uint16_t grain_seed; + uint8_t update_grain; + uint8_t film_grain_params_ref_idx; + uint8_t num_y_points; + uint8_t point_y_value[14]; + uint8_t point_y_scaling[14]; + uint8_t chroma_scaling_from_luma; + uint8_t num_cb_points; + uint8_t point_cb_value[10]; + uint8_t point_cb_scaling[10]; + uint8_t num_cr_points; + uint8_t point_cr_value[10]; + uint8_t point_cr_scaling[10]; + uint8_t grain_scaling_minus_8; + uint8_t ar_coeff_lag; + uint8_t ar_coeffs_y_plus_128[24]; + uint8_t ar_coeffs_cb_plus_128[25]; + uint8_t ar_coeffs_cr_plus_128[25]; + uint8_t ar_coeff_shift_minus_6; + uint8_t grain_scale_shift; + uint8_t cb_mult; + uint8_t cb_luma_mult; + uint16_t cb_offset; + uint8_t cr_mult; + uint8_t cr_luma_mult; + uint16_t cr_offset; + uint8_t overlap_flag; + uint8_t clip_to_restricted_range; +} AV1RawFilmGrainParams; + +typedef struct AV1RawFrameHeader { + uint8_t show_existing_frame; + uint8_t frame_to_show_map_idx; + uint32_t frame_presentation_time; + uint32_t display_frame_id; + + uint8_t frame_type; + uint8_t show_frame; + uint8_t showable_frame; + + uint8_t error_resilient_mode; + uint8_t disable_cdf_update; + uint8_t allow_screen_content_tools; + uint8_t force_integer_mv; + + uint32_t current_frame_id; + uint8_t frame_size_override_flag; + uint8_t order_hint; + + uint8_t buffer_removal_time_present_flag; + uint32_t buffer_removal_time[AV1_MAX_OPERATING_POINTS]; + + uint8_t primary_ref_frame; + uint16_t frame_width_minus_1; + uint16_t frame_height_minus_1; + uint8_t use_superres; + uint8_t coded_denom; + uint8_t render_and_frame_size_different; + uint16_t render_width_minus_1; + uint16_t render_height_minus_1; + + uint8_t found_ref[AV1_REFS_PER_FRAME]; + + uint8_t refresh_frame_flags; + uint8_t allow_intrabc; + uint8_t ref_order_hint[AV1_NUM_REF_FRAMES]; + uint8_t frame_refs_short_signaling; + uint8_t last_frame_idx; + uint8_t golden_frame_idx; + int8_t ref_frame_idx[AV1_REFS_PER_FRAME]; + uint32_t delta_frame_id_minus1[AV1_REFS_PER_FRAME]; + + uint8_t allow_high_precision_mv; + uint8_t is_filter_switchable; + uint8_t interpolation_filter; + uint8_t is_motion_mode_switchable; + uint8_t use_ref_frame_mvs; + + uint8_t disable_frame_end_update_cdf; + + uint8_t uniform_tile_spacing_flag; + uint8_t tile_cols_log2; + uint8_t tile_rows_log2; + uint8_t width_in_sbs_minus_1[AV1_MAX_TILE_COLS]; + uint8_t height_in_sbs_minus_1[AV1_MAX_TILE_ROWS]; + uint16_t context_update_tile_id; + uint8_t tile_size_bytes_minus1; + + // These are derived values, but it's very unhelpful to have to + // recalculate them all the time so we store them here. + uint16_t tile_cols; + uint16_t tile_rows; + + uint8_t base_q_idx; + int8_t delta_q_y_dc; + uint8_t diff_uv_delta; + int8_t delta_q_u_dc; + int8_t delta_q_u_ac; + int8_t delta_q_v_dc; + int8_t delta_q_v_ac; + uint8_t using_qmatrix; + uint8_t qm_y; + uint8_t qm_u; + uint8_t qm_v; + + uint8_t segmentation_enabled; + uint8_t segmentation_update_map; + uint8_t segmentation_temporal_update; + uint8_t segmentation_update_data; + uint8_t feature_enabled[AV1_MAX_SEGMENTS][AV1_SEG_LVL_MAX]; + int16_t feature_value[AV1_MAX_SEGMENTS][AV1_SEG_LVL_MAX]; + + uint8_t delta_q_present; + uint8_t delta_q_res; + uint8_t delta_lf_present; + uint8_t delta_lf_res; + uint8_t delta_lf_multi; + + uint8_t loop_filter_level[4]; + uint8_t loop_filter_sharpness; + uint8_t loop_filter_delta_enabled; + uint8_t loop_filter_delta_update; + uint8_t update_ref_delta[AV1_TOTAL_REFS_PER_FRAME]; + int8_t loop_filter_ref_deltas[AV1_TOTAL_REFS_PER_FRAME]; + uint8_t update_mode_delta[2]; + int8_t loop_filter_mode_deltas[2]; + + uint8_t cdef_damping_minus_3; + uint8_t cdef_bits; + uint8_t cdef_y_pri_strength[8]; + uint8_t cdef_y_sec_strength[8]; + uint8_t cdef_uv_pri_strength[8]; + uint8_t cdef_uv_sec_strength[8]; + + uint8_t lr_type[3]; + uint8_t lr_unit_shift; + uint8_t lr_uv_shift; + + uint8_t tx_mode; + uint8_t reference_select; + uint8_t skip_mode_present; + + uint8_t allow_warped_motion; + uint8_t reduced_tx_set; + + uint8_t is_global[AV1_TOTAL_REFS_PER_FRAME]; + uint8_t is_rot_zoom[AV1_TOTAL_REFS_PER_FRAME]; + uint8_t is_translation[AV1_TOTAL_REFS_PER_FRAME]; + //AV1RawSubexp gm_params[AV1_TOTAL_REFS_PER_FRAME][6]; + uint32_t gm_params[AV1_TOTAL_REFS_PER_FRAME][6]; + + AV1RawFilmGrainParams film_grain; +} AV1RawFrameHeader; + +typedef struct AV1RawTileData { + uint8_t *data; + AVBufferRef *data_ref; + size_t data_size; +} AV1RawTileData; + +typedef struct AV1RawTileGroup { + uint8_t tile_start_and_end_present_flag; + uint16_t tg_start; + uint16_t tg_end; + + AV1RawTileData tile_data; +} AV1RawTileGroup; + +typedef struct AV1RawFrame { + AV1RawFrameHeader header; + AV1RawTileGroup tile_group; +} AV1RawFrame; + +typedef struct AV1RawTileList { + uint8_t output_frame_width_in_tiles_minus_1; + uint8_t output_frame_height_in_tiles_minus_1; + uint16_t tile_count_minus_1; + + AV1RawTileData tile_data; +} AV1RawTileList; + +typedef struct AV1RawMetadataHDRCLL { + uint16_t max_cll; + uint16_t max_fall; +} AV1RawMetadataHDRCLL; + +typedef struct AV1RawMetadataHDRMDCV { + uint16_t primary_chromaticity_x[3]; + uint16_t primary_chromaticity_y[3]; + uint16_t white_point_chromaticity_x; + uint16_t white_point_chromaticity_y; + uint32_t luminance_max; + uint32_t luminance_min; +} AV1RawMetadataHDRMDCV; + +typedef struct AV1RawMetadataScalability { + uint8_t scalability_mode_idc; + uint8_t spatial_layers_cnt_minus_1; + uint8_t spatial_layer_dimensions_present_flag; + uint8_t spatial_layer_description_present_flag; + uint8_t temporal_group_description_present_flag; + uint8_t scalability_structure_reserved_3bits; + uint16_t spatial_layer_max_width[4]; + uint16_t spatial_layer_max_height[4]; + uint8_t spatial_layer_ref_id[4]; + uint8_t temporal_group_size; + uint8_t temporal_group_temporal_id[255]; + uint8_t temporal_group_temporal_switching_up_point_flag[255]; + uint8_t temporal_group_spatial_switching_up_point_flag[255]; + uint8_t temporal_group_ref_cnt[255]; + uint8_t temporal_group_ref_pic_diff[255][7]; +} AV1RawMetadataScalability; + +typedef struct AV1RawMetadataITUTT35 { + uint8_t itu_t_t35_country_code; + uint8_t itu_t_t35_country_code_extension_byte; + + uint8_t *payload; + AVBufferRef *payload_ref; + size_t payload_size; +} AV1RawMetadataITUTT35; + +typedef struct AV1RawMetadataTimecode { + uint8_t counting_type; + uint8_t full_timestamp_flag; + uint8_t discontinuity_flag; + uint8_t cnt_dropped_flag; + uint16_t n_frames; + uint8_t seconds_value; + uint8_t minutes_value; + uint8_t hours_value; + uint8_t seconds_flag; + uint8_t minutes_flag; + uint8_t hours_flag; + uint8_t time_offset_length; + uint32_t time_offset_value; +} AV1RawMetadataTimecode; + +typedef struct AV1RawMetadata { + uint64_t metadata_type; + union { + AV1RawMetadataHDRCLL hdr_cll; + AV1RawMetadataHDRMDCV hdr_mdcv; + AV1RawMetadataScalability scalability; + AV1RawMetadataITUTT35 itut_t35; + AV1RawMetadataTimecode timecode; + } metadata; +} AV1RawMetadata; + +typedef struct AV1RawPadding { + uint8_t *payload; + AVBufferRef *payload_ref; + size_t payload_size; +} AV1RawPadding; + + +typedef struct AV1RawOBU { + AV1RawOBUHeader header; + + size_t obu_size; + + union { + AV1RawSequenceHeader sequence_header; + AV1RawFrameHeader frame_header; + AV1RawFrame frame; + AV1RawTileGroup tile_group; + AV1RawTileList tile_list; + AV1RawMetadata metadata; + AV1RawPadding padding; + } obu; +} AV1RawOBU; + +typedef struct AV1ReferenceFrameState { + int valid; // RefValid + int frame_id; // RefFrameId + int upscaled_width; // RefUpscaledWidth + int frame_width; // RefFrameWidth + int frame_height; // RefFrameHeight + int render_width; // RefRenderWidth + int render_height; // RefRenderHeight + int frame_type; // RefFrameType + int subsampling_x; // RefSubsamplingX + int subsampling_y; // RefSubsamplingY + int bit_depth; // RefBitDepth + int order_hint; // RefOrderHint + + int8_t loop_filter_ref_deltas[AV1_TOTAL_REFS_PER_FRAME]; + int8_t loop_filter_mode_deltas[2]; + uint8_t feature_enabled[AV1_MAX_SEGMENTS][AV1_SEG_LVL_MAX]; + int16_t feature_value[AV1_MAX_SEGMENTS][AV1_SEG_LVL_MAX]; +} AV1ReferenceFrameState; + +typedef struct CodedBitstreamAV1Context { + const AVClass *class; + + AV1RawSequenceHeader *sequence_header; + AVBufferRef *sequence_header_ref; + + int seen_frame_header; + AVBufferRef *frame_header_ref; + uint8_t *frame_header; + size_t frame_header_size; + + int temporal_id; + int spatial_id; + int operating_point_idc; + + int bit_depth; + int order_hint; + int frame_width; + int frame_height; + int upscaled_width; + int render_width; + int render_height; + + int num_planes; + int coded_lossless; + int all_lossless; + int tile_cols; + int tile_rows; + int tile_num; + + AV1ReferenceFrameState ref[AV1_NUM_REF_FRAMES]; + + // AVOptions + int operating_point; +} CodedBitstreamAV1Context; + + +#endif /* AVCODEC_CBS_AV1_H */ diff --git a/third-party/cbs/include/cbs/cbs_bsf.h b/third-party/cbs/include/cbs/cbs_bsf.h new file mode 100644 index 00000000..0cfb64b4 --- /dev/null +++ b/third-party/cbs/include/cbs/cbs_bsf.h @@ -0,0 +1,131 @@ +/* + * 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_BSF_H +#define AVCODEC_CBS_BSF_H + +#include "cbs.h" + + +typedef struct CBSBSFType { + enum AVCodecID codec_id; + + // Name of a frame fragment in this codec (e.g. "access unit", + // "temporal unit"). + const char *fragment_name; + + // Name of a unit for this BSF, for use in error messages (e.g. + // "NAL unit", "OBU"). + const char *unit_name; + + // Update the content of a fragment with whatever metadata changes + // are desired. The associated AVPacket is provided so that any side + // data associated with the fragment can be inspected or edited. If + // pkt is NULL, then an extradata header fragment is being updated. + int (*update_fragment)(AVBSFContext *bsf, AVPacket *pkt, + CodedBitstreamFragment *frag); +} CBSBSFType; + +// Common structure for all generic CBS BSF users. An instance of this +// structure must be the first member of the BSF private context (to be +// pointed to by AVBSFContext.priv_data). +typedef struct CBSBSFContext { + const AVClass *class; + const CBSBSFType *type; + + CodedBitstreamContext *input; + CodedBitstreamContext *output; + CodedBitstreamFragment fragment; +} CBSBSFContext; + +/** + * Initialise generic CBS BSF setup. + * + * Creates the input and output CBS instances, and applies the filter to + * the extradata on the input codecpar if any is present. + * + * Since it calls the update_fragment() function immediately to deal with + * extradata, this should be called after any codec-specific setup is done + * (probably at the end of the AVBitStreamFilter.init function). + */ +int ff_cbs_bsf_generic_init(AVBSFContext *bsf, const CBSBSFType *type); + +/** + * Close a generic CBS BSF instance. + * + * If no other deinitialisation is required then this function can be used + * directly as AVBitStreamFilter.close. + */ +void ff_cbs_bsf_generic_close(AVBSFContext *bsf); + +/** + * Filter operation for CBS BSF. + * + * Reads the input packet into a CBS fragment, calls update_fragment() on + * it, then writes the result to an output packet. If the input packet + * has AV_PKT_DATA_NEW_EXTRADATA side-data associated with it then it does + * the same thing to that new extradata to form the output side-data first. + * + * If the BSF does not do anything else then this function can be used + * directly as AVBitStreamFilter.filter. + */ +int ff_cbs_bsf_generic_filter(AVBSFContext *bsf, AVPacket *pkt); + + +// Options for element manipulation. +enum { + // Pass this element through unchanged. + BSF_ELEMENT_PASS, + // Insert this element, replacing any existing instances of it. + // Associated values may be provided explicitly (as addtional options) + // or implicitly (either as side data or deduced from other parts of + // the stream). + BSF_ELEMENT_INSERT, + // Remove this element if it appears in the stream. + BSF_ELEMENT_REMOVE, + // Extract this element to side data, so that further manipulation + // can happen elsewhere. + BSF_ELEMENT_EXTRACT, +}; + +#define BSF_ELEMENT_OPTIONS_PIR(name, help, field, opt_flags) \ + { name, help, OFFSET(field), AV_OPT_TYPE_INT, \ + { .i64 = BSF_ELEMENT_PASS }, \ + BSF_ELEMENT_PASS, BSF_ELEMENT_REMOVE, opt_flags, name }, \ + { "pass", NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = BSF_ELEMENT_PASS }, .flags = opt_flags, .unit = name }, \ + { "insert", NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = BSF_ELEMENT_INSERT }, .flags = opt_flags, .unit = name }, \ + { "remove", NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = BSF_ELEMENT_REMOVE }, .flags = opt_flags, .unit = name } + +#define BSF_ELEMENT_OPTIONS_PIRE(name, help, field, opt_flags) \ + { name, help, OFFSET(field), AV_OPT_TYPE_INT, \ + { .i64 = BSF_ELEMENT_PASS }, \ + BSF_ELEMENT_PASS, BSF_ELEMENT_EXTRACT, opt_flags, name }, \ + { "pass", NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = BSF_ELEMENT_PASS }, .flags = opt_flags, .unit = name }, \ + { "insert", NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = BSF_ELEMENT_INSERT }, .flags = opt_flags, .unit = name }, \ + { "remove", NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = BSF_ELEMENT_REMOVE }, .flags = opt_flags, .unit = name }, \ + { "extract", NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = BSF_ELEMENT_EXTRACT }, .flags = opt_flags, .unit = name } + + +#endif /* AVCODEC_CBS_BSF_H */ diff --git a/third-party/cbs/include/cbs/cbs_h264.h b/third-party/cbs/include/cbs/cbs_h264.h new file mode 100644 index 00000000..71397534 --- /dev/null +++ b/third-party/cbs/include/cbs/cbs_h264.h @@ -0,0 +1,406 @@ +/* + * 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_H264_H +#define AVCODEC_CBS_H264_H + +#include +#include + +#include "cbs.h" +#include "cbs_h2645.h" +#include "cbs_sei.h" +#include "h264.h" + + +typedef struct H264RawNALUnitHeader { + uint8_t nal_ref_idc; + uint8_t nal_unit_type; + + uint8_t svc_extension_flag; + uint8_t avc_3d_extension_flag; +} H264RawNALUnitHeader; + +typedef struct H264RawScalingList { + int8_t delta_scale[64]; +} H264RawScalingList; + +typedef struct H264RawHRD { + uint8_t cpb_cnt_minus1; + uint8_t bit_rate_scale; + uint8_t cpb_size_scale; + + uint32_t bit_rate_value_minus1[H264_MAX_CPB_CNT]; + uint32_t cpb_size_value_minus1[H264_MAX_CPB_CNT]; + uint8_t cbr_flag[H264_MAX_CPB_CNT]; + + uint8_t initial_cpb_removal_delay_length_minus1; + uint8_t cpb_removal_delay_length_minus1; + uint8_t dpb_output_delay_length_minus1; + uint8_t time_offset_length; +} H264RawHRD; + +typedef struct H264RawVUI { + uint8_t aspect_ratio_info_present_flag; + uint8_t aspect_ratio_idc; + uint16_t sar_width; + uint16_t sar_height; + + uint8_t overscan_info_present_flag; + uint8_t overscan_appropriate_flag; + + uint8_t video_signal_type_present_flag; + uint8_t video_format; + uint8_t video_full_range_flag; + uint8_t colour_description_present_flag; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + + uint8_t chroma_loc_info_present_flag; + uint8_t chroma_sample_loc_type_top_field; + uint8_t chroma_sample_loc_type_bottom_field; + + uint8_t timing_info_present_flag; + uint32_t num_units_in_tick; + uint32_t time_scale; + uint8_t fixed_frame_rate_flag; + + uint8_t nal_hrd_parameters_present_flag; + H264RawHRD nal_hrd_parameters; + uint8_t vcl_hrd_parameters_present_flag; + H264RawHRD vcl_hrd_parameters; + uint8_t low_delay_hrd_flag; + + uint8_t pic_struct_present_flag; + + uint8_t bitstream_restriction_flag; + uint8_t motion_vectors_over_pic_boundaries_flag; + uint8_t max_bytes_per_pic_denom; + uint8_t max_bits_per_mb_denom; + uint8_t log2_max_mv_length_horizontal; + uint8_t log2_max_mv_length_vertical; + uint8_t max_num_reorder_frames; + uint8_t max_dec_frame_buffering; +} H264RawVUI; + +typedef struct H264RawSPS { + H264RawNALUnitHeader nal_unit_header; + + uint8_t profile_idc; + uint8_t constraint_set0_flag; + uint8_t constraint_set1_flag; + uint8_t constraint_set2_flag; + uint8_t constraint_set3_flag; + uint8_t constraint_set4_flag; + uint8_t constraint_set5_flag; + uint8_t reserved_zero_2bits; + uint8_t level_idc; + + uint8_t seq_parameter_set_id; + + uint8_t chroma_format_idc; + uint8_t separate_colour_plane_flag; + uint8_t bit_depth_luma_minus8; + uint8_t bit_depth_chroma_minus8; + uint8_t qpprime_y_zero_transform_bypass_flag; + + uint8_t seq_scaling_matrix_present_flag; + uint8_t seq_scaling_list_present_flag[12]; + H264RawScalingList scaling_list_4x4[6]; + H264RawScalingList scaling_list_8x8[6]; + + uint8_t log2_max_frame_num_minus4; + uint8_t pic_order_cnt_type; + uint8_t log2_max_pic_order_cnt_lsb_minus4; + uint8_t delta_pic_order_always_zero_flag; + int32_t offset_for_non_ref_pic; + int32_t offset_for_top_to_bottom_field; + uint8_t num_ref_frames_in_pic_order_cnt_cycle; + int32_t offset_for_ref_frame[256]; + + uint8_t max_num_ref_frames; + uint8_t gaps_in_frame_num_allowed_flag; + + uint16_t pic_width_in_mbs_minus1; + uint16_t pic_height_in_map_units_minus1; + + uint8_t frame_mbs_only_flag; + uint8_t mb_adaptive_frame_field_flag; + uint8_t direct_8x8_inference_flag; + + uint8_t frame_cropping_flag; + uint16_t frame_crop_left_offset; + uint16_t frame_crop_right_offset; + uint16_t frame_crop_top_offset; + uint16_t frame_crop_bottom_offset; + + uint8_t vui_parameters_present_flag; + H264RawVUI vui; +} H264RawSPS; + +typedef struct H264RawSPSExtension { + H264RawNALUnitHeader nal_unit_header; + + uint8_t seq_parameter_set_id; + + uint8_t aux_format_idc; + uint8_t bit_depth_aux_minus8; + uint8_t alpha_incr_flag; + uint16_t alpha_opaque_value; + uint16_t alpha_transparent_value; + + uint8_t additional_extension_flag; +} H264RawSPSExtension; + +typedef struct H264RawPPS { + H264RawNALUnitHeader nal_unit_header; + + uint8_t pic_parameter_set_id; + uint8_t seq_parameter_set_id; + + uint8_t entropy_coding_mode_flag; + uint8_t bottom_field_pic_order_in_frame_present_flag; + + uint8_t num_slice_groups_minus1; + uint8_t slice_group_map_type; + uint16_t run_length_minus1[H264_MAX_SLICE_GROUPS]; + uint16_t top_left[H264_MAX_SLICE_GROUPS]; + uint16_t bottom_right[H264_MAX_SLICE_GROUPS]; + uint8_t slice_group_change_direction_flag; + uint16_t slice_group_change_rate_minus1; + uint16_t pic_size_in_map_units_minus1; + + uint8_t *slice_group_id; + AVBufferRef *slice_group_id_ref; + + uint8_t num_ref_idx_l0_default_active_minus1; + uint8_t num_ref_idx_l1_default_active_minus1; + + uint8_t weighted_pred_flag; + uint8_t weighted_bipred_idc; + + int8_t pic_init_qp_minus26; + int8_t pic_init_qs_minus26; + int8_t chroma_qp_index_offset; + + uint8_t deblocking_filter_control_present_flag; + uint8_t constrained_intra_pred_flag; + + uint8_t more_rbsp_data; + + uint8_t redundant_pic_cnt_present_flag; + uint8_t transform_8x8_mode_flag; + + uint8_t pic_scaling_matrix_present_flag; + uint8_t pic_scaling_list_present_flag[12]; + H264RawScalingList scaling_list_4x4[6]; + H264RawScalingList scaling_list_8x8[6]; + + int8_t second_chroma_qp_index_offset; +} H264RawPPS; + +typedef struct H264RawAUD { + H264RawNALUnitHeader nal_unit_header; + + uint8_t primary_pic_type; +} H264RawAUD; + +typedef struct H264RawSEIBufferingPeriod { + uint8_t seq_parameter_set_id; + struct { + uint32_t initial_cpb_removal_delay[H264_MAX_CPB_CNT]; + uint32_t initial_cpb_removal_delay_offset[H264_MAX_CPB_CNT]; + } nal, vcl; +} H264RawSEIBufferingPeriod; + +typedef struct H264RawSEIPicTimestamp { + uint8_t ct_type; + uint8_t nuit_field_based_flag; + uint8_t counting_type; + uint8_t full_timestamp_flag; + uint8_t discontinuity_flag; + uint8_t cnt_dropped_flag; + uint8_t n_frames; + uint8_t seconds_flag; + uint8_t seconds_value; + uint8_t minutes_flag; + uint8_t minutes_value; + uint8_t hours_flag; + uint8_t hours_value; + int32_t time_offset; +} H264RawSEIPicTimestamp; + +typedef struct H264RawSEIPicTiming { + uint32_t cpb_removal_delay; + uint32_t dpb_output_delay; + uint8_t pic_struct; + uint8_t clock_timestamp_flag[3]; + H264RawSEIPicTimestamp timestamp[3]; +} H264RawSEIPicTiming; + +typedef struct H264RawSEIPanScanRect { + uint32_t pan_scan_rect_id; + uint8_t pan_scan_rect_cancel_flag; + uint8_t pan_scan_cnt_minus1; + int32_t pan_scan_rect_left_offset[3]; + int32_t pan_scan_rect_right_offset[3]; + int32_t pan_scan_rect_top_offset[3]; + int32_t pan_scan_rect_bottom_offset[3]; + uint16_t pan_scan_rect_repetition_period; +} H264RawSEIPanScanRect; + +typedef struct H264RawSEIRecoveryPoint { + uint16_t recovery_frame_cnt; + uint8_t exact_match_flag; + uint8_t broken_link_flag; + uint8_t changing_slice_group_idc; +} H264RawSEIRecoveryPoint; + +typedef struct H264RawSEIDisplayOrientation { + uint8_t display_orientation_cancel_flag; + uint8_t hor_flip; + uint8_t ver_flip; + uint16_t anticlockwise_rotation; + uint16_t display_orientation_repetition_period; + uint8_t display_orientation_extension_flag; +} H264RawSEIDisplayOrientation; + +typedef struct H264RawSEI { + H264RawNALUnitHeader nal_unit_header; + SEIRawMessageList message_list; +} H264RawSEI; + +typedef struct H264RawSliceHeader { + H264RawNALUnitHeader nal_unit_header; + + uint32_t first_mb_in_slice; + uint8_t slice_type; + + uint8_t pic_parameter_set_id; + + uint8_t colour_plane_id; + + uint16_t frame_num; + uint8_t field_pic_flag; + uint8_t bottom_field_flag; + + uint16_t idr_pic_id; + + uint16_t pic_order_cnt_lsb; + int32_t delta_pic_order_cnt_bottom; + int32_t delta_pic_order_cnt[2]; + + uint8_t redundant_pic_cnt; + uint8_t direct_spatial_mv_pred_flag; + + uint8_t num_ref_idx_active_override_flag; + uint8_t num_ref_idx_l0_active_minus1; + uint8_t num_ref_idx_l1_active_minus1; + + uint8_t ref_pic_list_modification_flag_l0; + uint8_t ref_pic_list_modification_flag_l1; + struct { + uint8_t modification_of_pic_nums_idc; + int32_t abs_diff_pic_num_minus1; + uint8_t long_term_pic_num; + } rplm_l0[H264_MAX_RPLM_COUNT], rplm_l1[H264_MAX_RPLM_COUNT]; + + uint8_t luma_log2_weight_denom; + uint8_t chroma_log2_weight_denom; + + uint8_t luma_weight_l0_flag[H264_MAX_REFS]; + int8_t luma_weight_l0[H264_MAX_REFS]; + int8_t luma_offset_l0[H264_MAX_REFS]; + uint8_t chroma_weight_l0_flag[H264_MAX_REFS]; + int8_t chroma_weight_l0[H264_MAX_REFS][2]; + int8_t chroma_offset_l0[H264_MAX_REFS][2]; + + uint8_t luma_weight_l1_flag[H264_MAX_REFS]; + int8_t luma_weight_l1[H264_MAX_REFS]; + int8_t luma_offset_l1[H264_MAX_REFS]; + uint8_t chroma_weight_l1_flag[H264_MAX_REFS]; + int8_t chroma_weight_l1[H264_MAX_REFS][2]; + int8_t chroma_offset_l1[H264_MAX_REFS][2]; + + uint8_t no_output_of_prior_pics_flag; + uint8_t long_term_reference_flag; + + uint8_t adaptive_ref_pic_marking_mode_flag; + struct { + uint8_t memory_management_control_operation; + int32_t difference_of_pic_nums_minus1; + uint8_t long_term_pic_num; + uint8_t long_term_frame_idx; + uint8_t max_long_term_frame_idx_plus1; + } mmco[H264_MAX_MMCO_COUNT]; + + uint8_t cabac_init_idc; + + int8_t slice_qp_delta; + + uint8_t sp_for_switch_flag; + int8_t slice_qs_delta; + + uint8_t disable_deblocking_filter_idc; + int8_t slice_alpha_c0_offset_div2; + int8_t slice_beta_offset_div2; + + uint16_t slice_group_change_cycle; +} H264RawSliceHeader; + +typedef struct H264RawSlice { + H264RawSliceHeader header; + + uint8_t *data; + AVBufferRef *data_ref; + size_t data_size; + int data_bit_start; +} H264RawSlice; + +typedef struct H264RawFiller { + H264RawNALUnitHeader nal_unit_header; + + uint32_t filler_size; +} H264RawFiller; + + +typedef struct CodedBitstreamH264Context { + // Reader/writer context in common with the H.265 implementation. + CodedBitstreamH2645Context common; + + // All currently available parameter sets. These are updated when + // any parameter set NAL unit is read/written with this context. + AVBufferRef *sps_ref[H264_MAX_SPS_COUNT]; + AVBufferRef *pps_ref[H264_MAX_PPS_COUNT]; + H264RawSPS *sps[H264_MAX_SPS_COUNT]; + H264RawPPS *pps[H264_MAX_PPS_COUNT]; + + // The currently active parameter sets. These are updated when any + // NAL unit refers to the relevant parameter set. These pointers + // must also be present in the arrays above. + const H264RawSPS *active_sps; + const H264RawPPS *active_pps; + + // The NAL unit type of the most recent normal slice. This is required + // to be able to read/write auxiliary slices, because IdrPicFlag is + // otherwise unknown. + uint8_t last_slice_nal_unit_type; +} CodedBitstreamH264Context; + +#endif /* AVCODEC_CBS_H264_H */ diff --git a/third-party/cbs/include/cbs/cbs_h2645.h b/third-party/cbs/include/cbs/cbs_h2645.h new file mode 100644 index 00000000..03cfb7a0 --- /dev/null +++ b/third-party/cbs/include/cbs/cbs_h2645.h @@ -0,0 +1,36 @@ +/* + * 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_H2645_H +#define AVCODEC_CBS_H2645_H + +#include "h2645_parse.h" + + +typedef struct CodedBitstreamH2645Context { + // If set, the stream being read is in MP4 (AVCC/HVCC) format. If not + // set, the stream is assumed to be in annex B format. + int mp4; + // Size in bytes of the NAL length field for MP4 format. + int nal_length_size; + // Packet reader. + H2645Packet read_packet; +} CodedBitstreamH2645Context; + + +#endif /* AVCODEC_CBS_H2645_H */ diff --git a/third-party/cbs/include/cbs/cbs_h265.h b/third-party/cbs/include/cbs/cbs_h265.h new file mode 100644 index 00000000..73c19b2d --- /dev/null +++ b/third-party/cbs/include/cbs/cbs_h265.h @@ -0,0 +1,679 @@ +/* + * 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_H265_H +#define AVCODEC_CBS_H265_H + +#include +#include + +#include "cbs_h2645.h" +#include "cbs_sei.h" +#include "hevc.h" + +typedef struct H265RawNALUnitHeader { + uint8_t nal_unit_type; + uint8_t nuh_layer_id; + uint8_t nuh_temporal_id_plus1; +} H265RawNALUnitHeader; + +typedef struct H265RawProfileTierLevel { + uint8_t general_profile_space; + uint8_t general_tier_flag; + uint8_t general_profile_idc; + + uint8_t general_profile_compatibility_flag[32]; + + uint8_t general_progressive_source_flag; + uint8_t general_interlaced_source_flag; + uint8_t general_non_packed_constraint_flag; + uint8_t general_frame_only_constraint_flag; + + uint8_t general_max_12bit_constraint_flag; + uint8_t general_max_10bit_constraint_flag; + uint8_t general_max_8bit_constraint_flag; + uint8_t general_max_422chroma_constraint_flag; + uint8_t general_max_420chroma_constraint_flag; + uint8_t general_max_monochrome_constraint_flag; + uint8_t general_intra_constraint_flag; + uint8_t general_one_picture_only_constraint_flag; + uint8_t general_lower_bit_rate_constraint_flag; + uint8_t general_max_14bit_constraint_flag; + + uint8_t general_inbld_flag; + + uint8_t general_level_idc; + + uint8_t sub_layer_profile_present_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_level_present_flag[HEVC_MAX_SUB_LAYERS]; + + uint8_t sub_layer_profile_space[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_tier_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_profile_idc[HEVC_MAX_SUB_LAYERS]; + + uint8_t sub_layer_profile_compatibility_flag[HEVC_MAX_SUB_LAYERS][32]; + + uint8_t sub_layer_progressive_source_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_interlaced_source_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_non_packed_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_frame_only_constraint_flag[HEVC_MAX_SUB_LAYERS]; + + uint8_t sub_layer_max_12bit_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_max_10bit_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_max_8bit_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_max_422chroma_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_max_420chroma_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_max_monochrome_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_intra_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_one_picture_only_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_lower_bit_rate_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_max_14bit_constraint_flag[HEVC_MAX_SUB_LAYERS]; + + uint8_t sub_layer_inbld_flag[HEVC_MAX_SUB_LAYERS]; + + uint8_t sub_layer_level_idc[HEVC_MAX_SUB_LAYERS]; +} H265RawProfileTierLevel; + +typedef struct H265RawSubLayerHRDParameters { + uint32_t bit_rate_value_minus1[HEVC_MAX_CPB_CNT]; + uint32_t cpb_size_value_minus1[HEVC_MAX_CPB_CNT]; + uint32_t cpb_size_du_value_minus1[HEVC_MAX_CPB_CNT]; + uint32_t bit_rate_du_value_minus1[HEVC_MAX_CPB_CNT]; + uint8_t cbr_flag[HEVC_MAX_CPB_CNT]; +} H265RawSubLayerHRDParameters; + +typedef struct H265RawHRDParameters { + uint8_t nal_hrd_parameters_present_flag; + uint8_t vcl_hrd_parameters_present_flag; + + uint8_t sub_pic_hrd_params_present_flag; + uint8_t tick_divisor_minus2; + uint8_t du_cpb_removal_delay_increment_length_minus1; + uint8_t sub_pic_cpb_params_in_pic_timing_sei_flag; + uint8_t dpb_output_delay_du_length_minus1; + + uint8_t bit_rate_scale; + uint8_t cpb_size_scale; + uint8_t cpb_size_du_scale; + + uint8_t initial_cpb_removal_delay_length_minus1; + uint8_t au_cpb_removal_delay_length_minus1; + uint8_t dpb_output_delay_length_minus1; + + uint8_t fixed_pic_rate_general_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t fixed_pic_rate_within_cvs_flag[HEVC_MAX_SUB_LAYERS]; + uint16_t elemental_duration_in_tc_minus1[HEVC_MAX_SUB_LAYERS]; + uint8_t low_delay_hrd_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t cpb_cnt_minus1[HEVC_MAX_SUB_LAYERS]; + H265RawSubLayerHRDParameters nal_sub_layer_hrd_parameters[HEVC_MAX_SUB_LAYERS]; + H265RawSubLayerHRDParameters vcl_sub_layer_hrd_parameters[HEVC_MAX_SUB_LAYERS]; +} H265RawHRDParameters; + +typedef struct H265RawVUI { + uint8_t aspect_ratio_info_present_flag; + uint8_t aspect_ratio_idc; + uint16_t sar_width; + uint16_t sar_height; + + uint8_t overscan_info_present_flag; + uint8_t overscan_appropriate_flag; + + uint8_t video_signal_type_present_flag; + uint8_t video_format; + uint8_t video_full_range_flag; + uint8_t colour_description_present_flag; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + + uint8_t chroma_loc_info_present_flag; + uint8_t chroma_sample_loc_type_top_field; + uint8_t chroma_sample_loc_type_bottom_field; + + uint8_t neutral_chroma_indication_flag; + uint8_t field_seq_flag; + uint8_t frame_field_info_present_flag; + + uint8_t default_display_window_flag; + uint16_t def_disp_win_left_offset; + uint16_t def_disp_win_right_offset; + uint16_t def_disp_win_top_offset; + uint16_t def_disp_win_bottom_offset; + + uint8_t vui_timing_info_present_flag; + uint32_t vui_num_units_in_tick; + uint32_t vui_time_scale; + uint8_t vui_poc_proportional_to_timing_flag; + uint32_t vui_num_ticks_poc_diff_one_minus1; + uint8_t vui_hrd_parameters_present_flag; + H265RawHRDParameters hrd_parameters; + + uint8_t bitstream_restriction_flag; + uint8_t tiles_fixed_structure_flag; + uint8_t motion_vectors_over_pic_boundaries_flag; + uint8_t restricted_ref_pic_lists_flag; + uint16_t min_spatial_segmentation_idc; + uint8_t max_bytes_per_pic_denom; + uint8_t max_bits_per_min_cu_denom; + uint8_t log2_max_mv_length_horizontal; + uint8_t log2_max_mv_length_vertical; +} H265RawVUI; + +typedef struct H265RawExtensionData { + uint8_t *data; + AVBufferRef *data_ref; + size_t bit_length; +} H265RawExtensionData; + +typedef struct H265RawVPS { + H265RawNALUnitHeader nal_unit_header; + + uint8_t vps_video_parameter_set_id; + + uint8_t vps_base_layer_internal_flag; + uint8_t vps_base_layer_available_flag; + uint8_t vps_max_layers_minus1; + uint8_t vps_max_sub_layers_minus1; + uint8_t vps_temporal_id_nesting_flag; + + H265RawProfileTierLevel profile_tier_level; + + uint8_t vps_sub_layer_ordering_info_present_flag; + uint8_t vps_max_dec_pic_buffering_minus1[HEVC_MAX_SUB_LAYERS]; + uint8_t vps_max_num_reorder_pics[HEVC_MAX_SUB_LAYERS]; + uint32_t vps_max_latency_increase_plus1[HEVC_MAX_SUB_LAYERS]; + + uint8_t vps_max_layer_id; + uint16_t vps_num_layer_sets_minus1; + uint8_t layer_id_included_flag[HEVC_MAX_LAYER_SETS][HEVC_MAX_LAYERS]; + + uint8_t vps_timing_info_present_flag; + uint32_t vps_num_units_in_tick; + uint32_t vps_time_scale; + uint8_t vps_poc_proportional_to_timing_flag; + uint32_t vps_num_ticks_poc_diff_one_minus1; + uint16_t vps_num_hrd_parameters; + uint16_t hrd_layer_set_idx[HEVC_MAX_LAYER_SETS]; + uint8_t cprms_present_flag[HEVC_MAX_LAYER_SETS]; + H265RawHRDParameters hrd_parameters[HEVC_MAX_LAYER_SETS]; + + uint8_t vps_extension_flag; + H265RawExtensionData extension_data; +} H265RawVPS; + +typedef struct H265RawSTRefPicSet { + uint8_t inter_ref_pic_set_prediction_flag; + + uint8_t delta_idx_minus1; + uint8_t delta_rps_sign; + uint16_t abs_delta_rps_minus1; + + uint8_t used_by_curr_pic_flag[HEVC_MAX_REFS]; + uint8_t use_delta_flag[HEVC_MAX_REFS]; + + uint8_t num_negative_pics; + uint8_t num_positive_pics; + uint16_t delta_poc_s0_minus1[HEVC_MAX_REFS]; + uint8_t used_by_curr_pic_s0_flag[HEVC_MAX_REFS]; + uint16_t delta_poc_s1_minus1[HEVC_MAX_REFS]; + uint8_t used_by_curr_pic_s1_flag[HEVC_MAX_REFS]; +} H265RawSTRefPicSet; + +typedef struct H265RawScalingList { + uint8_t scaling_list_pred_mode_flag[4][6]; + uint8_t scaling_list_pred_matrix_id_delta[4][6]; + int16_t scaling_list_dc_coef_minus8[4][6]; + int8_t scaling_list_delta_coeff[4][6][64]; +} H265RawScalingList; + +typedef struct H265RawSPS { + H265RawNALUnitHeader nal_unit_header; + + uint8_t sps_video_parameter_set_id; + + uint8_t sps_max_sub_layers_minus1; + uint8_t sps_temporal_id_nesting_flag; + + H265RawProfileTierLevel profile_tier_level; + + uint8_t sps_seq_parameter_set_id; + + uint8_t chroma_format_idc; + uint8_t separate_colour_plane_flag; + + uint16_t pic_width_in_luma_samples; + uint16_t pic_height_in_luma_samples; + + uint8_t conformance_window_flag; + uint16_t conf_win_left_offset; + uint16_t conf_win_right_offset; + uint16_t conf_win_top_offset; + uint16_t conf_win_bottom_offset; + + uint8_t bit_depth_luma_minus8; + uint8_t bit_depth_chroma_minus8; + + uint8_t log2_max_pic_order_cnt_lsb_minus4; + + uint8_t sps_sub_layer_ordering_info_present_flag; + uint8_t sps_max_dec_pic_buffering_minus1[HEVC_MAX_SUB_LAYERS]; + uint8_t sps_max_num_reorder_pics[HEVC_MAX_SUB_LAYERS]; + uint32_t sps_max_latency_increase_plus1[HEVC_MAX_SUB_LAYERS]; + + uint8_t log2_min_luma_coding_block_size_minus3; + uint8_t log2_diff_max_min_luma_coding_block_size; + uint8_t log2_min_luma_transform_block_size_minus2; + uint8_t log2_diff_max_min_luma_transform_block_size; + uint8_t max_transform_hierarchy_depth_inter; + uint8_t max_transform_hierarchy_depth_intra; + + uint8_t scaling_list_enabled_flag; + uint8_t sps_scaling_list_data_present_flag; + H265RawScalingList scaling_list; + + uint8_t amp_enabled_flag; + uint8_t sample_adaptive_offset_enabled_flag; + + uint8_t pcm_enabled_flag; + uint8_t pcm_sample_bit_depth_luma_minus1; + uint8_t pcm_sample_bit_depth_chroma_minus1; + uint8_t log2_min_pcm_luma_coding_block_size_minus3; + uint8_t log2_diff_max_min_pcm_luma_coding_block_size; + uint8_t pcm_loop_filter_disabled_flag; + + uint8_t num_short_term_ref_pic_sets; + H265RawSTRefPicSet st_ref_pic_set[HEVC_MAX_SHORT_TERM_REF_PIC_SETS]; + + uint8_t long_term_ref_pics_present_flag; + uint8_t num_long_term_ref_pics_sps; + uint16_t lt_ref_pic_poc_lsb_sps[HEVC_MAX_LONG_TERM_REF_PICS]; + uint8_t used_by_curr_pic_lt_sps_flag[HEVC_MAX_LONG_TERM_REF_PICS]; + + uint8_t sps_temporal_mvp_enabled_flag; + uint8_t strong_intra_smoothing_enabled_flag; + + uint8_t vui_parameters_present_flag; + H265RawVUI vui; + + uint8_t sps_extension_present_flag; + uint8_t sps_range_extension_flag; + uint8_t sps_multilayer_extension_flag; + uint8_t sps_3d_extension_flag; + uint8_t sps_scc_extension_flag; + uint8_t sps_extension_4bits; + + H265RawExtensionData extension_data; + + // Range extension. + uint8_t transform_skip_rotation_enabled_flag; + uint8_t transform_skip_context_enabled_flag; + uint8_t implicit_rdpcm_enabled_flag; + uint8_t explicit_rdpcm_enabled_flag; + uint8_t extended_precision_processing_flag; + uint8_t intra_smoothing_disabled_flag; + uint8_t high_precision_offsets_enabled_flag; + uint8_t persistent_rice_adaptation_enabled_flag; + uint8_t cabac_bypass_alignment_enabled_flag; + + // Screen content coding extension. + uint8_t sps_curr_pic_ref_enabled_flag; + uint8_t palette_mode_enabled_flag; + uint8_t palette_max_size; + uint8_t delta_palette_max_predictor_size; + uint8_t sps_palette_predictor_initializer_present_flag; + uint8_t sps_num_palette_predictor_initializer_minus1; + uint16_t sps_palette_predictor_initializers[3][128]; + + uint8_t motion_vector_resolution_control_idc; + uint8_t intra_boundary_filtering_disable_flag; +} H265RawSPS; + +typedef struct H265RawPPS { + H265RawNALUnitHeader nal_unit_header; + + uint8_t pps_pic_parameter_set_id; + uint8_t pps_seq_parameter_set_id; + + uint8_t dependent_slice_segments_enabled_flag; + uint8_t output_flag_present_flag; + uint8_t num_extra_slice_header_bits; + uint8_t sign_data_hiding_enabled_flag; + uint8_t cabac_init_present_flag; + + uint8_t num_ref_idx_l0_default_active_minus1; + uint8_t num_ref_idx_l1_default_active_minus1; + + int8_t init_qp_minus26; + + uint8_t constrained_intra_pred_flag; + uint8_t transform_skip_enabled_flag; + uint8_t cu_qp_delta_enabled_flag; + uint8_t diff_cu_qp_delta_depth; + + int8_t pps_cb_qp_offset; + int8_t pps_cr_qp_offset; + uint8_t pps_slice_chroma_qp_offsets_present_flag; + + uint8_t weighted_pred_flag; + uint8_t weighted_bipred_flag; + + uint8_t transquant_bypass_enabled_flag; + uint8_t tiles_enabled_flag; + uint8_t entropy_coding_sync_enabled_flag; + + uint8_t num_tile_columns_minus1; + uint8_t num_tile_rows_minus1; + uint8_t uniform_spacing_flag; + uint16_t column_width_minus1[HEVC_MAX_TILE_COLUMNS]; + uint16_t row_height_minus1[HEVC_MAX_TILE_ROWS]; + uint8_t loop_filter_across_tiles_enabled_flag; + + uint8_t pps_loop_filter_across_slices_enabled_flag; + uint8_t deblocking_filter_control_present_flag; + uint8_t deblocking_filter_override_enabled_flag; + uint8_t pps_deblocking_filter_disabled_flag; + int8_t pps_beta_offset_div2; + int8_t pps_tc_offset_div2; + + uint8_t pps_scaling_list_data_present_flag; + H265RawScalingList scaling_list; + + uint8_t lists_modification_present_flag; + uint8_t log2_parallel_merge_level_minus2; + + uint8_t slice_segment_header_extension_present_flag; + + uint8_t pps_extension_present_flag; + uint8_t pps_range_extension_flag; + uint8_t pps_multilayer_extension_flag; + uint8_t pps_3d_extension_flag; + uint8_t pps_scc_extension_flag; + uint8_t pps_extension_4bits; + + H265RawExtensionData extension_data; + + // Range extension. + uint8_t log2_max_transform_skip_block_size_minus2; + uint8_t cross_component_prediction_enabled_flag; + uint8_t chroma_qp_offset_list_enabled_flag; + uint8_t diff_cu_chroma_qp_offset_depth; + uint8_t chroma_qp_offset_list_len_minus1; + int8_t cb_qp_offset_list[6]; + int8_t cr_qp_offset_list[6]; + uint8_t log2_sao_offset_scale_luma; + uint8_t log2_sao_offset_scale_chroma; + + // Screen content coding extension. + uint8_t pps_curr_pic_ref_enabled_flag; + uint8_t residual_adaptive_colour_transform_enabled_flag; + uint8_t pps_slice_act_qp_offsets_present_flag; + int8_t pps_act_y_qp_offset_plus5; + int8_t pps_act_cb_qp_offset_plus5; + int8_t pps_act_cr_qp_offset_plus3; + + uint8_t pps_palette_predictor_initializer_present_flag; + uint8_t pps_num_palette_predictor_initializer; + uint8_t monochrome_palette_flag; + uint8_t luma_bit_depth_entry_minus8; + uint8_t chroma_bit_depth_entry_minus8; + uint16_t pps_palette_predictor_initializers[3][128]; +} H265RawPPS; + +typedef struct H265RawAUD { + H265RawNALUnitHeader nal_unit_header; + + uint8_t pic_type; +} H265RawAUD; + +typedef struct H265RawSliceHeader { + H265RawNALUnitHeader nal_unit_header; + + uint8_t first_slice_segment_in_pic_flag; + uint8_t no_output_of_prior_pics_flag; + uint8_t slice_pic_parameter_set_id; + + uint8_t dependent_slice_segment_flag; + uint16_t slice_segment_address; + + uint8_t slice_reserved_flag[8]; + uint8_t slice_type; + + uint8_t pic_output_flag; + uint8_t colour_plane_id; + + uint16_t slice_pic_order_cnt_lsb; + + uint8_t short_term_ref_pic_set_sps_flag; + H265RawSTRefPicSet short_term_ref_pic_set; + uint8_t short_term_ref_pic_set_idx; + + uint8_t num_long_term_sps; + uint8_t num_long_term_pics; + uint8_t lt_idx_sps[HEVC_MAX_REFS]; + uint8_t poc_lsb_lt[HEVC_MAX_REFS]; + uint8_t used_by_curr_pic_lt_flag[HEVC_MAX_REFS]; + uint8_t delta_poc_msb_present_flag[HEVC_MAX_REFS]; + uint32_t delta_poc_msb_cycle_lt[HEVC_MAX_REFS]; + + uint8_t slice_temporal_mvp_enabled_flag; + + uint8_t slice_sao_luma_flag; + uint8_t slice_sao_chroma_flag; + + uint8_t num_ref_idx_active_override_flag; + uint8_t num_ref_idx_l0_active_minus1; + uint8_t num_ref_idx_l1_active_minus1; + + uint8_t ref_pic_list_modification_flag_l0; + uint8_t list_entry_l0[HEVC_MAX_REFS]; + uint8_t ref_pic_list_modification_flag_l1; + uint8_t list_entry_l1[HEVC_MAX_REFS]; + + uint8_t mvd_l1_zero_flag; + uint8_t cabac_init_flag; + uint8_t collocated_from_l0_flag; + uint8_t collocated_ref_idx; + + uint8_t luma_log2_weight_denom; + int8_t delta_chroma_log2_weight_denom; + uint8_t luma_weight_l0_flag[HEVC_MAX_REFS]; + uint8_t chroma_weight_l0_flag[HEVC_MAX_REFS]; + int8_t delta_luma_weight_l0[HEVC_MAX_REFS]; + int16_t luma_offset_l0[HEVC_MAX_REFS]; + int8_t delta_chroma_weight_l0[HEVC_MAX_REFS][2]; + int16_t chroma_offset_l0[HEVC_MAX_REFS][2]; + uint8_t luma_weight_l1_flag[HEVC_MAX_REFS]; + uint8_t chroma_weight_l1_flag[HEVC_MAX_REFS]; + int8_t delta_luma_weight_l1[HEVC_MAX_REFS]; + int16_t luma_offset_l1[HEVC_MAX_REFS]; + int8_t delta_chroma_weight_l1[HEVC_MAX_REFS][2]; + int16_t chroma_offset_l1[HEVC_MAX_REFS][2]; + + uint8_t five_minus_max_num_merge_cand; + uint8_t use_integer_mv_flag; + + int8_t slice_qp_delta; + int8_t slice_cb_qp_offset; + int8_t slice_cr_qp_offset; + int8_t slice_act_y_qp_offset; + int8_t slice_act_cb_qp_offset; + int8_t slice_act_cr_qp_offset; + uint8_t cu_chroma_qp_offset_enabled_flag; + + uint8_t deblocking_filter_override_flag; + uint8_t slice_deblocking_filter_disabled_flag; + int8_t slice_beta_offset_div2; + int8_t slice_tc_offset_div2; + uint8_t slice_loop_filter_across_slices_enabled_flag; + + uint16_t num_entry_point_offsets; + uint8_t offset_len_minus1; + uint32_t entry_point_offset_minus1[HEVC_MAX_ENTRY_POINT_OFFSETS]; + + uint16_t slice_segment_header_extension_length; + uint8_t slice_segment_header_extension_data_byte[256]; +} H265RawSliceHeader; + + +typedef struct H265RawSlice { + H265RawSliceHeader header; + + uint8_t *data; + AVBufferRef *data_ref; + size_t data_size; + int data_bit_start; +} H265RawSlice; + + +typedef struct H265RawSEIBufferingPeriod { + uint8_t bp_seq_parameter_set_id; + uint8_t irap_cpb_params_present_flag; + uint32_t cpb_delay_offset; + uint32_t dpb_delay_offset; + uint8_t concatenation_flag; + uint32_t au_cpb_removal_delay_delta_minus1; + + uint32_t nal_initial_cpb_removal_delay[HEVC_MAX_CPB_CNT]; + uint32_t nal_initial_cpb_removal_offset[HEVC_MAX_CPB_CNT]; + uint32_t nal_initial_alt_cpb_removal_delay[HEVC_MAX_CPB_CNT]; + uint32_t nal_initial_alt_cpb_removal_offset[HEVC_MAX_CPB_CNT]; + + uint32_t vcl_initial_cpb_removal_delay[HEVC_MAX_CPB_CNT]; + uint32_t vcl_initial_cpb_removal_offset[HEVC_MAX_CPB_CNT]; + uint32_t vcl_initial_alt_cpb_removal_delay[HEVC_MAX_CPB_CNT]; + uint32_t vcl_initial_alt_cpb_removal_offset[HEVC_MAX_CPB_CNT]; + + uint8_t use_alt_cpb_params_flag; +} H265RawSEIBufferingPeriod; + +typedef struct H265RawSEIPicTiming { + uint8_t pic_struct; + uint8_t source_scan_type; + uint8_t duplicate_flag; + + uint32_t au_cpb_removal_delay_minus1; + uint32_t pic_dpb_output_delay; + uint32_t pic_dpb_output_du_delay; + + uint16_t num_decoding_units_minus1; + uint8_t du_common_cpb_removal_delay_flag; + uint32_t du_common_cpb_removal_delay_increment_minus1; + uint16_t num_nalus_in_du_minus1[HEVC_MAX_SLICE_SEGMENTS]; + uint32_t du_cpb_removal_delay_increment_minus1[HEVC_MAX_SLICE_SEGMENTS]; +} H265RawSEIPicTiming; + +typedef struct H265RawSEIPanScanRect { + uint32_t pan_scan_rect_id; + uint8_t pan_scan_rect_cancel_flag; + uint8_t pan_scan_cnt_minus1; + int32_t pan_scan_rect_left_offset[3]; + int32_t pan_scan_rect_right_offset[3]; + int32_t pan_scan_rect_top_offset[3]; + int32_t pan_scan_rect_bottom_offset[3]; + uint16_t pan_scan_rect_persistence_flag; +} H265RawSEIPanScanRect; + +typedef struct H265RawSEIRecoveryPoint { + int16_t recovery_poc_cnt; + uint8_t exact_match_flag; + uint8_t broken_link_flag; +} H265RawSEIRecoveryPoint; + +typedef struct H265RawSEIDisplayOrientation { + uint8_t display_orientation_cancel_flag; + uint8_t hor_flip; + uint8_t ver_flip; + uint16_t anticlockwise_rotation; + uint16_t display_orientation_repetition_period; + uint8_t display_orientation_persistence_flag; +} H265RawSEIDisplayOrientation; + +typedef struct H265RawSEIActiveParameterSets { + uint8_t active_video_parameter_set_id; + uint8_t self_contained_cvs_flag; + uint8_t no_parameter_set_update_flag; + uint8_t num_sps_ids_minus1; + uint8_t active_seq_parameter_set_id[HEVC_MAX_SPS_COUNT]; + uint8_t layer_sps_idx[HEVC_MAX_LAYERS]; +} H265RawSEIActiveParameterSets; + +typedef struct H265RawSEIDecodedPictureHash { + uint8_t hash_type; + uint8_t picture_md5[3][16]; + uint16_t picture_crc[3]; + uint32_t picture_checksum[3]; +} H265RawSEIDecodedPictureHash; + +typedef struct H265RawSEITimeCode { + uint8_t num_clock_ts; + uint8_t clock_timestamp_flag[3]; + uint8_t units_field_based_flag[3]; + uint8_t counting_type[3]; + uint8_t full_timestamp_flag[3]; + uint8_t discontinuity_flag[3]; + uint8_t cnt_dropped_flag[3]; + uint16_t n_frames[3]; + uint8_t seconds_value[3]; + uint8_t minutes_value[3]; + uint8_t hours_value[3]; + uint8_t seconds_flag[3]; + uint8_t minutes_flag[3]; + uint8_t hours_flag[3]; + uint8_t time_offset_length[3]; + int32_t time_offset_value[3]; +} H265RawSEITimeCode; + +typedef struct H265RawSEIAlphaChannelInfo { + uint8_t alpha_channel_cancel_flag; + uint8_t alpha_channel_use_idc; + uint8_t alpha_channel_bit_depth_minus8; + uint16_t alpha_transparent_value; + uint16_t alpha_opaque_value; + uint8_t alpha_channel_incr_flag; + uint8_t alpha_channel_clip_flag; + uint8_t alpha_channel_clip_type_flag; +} H265RawSEIAlphaChannelInfo; + +typedef struct H265RawSEI { + H265RawNALUnitHeader nal_unit_header; + SEIRawMessageList message_list; +} H265RawSEI; + +typedef struct CodedBitstreamH265Context { + // Reader/writer context in common with the H.264 implementation. + CodedBitstreamH2645Context common; + + // All currently available parameter sets. These are updated when + // any parameter set NAL unit is read/written with this context. + AVBufferRef *vps_ref[HEVC_MAX_VPS_COUNT]; + AVBufferRef *sps_ref[HEVC_MAX_SPS_COUNT]; + AVBufferRef *pps_ref[HEVC_MAX_PPS_COUNT]; + H265RawVPS *vps[HEVC_MAX_VPS_COUNT]; + H265RawSPS *sps[HEVC_MAX_SPS_COUNT]; + H265RawPPS *pps[HEVC_MAX_PPS_COUNT]; + + // The currently active parameter sets. These are updated when any + // NAL unit refers to the relevant parameter set. These pointers + // must also be present in the arrays above. + const H265RawVPS *active_vps; + const H265RawSPS *active_sps; + const H265RawPPS *active_pps; +} CodedBitstreamH265Context; + + +#endif /* AVCODEC_CBS_H265_H */ diff --git a/third-party/cbs/include/cbs/cbs_jpeg.h b/third-party/cbs/include/cbs/cbs_jpeg.h new file mode 100644 index 00000000..c2ee8c5e --- /dev/null +++ b/third-party/cbs/include/cbs/cbs_jpeg.h @@ -0,0 +1,123 @@ +/* + * 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_JPEG_H +#define AVCODEC_CBS_JPEG_H + +#include +#include + +#include + + +enum { + JPEG_MARKER_SOF0 = 0xc0, + JPEG_MARKER_SOF1 = 0xc1, + JPEG_MARKER_SOF2 = 0xc2, + JPEG_MARKER_SOF3 = 0xc3, + + JPEG_MARKER_DHT = 0xc4, + JPEG_MARKER_SOI = 0xd8, + JPEG_MARKER_EOI = 0xd9, + JPEG_MARKER_SOS = 0xda, + JPEG_MARKER_DQT = 0xdb, + + JPEG_MARKER_APPN = 0xe0, + JPEG_MARKER_JPGN = 0xf0, + JPEG_MARKER_COM = 0xfe, +}; + +enum { + JPEG_MAX_COMPONENTS = 255, + + JPEG_MAX_HEIGHT = 65535, + JPEG_MAX_WIDTH = 65535, +}; + + +typedef struct JPEGRawFrameHeader { + uint16_t Lf; + uint8_t P; + uint16_t Y; + uint16_t X; + uint16_t Nf; + + uint8_t C[JPEG_MAX_COMPONENTS]; + uint8_t H[JPEG_MAX_COMPONENTS]; + uint8_t V[JPEG_MAX_COMPONENTS]; + uint8_t Tq[JPEG_MAX_COMPONENTS]; +} JPEGRawFrameHeader; + +typedef struct JPEGRawScanHeader { + uint16_t Ls; + uint8_t Ns; + + uint8_t Cs[JPEG_MAX_COMPONENTS]; + uint8_t Td[JPEG_MAX_COMPONENTS]; + uint8_t Ta[JPEG_MAX_COMPONENTS]; + + uint8_t Ss; + uint8_t Se; + uint8_t Ah; + uint8_t Al; +} JPEGRawScanHeader; + +typedef struct JPEGRawScan { + JPEGRawScanHeader header; + uint8_t *data; + AVBufferRef *data_ref; + size_t data_size; +} JPEGRawScan; + +typedef struct JPEGRawQuantisationTable { + uint8_t Pq; + uint8_t Tq; + uint16_t Q[64]; +} JPEGRawQuantisationTable; + +typedef struct JPEGRawQuantisationTableSpecification { + uint16_t Lq; + JPEGRawQuantisationTable table[4]; +} JPEGRawQuantisationTableSpecification; + +typedef struct JPEGRawHuffmanTable { + uint8_t Tc; + uint8_t Th; + uint8_t L[16]; + uint8_t V[224]; +} JPEGRawHuffmanTable; + +typedef struct JPEGRawHuffmanTableSpecification { + uint16_t Lh; + JPEGRawHuffmanTable table[8]; +} JPEGRawHuffmanTableSpecification; + +typedef struct JPEGRawApplicationData { + uint16_t Lp; + uint8_t *Ap; + AVBufferRef *Ap_ref; +} JPEGRawApplicationData; + +typedef struct JPEGRawComment { + uint16_t Lc; + uint8_t *Cm; + AVBufferRef *Cm_ref; +} JPEGRawComment; + + +#endif /* AVCODEC_CBS_JPEG_H */ diff --git a/third-party/cbs/include/cbs/cbs_mpeg2.h b/third-party/cbs/include/cbs/cbs_mpeg2.h new file mode 100644 index 00000000..858cb543 --- /dev/null +++ b/third-party/cbs/include/cbs/cbs_mpeg2.h @@ -0,0 +1,231 @@ +/* + * 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_MPEG2_H +#define AVCODEC_CBS_MPEG2_H + +#include +#include + +#include + + +enum { + MPEG2_START_PICTURE = 0x00, + MPEG2_START_SLICE_MIN = 0x01, + MPEG2_START_SLICE_MAX = 0xaf, + MPEG2_START_USER_DATA = 0xb2, + MPEG2_START_SEQUENCE_HEADER = 0xb3, + MPEG2_START_SEQUENCE_ERROR = 0xb4, + MPEG2_START_EXTENSION = 0xb5, + MPEG2_START_SEQUENCE_END = 0xb7, + MPEG2_START_GROUP = 0xb8, +}; + +#define MPEG2_START_IS_SLICE(type) \ + ((type) >= MPEG2_START_SLICE_MIN && \ + (type) <= MPEG2_START_SLICE_MAX) + +enum { + MPEG2_EXTENSION_SEQUENCE = 0x1, + MPEG2_EXTENSION_SEQUENCE_DISPLAY = 0x2, + MPEG2_EXTENSION_QUANT_MATRIX = 0x3, + MPEG2_EXTENSION_COPYRIGHT = 0x4, + MPEG2_EXTENSION_SEQUENCE_SCALABLE = 0x5, + MPEG2_EXTENSION_PICTURE_DISPLAY = 0x7, + MPEG2_EXTENSION_PICTURE_CODING = 0x8, + MPEG2_EXTENSION_PICTURE_SPATIAL_SCALABLE = 0x9, + MPEG2_EXTENSION_PICTURE_TEMPORAL_SCALABLE = 0xa, + MPEG2_EXTENSION_CAMERA_PARAMETERS = 0xb, + MPEG2_EXTENSION_ITU_T = 0xc, +}; + + +typedef struct MPEG2RawSequenceHeader { + uint8_t sequence_header_code; + + uint16_t horizontal_size_value; + uint16_t vertical_size_value; + uint8_t aspect_ratio_information; + uint8_t frame_rate_code; + uint32_t bit_rate_value; + uint16_t vbv_buffer_size_value; + uint8_t constrained_parameters_flag; + + uint8_t load_intra_quantiser_matrix; + uint8_t intra_quantiser_matrix[64]; + uint8_t load_non_intra_quantiser_matrix; + uint8_t non_intra_quantiser_matrix[64]; +} MPEG2RawSequenceHeader; + +typedef struct MPEG2RawUserData { + uint8_t user_data_start_code; + + uint8_t *user_data; + AVBufferRef *user_data_ref; + size_t user_data_length; +} MPEG2RawUserData; + +typedef struct MPEG2RawSequenceExtension { + uint8_t profile_and_level_indication; + uint8_t progressive_sequence; + uint8_t chroma_format; + uint8_t horizontal_size_extension; + uint8_t vertical_size_extension; + uint16_t bit_rate_extension; + uint8_t vbv_buffer_size_extension; + uint8_t low_delay; + uint8_t frame_rate_extension_n; + uint8_t frame_rate_extension_d; +} MPEG2RawSequenceExtension; + +typedef struct MPEG2RawSequenceDisplayExtension { + uint8_t video_format; + + uint8_t colour_description; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + + uint16_t display_horizontal_size; + uint16_t display_vertical_size; +} MPEG2RawSequenceDisplayExtension; + +typedef struct MPEG2RawGroupOfPicturesHeader { + uint8_t group_start_code; + + uint32_t time_code; + uint8_t closed_gop; + uint8_t broken_link; +} MPEG2RawGroupOfPicturesHeader; + +typedef struct MPEG2RawExtraInformation { + uint8_t *extra_information; + AVBufferRef *extra_information_ref; + size_t extra_information_length; +} MPEG2RawExtraInformation; + +typedef struct MPEG2RawPictureHeader { + uint8_t picture_start_code; + + uint16_t temporal_reference; + uint8_t picture_coding_type; + uint16_t vbv_delay; + + uint8_t full_pel_forward_vector; + uint8_t forward_f_code; + uint8_t full_pel_backward_vector; + uint8_t backward_f_code; + + MPEG2RawExtraInformation extra_information_picture; +} MPEG2RawPictureHeader; + +typedef struct MPEG2RawPictureCodingExtension { + uint8_t f_code[2][2]; + + uint8_t intra_dc_precision; + uint8_t picture_structure; + uint8_t top_field_first; + uint8_t frame_pred_frame_dct; + uint8_t concealment_motion_vectors; + uint8_t q_scale_type; + uint8_t intra_vlc_format; + uint8_t alternate_scan; + uint8_t repeat_first_field; + uint8_t chroma_420_type; + uint8_t progressive_frame; + + uint8_t composite_display_flag; + uint8_t v_axis; + uint8_t field_sequence; + uint8_t sub_carrier; + uint8_t burst_amplitude; + uint8_t sub_carrier_phase; +} MPEG2RawPictureCodingExtension; + +typedef struct MPEG2RawQuantMatrixExtension { + uint8_t load_intra_quantiser_matrix; + uint8_t intra_quantiser_matrix[64]; + uint8_t load_non_intra_quantiser_matrix; + uint8_t non_intra_quantiser_matrix[64]; + uint8_t load_chroma_intra_quantiser_matrix; + uint8_t chroma_intra_quantiser_matrix[64]; + uint8_t load_chroma_non_intra_quantiser_matrix; + uint8_t chroma_non_intra_quantiser_matrix[64]; +} MPEG2RawQuantMatrixExtension; + +typedef struct MPEG2RawPictureDisplayExtension { + int16_t frame_centre_horizontal_offset[3]; + int16_t frame_centre_vertical_offset[3]; +} MPEG2RawPictureDisplayExtension; + +typedef struct MPEG2RawExtensionData { + uint8_t extension_start_code; + uint8_t extension_start_code_identifier; + + union { + MPEG2RawSequenceExtension sequence; + MPEG2RawSequenceDisplayExtension sequence_display; + MPEG2RawQuantMatrixExtension quant_matrix; + MPEG2RawPictureCodingExtension picture_coding; + MPEG2RawPictureDisplayExtension picture_display; + } data; +} MPEG2RawExtensionData; + +typedef struct MPEG2RawSliceHeader { + uint8_t slice_vertical_position; + + uint8_t slice_vertical_position_extension; + uint8_t priority_breakpoint; + + uint8_t quantiser_scale_code; + + uint8_t slice_extension_flag; + uint8_t intra_slice; + uint8_t slice_picture_id_enable; + uint8_t slice_picture_id; + + MPEG2RawExtraInformation extra_information_slice; +} MPEG2RawSliceHeader; + +typedef struct MPEG2RawSlice { + MPEG2RawSliceHeader header; + + uint8_t *data; + AVBufferRef *data_ref; + size_t data_size; + int data_bit_start; +} MPEG2RawSlice; + +typedef struct MPEG2RawSequenceEnd { + uint8_t sequence_end_code; +} MPEG2RawSequenceEnd; + + +typedef struct CodedBitstreamMPEG2Context { + // Elements stored in headers which are required for other decoding. + uint16_t horizontal_size; + uint16_t vertical_size; + uint8_t scalable; + uint8_t scalable_mode; + uint8_t progressive_sequence; + uint8_t number_of_frame_centre_offsets; +} CodedBitstreamMPEG2Context; + + +#endif /* AVCODEC_CBS_MPEG2_H */ diff --git a/third-party/cbs/include/cbs/cbs_sei.h b/third-party/cbs/include/cbs/cbs_sei.h new file mode 100644 index 00000000..d20bdda6 --- /dev/null +++ b/third-party/cbs/include/cbs/cbs_sei.h @@ -0,0 +1,200 @@ +/* + * 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_SEI_H +#define AVCODEC_CBS_SEI_H + +#include +#include + +#include + +#include "cbs.h" +#include "sei.h" + + +typedef struct SEIRawFillerPayload { + uint32_t payload_size; +} SEIRawFillerPayload; + +typedef struct SEIRawUserDataRegistered { + uint8_t itu_t_t35_country_code; + uint8_t itu_t_t35_country_code_extension_byte; + uint8_t *data; + AVBufferRef *data_ref; + size_t data_length; +} SEIRawUserDataRegistered; + +typedef struct SEIRawUserDataUnregistered { + uint8_t uuid_iso_iec_11578[16]; + uint8_t *data; + AVBufferRef *data_ref; + size_t data_length; +} SEIRawUserDataUnregistered; + +typedef struct SEIRawMasteringDisplayColourVolume { + uint16_t display_primaries_x[3]; + uint16_t display_primaries_y[3]; + uint16_t white_point_x; + uint16_t white_point_y; + uint32_t max_display_mastering_luminance; + uint32_t min_display_mastering_luminance; +} SEIRawMasteringDisplayColourVolume; + +typedef struct SEIRawContentLightLevelInfo { + uint16_t max_content_light_level; + uint16_t max_pic_average_light_level; +} SEIRawContentLightLevelInfo; + +typedef struct SEIRawAlternativeTransferCharacteristics { + uint8_t preferred_transfer_characteristics; +} SEIRawAlternativeTransferCharacteristics; + +typedef struct SEIRawMessage { + uint32_t payload_type; + uint32_t payload_size; + void *payload; + AVBufferRef *payload_ref; + uint8_t *extension_data; + AVBufferRef *extension_data_ref; + size_t extension_bit_length; +} SEIRawMessage; + +typedef struct SEIRawMessageList { + SEIRawMessage *messages; + int nb_messages; + int nb_messages_allocated; +} SEIRawMessageList; + + +typedef struct SEIMessageState { + // The type of the payload being written. + uint32_t payload_type; + // When reading, contains the size of the payload to allow finding the + // end of variable-length fields (such as user_data_payload_byte[]). + // (When writing, the size will be derived from the total number of + // bytes actually written.) + uint32_t payload_size; + // When writing, indicates that payload extension data is present so + // all extended fields must be written. May be updated by the writer + // to indicate that extended fields have been written, so the extension + // end bits must be written too. + uint8_t extension_present; +} SEIMessageState; + +struct GetBitContext; +struct PutBitContext; + +typedef int (*SEIMessageReadFunction)(CodedBitstreamContext *ctx, + struct GetBitContext *rw, + void *current, + SEIMessageState *sei); + +typedef int (*SEIMessageWriteFunction)(CodedBitstreamContext *ctx, + struct PutBitContext *rw, + void *current, + SEIMessageState *sei); + +typedef struct SEIMessageTypeDescriptor { + // Payload type for the message. (-1 in this field ends a list.) + int type; + // Valid in a prefix SEI NAL unit (always for H.264). + uint8_t prefix; + // Valid in a suffix SEI NAL unit (never for H.264). + uint8_t suffix; + // Size of the decomposed structure. + size_t size; + // Read bitstream into SEI message. + SEIMessageReadFunction read; + // Write bitstream from SEI message. + SEIMessageWriteFunction write; +} SEIMessageTypeDescriptor; + +// Macro for the read/write pair. The clumsy cast is needed because the +// current pointer is typed in all of the read/write functions but has to +// be void here to fit all cases. +#define SEI_MESSAGE_RW(codec, name) \ + .read = (SEIMessageReadFunction)cbs_##codec##_read_##name, \ + .write = (SEIMessageWriteFunction)cbs_##codec##_write_##name + +// End-of-list sentinel element. +#define SEI_MESSAGE_TYPE_END \ + { .type = -1 } + + +/** + * Find the type descriptor for the given payload type. + * + * Returns NULL if the payload type is not known. + */ +const SEIMessageTypeDescriptor *ff_cbs_sei_find_type(CodedBitstreamContext *ctx, + int payload_type); + +/** + * Allocate a new payload for the given SEI message. + */ +int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message, + const SEIMessageTypeDescriptor *desc); + +/** + * Allocate a new empty SEI message in a message list. + * + * The new message is in place nb_messages - 1. + */ +int ff_cbs_sei_list_add(SEIRawMessageList *list); + +/** + * Free all SEI messages in a message list. + */ +void ff_cbs_sei_free_message_list(SEIRawMessageList *list); + +/** + * Add an SEI message to an access unit. + * + * Will add to an existing SEI NAL unit, or create a new one for the + * message if there is no suitable existing one. + * + * Takes a new reference to payload_buf, if set. If payload_buf is + * NULL then the new message will not be reference counted. + */ +int ff_cbs_sei_add_message(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + int prefix, + uint32_t payload_type, + void *payload_data, + AVBufferRef *payload_buf); + +/** + * Iterate over messages with the given payload type in an access unit. + * + * Set message to NULL in the first call. Returns 0 while more messages + * are available, AVERROR(ENOENT) when all messages have been found. + */ +int ff_cbs_sei_find_message(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + uint32_t payload_type, + SEIRawMessage **message); + +/** + * Delete all messages with the given payload type from an access unit. + */ +void ff_cbs_sei_delete_message_type(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + uint32_t payload_type); + +#endif /* AVCODEC_CBS_SEI_H */ diff --git a/third-party/cbs/include/cbs/cbs_vp9.h b/third-party/cbs/include/cbs/cbs_vp9.h new file mode 100644 index 00000000..62754498 --- /dev/null +++ b/third-party/cbs/include/cbs/cbs_vp9.h @@ -0,0 +1,213 @@ +/* + * 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_VP9_H +#define AVCODEC_CBS_VP9_H + +#include +#include + +#include "cbs.h" + + +// Miscellaneous constants (section 3). +enum { + VP9_REFS_PER_FRAME = 3, + + VP9_MIN_TILE_WIDTH_B64 = 4, + VP9_MAX_TILE_WIDTH_B64 = 64, + + VP9_NUM_REF_FRAMES = 8, + VP9_MAX_REF_FRAMES = 4, + + VP9_MAX_SEGMENTS = 8, + VP9_SEG_LVL_MAX = 4, +}; + +// Frame types (section 7.2). +enum { + VP9_KEY_FRAME = 0, + VP9_NON_KEY_FRAME = 1, +}; + +// Frame sync bytes (section 7.2.1). +enum { + VP9_FRAME_SYNC_0 = 0x49, + VP9_FRAME_SYNC_1 = 0x83, + VP9_FRAME_SYNC_2 = 0x42, +}; + +// Color space values (section 7.2.2). +enum { + VP9_CS_UNKNOWN = 0, + VP9_CS_BT_601 = 1, + VP9_CS_BT_709 = 2, + VP9_CS_SMPTE_170 = 3, + VP9_CS_SMPTE_240 = 4, + VP9_CS_BT_2020 = 5, + VP9_CS_RESERVED = 6, + VP9_CS_RGB = 7, +}; + +// Reference frame types (section 7.4.12). +enum { + VP9_INTRA_FRAME = 0, + VP9_LAST_FRAME = 1, + VP9_GOLDEN_FRAME = 2, + VP9_ALTREF_FRAME = 3, +}; + +// Superframe properties (section B.3). +enum { + VP9_MAX_FRAMES_IN_SUPERFRAME = 8, + + VP9_SUPERFRAME_MARKER = 6, +}; + + +typedef struct VP9RawFrameHeader { + uint8_t frame_marker; + uint8_t profile_low_bit; + uint8_t profile_high_bit; + + uint8_t show_existing_frame; + uint8_t frame_to_show_map_idx; + + uint8_t frame_type; + uint8_t show_frame; + uint8_t error_resilient_mode; + + // Color config. + uint8_t ten_or_twelve_bit; + uint8_t color_space; + uint8_t color_range; + uint8_t subsampling_x; + uint8_t subsampling_y; + + uint8_t refresh_frame_flags; + + uint8_t intra_only; + uint8_t reset_frame_context; + + uint8_t ref_frame_idx[VP9_REFS_PER_FRAME]; + uint8_t ref_frame_sign_bias[VP9_MAX_REF_FRAMES]; + + uint8_t allow_high_precision_mv; + + uint8_t refresh_frame_context; + uint8_t frame_parallel_decoding_mode; + + uint8_t frame_context_idx; + + // Frame/render size. + uint8_t found_ref[VP9_REFS_PER_FRAME]; + uint16_t frame_width_minus_1; + uint16_t frame_height_minus_1; + uint8_t render_and_frame_size_different; + uint16_t render_width_minus_1; + uint16_t render_height_minus_1; + + // Interpolation filter. + uint8_t is_filter_switchable; + uint8_t raw_interpolation_filter_type; + + // Loop filter params. + uint8_t loop_filter_level; + uint8_t loop_filter_sharpness; + uint8_t loop_filter_delta_enabled; + uint8_t loop_filter_delta_update; + uint8_t update_ref_delta[VP9_MAX_REF_FRAMES]; + int8_t loop_filter_ref_deltas[VP9_MAX_REF_FRAMES]; + uint8_t update_mode_delta[2]; + int8_t loop_filter_mode_deltas[2]; + + // Quantization params. + uint8_t base_q_idx; + int8_t delta_q_y_dc; + int8_t delta_q_uv_dc; + int8_t delta_q_uv_ac; + + // Segmentation params. + uint8_t segmentation_enabled; + uint8_t segmentation_update_map; + uint8_t segmentation_tree_probs[7]; + uint8_t segmentation_temporal_update; + uint8_t segmentation_pred_prob[3]; + uint8_t segmentation_update_data; + uint8_t segmentation_abs_or_delta_update; + uint8_t feature_enabled[VP9_MAX_SEGMENTS][VP9_SEG_LVL_MAX]; + uint8_t feature_value[VP9_MAX_SEGMENTS][VP9_SEG_LVL_MAX]; + uint8_t feature_sign[VP9_MAX_SEGMENTS][VP9_SEG_LVL_MAX]; + + // Tile info. + uint8_t tile_cols_log2; + uint8_t tile_rows_log2; + + uint16_t header_size_in_bytes; +} VP9RawFrameHeader; + +typedef struct VP9RawFrame { + VP9RawFrameHeader header; + + uint8_t *data; + AVBufferRef *data_ref; + size_t data_size; +} VP9RawFrame; + +typedef struct VP9RawSuperframeIndex { + uint8_t superframe_marker; + uint8_t bytes_per_framesize_minus_1; + uint8_t frames_in_superframe_minus_1; + uint32_t frame_sizes[VP9_MAX_FRAMES_IN_SUPERFRAME]; +} VP9RawSuperframeIndex; + +typedef struct VP9RawSuperframe { + VP9RawFrame frames[VP9_MAX_FRAMES_IN_SUPERFRAME]; + VP9RawSuperframeIndex index; +} VP9RawSuperframe; + +typedef struct VP9ReferenceFrameState { + int frame_width; // RefFrameWidth + int frame_height; // RefFrameHeight + int subsampling_x; // RefSubsamplingX + int subsampling_y; // RefSubsamplingY + int bit_depth; // RefBitDepth +} VP9ReferenceFrameState; + +typedef struct CodedBitstreamVP9Context { + int profile; + + // Frame dimensions in 8x8 mode info blocks. + uint16_t mi_cols; + uint16_t mi_rows; + // Frame dimensions in 64x64 superblocks. + uint16_t sb64_cols; + uint16_t sb64_rows; + + int frame_width; + int frame_height; + + uint8_t subsampling_x; + uint8_t subsampling_y; + int bit_depth; + + VP9ReferenceFrameState ref[VP9_NUM_REF_FRAMES]; +} CodedBitstreamVP9Context; + + +#endif /* AVCODEC_CBS_VP9_H */ diff --git a/third-party/cbs/include/cbs/h264.h b/third-party/cbs/include/cbs/h264.h new file mode 100644 index 00000000..7fc4d07e --- /dev/null +++ b/third-party/cbs/include/cbs/h264.h @@ -0,0 +1,113 @@ +/* + * 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 + */ + +/** + * @file + * H.264 common definitions + */ + +#ifndef AVCODEC_H264_H +#define AVCODEC_H264_H + +#define QP_MAX_NUM (51 + 6 * 6) // The maximum supported qp + +/* + * Table 7-1 – NAL unit type codes, syntax element categories, and NAL unit type classes in + * T-REC-H.264-201704 + */ +enum { + H264_NAL_UNSPECIFIED = 0, + H264_NAL_SLICE = 1, + H264_NAL_DPA = 2, + H264_NAL_DPB = 3, + H264_NAL_DPC = 4, + H264_NAL_IDR_SLICE = 5, + H264_NAL_SEI = 6, + H264_NAL_SPS = 7, + H264_NAL_PPS = 8, + H264_NAL_AUD = 9, + H264_NAL_END_SEQUENCE = 10, + H264_NAL_END_STREAM = 11, + H264_NAL_FILLER_DATA = 12, + H264_NAL_SPS_EXT = 13, + H264_NAL_PREFIX = 14, + H264_NAL_SUB_SPS = 15, + H264_NAL_DPS = 16, + H264_NAL_RESERVED17 = 17, + H264_NAL_RESERVED18 = 18, + H264_NAL_AUXILIARY_SLICE = 19, + H264_NAL_EXTEN_SLICE = 20, + H264_NAL_DEPTH_EXTEN_SLICE = 21, + H264_NAL_RESERVED22 = 22, + H264_NAL_RESERVED23 = 23, + H264_NAL_UNSPECIFIED24 = 24, + H264_NAL_UNSPECIFIED25 = 25, + H264_NAL_UNSPECIFIED26 = 26, + H264_NAL_UNSPECIFIED27 = 27, + H264_NAL_UNSPECIFIED28 = 28, + H264_NAL_UNSPECIFIED29 = 29, + H264_NAL_UNSPECIFIED30 = 30, + H264_NAL_UNSPECIFIED31 = 31, +}; + + +enum { + // 7.4.2.1.1: seq_parameter_set_id is in [0, 31]. + H264_MAX_SPS_COUNT = 32, + // 7.4.2.2: pic_parameter_set_id is in [0, 255]. + H264_MAX_PPS_COUNT = 256, + + // A.3: MaxDpbFrames is bounded above by 16. + H264_MAX_DPB_FRAMES = 16, + // 7.4.2.1.1: max_num_ref_frames is in [0, MaxDpbFrames], and + // each reference frame can have two fields. + H264_MAX_REFS = 2 * H264_MAX_DPB_FRAMES, + + // 7.4.3.1: modification_of_pic_nums_idc is not equal to 3 at most + // num_ref_idx_lN_active_minus1 + 1 times (that is, once for each + // possible reference), then equal to 3 once. + H264_MAX_RPLM_COUNT = H264_MAX_REFS + 1, + + // 7.4.3.3: in the worst case, we begin with a full short-term + // reference picture list. Each picture in turn is moved to the + // long-term list (type 3) and then discarded from there (type 2). + // Then, we set the length of the long-term list (type 4), mark + // the current picture as long-term (type 6) and terminate the + // process (type 0). + H264_MAX_MMCO_COUNT = H264_MAX_REFS * 2 + 3, + + // A.2.1, A.2.3: profiles supporting FMO constrain + // num_slice_groups_minus1 to be in [0, 7]. + H264_MAX_SLICE_GROUPS = 8, + + // E.2.2: cpb_cnt_minus1 is in [0, 31]. + H264_MAX_CPB_CNT = 32, + + // A.3: in table A-1 the highest level allows a MaxFS of 139264. + H264_MAX_MB_PIC_SIZE = 139264, + // A.3.1, A.3.2: PicWidthInMbs and PicHeightInMbs are constrained + // to be not greater than sqrt(MaxFS * 8). Hence height/width are + // bounded above by sqrt(139264 * 8) = 1055.5 macroblocks. + H264_MAX_MB_WIDTH = 1055, + H264_MAX_MB_HEIGHT = 1055, + H264_MAX_WIDTH = H264_MAX_MB_WIDTH * 16, + H264_MAX_HEIGHT = H264_MAX_MB_HEIGHT * 16, +}; + + +#endif /* AVCODEC_H264_H */ diff --git a/third-party/cbs/include/cbs/h2645_parse.h b/third-party/cbs/include/cbs/h2645_parse.h new file mode 100644 index 00000000..4b445e01 --- /dev/null +++ b/third-party/cbs/include/cbs/h2645_parse.h @@ -0,0 +1,152 @@ +/* + * H.264/HEVC common parsing code + * + * 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_H2645_PARSE_H +#define AVCODEC_H2645_PARSE_H + +#include + +#include +#include + + +/** + * CACHED_BITSTREAM_READER can only be true if it's used by a decoder + * Thus, Sunshine doesn't need to worry about it + */ +typedef struct GetBitContext { + const uint8_t *buffer, *buffer_end; +#if CACHED_BITSTREAM_READER + uint64_t cache; + unsigned bits_left; +#endif + int index; + int size_in_bits; + int size_in_bits_plus8; +} GetBitContext; + +#define MAX_MBPAIR_SIZE (256 * 1024) // a tighter bound could be calculated if someone cares about a few bytes + +typedef struct H2645NAL { + uint8_t *rbsp_buffer; + + int size; + const uint8_t *data; + + /** + * Size, in bits, of just the data, excluding the stop bit and any trailing + * padding. I.e. what HEVC calls SODB. + */ + int size_bits; + + int raw_size; + const uint8_t *raw_data; + + GetBitContext gb; + + /** + * NAL unit type + */ + int type; + + /** + * HEVC only, nuh_temporal_id_plus_1 - 1 + */ + int temporal_id; + + /* + * HEVC only, identifier of layer to which nal unit belongs + */ + int nuh_layer_id; + + int skipped_bytes; + int skipped_bytes_pos_size; + int *skipped_bytes_pos; + /** + * H.264 only, nal_ref_idc + */ + int ref_idc; +} H2645NAL; + +typedef struct H2645RBSP { + uint8_t *rbsp_buffer; + AVBufferRef *rbsp_buffer_ref; + int rbsp_buffer_alloc_size; + int rbsp_buffer_size; +} H2645RBSP; + +/* an input packet split into unescaped NAL units */ +typedef struct H2645Packet { + H2645NAL *nals; + H2645RBSP rbsp; + int nb_nals; + int nals_allocated; + unsigned nal_buffer_size; +} H2645Packet; + +/** + * Extract the raw (unescaped) bitstream. + */ +int ff_h2645_extract_rbsp(const uint8_t *src, int length, H2645RBSP *rbsp, + H2645NAL *nal, int small_padding); + +/** + * Split an input packet into NAL units. + * + * If data == raw_data holds true for a NAL unit of the returned pkt, then + * said NAL unit does not contain any emulation_prevention_three_byte and + * the data is contained in the input buffer pointed to by buf. + * Otherwise, the unescaped data is part of the rbsp_buffer described by the + * packet's H2645RBSP. + * + * If the packet's rbsp_buffer_ref is not NULL, the underlying AVBuffer must + * own rbsp_buffer. If not and rbsp_buffer is not NULL, use_ref must be 0. + * If use_ref is set, rbsp_buffer will be reference-counted and owned by + * the underlying AVBuffer of rbsp_buffer_ref. + */ +int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, + void *logctx, int is_nalff, int nal_length_size, + enum AVCodecID codec_id, int small_padding, int use_ref); + +/** + * Free all the allocated memory in the packet. + */ +void ff_h2645_packet_uninit(H2645Packet *pkt); + +static inline int get_nalsize(int nal_length_size, const uint8_t *buf, + int buf_size, int *buf_index, void *logctx) { + int i, nalsize = 0; + + if(*buf_index >= buf_size - nal_length_size) { + // the end of the buffer is reached, refill it + return AVERROR(EAGAIN); + } + + for(i = 0; i < nal_length_size; i++) + nalsize = ((unsigned)nalsize << 8) | buf[(*buf_index)++]; + if(nalsize <= 0 || nalsize > buf_size - *buf_index) { + av_log(logctx, AV_LOG_ERROR, + "Invalid NAL unit size (%d > %d).\n", nalsize, buf_size - *buf_index); + return AVERROR_INVALIDDATA; + } + return nalsize; +} + +#endif /* AVCODEC_H2645_PARSE_H */ diff --git a/third-party/cbs/include/cbs/hevc.h b/third-party/cbs/include/cbs/hevc.h new file mode 100644 index 00000000..76707f1e --- /dev/null +++ b/third-party/cbs/include/cbs/hevc.h @@ -0,0 +1,160 @@ +/* + * HEVC shared code + * + * 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_HEVC_H +#define AVCODEC_HEVC_H + +/** + * Table 7-1 – NAL unit type codes and NAL unit type classes in + * T-REC-H.265-201802 + */ +enum HEVCNALUnitType { + HEVC_NAL_TRAIL_N = 0, + HEVC_NAL_TRAIL_R = 1, + HEVC_NAL_TSA_N = 2, + HEVC_NAL_TSA_R = 3, + HEVC_NAL_STSA_N = 4, + HEVC_NAL_STSA_R = 5, + HEVC_NAL_RADL_N = 6, + HEVC_NAL_RADL_R = 7, + HEVC_NAL_RASL_N = 8, + HEVC_NAL_RASL_R = 9, + HEVC_NAL_VCL_N10 = 10, + HEVC_NAL_VCL_R11 = 11, + HEVC_NAL_VCL_N12 = 12, + HEVC_NAL_VCL_R13 = 13, + HEVC_NAL_VCL_N14 = 14, + HEVC_NAL_VCL_R15 = 15, + HEVC_NAL_BLA_W_LP = 16, + HEVC_NAL_BLA_W_RADL = 17, + HEVC_NAL_BLA_N_LP = 18, + HEVC_NAL_IDR_W_RADL = 19, + HEVC_NAL_IDR_N_LP = 20, + HEVC_NAL_CRA_NUT = 21, + HEVC_NAL_RSV_IRAP_VCL22 = 22, + HEVC_NAL_RSV_IRAP_VCL23 = 23, + HEVC_NAL_RSV_VCL24 = 24, + HEVC_NAL_RSV_VCL25 = 25, + HEVC_NAL_RSV_VCL26 = 26, + HEVC_NAL_RSV_VCL27 = 27, + HEVC_NAL_RSV_VCL28 = 28, + HEVC_NAL_RSV_VCL29 = 29, + HEVC_NAL_RSV_VCL30 = 30, + HEVC_NAL_RSV_VCL31 = 31, + HEVC_NAL_VPS = 32, + HEVC_NAL_SPS = 33, + HEVC_NAL_PPS = 34, + HEVC_NAL_AUD = 35, + HEVC_NAL_EOS_NUT = 36, + HEVC_NAL_EOB_NUT = 37, + HEVC_NAL_FD_NUT = 38, + HEVC_NAL_SEI_PREFIX = 39, + HEVC_NAL_SEI_SUFFIX = 40, + HEVC_NAL_RSV_NVCL41 = 41, + HEVC_NAL_RSV_NVCL42 = 42, + HEVC_NAL_RSV_NVCL43 = 43, + HEVC_NAL_RSV_NVCL44 = 44, + HEVC_NAL_RSV_NVCL45 = 45, + HEVC_NAL_RSV_NVCL46 = 46, + HEVC_NAL_RSV_NVCL47 = 47, + HEVC_NAL_UNSPEC48 = 48, + HEVC_NAL_UNSPEC49 = 49, + HEVC_NAL_UNSPEC50 = 50, + HEVC_NAL_UNSPEC51 = 51, + HEVC_NAL_UNSPEC52 = 52, + HEVC_NAL_UNSPEC53 = 53, + HEVC_NAL_UNSPEC54 = 54, + HEVC_NAL_UNSPEC55 = 55, + HEVC_NAL_UNSPEC56 = 56, + HEVC_NAL_UNSPEC57 = 57, + HEVC_NAL_UNSPEC58 = 58, + HEVC_NAL_UNSPEC59 = 59, + HEVC_NAL_UNSPEC60 = 60, + HEVC_NAL_UNSPEC61 = 61, + HEVC_NAL_UNSPEC62 = 62, + HEVC_NAL_UNSPEC63 = 63, +}; + +enum HEVCSliceType { + HEVC_SLICE_B = 0, + HEVC_SLICE_P = 1, + HEVC_SLICE_I = 2, +}; + +enum { + // 7.4.3.1: vps_max_layers_minus1 is in [0, 62]. + HEVC_MAX_LAYERS = 63, + // 7.4.3.1: vps_max_sub_layers_minus1 is in [0, 6]. + HEVC_MAX_SUB_LAYERS = 7, + // 7.4.3.1: vps_num_layer_sets_minus1 is in [0, 1023]. + HEVC_MAX_LAYER_SETS = 1024, + + // 7.4.2.1: vps_video_parameter_set_id is u(4). + HEVC_MAX_VPS_COUNT = 16, + // 7.4.3.2.1: sps_seq_parameter_set_id is in [0, 15]. + HEVC_MAX_SPS_COUNT = 16, + // 7.4.3.3.1: pps_pic_parameter_set_id is in [0, 63]. + HEVC_MAX_PPS_COUNT = 64, + + // A.4.2: MaxDpbSize is bounded above by 16. + HEVC_MAX_DPB_SIZE = 16, + // 7.4.3.1: vps_max_dec_pic_buffering_minus1[i] is in [0, MaxDpbSize - 1]. + HEVC_MAX_REFS = HEVC_MAX_DPB_SIZE, + + // 7.4.3.2.1: num_short_term_ref_pic_sets is in [0, 64]. + HEVC_MAX_SHORT_TERM_REF_PIC_SETS = 64, + // 7.4.3.2.1: num_long_term_ref_pics_sps is in [0, 32]. + HEVC_MAX_LONG_TERM_REF_PICS = 32, + + // A.3: all profiles require that CtbLog2SizeY is in [4, 6]. + HEVC_MIN_LOG2_CTB_SIZE = 4, + HEVC_MAX_LOG2_CTB_SIZE = 6, + + // E.3.2: cpb_cnt_minus1[i] is in [0, 31]. + HEVC_MAX_CPB_CNT = 32, + + // A.4.1: in table A.6 the highest level allows a MaxLumaPs of 35 651 584. + HEVC_MAX_LUMA_PS = 35651584, + // A.4.1: pic_width_in_luma_samples and pic_height_in_luma_samples are + // constrained to be not greater than sqrt(MaxLumaPs * 8). Hence height/ + // width are bounded above by sqrt(8 * 35651584) = 16888.2 samples. + HEVC_MAX_WIDTH = 16888, + HEVC_MAX_HEIGHT = 16888, + + // A.4.1: table A.6 allows at most 22 tile rows for any level. + HEVC_MAX_TILE_ROWS = 22, + // A.4.1: table A.6 allows at most 20 tile columns for any level. + HEVC_MAX_TILE_COLUMNS = 20, + + // A.4.2: table A.6 allows at most 600 slice segments for any level. + HEVC_MAX_SLICE_SEGMENTS = 600, + + // 7.4.7.1: in the worst case (tiles_enabled_flag and + // entropy_coding_sync_enabled_flag are both set), entry points can be + // placed at the beginning of every Ctb row in every tile, giving an + // upper bound of (num_tile_columns_minus1 + 1) * PicHeightInCtbsY - 1. + // Only a stream with very high resolution and perverse parameters could + // get near that, though, so set a lower limit here with the maximum + // possible value for 4K video (at most 135 16x16 Ctb rows). + HEVC_MAX_ENTRY_POINT_OFFSETS = HEVC_MAX_TILE_COLUMNS * 135, +}; + + +#endif /* AVCODEC_HEVC_H */ diff --git a/third-party/cbs/include/cbs/sei.h b/third-party/cbs/include/cbs/sei.h new file mode 100644 index 00000000..4a35109b --- /dev/null +++ b/third-party/cbs/include/cbs/sei.h @@ -0,0 +1,140 @@ +/* + * 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_SEI_H +#define AVCODEC_SEI_H + +// SEI payload types form a common namespace between the H.264, H.265 +// and H.266 standards. A given payload type always has the same +// meaning, but some names have different payload types in different +// standards (e.g. scalable-nesting is 30 in H.264 but 133 in H.265). +// The content of the payload data depends on the standard, though +// many generic parts have the same interpretation everywhere (such as +// mastering-display-colour-volume and user-data-unregistered). +enum { + SEI_TYPE_BUFFERING_PERIOD = 0, + SEI_TYPE_PIC_TIMING = 1, + SEI_TYPE_PAN_SCAN_RECT = 2, + SEI_TYPE_FILLER_PAYLOAD = 3, + SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35 = 4, + SEI_TYPE_USER_DATA_UNREGISTERED = 5, + SEI_TYPE_RECOVERY_POINT = 6, + SEI_TYPE_DEC_REF_PIC_MARKING_REPETITION = 7, + SEI_TYPE_SPARE_PIC = 8, + SEI_TYPE_SCENE_INFO = 9, + SEI_TYPE_SUB_SEQ_INFO = 10, + SEI_TYPE_SUB_SEQ_LAYER_CHARACTERISTICS = 11, + SEI_TYPE_SUB_SEQ_CHARACTERISTICS = 12, + SEI_TYPE_FULL_FRAME_FREEZE = 13, + SEI_TYPE_FULL_FRAME_FREEZE_RELEASE = 14, + SEI_TYPE_FULL_FRAME_SNAPSHOT = 15, + SEI_TYPE_PROGRESSIVE_REFINEMENT_SEGMENT_START = 16, + SEI_TYPE_PROGRESSIVE_REFINEMENT_SEGMENT_END = 17, + SEI_TYPE_MOTION_CONSTRAINED_SLICE_GROUP_SET = 18, + SEI_TYPE_FILM_GRAIN_CHARACTERISTICS = 19, + SEI_TYPE_DEBLOCKING_FILTER_DISPLAY_PREFERENCE = 20, + SEI_TYPE_STEREO_VIDEO_INFO = 21, + SEI_TYPE_POST_FILTER_HINT = 22, + SEI_TYPE_TONE_MAPPING_INFO = 23, + SEI_TYPE_SCALABILITY_INFO = 24, + SEI_TYPE_SUB_PIC_SCALABLE_LAYER = 25, + SEI_TYPE_NON_REQUIRED_LAYER_REP = 26, + SEI_TYPE_PRIORITY_LAYER_INFO = 27, + SEI_TYPE_LAYERS_NOT_PRESENT_4 = 28, + SEI_TYPE_LAYER_DEPENDENCY_CHANGE = 29, + SEI_TYPE_SCALABLE_NESTING_4 = 30, + SEI_TYPE_BASE_LAYER_TEMPORAL_HRD = 31, + SEI_TYPE_QUALITY_LAYER_INTEGRITY_CHECK = 32, + SEI_TYPE_REDUNDANT_PIC_PROPERTY = 33, + SEI_TYPE_TL0_DEP_REP_INDEX = 34, + SEI_TYPE_TL_SWITCHING_POINT = 35, + SEI_TYPE_PARALLEL_DECODING_INFO = 36, + SEI_TYPE_MVC_SCALABLE_NESTING = 37, + SEI_TYPE_VIEW_SCALABILITY_INFO = 38, + SEI_TYPE_MULTIVIEW_SCENE_INFO_4 = 39, + SEI_TYPE_MULTIVIEW_ACQUISITION_INFO_4 = 40, + SEI_TYPE_NON_REQUIRED_VIEW_COMPONENT = 41, + SEI_TYPE_VIEW_DEPENDENCY_CHANGE = 42, + SEI_TYPE_OPERATION_POINTS_NOT_PRESENT = 43, + SEI_TYPE_BASE_VIEW_TEMPORAL_HRD = 44, + SEI_TYPE_FRAME_PACKING_ARRANGEMENT = 45, + SEI_TYPE_MULTIVIEW_VIEW_POSITION_4 = 46, + SEI_TYPE_DISPLAY_ORIENTATION = 47, + SEI_TYPE_MVCD_SCALABLE_NESTING = 48, + SEI_TYPE_MVCD_VIEW_SCALABILITY_INFO = 49, + SEI_TYPE_DEPTH_REPRESENTATION_INFO_4 = 50, + SEI_TYPE_THREE_DIMENSIONAL_REFERENCE_DISPLAYS_INFO_4 = 51, + SEI_TYPE_DEPTH_TIMING = 52, + SEI_TYPE_DEPTH_SAMPLING_INFO = 53, + SEI_TYPE_CONSTRAINED_DEPTH_PARAMETER_SET_IDENTIFIER = 54, + SEI_TYPE_GREEN_METADATA = 56, + SEI_TYPE_STRUCTURE_OF_PICTURES_INFO = 128, + SEI_TYPE_ACTIVE_PARAMETER_SETS = 129, + SEI_TYPE_PARAMETER_SETS_INCLUSION_INDICATION = SEI_TYPE_ACTIVE_PARAMETER_SETS, + SEI_TYPE_DECODING_UNIT_INFO = 130, + SEI_TYPE_TEMPORAL_SUB_LAYER_ZERO_IDX = 131, + SEI_TYPE_DECODED_PICTURE_HASH = 132, + SEI_TYPE_SCALABLE_NESTING_5 = 133, + SEI_TYPE_REGION_REFRESH_INFO = 134, + SEI_TYPE_NO_DISPLAY = 135, + SEI_TYPE_TIME_CODE = 136, + SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME = 137, + SEI_TYPE_SEGMENTED_RECT_FRAME_PACKING_ARRANGEMENT = 138, + SEI_TYPE_TEMPORAL_MOTION_CONSTRAINED_TILE_SETS = 139, + SEI_TYPE_CHROMA_RESAMPLING_FILTER_HINT = 140, + SEI_TYPE_KNEE_FUNCTION_INFO = 141, + SEI_TYPE_COLOUR_REMAPPING_INFO = 142, + SEI_TYPE_DEINTERLACED_FIELD_IDENTIFICATION = 143, + SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO = 144, + SEI_TYPE_DEPENDENT_RAP_INDICATION = 145, + SEI_TYPE_CODED_REGION_COMPLETION = 146, + SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS = 147, + SEI_TYPE_AMBIENT_VIEWING_ENVIRONMENT = 148, + SEI_TYPE_CONTENT_COLOUR_VOLUME = 149, + SEI_TYPE_EQUIRECTANGULAR_PROJECTION = 150, + SEI_TYPE_CUBEMAP_PROJECTION = 151, + SEI_TYPE_FISHEYE_VIDEO_INFO = 152, + SEI_TYPE_SPHERE_ROTATION = 154, + SEI_TYPE_REGIONWISE_PACKING = 155, + SEI_TYPE_OMNI_VIEWPORT = 156, + SEI_TYPE_REGIONAL_NESTING = 157, + SEI_TYPE_MCTS_EXTRACTION_INFO_SETS = 158, + SEI_TYPE_MCTS_EXTRACTION_INFO_NESTING = 159, + SEI_TYPE_LAYERS_NOT_PRESENT_5 = 160, + SEI_TYPE_INTER_LAYER_CONSTRAINED_TILE_SETS = 161, + SEI_TYPE_BSP_NESTING = 162, + SEI_TYPE_BSP_INITIAL_ARRIVAL_TIME = 163, + SEI_TYPE_SUB_BITSTREAM_PROPERTY = 164, + SEI_TYPE_ALPHA_CHANNEL_INFO = 165, + SEI_TYPE_OVERLAY_INFO = 166, + SEI_TYPE_TEMPORAL_MV_PREDICTION_CONSTRAINTS = 167, + SEI_TYPE_FRAME_FIELD_INFO = 168, + SEI_TYPE_THREE_DIMENSIONAL_REFERENCE_DISPLAYS_INFO = 176, + SEI_TYPE_DEPTH_REPRESENTATION_INFO_5 = 177, + SEI_TYPE_MULTIVIEW_SCENE_INFO_5 = 178, + SEI_TYPE_MULTIVIEW_ACQUISITION_INFO_5 = 179, + SEI_TYPE_MULTIVIEW_VIEW_POSITION_5 = 180, + SEI_TYPE_ALTERNATIVE_DEPTH_INFO = 181, + SEI_TYPE_SEI_MANIFEST = 200, + SEI_TYPE_SEI_PREFIX_INDICATION = 201, + SEI_TYPE_ANNOTATED_REGIONS = 202, + SEI_TYPE_SUBPIC_LEVEL_INFO = 203, + SEI_TYPE_SAMPLE_ASPECT_RATIO_INFO = 204, +}; + +#endif /* AVCODEC_SEI_H */ diff --git a/third-party/cbs/intmath.h b/third-party/cbs/intmath.h new file mode 100644 index 00000000..2e946b71 --- /dev/null +++ b/third-party/cbs/intmath.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2010 Mans Rullgard + * + * 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 AVUTIL_INTMATH_H +#define AVUTIL_INTMATH_H + +#include + +#include "attributes.h" + +#if ARCH_ARM +#include "arm/intmath.h" +#endif +#if ARCH_X86 +#include "x86/intmath.h" +#endif + +#if HAVE_FAST_CLZ +#if AV_GCC_VERSION_AT_LEAST(3, 4) +#ifndef ff_log2 +#define ff_log2(x) (31 - __builtin_clz((x) | 1)) +#ifndef ff_log2_16bit +#define ff_log2_16bit av_log2 +#endif +#endif /* ff_log2 */ +#endif /* AV_GCC_VERSION_AT_LEAST(3,4) */ +#endif + +extern const uint8_t ff_log2_tab[256]; + +#ifndef ff_log2 +#define ff_log2 ff_log2_c +static av_always_inline av_const int ff_log2_c(unsigned int v) { + int n = 0; + if(v & 0xffff0000) { + v >>= 16; + n += 16; + } + if(v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} +#endif + +#ifndef ff_log2_16bit +#define ff_log2_16bit ff_log2_16bit_c +static av_always_inline av_const int ff_log2_16bit_c(unsigned int v) { + int n = 0; + if(v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} +#endif + +#define av_log2 ff_log2 +#define av_log2_16bit ff_log2_16bit + +/** + * @addtogroup lavu_math + * @{ + */ + +#if HAVE_FAST_CLZ +#if AV_GCC_VERSION_AT_LEAST(3, 4) +#ifndef ff_ctz +#define ff_ctz(v) __builtin_ctz(v) +#endif +#ifndef ff_ctzll +#define ff_ctzll(v) __builtin_ctzll(v) +#endif +#ifndef ff_clz +#define ff_clz(v) __builtin_clz(v) +#endif +#endif +#endif + +#ifndef ff_ctz +#define ff_ctz ff_ctz_c +/** + * Trailing zero bit count. + * + * @param v input value. If v is 0, the result is undefined. + * @return the number of trailing 0-bits + */ +/* We use the De-Bruijn method outlined in: + * http://supertech.csail.mit.edu/papers/debruijn.pdf. */ +static av_always_inline av_const int ff_ctz_c(int v) { + static const uint8_t debruijn_ctz32[32] = { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 + }; + return debruijn_ctz32[(uint32_t)((v & -v) * 0x077CB531U) >> 27]; +} +#endif + +#ifndef ff_ctzll +#define ff_ctzll ff_ctzll_c +/* We use the De-Bruijn method outlined in: + * http://supertech.csail.mit.edu/papers/debruijn.pdf. */ +static av_always_inline av_const int ff_ctzll_c(long long v) { + static const uint8_t debruijn_ctz64[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 + }; + return debruijn_ctz64[(uint64_t)((v & -v) * 0x022FDD63CC95386DU) >> 58]; +} +#endif + +#ifndef ff_clz +#define ff_clz ff_clz_c +static av_always_inline av_const unsigned ff_clz_c(unsigned x) { + unsigned i = sizeof(x) * 8; + + while(x) { + x >>= 1; + i--; + } + + return i; +} +#endif + +#if AV_GCC_VERSION_AT_LEAST(3, 4) +#ifndef av_parity +#define av_parity __builtin_parity +#endif +#endif + +/** + * @} + */ +#endif /* AVUTIL_INTMATH_H */ diff --git a/third-party/cbs/mathops.h b/third-party/cbs/mathops.h new file mode 100644 index 00000000..3441e173 --- /dev/null +++ b/third-party/cbs/mathops.h @@ -0,0 +1,255 @@ +/* + * simple math operations + * Copyright (c) 2001, 2002 Fabrice Bellard + * Copyright (c) 2006 Michael Niedermayer et al + * + * 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_MATHOPS_H +#define AVCODEC_MATHOPS_H + +#include + +#include + +#define MAX_NEG_CROP 1024 + +extern const uint8_t ff_reverse[256]; +extern const uint32_t ff_inverse[257]; +extern const uint8_t ff_sqrt_tab[256]; +extern const uint8_t ff_crop_tab[256 + 2 * MAX_NEG_CROP]; +extern const uint8_t ff_zigzag_direct[64]; +extern const uint8_t ff_zigzag_scan[16 + 1]; + +#if ARCH_ARM +#include "arm/mathops.h" +#elif ARCH_AVR32 +#include "avr32/mathops.h" +#elif ARCH_MIPS +#include "mips/mathops.h" +#elif ARCH_PPC +#include "ppc/mathops.h" +#elif ARCH_X86 +#include "x86/mathops.h" +#endif + +/* generic implementation */ + +#ifndef MUL64 +#define MUL64(a, b) ((int64_t)(a) * (int64_t)(b)) +#endif + +#ifndef MULL +#define MULL(a, b, s) (MUL64(a, b) >> (s)) +#endif + +#ifndef MULH +static av_always_inline int MULH(int a, int b) { + return MUL64(a, b) >> 32; +} +#endif + +#ifndef UMULH +static av_always_inline unsigned UMULH(unsigned a, unsigned b) { + return ((uint64_t)(a) * (uint64_t)(b)) >> 32; +} +#endif + +#ifndef MAC64 +#define MAC64(d, a, b) ((d) += MUL64(a, b)) +#endif + +#ifndef MLS64 +#define MLS64(d, a, b) ((d) -= MUL64(a, b)) +#endif + +/* signed 16x16 -> 32 multiply add accumulate */ +#ifndef MAC16 +#define MAC16(rt, ra, rb) rt += (ra) * (rb) +#endif + +/* signed 16x16 -> 32 multiply */ +#ifndef MUL16 +#define MUL16(ra, rb) ((ra) * (rb)) +#endif + +#ifndef MLS16 +#define MLS16(rt, ra, rb) ((rt) -= (ra) * (rb)) +#endif + +/* median of 3 */ +#ifndef mid_pred +#define mid_pred mid_pred +static inline av_const int mid_pred(int a, int b, int c) { + if(a > b) { + if(c > b) { + if(c > a) b = a; + else + b = c; + } + } + else { + if(b > c) { + if(c > a) b = c; + else + b = a; + } + } + return b; +} +#endif + +#ifndef median4 +#define median4 median4 +static inline av_const int median4(int a, int b, int c, int d) { + if(a < b) { + if(c < d) return (FFMIN(b, d) + FFMAX(a, c)) / 2; + else + return (FFMIN(b, c) + FFMAX(a, d)) / 2; + } + else { + if(c < d) return (FFMIN(a, d) + FFMAX(b, c)) / 2; + else + return (FFMIN(a, c) + FFMAX(b, d)) / 2; + } +} +#endif + +#ifndef sign_extend +static inline av_const int sign_extend(int val, unsigned bits) { + unsigned shift = 8 * sizeof(int) - bits; + union { + unsigned u; + int s; + } v = { (unsigned)val << shift }; + return v.s >> shift; +} +#endif + +#ifndef zero_extend +static inline av_const unsigned zero_extend(unsigned val, unsigned bits) { + return (val << ((8 * sizeof(int)) - bits)) >> ((8 * sizeof(int)) - bits); +} +#endif + +#ifndef COPY3_IF_LT +#define COPY3_IF_LT(x, y, a, b, c, d) \ + if((y) < (x)) { \ + (x) = (y); \ + (a) = (b); \ + (c) = (d); \ + } +#endif + +#ifndef MASK_ABS +#define MASK_ABS(mask, level) \ + do { \ + mask = level >> 31; \ + level = (level ^ mask) - mask; \ + } while(0) +#endif + +#ifndef NEG_SSR32 +#define NEG_SSR32(a, s) (((int32_t)(a)) >> (32 - (s))) +#endif + +#ifndef NEG_USR32 +#define NEG_USR32(a, s) (((uint32_t)(a)) >> (32 - (s))) +#endif + +#if HAVE_BIGENDIAN +#ifndef PACK_2U8 +#define PACK_2U8(a, b) (((a) << 8) | (b)) +#endif +#ifndef PACK_4U8 +#define PACK_4U8(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) +#endif +#ifndef PACK_2U16 +#define PACK_2U16(a, b) (((a) << 16) | (b)) +#endif +#else +#ifndef PACK_2U8 +#define PACK_2U8(a, b) (((b) << 8) | (a)) +#endif +#ifndef PACK_4U2 +#define PACK_4U8(a, b, c, d) (((d) << 24) | ((c) << 16) | ((b) << 8) | (a)) +#endif +#ifndef PACK_2U16 +#define PACK_2U16(a, b) (((b) << 16) | (a)) +#endif +#endif + +#ifndef PACK_2S8 +#define PACK_2S8(a, b) PACK_2U8((a)&255, (b)&255) +#endif +#ifndef PACK_4S8 +#define PACK_4S8(a, b, c, d) PACK_4U8((a)&255, (b)&255, (c)&255, (d)&255) +#endif +#ifndef PACK_2S16 +#define PACK_2S16(a, b) PACK_2U16((a)&0xffff, (b)&0xffff) +#endif + +#ifndef FASTDIV +#define FASTDIV(a, b) ((uint32_t)((((uint64_t)a) * ff_inverse[b]) >> 32)) +#endif /* FASTDIV */ + +#ifndef ff_sqrt +#define ff_sqrt ff_sqrt +static inline av_const unsigned int ff_sqrt(unsigned int a) { + unsigned int b; + + if(a < 255) return (ff_sqrt_tab[a + 1] - 1) >> 4; + else if(a < (1 << 12)) + b = ff_sqrt_tab[a >> 4] >> 2; +#if !CONFIG_SMALL + else if(a < (1 << 14)) + b = ff_sqrt_tab[a >> 6] >> 1; + else if(a < (1 << 16)) + b = ff_sqrt_tab[a >> 8]; +#endif + else { + int s = av_log2_16bit(a >> 16) >> 1; + unsigned int c = a >> (s + 2); + b = ff_sqrt_tab[c >> (s + 8)]; + b = FASTDIV(c, b) + (b << s); + } + + return b - (a < b * b); +} +#endif + +static inline av_const float ff_sqrf(float a) { + return a * a; +} + +static inline int8_t ff_u8_to_s8(uint8_t a) { + union { + uint8_t u8; + int8_t s8; + } b; + b.u8 = a; + return b.s8; +} + +static av_always_inline uint32_t bitswap_32(uint32_t x) { + return (uint32_t)ff_reverse[x & 0xFF] << 24 | + (uint32_t)ff_reverse[(x >> 8) & 0xFF] << 16 | + (uint32_t)ff_reverse[(x >> 16) & 0xFF] << 8 | + (uint32_t)ff_reverse[x >> 24]; +} + +#endif /* AVCODEC_MATHOPS_H */ diff --git a/third-party/cbs/mips/mathops.h b/third-party/cbs/mips/mathops.h new file mode 100644 index 00000000..eab6c16d --- /dev/null +++ b/third-party/cbs/mips/mathops.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009 Mans Rullgard + * Copyright (c) 2015 Zhou Xiaoyong + * + * 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_MIPS_MATHOPS_H +#define AVCODEC_MIPS_MATHOPS_H + +#include + +#include + +#if HAVE_INLINE_ASM + +#if HAVE_LOONGSON3 + +#define MULH MULH +static inline av_const int MULH(int a, int b) { + int c; + __asm__("dmult %1, %2 \n\t" + "mflo %0 \n\t" + "dsrl %0, %0, 32 \n\t" + : "=r"(c) + : "r"(a), "r"(b) + : "hi", "lo"); + return c; +} + +#define mid_pred mid_pred +static inline av_const int mid_pred(int a, int b, int c) { + int t = b; + __asm__("sgt $8, %1, %2 \n\t" + "movn %0, %1, $8 \n\t" + "movn %1, %2, $8 \n\t" + "sgt $8, %1, %3 \n\t" + "movz %1, %3, $8 \n\t" + "sgt $8, %0, %1 \n\t" + "movn %0, %1, $8 \n\t" + : "+&r"(t), "+&r"(a) + : "r"(b), "r"(c) + : "$8"); + return t; +} + +#endif /* HAVE_LOONGSON3 */ + +#endif /* HAVE_INLINE_ASM */ + +#endif /* AVCODEC_MIPS_MATHOPS_H */ diff --git a/third-party/cbs/ppc/mathops.h b/third-party/cbs/ppc/mathops.h new file mode 100644 index 00000000..da1da982 --- /dev/null +++ b/third-party/cbs/ppc/mathops.h @@ -0,0 +1,87 @@ +/* + * simple math operations + * Copyright (c) 2001, 2002 Fabrice Bellard + * Copyright (c) 2006 Michael Niedermayer et al + * + * 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_PPC_MATHOPS_H +#define AVCODEC_PPC_MATHOPS_H + +#include + +#include + +#if HAVE_PPC4XX +/* signed 16x16 -> 32 multiply add accumulate */ +#define MAC16(rt, ra, rb) \ + __asm__("maclhw %0, %2, %3" \ + : "=r"(rt) \ + : "0"(rt), "r"(ra), "r"(rb)); + +/* signed 16x16 -> 32 multiply */ +#define MUL16(ra, rb) \ + ({ int __rt; \ + __asm__ ("mullhw %0, %1, %2" : "=r" (__rt) : "r" (ra), "r" (rb)); \ + __rt; }) +#endif + +#define MULH MULH +static inline av_const int MULH(int a, int b) { + int r; + __asm__("mulhw %0, %1, %2" + : "=r"(r) + : "r"(a), "r"(b)); + return r; +} + +#if !ARCH_PPC64 +static inline av_const int64_t MAC64(int64_t d, int a, int b) { + union { + uint64_t x; + unsigned hl[2]; + } x = { d }; + int h, l; + __asm__("mullw %3, %4, %5 \n\t" + "mulhw %2, %4, %5 \n\t" + "addc %1, %1, %3 \n\t" + "adde %0, %0, %2 \n\t" + : "+r"(x.hl[0]), "+r"(x.hl[1]), "=&r"(h), "=&r"(l) + : "r"(a), "r"(b)); + return x.x; +} +#define MAC64(d, a, b) ((d) = MAC64(d, a, b)) + +static inline av_const int64_t MLS64(int64_t d, int a, int b) { + union { + uint64_t x; + unsigned hl[2]; + } x = { d }; + int h, l; + __asm__("mullw %3, %4, %5 \n\t" + "mulhw %2, %4, %5 \n\t" + "subfc %1, %3, %1 \n\t" + "subfe %0, %2, %0 \n\t" + : "+r"(x.hl[0]), "+r"(x.hl[1]), "=&r"(h), "=&r"(l) + : "r"(a), "r"(b)); + return x.x; +} +#define MLS64(d, a, b) ((d) = MLS64(d, a, b)) +#endif + +#endif /* AVCODEC_PPC_MATHOPS_H */ diff --git a/third-party/cbs/put_bits.h b/third-party/cbs/put_bits.h new file mode 100644 index 00000000..36e401e0 --- /dev/null +++ b/third-party/cbs/put_bits.h @@ -0,0 +1,405 @@ +/* + * copyright (c) 2004 Michael Niedermayer + * + * 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 + */ + +/** + * @file + * bitstream writer API + */ + +#ifndef AVCODEC_PUT_BITS_H +#define AVCODEC_PUT_BITS_H + +#include +#include + +#include +#include + +#if ARCH_X86_64 +// TODO: Benchmark and optionally enable on other 64-bit architectures. +typedef uint64_t BitBuf; +#define AV_WBBUF AV_WB64 +#define AV_WLBUF AV_WL64 +#else +typedef uint32_t BitBuf; +#define AV_WBBUF AV_WB32 +#define AV_WLBUF AV_WL32 +#endif + +static const int BUF_BITS = 8 * sizeof(BitBuf); + +typedef struct PutBitContext { + BitBuf bit_buf; + int bit_left; + uint8_t *buf, *buf_ptr, *buf_end; +} PutBitContext; + +/** + * Initialize the PutBitContext s. + * + * @param buffer the buffer where to put bits + * @param buffer_size the size in bytes of buffer + */ +static inline void init_put_bits(PutBitContext *s, uint8_t *buffer, + int buffer_size) { + if(buffer_size < 0) { + buffer_size = 0; + buffer = NULL; + } + + s->buf = buffer; + s->buf_end = s->buf + buffer_size; + s->buf_ptr = s->buf; + s->bit_left = BUF_BITS; + s->bit_buf = 0; +} + +/** + * @return the total number of bits written to the bitstream. + */ +static inline int put_bits_count(PutBitContext *s) { + return (s->buf_ptr - s->buf) * 8 + BUF_BITS - s->bit_left; +} + +/** + * @return the number of bytes output so far; may only be called + * when the PutBitContext is freshly initialized or flushed. + */ +static inline int put_bytes_output(const PutBitContext *s) { + av_assert2(s->bit_left == BUF_BITS); + return s->buf_ptr - s->buf; +} + +/** + * @param round_up When set, the number of bits written so far will be + * rounded up to the next byte. + * @return the number of bytes output so far. + */ +static inline int put_bytes_count(const PutBitContext *s, int round_up) { + return s->buf_ptr - s->buf + ((BUF_BITS - s->bit_left + (round_up ? 7 : 0)) >> 3); +} + +/** + * Rebase the bit writer onto a reallocated buffer. + * + * @param buffer the buffer where to put bits + * @param buffer_size the size in bytes of buffer, + * must be large enough to hold everything written so far + */ +static inline void rebase_put_bits(PutBitContext *s, uint8_t *buffer, + int buffer_size) { + av_assert0(8 * buffer_size >= put_bits_count(s)); + + s->buf_end = buffer + buffer_size; + s->buf_ptr = buffer + (s->buf_ptr - s->buf); + s->buf = buffer; +} + +/** + * @return the number of bits available in the bitstream. + */ +static inline int put_bits_left(PutBitContext *s) { + return (s->buf_end - s->buf_ptr) * 8 - BUF_BITS + s->bit_left; +} + +/** + * @param round_up When set, the number of bits written will be + * rounded up to the next byte. + * @return the number of bytes left. + */ +static inline int put_bytes_left(const PutBitContext *s, int round_up) { + return s->buf_end - s->buf_ptr - ((BUF_BITS - s->bit_left + (round_up ? 7 : 0)) >> 3); +} + +/** + * Pad the end of the output stream with zeros. + */ +static inline void flush_put_bits(PutBitContext *s) { +#ifndef BITSTREAM_WRITER_LE + if(s->bit_left < BUF_BITS) + s->bit_buf <<= s->bit_left; +#endif + while(s->bit_left < BUF_BITS) { + av_assert0(s->buf_ptr < s->buf_end); +#ifdef BITSTREAM_WRITER_LE + *s->buf_ptr++ = s->bit_buf; + s->bit_buf >>= 8; +#else + *s->buf_ptr++ = s->bit_buf >> (BUF_BITS - 8); + s->bit_buf <<= 8; +#endif + s->bit_left += 8; + } + s->bit_left = BUF_BITS; + s->bit_buf = 0; +} + +static inline void flush_put_bits_le(PutBitContext *s) { + while(s->bit_left < BUF_BITS) { + av_assert0(s->buf_ptr < s->buf_end); + *s->buf_ptr++ = s->bit_buf; + s->bit_buf >>= 8; + s->bit_left += 8; + } + s->bit_left = BUF_BITS; + s->bit_buf = 0; +} + +#ifdef BITSTREAM_WRITER_LE +#define ff_put_string ff_put_string_unsupported_here +#define ff_copy_bits ff_copy_bits_unsupported_here +#else + +/** + * Put the string string in the bitstream. + * + * @param terminate_string 0-terminates the written string if value is 1 + */ +void ff_put_string(PutBitContext *pb, const char *string, + int terminate_string); + +/** + * Copy the content of src to the bitstream. + * + * @param length the number of bits of src to copy + */ +void ff_copy_bits(PutBitContext *pb, const uint8_t *src, int length); +#endif + +static inline void put_bits_no_assert(PutBitContext *s, int n, BitBuf value) { + BitBuf bit_buf; + int bit_left; + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + /* XXX: optimize */ +#ifdef BITSTREAM_WRITER_LE + bit_buf |= value << (BUF_BITS - bit_left); + if(n >= bit_left) { + if(s->buf_end - s->buf_ptr >= sizeof(BitBuf)) { + AV_WLBUF(s->buf_ptr, bit_buf); + s->buf_ptr += sizeof(BitBuf); + } + else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_buf = value >> bit_left; + bit_left += BUF_BITS; + } + bit_left -= n; +#else + if(n < bit_left) { + bit_buf = (bit_buf << n) | value; + bit_left -= n; + } + else { + bit_buf <<= bit_left; + bit_buf |= value >> (n - bit_left); + if(s->buf_end - s->buf_ptr >= sizeof(BitBuf)) { + AV_WBBUF(s->buf_ptr, bit_buf); + s->buf_ptr += sizeof(BitBuf); + } + else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_left += BUF_BITS - n; + bit_buf = value; + } +#endif + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} + +/** + * Write up to 31 bits into a bitstream. + * Use put_bits32 to write 32 bits. + */ +static inline void put_bits(PutBitContext *s, int n, BitBuf value) { + av_assert2(n <= 31 && value < (1UL << n)); + put_bits_no_assert(s, n, value); +} + +static inline void put_bits_le(PutBitContext *s, int n, BitBuf value) { + BitBuf bit_buf; + int bit_left; + + av_assert2(n <= 31 && value < (1UL << n)); + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + bit_buf |= value << (BUF_BITS - bit_left); + if(n >= bit_left) { + if(s->buf_end - s->buf_ptr >= sizeof(BitBuf)) { + AV_WLBUF(s->buf_ptr, bit_buf); + s->buf_ptr += sizeof(BitBuf); + } + else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_buf = value >> bit_left; + bit_left += BUF_BITS; + } + bit_left -= n; + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} + +static inline void put_sbits(PutBitContext *pb, int n, int32_t value) { + av_assert2(n >= 0 && n <= 31); + + put_bits(pb, n, av_mod_uintp2(value, n)); +} + +/** + * Write exactly 32 bits into a bitstream. + */ +static void av_unused put_bits32(PutBitContext *s, uint32_t value) { + BitBuf bit_buf; + int bit_left; + + if(BUF_BITS > 32) { + put_bits_no_assert(s, 32, value); + return; + } + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + +#ifdef BITSTREAM_WRITER_LE + bit_buf |= (BitBuf)value << (BUF_BITS - bit_left); + if(s->buf_end - s->buf_ptr >= sizeof(BitBuf)) { + AV_WLBUF(s->buf_ptr, bit_buf); + s->buf_ptr += sizeof(BitBuf); + } + else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_buf = (uint64_t)value >> bit_left; +#else + bit_buf = (uint64_t)bit_buf << bit_left; + bit_buf |= (BitBuf)value >> (BUF_BITS - bit_left); + if(s->buf_end - s->buf_ptr >= sizeof(BitBuf)) { + AV_WBBUF(s->buf_ptr, bit_buf); + s->buf_ptr += sizeof(BitBuf); + } + else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_buf = value; +#endif + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} + +/** + * Write up to 64 bits into a bitstream. + */ +static inline void put_bits64(PutBitContext *s, int n, uint64_t value) { + av_assert2((n == 64) || (n < 64 && value < (UINT64_C(1) << n))); + + if(n < 32) + put_bits(s, n, value); + else if(n == 32) + put_bits32(s, value); + else if(n < 64) { + uint32_t lo = value & 0xffffffff; + uint32_t hi = value >> 32; +#ifdef BITSTREAM_WRITER_LE + put_bits32(s, lo); + put_bits(s, n - 32, hi); +#else + put_bits(s, n - 32, hi); + put_bits32(s, lo); +#endif + } + else { + uint32_t lo = value & 0xffffffff; + uint32_t hi = value >> 32; +#ifdef BITSTREAM_WRITER_LE + put_bits32(s, lo); + put_bits32(s, hi); +#else + put_bits32(s, hi); + put_bits32(s, lo); +#endif + } +} + +/** + * Return the pointer to the byte where the bitstream writer will put + * the next bit. + */ +static inline uint8_t *put_bits_ptr(PutBitContext *s) { + return s->buf_ptr; +} + +/** + * Skip the given number of bytes. + * PutBitContext must be flushed & aligned to a byte boundary before calling this. + */ +static inline void skip_put_bytes(PutBitContext *s, int n) { + av_assert2((put_bits_count(s) & 7) == 0); + av_assert2(s->bit_left == BUF_BITS); + av_assert0(n <= s->buf_end - s->buf_ptr); + s->buf_ptr += n; +} + +/** + * Skip the given number of bits. + * Must only be used if the actual values in the bitstream do not matter. + * If n is < 0 the behavior is undefined. + */ +static inline void skip_put_bits(PutBitContext *s, int n) { + unsigned bits = BUF_BITS - s->bit_left + n; + s->buf_ptr += sizeof(BitBuf) * (bits / BUF_BITS); + s->bit_left = BUF_BITS - (bits & (BUF_BITS - 1)); +} + +/** + * Change the end of the buffer. + * + * @param size the new size in bytes of the buffer where to put bits + */ +static inline void set_put_bits_buffer_size(PutBitContext *s, int size) { + av_assert0(size <= INT_MAX / 8 - BUF_BITS); + s->buf_end = s->buf + size; +} + +/** + * Pad the bitstream with zeros up to the next byte boundary. + */ +static inline void align_put_bits(PutBitContext *s) { + put_bits(s, s->bit_left & 7, 0); +} + +#undef AV_WBBUF +#undef AV_WLBUF + +#endif /* AVCODEC_PUT_BITS_H */ diff --git a/third-party/cbs/vlc.h b/third-party/cbs/vlc.h new file mode 100644 index 00000000..aaa21a9c --- /dev/null +++ b/third-party/cbs/vlc.h @@ -0,0 +1,140 @@ +/* + * 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_VLC_H +#define AVCODEC_VLC_H + +#include + +#define VLC_TYPE int16_t + +typedef struct VLC { + int bits; + VLC_TYPE (*table) + [2]; ///< code, bits + int table_size, table_allocated; +} VLC; + +typedef struct RL_VLC_ELEM { + int16_t level; + int8_t len; + uint8_t run; +} RL_VLC_ELEM; + +#define init_vlc(vlc, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + flags) \ + ff_init_vlc_sparse(vlc, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + NULL, 0, 0, flags) + +int ff_init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size, + const void *symbols, int symbols_wrap, int symbols_size, + int flags); + +/** + * Build VLC decoding tables suitable for use with get_vlc2() + * + * This function takes lengths and symbols and calculates the codes from them. + * For this the input lengths and symbols have to be sorted according to "left + * nodes in the corresponding tree first". + * + * @param[in,out] vlc The VLC to be initialized; table and table_allocated + * must have been set when initializing a static VLC, + * otherwise this will be treated as uninitialized. + * @param[in] nb_bits The number of bits to use for the VLC table; + * higher values take up more memory and cache, but + * allow to read codes with fewer reads. + * @param[in] nb_codes The number of provided length and (if supplied) symbol + * entries. + * @param[in] lens The lengths of the codes. Entries > 0 correspond to + * valid codes; entries == 0 will be skipped and entries + * with len < 0 indicate that the tree is incomplete and + * has an open end of length -len at this position. + * @param[in] lens_wrap Stride (in bytes) of the lengths. + * @param[in] symbols The symbols, i.e. what is returned from get_vlc2() + * when the corresponding code is encountered. + * May be NULL, then 0, 1, 2, 3, 4,... will be used. + * @param[in] symbols_wrap Stride (in bytes) of the symbols. + * @param[in] symbols_size Size of the symbols. 1 and 2 are supported. + * @param[in] offset An offset to apply to all the valid symbols. + * @param[in] flags A combination of the INIT_VLC_* flags; notice that + * INIT_VLC_INPUT_LE is pointless and ignored. + */ +int ff_init_vlc_from_lengths(VLC *vlc, int nb_bits, int nb_codes, + const int8_t *lens, int lens_wrap, + const void *symbols, int symbols_wrap, int symbols_size, + int offset, int flags, void *logctx); + +void ff_free_vlc(VLC *vlc); + +/* If INIT_VLC_INPUT_LE is set, the LSB bit of the codes used to + * initialize the VLC table is the first bit to be read. */ +#define INIT_VLC_INPUT_LE 2 +/* If set the VLC is intended for a little endian bitstream reader. */ +#define INIT_VLC_OUTPUT_LE 8 +#define INIT_VLC_LE (INIT_VLC_INPUT_LE | INIT_VLC_OUTPUT_LE) +#define INIT_VLC_USE_NEW_STATIC 4 +#define INIT_VLC_STATIC_OVERLONG (1 | INIT_VLC_USE_NEW_STATIC) + +#define INIT_CUSTOM_VLC_SPARSE_STATIC(vlc, bits, a, b, c, d, e, f, g, \ + h, i, j, flags, static_size) \ + do { \ + static VLC_TYPE table[static_size][2]; \ + (vlc)->table = table; \ + (vlc)->table_allocated = static_size; \ + ff_init_vlc_sparse(vlc, bits, a, b, c, d, e, f, g, h, i, j, \ + flags | INIT_VLC_USE_NEW_STATIC); \ + } while(0) + +#define INIT_VLC_SPARSE_STATIC(vlc, bits, a, b, c, d, e, f, g, h, i, j, static_size) \ + INIT_CUSTOM_VLC_SPARSE_STATIC(vlc, bits, a, b, c, d, e, f, g, \ + h, i, j, 0, static_size) + +#define INIT_LE_VLC_SPARSE_STATIC(vlc, bits, a, b, c, d, e, f, g, h, i, j, static_size) \ + INIT_CUSTOM_VLC_SPARSE_STATIC(vlc, bits, a, b, c, d, e, f, g, \ + h, i, j, INIT_VLC_LE, static_size) + +#define INIT_CUSTOM_VLC_STATIC(vlc, bits, a, b, c, d, e, f, g, flags, static_size) \ + INIT_CUSTOM_VLC_SPARSE_STATIC(vlc, bits, a, b, c, d, e, f, g, \ + NULL, 0, 0, flags, static_size) + +#define INIT_VLC_STATIC(vlc, bits, a, b, c, d, e, f, g, static_size) \ + INIT_VLC_SPARSE_STATIC(vlc, bits, a, b, c, d, e, f, g, NULL, 0, 0, static_size) + +#define INIT_LE_VLC_STATIC(vlc, bits, a, b, c, d, e, f, g, static_size) \ + INIT_LE_VLC_SPARSE_STATIC(vlc, bits, a, b, c, d, e, f, g, NULL, 0, 0, static_size) + +#define INIT_VLC_STATIC_FROM_LENGTHS(vlc, bits, nb_codes, lens, len_wrap, \ + symbols, symbols_wrap, symbols_size, \ + offset, flags, static_size) \ + do { \ + static VLC_TYPE table[static_size][2]; \ + (vlc)->table = table; \ + (vlc)->table_allocated = static_size; \ + ff_init_vlc_from_lengths(vlc, bits, nb_codes, lens, len_wrap, \ + symbols, symbols_wrap, symbols_size, \ + offset, flags | INIT_VLC_USE_NEW_STATIC, \ + NULL); \ + } while(0) + +#endif /* AVCODEC_VLC_H */ diff --git a/third-party/cbs/x86/asm.h b/third-party/cbs/x86/asm.h new file mode 100644 index 00000000..0a060499 --- /dev/null +++ b/third-party/cbs/x86/asm.h @@ -0,0 +1,157 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * 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 AVUTIL_X86_ASM_H +#define AVUTIL_X86_ASM_H + +#include + +typedef struct xmm_reg { + uint64_t a, b; +} xmm_reg; +typedef struct ymm_reg { + uint64_t a, b, c, d; +} ymm_reg; + +#if ARCH_X86_64 +#define FF_OPSIZE "q" +#define FF_REG_a "rax" +#define FF_REG_b "rbx" +#define FF_REG_c "rcx" +#define FF_REG_d "rdx" +#define FF_REG_D "rdi" +#define FF_REG_S "rsi" +#define FF_PTR_SIZE "8" +typedef int64_t x86_reg; + +/* FF_REG_SP is defined in Solaris sys headers, so use FF_REG_sp */ +#define FF_REG_sp "rsp" +#define FF_REG_BP "rbp" +#define FF_REGBP rbp +#define FF_REGa rax +#define FF_REGb rbx +#define FF_REGc rcx +#define FF_REGd rdx +#define FF_REGSP rsp + +#elif ARCH_X86_32 + +#define FF_OPSIZE "l" +#define FF_REG_a "eax" +#define FF_REG_b "ebx" +#define FF_REG_c "ecx" +#define FF_REG_d "edx" +#define FF_REG_D "edi" +#define FF_REG_S "esi" +#define FF_PTR_SIZE "4" +typedef int32_t x86_reg; + +#define FF_REG_sp "esp" +#define FF_REG_BP "ebp" +#define FF_REGBP ebp +#define FF_REGa eax +#define FF_REGb ebx +#define FF_REGc ecx +#define FF_REGd edx +#define FF_REGSP esp +#else +typedef int x86_reg; +#endif + +#define HAVE_7REGS (ARCH_X86_64 || (HAVE_EBX_AVAILABLE && HAVE_EBP_AVAILABLE)) +#define HAVE_6REGS (ARCH_X86_64 || (HAVE_EBX_AVAILABLE || HAVE_EBP_AVAILABLE)) + +#if ARCH_X86_64 && defined(PIC) +#define BROKEN_RELOCATIONS 1 +#endif + +/* + * If gcc is not set to support sse (-msse) it will not accept xmm registers + * in the clobber list for inline asm. XMM_CLOBBERS takes a list of xmm + * registers to be marked as clobbered and evaluates to nothing if they are + * not supported, or to the list itself if they are supported. Since a clobber + * list may not be empty, XMM_CLOBBERS_ONLY should be used if the xmm + * registers are the only in the clobber list. + * For example a list with "eax" and "xmm0" as clobbers should become: + * : XMM_CLOBBERS("xmm0",) "eax" + * and a list with only "xmm0" should become: + * XMM_CLOBBERS_ONLY("xmm0") + */ +#if HAVE_XMM_CLOBBERS +#define XMM_CLOBBERS(...) __VA_ARGS__ +#define XMM_CLOBBERS_ONLY(...) : __VA_ARGS__ +#else +#define XMM_CLOBBERS(...) +#define XMM_CLOBBERS_ONLY(...) +#endif + +/* Use to export labels from asm. */ +#define LABEL_MANGLE(a) EXTERN_PREFIX #a + +// Use rip-relative addressing if compiling PIC code on x86-64. +#if ARCH_X86_64 && defined(PIC) +#define LOCAL_MANGLE(a) #a "(%%rip)" +#else +#define LOCAL_MANGLE(a) #a +#endif + +#if HAVE_INLINE_ASM_DIRECT_SYMBOL_REFS +#define MANGLE(a) EXTERN_PREFIX LOCAL_MANGLE(a) +#define NAMED_CONSTRAINTS_ADD(...) +#define NAMED_CONSTRAINTS(...) +#define NAMED_CONSTRAINTS_ARRAY_ADD(...) +#define NAMED_CONSTRAINTS_ARRAY(...) +#else +/* When direct symbol references are used in code passed to a compiler that does not support them + * then these references need to be converted to named asm constraints instead. + * Instead of returning a direct symbol MANGLE now returns a named constraint for that specific symbol. + * In order for this to work there must also be a corresponding entry in the asm-interface. To add this + * entry use the macro NAMED_CONSTRAINTS() and pass in a list of each symbol reference used in the + * corresponding block of code. (e.g. NAMED_CONSTRAINTS(var1,var2,var3) where var1 is the first symbol etc. ). + * If there are already existing constraints then use NAMED_CONSTRAINTS_ADD to add to the existing constraint list. + */ +#define MANGLE(a) "%[" #a "]" +// Intel/MSVC does not correctly expand va-args so we need a rather ugly hack in order to get it to work +#define FE_0(P, X) P(X) +#define FE_1(P, X, X1) P(X), FE_0(P, X1) +#define FE_2(P, X, X1, X2) P(X), FE_1(P, X1, X2) +#define FE_3(P, X, X1, X2, X3) P(X), FE_2(P, X1, X2, X3) +#define FE_4(P, X, X1, X2, X3, X4) P(X), FE_3(P, X1, X2, X3, X4) +#define FE_5(P, X, X1, X2, X3, X4, X5) P(X), FE_4(P, X1, X2, X3, X4, X5) +#define FE_6(P, X, X1, X2, X3, X4, X5, X6) P(X), FE_5(P, X1, X2, X3, X4, X5, X6) +#define FE_7(P, X, X1, X2, X3, X4, X5, X6, X7) P(X), FE_6(P, X1, X2, X3, X4, X5, X6, X7) +#define FE_8(P, X, X1, X2, X3, X4, X5, X6, X7, X8) P(X), FE_7(P, X1, X2, X3, X4, X5, X6, X7, X8) +#define FE_9(P, X, X1, X2, X3, X4, X5, X6, X7, X8, X9) P(X), FE_8(P, X1, X2, X3, X4, X5, X6, X7, X8, X9) +#define GET_FE_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, NAME, ...) NAME +#define GET_FE(A) GET_FE_IMPL A +#define GET_FE_GLUE(x, y) x y +#define FOR_EACH_VA(P, ...) GET_FE_GLUE(GET_FE((__VA_ARGS__, FE_9, FE_8, FE_7, FE_6, FE_5, FE_4, FE_3, FE_2, FE_1, FE_0)), (P, __VA_ARGS__)) +#define NAME_CONSTRAINT(x) [x] "m"(x) +// Parameters are a list of each symbol reference required +#define NAMED_CONSTRAINTS_ADD(...) , FOR_EACH_VA(NAME_CONSTRAINT, __VA_ARGS__) +// Same but without comma for when there are no previously defined constraints +#define NAMED_CONSTRAINTS(...) FOR_EACH_VA(NAME_CONSTRAINT, __VA_ARGS__) +// Same as above NAMED_CONSTRAINTS except used for passing arrays/pointers instead of normal variables +#define NAME_CONSTRAINT_ARRAY(x) [x] "m"(*x) +#define NAMED_CONSTRAINTS_ARRAY_ADD(...) , FOR_EACH_VA(NAME_CONSTRAINT_ARRAY, __VA_ARGS__) +#define NAMED_CONSTRAINTS_ARRAY(...) FOR_EACH_VA(NAME_CONSTRAINT_ARRAY, __VA_ARGS__) +#endif + +#endif /* AVUTIL_X86_ASM_H */ diff --git a/third-party/cbs/x86/intmath.h b/third-party/cbs/x86/intmath.h new file mode 100644 index 00000000..54bf4aa1 --- /dev/null +++ b/third-party/cbs/x86/intmath.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2015 James Almer + * + * 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 AVUTIL_X86_INTMATH_H +#define AVUTIL_X86_INTMATH_H + +#include +#include +#if HAVE_FAST_CLZ +#if defined(_MSC_VER) +#include +#elif defined(__INTEL_COMPILER) +#include +#endif +#endif + +#if HAVE_FAST_CLZ +#if(defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1216)) || defined(_MSC_VER) +#if defined(__INTEL_COMPILER) +#define ff_log2(x) (_bit_scan_reverse((x) | 1)) +#else +#define ff_log2 ff_log2_x86 +static av_always_inline av_const int ff_log2_x86(unsigned int v) { + unsigned long n; + _BitScanReverse(&n, v | 1); + return n; +} +#endif +#define ff_log2_16bit av_log2 + +#if defined(__INTEL_COMPILER) || (defined(_MSC_VER) && (_MSC_VER >= 1700) && \ + (defined(__BMI__) || !defined(__clang__))) +#define ff_ctz(v) _tzcnt_u32(v) + +#if ARCH_X86_64 +#define ff_ctzll(v) _tzcnt_u64(v) +#else +#define ff_ctzll ff_ctzll_x86 +static av_always_inline av_const int ff_ctzll_x86(long long v) { + return ((uint32_t)v == 0) ? _tzcnt_u32((uint32_t)(v >> 32)) + 32 : _tzcnt_u32((uint32_t)v); +} +#endif +#endif /* _MSC_VER */ + +#endif /* __INTEL_COMPILER */ + +#endif /* HAVE_FAST_CLZ */ + +#if defined(__GNUC__) + +/* Our generic version of av_popcount is faster than GCC's built-in on + * CPUs that don't support the popcnt instruction. + */ +#if defined(__POPCNT__) +#define av_popcount __builtin_popcount +#if ARCH_X86_64 +#define av_popcount64 __builtin_popcountll +#endif + +#endif /* __POPCNT__ */ + +#if defined(__BMI2__) + +#if AV_GCC_VERSION_AT_LEAST(5, 1) +#define av_mod_uintp2 __builtin_ia32_bzhi_si +#elif HAVE_INLINE_ASM +/* GCC releases before 5.1.0 have a broken bzhi builtin, so for those we + * implement it using inline assembly + */ +#define av_mod_uintp2 av_mod_uintp2_bmi2 +static av_always_inline av_const unsigned av_mod_uintp2_bmi2(unsigned a, unsigned p) { + if(av_builtin_constant_p(p)) + return a & ((1 << p) - 1); + else { + unsigned x; + __asm__("bzhi %2, %1, %0 \n\t" + : "=r"(x) + : "rm"(a), "r"(p)); + return x; + } +} +#endif /* AV_GCC_VERSION_AT_LEAST */ + +#endif /* __BMI2__ */ + +#ifdef av_clipd +#undef av_clipd +#endif + +#ifdef av_clipf +#undef av_clipf +#endif + +#if defined(__SSE2__) && !defined(__INTEL_COMPILER) + +#define av_clipd av_clipd_sse2 +static av_always_inline av_const double av_clipd_sse2(double a, double amin, double amax) { +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if(amin > amax) abort(); +#endif + __asm__("minsd %2, %0 \n\t" + "maxsd %1, %0 \n\t" + : "+&x"(a) + : "xm"(amin), "xm"(amax)); + return a; +} + +#endif /* __SSE2__ */ + +#if defined(__SSE__) && !defined(__INTEL_COMPILER) + +#define av_clipf av_clipf_sse +static av_always_inline av_const float av_clipf_sse(float a, float amin, float amax) { +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if(amin > amax) abort(); +#endif + __asm__("minss %2, %0 \n\t" + "maxss %1, %0 \n\t" + : "+&x"(a) + : "xm"(amin), "xm"(amax)); + return a; +} + +#endif /* __SSE__ */ + +#endif /* __GNUC__ */ + +#endif /* AVUTIL_X86_INTMATH_H */ diff --git a/third-party/cbs/x86/mathops.h b/third-party/cbs/x86/mathops.h new file mode 100644 index 00000000..e653c531 --- /dev/null +++ b/third-party/cbs/x86/mathops.h @@ -0,0 +1,121 @@ +/* + * simple math operations + * Copyright (c) 2006 Michael Niedermayer et al + * + * 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_X86_MATHOPS_H +#define AVCODEC_X86_MATHOPS_H + +#include + +#include "asm.h" + +#if HAVE_INLINE_ASM + +#if ARCH_X86_32 + +#define MULL MULL +static av_always_inline av_const int MULL(int a, int b, unsigned shift) { + int rt, dummy; + __asm__( + "imull %3 \n\t" + "shrdl %4, %%edx, %%eax \n\t" + : "=a"(rt), "=d"(dummy) + : "a"(a), "rm"(b), "ci"((uint8_t)shift)); + return rt; +} + +#define MULH MULH +static av_always_inline av_const int MULH(int a, int b) { + int rt, dummy; + __asm__( + "imull %3" + : "=d"(rt), "=a"(dummy) + : "a"(a), "rm"(b)); + return rt; +} + +#define MUL64 MUL64 +static av_always_inline av_const int64_t MUL64(int a, int b) { + int64_t rt; + __asm__( + "imull %2" + : "=A"(rt) + : "a"(a), "rm"(b)); + return rt; +} + +#endif /* ARCH_X86_32 */ + +#if HAVE_I686 +/* median of 3 */ +#define mid_pred mid_pred +static inline av_const int mid_pred(int a, int b, int c) { + int i = b; + __asm__( + "cmp %2, %1 \n\t" + "cmovg %1, %0 \n\t" + "cmovg %2, %1 \n\t" + "cmp %3, %1 \n\t" + "cmovl %3, %1 \n\t" + "cmp %1, %0 \n\t" + "cmovg %1, %0 \n\t" + : "+&r"(i), "+&r"(a) + : "r"(b), "r"(c)); + return i; +} + +#if HAVE_6REGS +#define COPY3_IF_LT(x, y, a, b, c, d) \ + __asm__ volatile( \ + "cmpl %0, %3 \n\t" \ + "cmovl %3, %0 \n\t" \ + "cmovl %4, %1 \n\t" \ + "cmovl %5, %2 \n\t" \ + : "+&r"(x), "+&r"(a), "+r"(c) \ + : "r"(y), "r"(b), "r"(d)); +#endif /* HAVE_6REGS */ + +#endif /* HAVE_I686 */ + +#define MASK_ABS(mask, level) \ + __asm__("cdq \n\t" \ + "xorl %1, %0 \n\t" \ + "subl %1, %0 \n\t" \ + : "+a"(level), "=&d"(mask)) + +// avoid +32 for shift optimization (gcc should do that ...) +#define NEG_SSR32 NEG_SSR32 +static inline int32_t NEG_SSR32(int32_t a, int8_t s) { + __asm__("sarl %1, %0\n\t" + : "+r"(a) + : "ic"((uint8_t)(-s))); + return a; +} + +#define NEG_USR32 NEG_USR32 +static inline uint32_t NEG_USR32(uint32_t a, int8_t s) { + __asm__("shrl %1, %0\n\t" + : "+r"(a) + : "ic"((uint8_t)(-s))); + return a; +} + +#endif /* HAVE_INLINE_ASM */ +#endif /* AVCODEC_X86_MATHOPS_H */