From: averne via ffmpeg-devel <ffmpeg-devel@ffmpeg.org>
To: ffmpeg-devel@ffmpeg.org
Cc: averne <code@ffmpeg.org>
Subject: [FFmpeg-devel] [PATCH] [GSoC 25] avcodec/prores: add parser (PR #20752)
Date: Sat, 25 Oct 2025 19:39:59 -0000
Message-ID: <176142120047.25.3155517399692984888@7d278768979e> (raw)
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 <averne381@gmail.com>
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 -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
reply other threads:[~2025-10-25 19:40 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=176142120047.25.3155517399692984888@7d278768979e \
--to=ffmpeg-devel@ffmpeg.org \
--cc=code@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