* [FFmpeg-devel] [PATCH v1 2/8] avcodec/apv_parser: Added parser implementation for APV format
[not found] <CGME20250423141230eucas1p1962c2698d09aced37fa5551493a693b8@eucas1p1.samsung.com>
@ 2025-04-23 14:12 ` Dawid Kozinski
2025-04-23 14:27 ` James Almer
2025-04-23 21:14 ` Mark Thompson
0 siblings, 2 replies; 3+ messages in thread
From: Dawid Kozinski @ 2025-04-23 14:12 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Dawid Kozinski
- 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".
^ permalink raw reply [flat|nested] 3+ messages in thread