From: Dawid Kozinski <d.kozinski@samsung.com> To: ffmpeg-devel@ffmpeg.org Cc: Dawid Kozinski <d.kozinski@samsung.com> Subject: [FFmpeg-devel] [PATCH v1 2/8] avcodec/apv_parser: Added parser implementation for APV format Date: Wed, 23 Apr 2025 16:12:26 +0200 Message-ID: <20250423141226.1857892-1-d.kozinski@samsung.com> (raw) In-Reply-To: <CGME20250423141230eucas1p1962c2698d09aced37fa5551493a693b8@eucas1p1.samsung.com> - Added constants definitions for APV parser - Provided parsing following APV RFC - APV parser registration Signed-off-by: Dawid Kozinski <d.kozinski@samsung.com> --- configure | 2 + libavcodec/Makefile | 2 + libavcodec/apv.h | 93 ++++++++ libavcodec/apv_parse.c | 32 +++ libavcodec/apv_parse.h | 81 +++++++ libavcodec/apv_parser.c | 141 +++++++++++ libavcodec/apv_ps.c | 503 ++++++++++++++++++++++++++++++++++++++++ libavcodec/apv_ps.h | 188 +++++++++++++++ libavcodec/parsers.c | 1 + 9 files changed, 1043 insertions(+) create mode 100644 libavcodec/apv.h create mode 100644 libavcodec/apv_parse.c create mode 100644 libavcodec/apv_parse.h create mode 100644 libavcodec/apv_parser.c create mode 100644 libavcodec/apv_ps.c create mode 100644 libavcodec/apv_ps.h diff --git a/configure b/configure index c94b8eac43..294f7e4a9d 100755 --- a/configure +++ b/configure @@ -2555,6 +2555,7 @@ CONFIG_EXTRA=" aandcttables ac3dsp adts_header + apvparse atsc_a53 audio_frame_queue audiodsp @@ -3481,6 +3482,7 @@ vvc_qsv_decoder_select="vvc_mp4toannexb_bsf qsvdec" # parsers aac_parser_select="adts_header mpeg4audio" +apv_parser_select="apvparse" av1_parser_select="cbs_av1" evc_parser_select="evcparse" ffv1_parser_select="rangecoder" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 7bd1dbec9a..3ae6dd17ea 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -76,6 +76,7 @@ OBJS-$(CONFIG_AANDCTTABLES) += aandcttab.o OBJS-$(CONFIG_AC3DSP) += ac3dsp.o ac3.o ac3tab.o OBJS-$(CONFIG_ADTS_HEADER) += adts_header.o mpeg4audio_sample_rates.o OBJS-$(CONFIG_AMF) += amfenc.o amfdec.o +OBJS-$(CONFIG_APVPARSE) += apv_parse.o apv_ps.o OBJS-$(CONFIG_AUDIO_FRAME_QUEUE) += audio_frame_queue.o OBJS-$(CONFIG_ATSC_A53) += atsc_a53.o OBJS-$(CONFIG_AUDIODSP) += audiodsp.o @@ -1196,6 +1197,7 @@ OBJS-$(CONFIG_AC3_PARSER) += aac_ac3_parser.o ac3tab.o \ ac3_channel_layout_tab.o OBJS-$(CONFIG_ADX_PARSER) += adx_parser.o OBJS-$(CONFIG_AMR_PARSER) += amr_parser.o +OBJS-$(CONFIG_APV_PARSER) += apv_parser.o OBJS-$(CONFIG_AV1_PARSER) += av1_parser.o av1_parse.o OBJS-$(CONFIG_AVS2_PARSER) += avs2.o avs2_parser.o OBJS-$(CONFIG_AVS3_PARSER) += avs3_parser.o diff --git a/libavcodec/apv.h b/libavcodec/apv.h new file mode 100644 index 0000000000..f40515440b --- /dev/null +++ b/libavcodec/apv.h @@ -0,0 +1,93 @@ +/* + * APV definitions and enums + * + * Copyright (c) 2025 Dawid Kozinski <d.kozinski@samsung.com> + * + * 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_APV_H +#define AVCODEC_APV_H + +// The length field that indicates the length in bytes of the following Frame Data is configured to be of 4 bytes +// A four-byte length Frame Data Size syntax element, which indicates the size of the Frame Data in bytes, may precede the Frame Data, depending on the application. +#define APV_AU_SIZE_PREFIX_LENGTH (4) /* byte */ +#define APV_PBU_SIZE_PREFIX_LENGTH (4) /* byte */ +#define APV_SIGNATURE_LENGTH (4) /* byte */ + +// @deprecated +#define APV_FRAME_DATA_SIZE_PREFIX_LENGTH (4) /* byte */ + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#section-5.3.3 +#define APV_PBU_HEADER_SIZE (4) /* byte */ + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#section-5.3.6 +#define APV_FRAME_INFO_SIZE (14) /* byte */ + +/* size of macroblock */ +#define APV_LOG2_MB (4) +#define APV_MB (1<<APV_LOG2_MB) +#define APV_MB_W (1<<APV_LOG2_MB) +#define APV_MB_H (1<<APV_LOG2_MB) +#define APV_MB_D (APV_MB_W * APV_MB_H) + +/* size of block */ +#define APV_LOG2_BLOCK (3) +#define APV_BLOCK (1<<APV_LOG2_BLOCK) +#define APV_BLOCK_W (1<<APV_LOG2_BLOCK) +#define APV_BLOCK_H (1<<APV_LOG2_BLOCK) +#define APV_BLOCK_D (APV_BLOCK_W * APV_BLOCK_H) + +/* @see WD1 APV spec section 7.3.2.2*/ +#define APV_PREV_DC_DIFF 40 + +/* size of macroblock */ +enum { + APV_MB_WIDTH = 16, + APV_MB_HEIGHT = 16, +}; + +/* Color components */ +enum { + APV_COLOR_COMP_Y = 0, /* Y luma */ + APV_COLOR_COMP_U = 1, /* Cb Chroma */ + APV_COLOR_COMP_V = 2, /* Cr Chroma */ + APV_COLOR_COMP_A = 3, /* Alpha */ + APV_COLOR_COMP_NUM = 4 /* number of color component */ +}; + +/* size of block */ +#define LOG2_BLK (3) +#define LOG2_BLK_W (3) +#define LOG2_BLK_H (3) +#define BLK_W (1 << LOG2_BLK) +#define BLK_H (1 << LOG2_BLK) +#define BLK_D (BLK_W * BLK_H) + +const static uint16_t ScanOrder[BLK_D] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, +}; + +#endif // AVCODEC_APV_H diff --git a/libavcodec/apv_parse.c b/libavcodec/apv_parse.c new file mode 100644 index 0000000000..c6b16679d9 --- /dev/null +++ b/libavcodec/apv_parse.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Dawid Kozinski <d.kozinski@samsung.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "parser.h" + +#include "apv.h" +#include "apv_parse.h" + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-frame +int ff_apv_parse_frame_data(GetBitContext *gb, APVFrameData *fd) +{ + ff_apv_parse_frame_header(gb, &fd->frame_data_header); + + return 0; +} diff --git a/libavcodec/apv_parse.h b/libavcodec/apv_parse.h new file mode 100644 index 0000000000..78af9d8f89 --- /dev/null +++ b/libavcodec/apv_parse.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025 Dawid Kozinski <d.kozinski@samsung.com> + * + * 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 + * APV decoder/parser shared code + */ + +#ifndef AVCODEC_APV_PARSE_H +#define AVCODEC_APV_PARSE_H + +#include <stdint.h> + +#include "libavutil/log.h" +#include "apv.h" +#include "apv_ps.h" + +static inline uint32_t apv_read_frame_data_size(const uint8_t *bits, int bits_size, void *logctx) +{ + uint32_t frame_data_size = 0; + + if (bits_size < APV_FRAME_DATA_SIZE_PREFIX_LENGTH) { + av_log(logctx, AV_LOG_ERROR, "Can't read Frame Data size\n"); + return 0; + } + + frame_data_size = AV_RB32(bits); + + return frame_data_size; +} + +// @see 12.1. Raw bitstream format [https://www.ietf.org/archive/id/draft-lim-apv-04.html#section-12.1] +static inline uint32_t apv_read_au_size(const uint8_t *bits, int bits_size, void *logctx) +{ + uint32_t au_size = 0; + + if (bits_size < APV_AU_SIZE_PREFIX_LENGTH) { + av_log(logctx, AV_LOG_ERROR, "Can't read Access Unit size\n"); + return 0; + } + + au_size = AV_RB32(bits); + + return au_size; +} + +static inline uint32_t apv_read_pbu_size(const uint8_t *bits, int bits_size, void *logctx) +{ + uint32_t pbu_size = 0; + + if (bits_size < APV_PBU_SIZE_PREFIX_LENGTH) { + av_log(logctx, AV_LOG_ERROR, "Can't read PBU (primitive bitstream unit) size\n"); + return 0; + } + + pbu_size = AV_RB32(bits); + + return pbu_size; +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-frame +int ff_apv_parse_frame_data(GetBitContext *gb, APVFrameData *fd); + +#endif /* AVCODEC_APV_PARSE_H */ diff --git a/libavcodec/apv_parser.c b/libavcodec/apv_parser.c new file mode 100644 index 0000000000..cc5b59e205 --- /dev/null +++ b/libavcodec/apv_parser.c @@ -0,0 +1,141 @@ +/* + * APV format parser + * + * Copyright (C) 2025 Dawid Kozinski <d.kozinski@samsung.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "parser.h" +#include "bytestream.h" +#include "apv.h" +#include "apv_parse.h" + +typedef struct APVParserContext { + APVParamSets ps; + + int parsed_extradata; +} APVParserContext; + +/** + * @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#section-12.1 + * + * Parse APV bitstream + * + * @param s codec parser context + * @param avctx codec context + * @param buf buffer with field/frame data + * @param buf_size size of the buffer + */ +static int parse_apv_bitstream(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t *buf, int buf_size) +{ + const uint8_t *data = buf; + int data_size = buf_size; + + if (data_size > 0) { + int au_size = 0; + + // Buffer size is not enough for buffer to store Frame Data 4-bytes prefix (length) + if (data_size < APV_AU_SIZE_PREFIX_LENGTH) + return AVERROR_INVALIDDATA; + + au_size = apv_read_au_size(data, APV_AU_SIZE_PREFIX_LENGTH, avctx); + + if (!au_size || au_size > INT_MAX) + return AVERROR_INVALIDDATA; + + data += APV_AU_SIZE_PREFIX_LENGTH; + data_size -= APV_AU_SIZE_PREFIX_LENGTH; + + if (data_size < au_size) + return AVERROR_INVALIDDATA; + } + return 0; +} + +// Decoding Frame Data from apvC (APVDecoderConfigurationRecord) +static int decode_extradata(AVCodecParserContext *s, AVCodecContext *avctx) +{ + const uint8_t *data = avctx->extradata; + int size = avctx->extradata_size; + int ret = 0; + if (!data || size <= 0) + return -1; + + return ret; +} + +static int apv_parse(AVCodecParserContext *s, AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + int next; + int ret; + APVParserContext *ctx = s->priv_data; + + s->picture_structure = AV_PICTURE_STRUCTURE_FRAME; + s->key_frame = 1; + + if (avctx->extradata && !ctx->parsed_extradata) { + decode_extradata(s, avctx); + ctx->parsed_extradata = 1; + } + + next = buf_size; + + ret = parse_apv_bitstream(s, avctx, buf, buf_size); + if(ret < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + + // poutbuf contains just one Access Unit + *poutbuf = buf; + *poutbuf_size = buf_size; + + return next; +} + +static void apv_parser_close(AVCodecParserContext *s) +{ + APVParserContext *ctx = s->priv_data; + + if(ctx->ps.frame_data.frame_data_header.tile_info.ColStarts) { + free(ctx->ps.frame_data.frame_data_header.tile_info.ColStarts); + ctx->ps.frame_data.frame_data_header.tile_info.ColStarts = NULL; + } + + if(ctx->ps.frame_data.frame_data_header.tile_info.RowStarts) { + free(ctx->ps.frame_data.frame_data_header.tile_info.RowStarts); + ctx->ps.frame_data.frame_data_header.tile_info.RowStarts = NULL; + } + + if(ctx->ps.frame_data.frame_data_header.tile_info.tile_size_in_fh) { + free(ctx->ps.frame_data.frame_data_header.tile_info.tile_size_in_fh); + ctx->ps.frame_data.frame_data_header.tile_info.tile_size_in_fh = NULL; + } + + ff_apv_ps_free(&ctx->ps); +} + +const AVCodecParser ff_apv_parser = { + .codec_ids = { AV_CODEC_ID_APV }, + .priv_data_size = sizeof(APVParserContext), + .parser_parse = apv_parse, + .parser_close = apv_parser_close, +}; diff --git a/libavcodec/apv_ps.c b/libavcodec/apv_ps.c new file mode 100644 index 0000000000..a9fa0c8030 --- /dev/null +++ b/libavcodec/apv_ps.c @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2025 Dawid Kozinski <d.kozinski@samsung.com> + * + * 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 "golomb.h" +#include "parser.h" +#include "apv.h" +#include "apv_ps.h" + +#define ffapv_max(a,b) \ +({ \ + __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; \ +}) + +#define ffapv_min(a,b) \ +({ \ + __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; \ +}) + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-arithmetic-operators +#define ffapv_clip3(min, max, val) ffapv_max( (min), ffapv_min((max), (val)) ) + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#section-5.3.3 +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-primitive-bitstream-unit-he +int ff_apv_parse_pbu_header(GetBitContext *gb, APVPBUHeader *pbuh) +{ + pbuh->pbu_type = get_bits(gb, 8); + pbuh->group_id = get_bits(gb, 16); + pbuh->reserved_zer_8bits = get_bits(gb, 8); + + return 0; +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-tile-info +int ff_apv_tile_info(GetBitContext *gb, const APVFrameDataHeader *fdh, APVTileInfo *ti) +{ + // @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-source-decoded-and-output-f + int MbWidth = APV_MB_WIDTH; + int MbHeight = APV_MB_HEIGHT; + + int FrameWidthInSamplesY; + int FrameHeightInSamplesY; + int FrameWidthInMbsY; + int FrameHeightInMbsY; + + int startMb = 0; + int i = 0; + + ti->tile_width_in_mbs = get_bits(gb, 20); + ti->tile_height_in_mbs = get_bits(gb, 20); + + FrameWidthInSamplesY = fdh->frame_info.frame_width; + FrameHeightInSamplesY = fdh->frame_info.frame_height; + FrameWidthInMbsY = ceil( FrameWidthInSamplesY / MbWidth ); + FrameHeightInMbsY = ceil( FrameHeightInSamplesY / MbHeight ); + + if(!ti->ColStarts) + free(ti->ColStarts); + + // @todo remember to free it + ti->ColStarts = malloc(sizeof(int) * FrameWidthInMbsY); + + for( i = 0; startMb < FrameWidthInMbsY; i++ ) { + ti->ColStarts[ i ] = startMb * MbWidth; + startMb += ti->tile_width_in_mbs; + } + + ti->ColStarts[ i ] = FrameWidthInMbsY * MbWidth; + ti->TileCols = i; + + startMb = 0; + + if(!ti->RowStarts) + free(ti->RowStarts); + + // @todo remember to free it + ti->RowStarts = malloc(sizeof(int) * FrameHeightInMbsY); + + for( i = 0; startMb < FrameHeightInMbsY; i++ ) { + ti->RowStarts[ i ] = startMb * MbHeight; + startMb += ti->tile_height_in_mbs + 1; + } + + ti->RowStarts[ i ] = FrameHeightInMbsY * MbHeight; + ti->TileRows = i; + ti->NumTiles = ti->TileCols * ti->TileRows; + + if(!ti->tile_size_in_fh) + free(ti->tile_size_in_fh); + + // @todo remember to free it + ti->tile_size_in_fh = malloc(sizeof(uint32_t) * ti->NumTiles); + + for( i = 0; i < ti->NumTiles ; i++ ) + ti->tile_size_in_fh[i] = get_bits(gb, 32); + + return 0; +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-byte_aligned +// byte_aligned( ) is specified as follows: +// — If the current position in the bitstream is on a byte boundary, i.e., the next bit in the bitstream is the first bit in a byte, the return value of byte_aligned( ) is equal to TRUE. +// — Otherwise, the return value of byte_aligned( ) is equal to FALSE. +// +static int byte_aligned(GetBitContext *gb) +{ + int bits_count = get_bits_count(gb); + if (bits_count % 8) + return 1; + else + return 0; +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-byte-alignment +int ff_apv_byte_alignment(GetBitContext *gb, APVByteAlignemnt *ba) +{ + while(!byte_aligned(gb)) + ba->alignment_bit_equal_to_zero = get_bits1(gb); + return 0; +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-quantization-matrix +int ff_apv_quantization_matrix(GetBitContext *gb, int num_comp, APVQuantizationMatrix *qm) +{ + for( int cIdx = 0; cIdx < num_comp; cIdx ++ ) { + for( int y = 0; y < 8; y ++ ) { + for( int x = 0; x < 8; x ++ ) + qm->q_matrix[ cIdx ][ x ][ y ] = get_bits(gb, 8); + } + } + return 0; +} + +// https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-frame-information +int ff_apv_parse_frame_info(GetBitContext *gb, APVFrameInfo *frame_info) +{ + frame_info->profile_idc = get_bits(gb, 8); + frame_info->level_idc = get_bits(gb, 8); + frame_info->band_idc = get_bits(gb, 3); + frame_info->reserved_zero_5bits = get_bits(gb, 5); + frame_info->frame_width = get_bits(gb, 24); + frame_info->frame_height = get_bits(gb, 24); + frame_info->chroma_format_idc = get_bits(gb, 4); + frame_info->bit_depth_minus8 = get_bits(gb, 4); + frame_info->capture_time_distance = get_bits(gb, 8); + frame_info->reserved_zero_8bits = get_bits(gb, 8); + + return 0; +} + +static int num_component(int chroma_format_idc) { + int NumComps = 0; + + switch (chroma_format_idc) + { + case 0: + NumComps = 1; + break; + case 2: + case 3: + NumComps = 3; + break; + case 4: + NumComps = 4; + break; + + default: + break; + } + return NumComps; +} + +static int sub_width_c(int chroma_format_idc) { + int SubWidthC = 0; + + switch (chroma_format_idc) + { + case 0: + SubWidthC = 1; + break; + case 2: + SubWidthC = 2; + break; + case 3: + SubWidthC = 1; + break; + case 4: + SubWidthC = 1; + break; + + default: + break; + } + return SubWidthC; +} + +static int apv_parse_pbu_header(GetBitContext *gb, APVPBUHeader *pbuh) +{ + pbuh->pbu_type = get_bits(gb, 8); + pbuh->group_id = get_bits(gb, 16); + pbuh->reserved_zer_8bits = get_bits(gb, 8); + + return 0; +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-frame-header + +int ff_apv_parse_frame_header(GetBitContext *gb, APVFrameDataHeader *frame_header) +{ + int ret = 0; + int NumComps = APV_COLOR_COMP_NUM; + + ret = ff_apv_parse_frame_info(gb, &frame_header->frame_info); + + frame_header->reserved_zero_8bits = get_bits(gb, 8); + frame_header->color_description_present_flag = get_bits(gb, 1); + + if(frame_header->color_description_present_flag) { + frame_header->color_primaries = get_bits(gb, 8); + frame_header->transfer_characteristics = get_bits(gb, 8); + frame_header->matrix_coefficients = get_bits(gb, 8); + } + + frame_header->use_q_matrix = get_bits(gb, 1); + + NumComps = num_component(frame_header->frame_info.chroma_format_idc); + if(NumComps == 0) { + return -1; + } + + if(frame_header->use_q_matrix) + ret = ff_apv_quantization_matrix(gb, NumComps, &frame_header->quantization_matrix); + + ff_apv_tile_info(gb, frame_header, &frame_header->tile_info); + frame_header->reserved_zero_8bits_2 = get_bits(gb, 8); + + ff_apv_byte_alignment(gb, &frame_header->byte_alignent); + + return ret; +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-process-for-variable-length- +static int read_vlc(GetBitContext *gb, uint32_t kParam) +{ + + uint32_t symbolValue = 0; + uint8_t parseExpGolomb = 1; + uint32_t k = kParam; + uint32_t stopLoop = 0; + + if( get_bits(gb, 1) == 1 ) + parseExpGolomb = 0; + else { + if( get_bits(gb, 1) == 0 ) { + symbolValue += ( 1 << k ); + parseExpGolomb = 0; + } else { + symbolValue += ( 2 << k ); + parseExpGolomb = 1; + } + } + + if( parseExpGolomb ) { + do { + if( get_bits(gb, 1) == 1 ) + stopLoop = 1; + else { + symbolValue += ( 1 << k ); + k++; + } + } while( !stopLoop ); + } + + if( k > 0 ) + symbolValue += get_bits(gb, k); + + return symbolValue; +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-ac-coefficient-coding +static void ac_coeff_coding( GetBitContext *gb, uint32_t Prev1stAcLevel, int32_t TransCoeff[APV_COLOR_COMP_NUM][APV_MB_WIDTH][APV_MB_HEIGHT], uint32_t x0, uint32_t y0, int log2BlkWidth, int log2BlkHeight, int cIdx ) +{ + int scanPos = 1; + int firstAC = 1; + int PrevLevel = Prev1stAcLevel; + int PrevRun = 0; + + do { + int kParam = ffapv_clip3( 0, 2, PrevRun >> 2 ); + int coeff_zero_run = read_vlc(gb, kParam); // h(v) + + for( int i = 0; i < coeff_zero_run; i++ ) { + int blkPos = ScanOrder[ scanPos ]; + int xC = blkPos & ( ( 1 << log2BlkWidth ) - 1 ); + int yC = blkPos >> log2BlkWidth; + TransCoeff[ cIdx ][ x0 + xC ][ y0 + yC ] = 0; + scanPos++; + } + PrevRun = coeff_zero_run; + if( scanPos < ( 1 << ( log2BlkWidth + log2BlkHeight ) ) ) { + int kParam = ffapv_clip3( 0, 4, PrevLevel >> 2 ); + int abs_ac_coeff_minus1 = read_vlc(gb, kParam); + + uint8_t sign_ac_coeff = get_bits1(gb); + int level = ( abs_ac_coeff_minus1 + 1 ) * ( 1 - 2 * sign_ac_coeff ); + uint16_t blkPos = ScanOrder[ scanPos ]; + int xC = blkPos & ( ( 1 << log2BlkWidth ) - 1 ); + int yC = blkPos >> log2BlkWidth; + TransCoeff[ cIdx ][ x0 + xC ][ y0 + yC ] = level; + scanPos++; + PrevLevel = abs_ac_coeff_minus1 + 1; + if( firstAC == 1 ) { + firstAC = 0; + Prev1stAcLevel = PrevLevel; + } + } + } while ( scanPos < ( 1 << ( log2BlkWidth + log2BlkHeight ) ) ); +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-macroblock-layer +static int macroblock_layer( GetBitContext *gb, const APVFrameDataHeader *fdh, uint32_t Prev1stAcLevel, uint32_t xMb, uint32_t yMb, uint32_t cIdx ) +{ + + uint32_t MbWidth = APV_MB_WIDTH; + uint32_t MbHeight = APV_MB_HEIGHT; + + // @see 6.2 Source, decoded and output frame formats + // @see Table 2 — SubWidthC and SubHeightC values derived from chroma_format_idc + uint32_t SubWidthC = (fdh->frame_info.chroma_format_idc == 2) ? 2 : 1; + uint32_t SubHeightC = 1; + + // @see 6.2 Source, decoded and output frame formats + uint32_t MbWidthC = MbWidth / SubWidthC; + uint32_t MbHeightC = MbHeight / SubHeightC; + + uint32_t subW = ( cIdx == 0 ) ? 1 : SubWidthC; + uint32_t subH = ( cIdx == 0 ) ? 1 : SubHeightC; + uint32_t blkWidth = ( cIdx == 0 ) ? MbWidth : MbWidthC; + uint32_t blkHeight = ( cIdx == 0 ) ? MbHeight : MbHeightC; + + uint32_t TrSize = 8; + + // moved from tile_data + uint32_t PrevDC = 0; + uint32_t PrevDcDiff = APV_PREV_DC_DIFF; + + int32_t TransCoeff[APV_COLOR_COMP_NUM][APV_MB_WIDTH][APV_MB_HEIGHT]; + + for( int y = 0; y < blkHeight; y += TrSize ) { + for( int x = 0; x < blkWidth; x += TrSize ) { + + int kParam = ffapv_clip3( 0, 5, PrevDcDiff >> 2 ); + int abs_dc_coeff_diff = read_vlc(gb, kParam); // h(v) + int sign_dc_coeff_diff; // u(1) + + if( abs_dc_coeff_diff ) + sign_dc_coeff_diff = get_bits1(gb); // u(1) + + TransCoeff[ cIdx ][ xMb / subW + x ][ yMb / subH + y ] = PrevDC + abs_dc_coeff_diff * ( 1 - 2 * sign_dc_coeff_diff ); + PrevDC = TransCoeff[ cIdx ][ xMb / subW + x ][ yMb / subH + y ]; + PrevDcDiff = abs_dc_coeff_diff; + ac_coeff_coding( gb, Prev1stAcLevel, TransCoeff, xMb / subW + x, yMb / subH + y, log2( TrSize ), log2( TrSize ), cIdx ); + } + } + return 0; +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-tile-header +static int tile_header(GetBitContext *gb, const APVFrameDataHeader *fdh, APVTileHeader *th) +{ + int NumComps = num_component(fdh->frame_info.chroma_format_idc); + + th->tile_header_size = get_bits(gb, 16); + th->tile_index = get_bits(gb, 16); + + for(int i=0; i<NumComps; i++) { + th->tile_data_size[i] = get_bits(gb, 32); + } + + for(int i=0; i<NumComps; i++) { + th->tile_qp[i] = get_bits(gb, 8); + } + + th->reserved_zero_8bits = get_bits(gb, 8); + + ff_apv_byte_alignment(gb, &th->byte_alignent); + + return 0; +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-tile-data + +// @param cIdx specifying the color component of the current block, +static int tile_data(GetBitContext *gb, const APVFrameDataHeader *fdh, APVTile *tile, uint8_t tileIdx, uint8_t cIdx) +{ + int MbWidth = APV_MB_WIDTH; + int MbHeight = APV_MB_HEIGHT; + + uint32_t x0 = fdh->tile_info.ColStarts[ tileIdx % fdh->tile_info.TileCols ]; + uint32_t y0 = fdh->tile_info.RowStarts[ tileIdx / fdh->tile_info.TileCols ]; + + uint32_t numMbColsInTile = ( fdh->tile_info.ColStarts[ tileIdx % fdh->tile_info.TileCols + 1 ] + - fdh->tile_info.ColStarts[ tileIdx % fdh->tile_info.TileCols ] ) / MbWidth; + + uint32_t numMbRowsInTile = ( fdh->tile_info.RowStarts[ tileIdx / fdh->tile_info.TileCols + 1 ] + - fdh->tile_info.RowStarts[ tileIdx / fdh->tile_info.TileCols] ) / MbHeight; + + uint32_t numMbsInTile = numMbColsInTile * numMbRowsInTile; + + uint32_t Prev1stAcLevel = 0; + for( int i = 0; i < numMbsInTile; i++ ) { + uint32_t xMb = x0 + ( i % numMbColsInTile ) * MbWidth; + uint32_t yMb = y0 + ( i / numMbColsInTile ) * MbHeight; + macroblock_layer( gb, fdh, Prev1stAcLevel, xMb, yMb, cIdx ); + } + ff_apv_byte_alignment(gb, &tile->tile_data->byte_alignent); + + return 0; +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-tile +int ff_apv_parse_tile(GetBitContext *gb, const APVFrameDataHeader *fdh, APVTile *tile, uint8_t tileIdx) +{ + int ret = 0; + int NumComps = num_component(fdh->frame_info.chroma_format_idc); + + tile_header(gb, fdh, &tile->tile_header); + + for(int i=0; i<NumComps; i++) { + tile_data(gb, fdh, tile, tileIdx, i); + } + + return ret; +} + +void ff_apv_ps_free(APVParamSets *ps) +{ + APVFrameData* fd = &ps->frame_data; + int num_tiles = fd->frame_data_header.tile_info.NumTiles; + + for( int i = 0; i < num_tiles; i++ ) + free(fd->tiles[i]); + + free(fd->tiles); +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-metadata-payload-syntax +static int metadata_payload( GetBitContext *gb, uint32_t metadataSize ) +{ + do { + uint16_t size; + + skip_bits(gb, 16); // u(16) + + size = get_bits(gb, 16); // u(16) + + skip_bits(gb, size * 8); // value u(size*8); + + } while (get_bits(gb, 16) != 0xFFFF); + + return 0; +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-metadata +int ff_apv_parse_metadata(GetBitContext *gb, APVFrameData *fd) +{ + uint16_t metadata_num = get_bits(gb, 16); // u(16) + for(int i = 0; i < metadata_num; i++ ) { + uint32_t metadata_size_minus1 = get_bits_long(gb, 32); // u(32) + metadata_payload( gb, metadata_size_minus1 + 1 ); + } + return 0; +} + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-filler +int ff_apv_parse_filler_data(GetBitContext *gb, APVFrameData *fd) +{ + uint8_t ff_byte = 0; + while( get_bits(gb, 8) == 0xFF ) + ff_byte = 0xff; // equal to 0xFF + + return ff_byte; +} diff --git a/libavcodec/apv_ps.h b/libavcodec/apv_ps.h new file mode 100644 index 0000000000..17809dd6bf --- /dev/null +++ b/libavcodec/apv_ps.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2025 Dawid Kozinski <d.kozinski@samsung.com> + * + * 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 + * APV decoder/parser shared code + */ + +#ifndef AVCODEC_APV_PS_H +#define AVCODEC_APV_PS_H + +#include <stdint.h> + +#include "apv.h" +#include "get_bits.h" + +/* size of block */ +#define APV_LOG2_BLOCK (3) +#define APV_BLOCK (1<<APV_LOG2_BLOCK) +#define APV_BLOCK_W (1<<APV_LOG2_BLOCK) +#define APV_BLOCK_H (1<<APV_LOG2_BLOCK) +#define APV_BLOCK_D (APV_BLOCK_W * APV_BLOCK_H) + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#section-5.3.17 +typedef struct APVByteAlignemnt { + uint8_t alignment_bit_equal_to_zero; /* equal to 0*/ // f(1) +} APVByteAlignemnt; + +// The sturcture reflects Tile Header layout +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#section-5.3.13 + +// The following descriptors specify the parsing process of each element +// u(n) - unsigned integer using n bits +// ue(v) - unsigned integer 0-th order Exp_Golomb-coded syntax element with the left bit first +typedef struct APVTileHeader { + uint16_t tile_header_size; // u(16) + uint16_t tile_index; // u(16) + + uint32_t tile_data_size[APV_COLOR_COMP_NUM]; // u(32) + + + uint8_t tile_qp[APV_COLOR_COMP_NUM]; // u(8) + uint8_t reserved_zero_8bits; // u(8) + + APVByteAlignemnt byte_alignent; + +} APVTileHeader; + +// The sturcture reflects Tile Info sturcture layout +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#section-5.3.8 +// +// The following descriptors specify the parsing process of each element +// u(n) - unsigned integer using n bits +// ue(v) - unsigned integer 0-th order Exp_Golomb-coded syntax element with the left bit first +typedef struct APVTileInfo { + uint32_t tile_width_in_mbs; // u(20) + uint32_t tile_height_in_mbs; // u(20) + uint8_t tile_size_present_in_fh_flag; // u(1) + uint32_t *tile_size_in_fh; // table of size NumTiles; elements of u(32) type + + uint32_t *ColStarts; // table of size FrameWidthInMbsY + uint32_t *RowStarts; // table of size FrameHeightInMbsY + uint32_t TileCols; + uint32_t TileRows; + uint32_t NumTiles; + +} APVTileInfo; + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-quantization-matrix +typedef struct APVQuantizationMatrix { + uint8_t q_matrix[3][8][8]; +} APVQuantizationMatrix; + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-frame-information +// 5.3.6. Frame information +typedef struct APVFrameInfo { + uint8_t profile_idc; // u(8) + uint8_t level_idc; // u(8) + uint8_t band_idc; // u(3) + uint8_t reserved_zero_5bits; // u(5) + uint32_t frame_width; // u(24) + uint32_t frame_height; // u(24) + uint8_t chroma_format_idc; // u(4) + uint8_t bit_depth_minus8; // u(4) + uint8_t capture_time_distance; // u(8) + uint16_t reserved_zero_8bits; // u(8) +} APVFrameInfo; + +typedef struct APVFrameDataHeader { + + struct APVFrameInfo frame_info; + uint8_t reserved_zero_8bits; // u(8) + + uint8_t color_description_present_flag; // u(1) + uint8_t color_primaries; // u(8) + uint8_t transfer_characteristics; // u(8) + uint8_t matrix_coefficients; // u(8) + + uint8_t use_q_matrix; // u(1) + + APVQuantizationMatrix quantization_matrix; + APVTileInfo tile_info; + + uint8_t reserved_zero_8bits_2; // u(8) + + APVByteAlignemnt byte_alignent; + +} APVFrameDataHeader; + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#section-5.3.3 +typedef struct APVPBUHeader { + uint8_t pbu_type; // u(8) + uint8_t group_id; // u(16) + uint8_t reserved_zer_8bits; // u(8) +} APVPBUHeader; + +typedef struct APVTileData { + uint32_t PrevDc; + uint32_t PrevDcDiff; + uint32_t numMbColsInTile; + uint32_t numMbRowsInTile; + uint32_t numMbsInTile; + uint32_t Prev1stAcLevel; + + APVByteAlignemnt byte_alignent; +} APVTileData; + +typedef struct APVTile { + APVTileHeader tile_header; + APVTileData tile_data[3]; +} APVTile; + +typedef struct APVFrameData { + APVFrameDataHeader frame_data_header; + APVTile **tiles; // table of pointers to elements of type APVTile; the size of table is NumTiles +} APVFrameData; + +typedef struct APVParamSets { + APVFrameData frame_data; +} APVParamSets; + +// https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-primitive-bitstream-unit-he +int ff_apv_parse_pbu_header(GetBitContext *gb, APVPBUHeader *fdh); + +// https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-frame-header +int ff_apv_parse_frame_header(GetBitContext *gb, APVFrameDataHeader *fdh); + +// https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-frame-information +int ff_apv_parse_frame_info(GetBitContext *gb, APVFrameInfo *frame_info); + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-frame-information +int ff_apv_tile_info(GetBitContext *gb, const APVFrameDataHeader *fdh, APVTileInfo *ti); + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-tile +int ff_apv_parse_tile(GetBitContext *gb, const APVFrameDataHeader *fdh, APVTile *tile, uint8_t tileIdx); + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-byte-alignment +int ff_apv_byte_alignment(GetBitContext *gb, APVByteAlignemnt *ba); + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-quantization-matrix +int ff_apv_quantization_matrix(GetBitContext *gb, int num_comp, APVQuantizationMatrix *qm); + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-metadata +int ff_apv_parse_metadata(GetBitContext *gb, APVFrameData *fd); + +// @see https://www.ietf.org/archive/id/draft-lim-apv-04.html#name-filler +int ff_apv_parse_filler_data(GetBitContext *gb, APVFrameData *fd); + +void ff_apv_ps_free(APVParamSets *ps); + +#endif /* AVCODEC_APV_PS_H */ diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c index 5387351fd0..21164f3751 100644 --- a/libavcodec/parsers.c +++ b/libavcodec/parsers.c @@ -25,6 +25,7 @@ extern const AVCodecParser ff_aac_latm_parser; extern const AVCodecParser ff_ac3_parser; extern const AVCodecParser ff_adx_parser; extern const AVCodecParser ff_amr_parser; +extern const AVCodecParser ff_apv_parser; extern const AVCodecParser ff_av1_parser; extern const AVCodecParser ff_avs2_parser; extern const AVCodecParser ff_avs3_parser; -- 2.34.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next parent reply other threads:[~2025-04-23 14:12 UTC|newest] Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top [not found] <CGME20250423141230eucas1p1962c2698d09aced37fa5551493a693b8@eucas1p1.samsung.com> 2025-04-23 14:12 ` Dawid Kozinski [this message] 2025-04-23 14:27 ` James Almer 2025-04-23 21:14 ` Mark Thompson
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20250423141226.1857892-1-d.kozinski@samsung.com \ --to=d.kozinski@samsung.com \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git