Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH] [GSoC 25] avcodec/prores: add parser (PR #20752)
@ 2025-10-25 19:39 averne via ffmpeg-devel
  0 siblings, 0 replies; only message in thread
From: averne via ffmpeg-devel @ 2025-10-25 19:39 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: averne

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

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2025-10-25 19:40 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-25 19:39 [FFmpeg-devel] [PATCH] [GSoC 25] avcodec/prores: add parser (PR #20752) averne via ffmpeg-devel

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