[FFmpeg-devel] [PATCH 1/2] avcodec: add an APV parser
James Almer
jamrial at gmail.com
Mon Apr 28 00:15:40 EEST 2025
Signed-off-by: James Almer <jamrial at gmail.com>
---
libavcodec/Makefile | 1 +
libavcodec/apv_parser.c | 165 ++++++++++++++++++++++++++++++++++++++++
libavcodec/parsers.c | 1 +
3 files changed, 167 insertions(+)
create mode 100644 libavcodec/apv_parser.c
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index e674671460..cc142bbae2 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1198,6 +1198,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_parser.c b/libavcodec/apv_parser.c
new file mode 100644
index 0000000000..53e5bb0921
--- /dev/null
+++ b/libavcodec/apv_parser.c
@@ -0,0 +1,165 @@
+/*
+ * 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 "avcodec.h"
+#include "bytestream.h"
+#include "apv.h"
+
+typedef struct APVParseContext {
+ uint8_t profile_idc;
+ uint8_t level_idc;
+
+ int frame_width;
+ int frame_height;
+
+ uint8_t color_primaries;
+ uint8_t transfer_characteristics;
+ uint8_t matrix_coefficients;
+ uint8_t full_range_flag;
+
+ enum AVPixelFormat pixel_format;
+} APVParseContext;
+
+static const enum AVPixelFormat apv_format_table[5][5] = {
+ { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16 },
+ { 0 }, // 4:2:0 is not valid.
+ { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV422P16 },
+ { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV444P16 },
+ { AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUVA444P16 },
+};
+
+static int apv_extract_header_info(AVCodecParserContext *s, GetByteContext *gbc)
+{
+ APVParseContext *p = s->priv_data;
+ int pbu_type, chroma_format_idc, bit_depth_minus8;
+ int byte;
+
+ pbu_type = bytestream2_get_byte(gbc);
+ bytestream2_skip(gbc, 2);
+
+ if (bytestream2_get_byte(gbc))
+ return AVERROR_INVALIDDATA;
+
+ if (pbu_type != APV_PBU_PRIMARY_FRAME)
+ return AVERROR_INVALIDDATA;
+
+ p->profile_idc = bytestream2_get_byte(gbc);
+ p->level_idc = bytestream2_get_byte(gbc);
+
+ if (bytestream2_get_byte(gbc) & 7)
+ return AVERROR_INVALIDDATA;
+
+ p->frame_width = bytestream2_get_be24(gbc);
+ p->frame_height = bytestream2_get_be24(gbc);
+ if (p->frame_width < 1 || p->frame_width > 65536 ||
+ p->frame_height < 1 || p->frame_height > 65536)
+ return AVERROR_INVALIDDATA;
+
+ byte = bytestream2_get_byte(gbc);
+ chroma_format_idc = byte >> 4;
+ bit_depth_minus8 = byte & 0xf;
+
+ if (bit_depth_minus8 > 8)
+ return AVERROR_INVALIDDATA;
+ if (bit_depth_minus8 % 2) {
+ // Odd bit depths are technically valid but not useful here.
+ return AVERROR_INVALIDDATA;
+ }
+
+ switch (chroma_format_idc) {
+ case APV_CHROMA_FORMAT_400:
+ case APV_CHROMA_FORMAT_422:
+ case APV_CHROMA_FORMAT_444:
+ case APV_CHROMA_FORMAT_4444:
+ p->pixel_format = apv_format_table[chroma_format_idc][bit_depth_minus8 / 2];
+ break;
+ default:
+ return AVERROR_INVALIDDATA;
+ }
+
+ bytestream2_skip(gbc, 1);
+
+ if (bytestream2_get_be16(gbc))
+ return AVERROR_INVALIDDATA;
+
+ // color_description_present_flag
+ if (bytestream2_peek_byte(gbc) >> 7) {
+ unsigned color_description;
+
+ color_description = bytestream2_get_be32(gbc);
+ p->color_primaries = (color_description >> 23) & 0xff;
+ p->transfer_characteristics = (color_description >> 15) & 0xff;
+ p->matrix_coefficients = (color_description >> 7) & 0xff;
+ p->full_range_flag = (color_description >> 6) & 1;
+ } else {
+ p->color_primaries = AVCOL_PRI_UNSPECIFIED;
+ p->transfer_characteristics = AVCOL_TRC_UNSPECIFIED;
+ p->matrix_coefficients = AVCOL_SPC_UNSPECIFIED;
+ p->full_range_flag = 0;
+ }
+
+ return 0;
+}
+
+static int parse(AVCodecParserContext *s,
+ AVCodecContext *avctx,
+ const uint8_t **poutbuf, int *poutbuf_size,
+ const uint8_t *buf, int buf_size)
+{
+ APVParseContext *p = s->priv_data;
+ GetByteContext gbc;
+
+ *poutbuf = buf;
+ *poutbuf_size = buf_size;
+
+ if (buf_size < 29)
+ return buf_size;
+
+ bytestream2_init(&gbc, buf, buf_size);
+
+ if (bytestream2_get_be32(&gbc) != APV_SIGNATURE)
+ return buf_size;
+ if (bytestream2_get_be32(&gbc) < 16) // pbu_size
+ return buf_size;
+ if (apv_extract_header_info(s, &gbc) < 0)
+ return buf_size;
+
+ s->key_frame = 1;
+ s->pict_type = AV_PICTURE_TYPE_I;
+ s->field_order = AV_FIELD_UNKNOWN;
+ s->picture_structure = AV_PICTURE_STRUCTURE_FRAME;
+ s->width = p->frame_width;
+ s->height = p->frame_height;
+ s->format = p->pixel_format;
+ avctx->profile = p->profile_idc;
+ avctx->level = p->level_idc;
+ avctx->chroma_sample_location = AVCHROMA_LOC_TOPLEFT;
+ avctx->color_primaries = p->color_primaries;
+ avctx->color_trc = p->transfer_characteristics;
+ avctx->colorspace = p->matrix_coefficients;
+ avctx->color_range = p->full_range_flag ? AVCOL_RANGE_JPEG
+ : AVCOL_RANGE_MPEG;
+
+ return buf_size;
+}
+
+const AVCodecParser ff_apv_parser = {
+ .codec_ids = { AV_CODEC_ID_APV },
+ .priv_data_size = sizeof(APVParseContext),
+ .parser_parse = parse,
+};
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.49.0
More information about the ffmpeg-devel
mailing list