PR #20752 opened by averne URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20752 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20752.patch
Split off from #20381. Adds a ProRes parser, which avoids going through a full-frame decode to parse headers. >From 46f936c70e15e37f6aee5621edbad0951901a800 Mon Sep 17 00:00:00 2001 From: averne <[email protected]> Date: Tue, 22 Jul 2025 19:06:55 +0200 Subject: [PATCH] avcodec/prores: add parser Introduce a basic parser for ProRes frame headers. This avoid having to decode an entire frame to extract codec information. --- libavcodec/Makefile | 1 + libavcodec/parsers.c | 1 + libavcodec/prores_parser.c | 128 +++++++++++++++++++++++++++++++++++++ libavcodec/proresdec.c | 12 ++-- libavformat/mov.c | 1 + 5 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 libavcodec/prores_parser.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 3d036de4b6..51cd3db30b 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1265,6 +1265,7 @@ OBJS-$(CONFIG_PNG_PARSER) += png_parser.o OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o OBJS-$(CONFIG_PRORES_RAW_PARSER) += prores_raw_parser.o OBJS-$(CONFIG_QOI_PARSER) += qoi_parser.o +OBJS-$(CONFIG_PRORES_PARSER) += prores_parser.o OBJS-$(CONFIG_RV34_PARSER) += rv34_parser.o OBJS-$(CONFIG_SBC_PARSER) += sbc_parser.o OBJS-$(CONFIG_SIPR_PARSER) += sipr_parser.o diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c index b12c48f79f..c922b65ce5 100644 --- a/libavcodec/parsers.c +++ b/libavcodec/parsers.c @@ -66,6 +66,7 @@ extern const AVCodecParser ff_mpeg4video_parser; extern const AVCodecParser ff_mpegaudio_parser; extern const AVCodecParser ff_mpegvideo_parser; extern const AVCodecParser ff_opus_parser; +extern const AVCodecParser ff_prores_parser; extern const AVCodecParser ff_png_parser; extern const AVCodecParser ff_pnm_parser; extern const AVCodecParser ff_prores_raw_parser; diff --git a/libavcodec/prores_parser.c b/libavcodec/prores_parser.c new file mode 100644 index 0000000000..d778f839bd --- /dev/null +++ b/libavcodec/prores_parser.c @@ -0,0 +1,128 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/intreadwrite.h" +#include "bytestream.h" + +#include "avcodec.h" + +static int parse(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + GetByteContext gb; + uint8_t flags, depth, chroma_format, alpha_channel_type; + + *poutbuf = buf; + *poutbuf_size = buf_size; + + /* Frame fields + frame header size */ + if (buf_size < 28) + return buf_size; + + bytestream2_init(&gb, buf, buf_size); + + /* Frame size */ + if (bytestream2_get_be32(&gb) != buf_size) + return buf_size; + + /* Frame identifier */ + if (bytestream2_get_le32(&gb) != MKTAG('i','c','p','f')) + return buf_size; + + /* Frame header size */ + if (bytestream2_get_be16(&gb) < 20) + return buf_size; + + bytestream2_skip(&gb, 6); /* Bitstream version, encoder identifier */ + + s->key_frame = 1; + s->pict_type = AV_PICTURE_TYPE_I; + + s->width = bytestream2_get_be16(&gb); + s->height = bytestream2_get_be16(&gb); + s->coded_width = FFALIGN(s->width, 16); + s->coded_height = FFALIGN(s->height, 16); + + flags = bytestream2_get_byte(&gb); + + /* Interlace mode */ + switch (flags >> 2 & 3) { + case 0: + s->field_order = AV_FIELD_PROGRESSIVE; + s->picture_structure = AV_PICTURE_STRUCTURE_FRAME; + break; + case 1: + s->field_order = AV_FIELD_TT; + s->picture_structure = AV_PICTURE_STRUCTURE_TOP_FIELD; + break; + case 2: + s->field_order = AV_FIELD_BB; + s->picture_structure = AV_PICTURE_STRUCTURE_BOTTOM_FIELD; + break; + default: + break; + } + + bytestream2_skip(&gb, 4); /* Aspect ratio information, frame rate code, color primaries, transfer characteristic, matrix coefficients */ + + /* Determine pixel format based on color depth, chroma format and alpha type */ + switch (avctx->codec_tag) { + case MKTAG('a','p','c','o'): + case MKTAG('a','p','c','s'): + case MKTAG('a','p','c','n'): + case MKTAG('a','p','c','h'): + depth = 10; + break; + case MKTAG('a','p','4','h'): + case MKTAG('a','p','4','x'): + depth = 12; + break; + default: + return buf_size; + } + + chroma_format = flags >> 6 & 3; + if (chroma_format < 2) + return buf_size; + + alpha_channel_type = bytestream2_get_byte(&gb) & 0xf; + + switch (depth | (chroma_format << 4) | (alpha_channel_type << 8)) { + case 10 | (2 << 4) | (0 << 8): s->format = AV_PIX_FMT_YUV422P10; break; + case 10 | (2 << 4) | (1 << 8): + case 10 | (2 << 4) | (2 << 8): s->format = AV_PIX_FMT_YUVA422P10; break; + case 10 | (3 << 4) | (0 << 8): s->format = AV_PIX_FMT_YUV444P10; break; + case 10 | (3 << 4) | (1 << 8): + case 10 | (3 << 4) | (2 << 8): s->format = AV_PIX_FMT_YUVA444P10; break; + case 12 | (2 << 4) | (0 << 8): s->format = AV_PIX_FMT_YUV422P12; break; + case 12 | (2 << 4) | (1 << 8): + case 12 | (2 << 4) | (2 << 8): s->format = AV_PIX_FMT_YUVA422P12; break; + case 12 | (3 << 4) | (0 << 8): s->format = AV_PIX_FMT_YUV444P12; break; + case 12 | (3 << 4) | (1 << 8): + case 12 | (3 << 4) | (2 << 8): s->format = AV_PIX_FMT_YUVA444P12; break; + } + + return buf_size; +} + +const AVCodecParser ff_prores_parser = { + .codec_ids = { AV_CODEC_ID_PRORES }, + .parser_parse = parse, +}; diff --git a/libavcodec/proresdec.c b/libavcodec/proresdec.c index deaf84bda0..fdd2e23f83 100644 --- a/libavcodec/proresdec.c +++ b/libavcodec/proresdec.c @@ -273,10 +273,10 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, #endif } - ctx->frame->color_primaries = buf[14]; - ctx->frame->color_trc = buf[15]; - ctx->frame->colorspace = buf[16]; - ctx->frame->color_range = AVCOL_RANGE_MPEG; + avctx->color_primaries = buf[14]; + avctx->color_trc = buf[15]; + avctx->colorspace = buf[16]; + avctx->color_range = AVCOL_RANGE_MPEG; ptr = buf + 20; flags = buf[19]; @@ -772,6 +772,9 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame, if (frame_hdr_size < 0) return frame_hdr_size; + if (avctx->skip_frame == AVDISCARD_ALL) + return 0; + buf += frame_hdr_size; buf_size -= frame_hdr_size; @@ -851,6 +854,7 @@ const FFCodec ff_prores_decoder = { FF_CODEC_DECODE_CB(decode_frame), UPDATE_THREAD_CONTEXT(update_thread_context), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, + .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .p.profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles), #if HWACCEL_MAX .hw_configs = (const AVCodecHWConfigInternal *const []) { diff --git a/libavformat/mov.c b/libavformat/mov.c index 81753d04e9..f5046832a1 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -2991,6 +2991,7 @@ static int mov_finalize_stsd_codec(MOVContext *c, AVIOContext *pb, sti->need_parsing = AVSTREAM_PARSE_FULL; break; case AV_CODEC_ID_PRORES_RAW: + case AV_CODEC_ID_PRORES: case AV_CODEC_ID_APV: case AV_CODEC_ID_EVC: case AV_CODEC_ID_AV1: -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
