PR #23274 opened by James Almer (jamrial)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23274
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23274.patch

Reduces code duplication.

The following step would be to make h2645_sei use these too.


>From 98a7a2e933381f8d46c739f77b4c3d2105472758 Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
Date: Fri, 29 May 2026 12:09:11 -0300
Subject: [PATCH 1/4] avcodec/itut35: add ITU-T T35 parsing helpers

Signed-off-by: James Almer <[email protected]>
---
 libavcodec/itut35.c | 297 ++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/itut35.h |  90 ++++++++++++++
 2 files changed, 387 insertions(+)
 create mode 100644 libavcodec/itut35.c

diff --git a/libavcodec/itut35.c b/libavcodec/itut35.c
new file mode 100644
index 0000000000..d191b4ca73
--- /dev/null
+++ b/libavcodec/itut35.c
@@ -0,0 +1,297 @@
+/*
+ * 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/buffer.h"
+#include "libavutil/frame.h"
+#include "libavutil/hdr_dynamic_metadata.h"
+#include "libavutil/internal.h"
+#include "libavutil/mem.h"
+
+#include "avcodec.h"
+#include "atsc_a53.h"
+#include "bytestream.h"
+#include "decode.h"
+#include "dovi_rpu.h"
+#include "itut35.h"
+#include "version.h"
+
+int ff_itut_t35_parse_buffer(FFITUTT35 *const itut_t35, const uint8_t *buf,
+                             size_t buf_size, int flags) {
+    GetByteContext gb;
+    int provider_code, provider_oriented_code = 0, country_code;
+
+    bytestream2_init(&gb, buf, buf_size);
+
+    if (flags & FF_ITUT_T35_FLAG_COUNTRY_CODE)
+        country_code = itut_t35->country_code;
+    else {
+        country_code = bytestream2_get_byte(&gb);
+        if (country_code == 0xFF) {
+            if (bytestream2_get_bytes_left(&gb) < 3)
+                return AVERROR_INVALIDDATA;
+
+            bytestream2_skipu(&gb, 1); // itu_t_t35_country_code_extension_byte
+        }
+    }
+
+    switch (country_code) {
+    case ITU_T_T35_COUNTRY_CODE_US:
+        if (bytestream2_get_bytes_left(&gb) < 2)
+            return AVERROR_INVALIDDATA;
+        provider_code = bytestream2_get_be16u(&gb);
+
+        switch (provider_code) {
+        case ITU_T_T35_PROVIDER_CODE_ATSC: {
+            provider_oriented_code = bytestream2_get_be32(&gb);
+            switch (provider_oriented_code) {
+            case MKBETAG('G', 'A', '9', '4'): { // closed captions
+                itut_t35->payload = gb.buffer;
+                itut_t35->payload_size = bytestream2_get_bytes_left(&gb);
+                break;
+            }
+            default: // ignore unsupported identifiers
+                return 0;
+            }
+            break;
+        }
+        case ITU_T_T35_PROVIDER_CODE_SAMSUNG: {
+            provider_oriented_code = bytestream2_get_be16(&gb);
+            int application_identifier = bytestream2_get_byte(&gb);
+
+            if (provider_oriented_code != 1 || application_identifier != 4)
+                return 0; // ignore
+
+            itut_t35->payload = gb.buffer;
+            itut_t35->payload_size = bytestream2_get_bytes_left(&gb);
+            break;
+        }
+        case ITU_T_T35_PROVIDER_CODE_DOLBY: {
+            provider_oriented_code = bytestream2_get_be32(&gb);
+            if (provider_oriented_code != 0x800)
+                return 0; // ignore
+
+            itut_t35->payload = gb.buffer;
+            itut_t35->payload_size = bytestream2_get_bytes_left(&gb);
+            break;
+        }
+        case ITU_T_T35_PROVIDER_CODE_SMPTE: {
+            provider_oriented_code = bytestream2_get_be16(&gb);
+            if (provider_oriented_code != 1)
+                return 0; // ignore
+
+            itut_t35->payload = gb.buffer;
+            itut_t35->payload_size = bytestream2_get_bytes_left(&gb);
+            break;
+        }
+        default: // ignore unsupported provider codes
+            return 0;
+        }
+        break;
+    case ITU_T_T35_COUNTRY_CODE_UK:
+        provider_oriented_code = bytestream2_get_byte(&gb); // 
t35_uk_country_code_second_octet
+        if (bytestream2_get_bytes_left(&gb) < 2)
+            return AVERROR_INVALIDDATA;
+
+        provider_code = bytestream2_get_be16u(&gb);
+        switch (provider_code) {
+        case ITU_T_T35_PROVIDER_CODE_VNOVA: {
+            if (bytestream2_get_bytes_left(&gb) < 2)
+                return AVERROR_INVALIDDATA;
+
+            itut_t35->payload = gb.buffer;
+            itut_t35->payload_size = bytestream2_get_bytes_left(&gb);
+            break;
+        }
+        default: // ignore unsupported provider codes
+            return 0;
+        }
+        break;
+
+    default: // ignore unsupported country codes
+        return 0;
+    }
+
+    itut_t35->country_code  = country_code;
+    itut_t35->provider_code = provider_code;
+    itut_t35->provider_oriented_code = provider_oriented_code;
+
+    return 1;
+}
+
+int ff_itut_t35_parse_payload_to_struct(AVCodecContext *const avctx, FFITUTT35 
*const itut_t35,
+                                        FFITUTT35Aux *const aux, FFITUTT35Meta 
*metadata)
+{
+    int ret;
+
+    switch (itut_t35->country_code) {
+    case ITU_T_T35_COUNTRY_CODE_US:
+        switch (itut_t35->provider_code) {
+        case ITU_T_T35_PROVIDER_CODE_ATSC: {
+            switch (itut_t35->provider_oriented_code) {
+            case MKBETAG('G', 'A', '9', '4'): // closed captions
+                ret = ff_parse_a53_cc(&metadata->a53_cc, itut_t35->payload, 
itut_t35->payload_size);
+                if (ret < 0)
+                    return ret;
+
+                break;
+            default: // ignore unsupported identifiers
+                break;
+            }
+            break;
+        }
+        case ITU_T_T35_PROVIDER_CODE_SAMSUNG: {
+            size_t size;
+            AVDynamicHDRPlus *hdrplus = av_dynamic_hdr_plus_alloc(&size);
+            if (!hdrplus)
+                return AVERROR(ENOMEM);
+
+            ret = av_dynamic_hdr_plus_from_t35(hdrplus, itut_t35->payload,
+                                               itut_t35->payload_size);
+            if (ret < 0)
+                return ret;
+
+            metadata->hdrplus = av_buffer_create((uint8_t *)hdrplus, size, 
NULL, NULL, 0);
+            if (!metadata->hdrplus) {
+                av_free(hdrplus);
+                return AVERROR(ENOMEM);
+            }
+
+            break;
+        }
+        case ITU_T_T35_PROVIDER_CODE_DOLBY: {
+            AVDOVIMetadata *dovi;
+
+            if (!aux || !aux->dovi)
+                return 0; // ignore
+
+            ret = ff_dovi_rpu_parse(aux->dovi, itut_t35->payload, 
itut_t35->payload_size, 0);
+            if (ret < 0)
+                av_log(avctx, AV_LOG_WARNING, "Error parsing DOVI OBU.\n");
+
+            ret = ff_dovi_get_metadata(aux->dovi, &dovi);
+            if (ret <= 0)
+                return ret;
+
+            metadata->dovi = av_buffer_create((uint8_t *)dovi, ret, NULL, 
NULL, 0);
+            if (!metadata->dovi) {
+                av_free(dovi);
+                return AVERROR(ENOMEM);
+            }
+
+            break;
+        }
+        case ITU_T_T35_PROVIDER_CODE_SMPTE: {
+            size_t size;
+            AVDynamicHDRSmpte2094App5 *hdr_smpte2094_app5 = 
av_dynamic_hdr_smpte2094_app5_alloc(&size);
+            if (!hdr_smpte2094_app5)
+                return AVERROR(ENOMEM);
+
+            ret = av_dynamic_hdr_smpte2094_app5_from_t35(hdr_smpte2094_app5, 
itut_t35->payload,
+                                                         
itut_t35->payload_size);
+            if (ret < 0)
+                return ret;
+
+            metadata->hdr_smpte2094_app5 = av_buffer_create((uint8_t 
*)hdr_smpte2094_app5, size, NULL, NULL, 0);
+            if (!metadata->hdr_smpte2094_app5) {
+                av_free(hdr_smpte2094_app5);
+                return AVERROR(ENOMEM);
+            }
+
+            break;
+        }
+        default:
+            break;
+        }
+        break;
+    case ITU_T_T35_COUNTRY_CODE_UK:
+        switch (itut_t35->provider_code) {
+        case ITU_T_T35_PROVIDER_CODE_VNOVA:
+            metadata->lcevc = av_buffer_alloc(itut_t35->payload_size);
+            if (!metadata->lcevc)
+                return AVERROR(ENOMEM);
+
+            memcpy(metadata->lcevc->data, itut_t35->payload, 
itut_t35->payload_size);
+
+            break;
+        default:
+            break;
+        }
+        break;
+
+    default:
+        // ignore unsupported provider codes
+        break;
+    }
+
+    return 0;
+}
+
+int ff_itut_t35_parse_payload_to_frame(AVCodecContext *const avctx, FFITUTT35 
*const itut_t35,
+                                       FFITUTT35Aux *const aux, AVFrame *const 
frame)
+{
+    FFITUTT35Meta metadata = { 0 };
+    int ret;
+
+    ret = ff_itut_t35_parse_payload_to_struct(avctx, itut_t35, aux, &metadata);
+    if (ret < 0)
+        return ret;
+
+    if (metadata.a53_cc) {
+        ret = ff_frame_new_side_data_from_buf(avctx, frame, 
AV_FRAME_DATA_A53_CC, &metadata.a53_cc);
+        if (ret < 0)
+            return ret;
+
+#if FF_API_CODEC_PROPS
+FF_DISABLE_DEPRECATION_WARNINGS
+        avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+    }
+
+    if (metadata.hdrplus) {
+        ret = ff_frame_new_side_data_from_buf(avctx, frame, 
AV_FRAME_DATA_DYNAMIC_HDR_PLUS,
+                                              &metadata.hdrplus);
+        if (ret < 0)
+            return ret;
+    }
+
+    if (metadata.dovi) {
+        AVFrameSideData *sd = av_frame_new_side_data_from_buf(frame, 
AV_FRAME_DATA_DOVI_METADATA,
+                                                              metadata.dovi);
+        if (!sd) {
+            av_buffer_unref(&metadata.dovi);
+            return AVERROR(ENOMEM);
+        }
+    }
+
+    if (metadata.hdr_smpte2094_app5) {
+        ret = ff_frame_new_side_data_from_buf(avctx, frame, 
AV_FRAME_DATA_DYNAMIC_HDR_SMPTE_2094_APP5,
+                                              &metadata.hdr_smpte2094_app5);
+        if (ret < 0)
+            return ret;
+    }
+
+    if (metadata.lcevc) {
+        ret = ff_frame_new_side_data_from_buf(avctx, frame, 
AV_FRAME_DATA_LCEVC,
+                                             &metadata.lcevc);
+        if (ret < 0)
+            return ret;
+    }
+
+    return 0;
+}
diff --git a/libavcodec/itut35.h b/libavcodec/itut35.h
index 3820fcfec4..8725459ef1 100644
--- a/libavcodec/itut35.h
+++ b/libavcodec/itut35.h
@@ -19,6 +19,13 @@
 #ifndef AVCODEC_ITUT35_H
 #define AVCODEC_ITUT35_H
 
+#include <stdint.h>
+#include <stddef.h>
+
+#include "libavutil/frame.h"
+#include "avcodec.h"
+#include "dovi_rpu.h"
+
 #define ITU_T_T35_COUNTRY_CODE_CN 0x26
 #define ITU_T_T35_COUNTRY_CODE_UK 0xB4
 #define ITU_T_T35_COUNTRY_CODE_US 0xB5
@@ -39,4 +46,87 @@
 #define ITU_T_T35_PROVIDER_CODE_SAMSUNG      0x003C
 #define ITU_T_T35_PROVIDER_CODE_SMPTE        0x0090
 
+typedef struct FFITUTT35 {
+    int country_code;
+
+    int provider_code;
+    int provider_oriented_code;
+
+    const uint8_t *payload;
+    size_t payload_size;
+} FFITUTT35;
+
+typedef struct FFITUTT35Meta {
+    AVBufferRef *a53_cc;
+    AVBufferRef *lcevc;
+    AVBufferRef *hdrplus;
+    AVBufferRef *hdr_smpte2094_app5;
+    AVBufferRef *dovi;
+} FFITUTT35Meta;
+
+typedef struct FFITUTT35Aux {
+    /**
+     * A DOVIContext. Must be set to a valid pointer in order to be parsed
+     * and filled.
+     */
+    DOVIContext *dovi;
+} FFITUTT35Aux;
+
+/**
+ * country_code is assumed to not be the first byte of the buffer and must
+ * be set by the caller beforehand.
+ */
+#define FF_ITUT_T35_FLAG_COUNTRY_CODE (1 << 0)
+
+/**
+ * Parse a raw ITU-T T35 buffer to get the country code, provider code,
+ * and set them plus the pointer and size in the FFITUTT35 struct to the
+ * start of the actual payload.
+ *
+ * @param  itut35 The struct to fill
+ * @param  buf    The input buffer
+ * @param  size   Size of the input buffer
+ * @param  flags  A combination of FF_ITUT_T35_FLAG_*
+ * @return        0 if nothing was done (e.g. the payload is of an unsupported
+ *                type), 1 on succes, or a negative AVERROR code on failure
+ *
+ * @note buf will remain owned by the caller, and no new allocations will
+ *       be made. Any pointer in the resulting struct will be valid as long
+ *       as buf is valid.
+ */
+int ff_itut_t35_parse_buffer(FFITUTT35 *itut35, const uint8_t *buf,
+                             size_t size, int flags);
+
+/**
+ * Parse a pre-processed ITU-T T35 payload to fill the metadata struct.
+ *
+ * @param  avctx    Used for logging and to get certain user options like
+ *                  err_recognition
+ * @param  itut35   The pre-filled struct
+ * @param  metadata A metadata struct. All the allocated buffer references
+ *                  are owned by the caller and must be freed accordingly.
+ * @param  aux      A struct containing extra contexts required by certain
+ *                  payload types. Any pointer present is owned by the caller.
+ *                  May be NULL, in which case the relevant payloads will not
+ *                  be parsed.
+ * @return          0 on succes, or a negative AVERROR code on failure
+ */
+int ff_itut_t35_parse_payload_to_struct(AVCodecContext *avctx, FFITUTT35 
*itut_t35,
+                                        FFITUTT35Aux *aux, FFITUTT35Meta 
*metadata);
+
+/**
+ * Parse a pre-processed ITU-T T35 payload to fill a frame's side data.
+ *
+ * @param  avctx    The context that generated the frame
+ * @param  itut35   The pre-filled struct
+ * @param  frame    A frame
+ * @param  aux      A struct containing extra contexts required by certain
+ *                  payload types. Any pointer present is owned by the caller.
+ *                  May be NULL, in which case the relevant payloads will not
+ *                  be parsed.
+ * @return          0 on succes, or a negative AVERROR code on failure
+ */
+int ff_itut_t35_parse_payload_to_frame(AVCodecContext *avctx, FFITUTT35 
*itut_t35,
+                                       FFITUTT35Aux *aux, AVFrame *frame);
+
 #endif /* AVCODEC_ITUT35_H */
-- 
2.52.0


>From 4cfa175db31c175e295451c195f90e8e96a25bf0 Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
Date: Fri, 29 May 2026 12:13:15 -0300
Subject: [PATCH 2/4] avcodec/av1dec: use the ITU-T T35 parsing helpers

Signed-off-by: James Almer <[email protected]>
---
 libavcodec/Makefile |   2 +-
 libavcodec/av1dec.c | 114 ++++----------------------------------------
 2 files changed, 11 insertions(+), 105 deletions(-)

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index ac3c4d1978..7bd0c0b6bd 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -272,7 +272,7 @@ OBJS-$(CONFIG_ATRAC3PAL_DECODER)       += atrac3plusdec.o 
atrac3plus.o \
 OBJS-$(CONFIG_ATRAC9_DECODER)          += atrac9dec.o
 OBJS-$(CONFIG_AURA_DECODER)            += cyuv.o
 OBJS-$(CONFIG_AURA2_DECODER)           += aura.o
-OBJS-$(CONFIG_AV1_DECODER)             += av1dec.o av1_parse.o
+OBJS-$(CONFIG_AV1_DECODER)             += av1dec.o av1_parse.o itut35.o
 OBJS-$(CONFIG_AV1_CUVID_DECODER)       += cuviddec.o
 OBJS-$(CONFIG_AV1_D3D12VA_ENCODER)     += d3d12va_encode_av1.o av1_levels.o
 OBJS-$(CONFIG_AV1_MEDIACODEC_DECODER)  += mediacodecdec.o
diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c
index 78edb3c8d4..30cc171973 100644
--- a/libavcodec/av1dec.c
+++ b/libavcodec/av1dec.c
@@ -968,113 +968,19 @@ fail:
 static int export_itut_t35(AVCodecContext *avctx, AVFrame *frame,
                            const AV1RawMetadataITUTT35 *itut_t35)
 {
-    GetByteContext gb;
     AV1DecContext *s = avctx->priv_data;
-    int ret, provider_code, country_code;
+    FFITUTT35 itut35 = { .country_code = itut_t35->itu_t_t35_country_code };
+    FFITUTT35Aux aux = { .dovi = &s->dovi };
+    int ret;
 
-    bytestream2_init(&gb, itut_t35->payload, itut_t35->payload_size);
+    ret = ff_itut_t35_parse_buffer(&itut35, itut_t35->payload, 
itut_t35->payload_size,
+                                   FF_ITUT_T35_FLAG_COUNTRY_CODE);
+    if (ret <= 0)
+        return ret;
 
-    country_code = itut_t35->itu_t_t35_country_code ;
-    switch (country_code) {
-    case ITU_T_T35_COUNTRY_CODE_US:
-        provider_code = bytestream2_get_be16(&gb);
-
-        switch (provider_code) {
-        case ITU_T_T35_PROVIDER_CODE_ATSC: {
-            uint32_t user_identifier = bytestream2_get_be32(&gb);
-            switch (user_identifier) {
-            case MKBETAG('G', 'A', '9', '4'): { // closed captions
-                AVBufferRef *buf = NULL;
-
-                ret = ff_parse_a53_cc(&buf, gb.buffer, 
bytestream2_get_bytes_left(&gb));
-                if (ret < 0)
-                    return ret;
-                if (!ret)
-                    break;
-
-                ret = ff_frame_new_side_data_from_buf(avctx, frame, 
AV_FRAME_DATA_A53_CC, &buf);
-                if (ret < 0)
-                    return ret;
-
-#if FF_API_CODEC_PROPS
-FF_DISABLE_DEPRECATION_WARNINGS
-                avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
-                break;
-            }
-            default: // ignore unsupported identifiers
-                break;
-            }
-            break;
-        }
-        case ITU_T_T35_PROVIDER_CODE_SAMSUNG: {
-            AVDynamicHDRPlus *hdrplus;
-            int provider_oriented_code = bytestream2_get_be16(&gb);
-            int application_identifier = bytestream2_get_byte(&gb);
-
-            if (provider_oriented_code != 1 || application_identifier != 4)
-                return 0; // ignore
-
-            hdrplus = av_dynamic_hdr_plus_create_side_data(frame);
-            if (!hdrplus)
-                return AVERROR(ENOMEM);
-
-            ret = av_dynamic_hdr_plus_from_t35(hdrplus, gb.buffer,
-                                                
bytestream2_get_bytes_left(&gb));
-            if (ret < 0)
-                return ret;
-            break;
-        }
-        case ITU_T_T35_PROVIDER_CODE_DOLBY: {
-            int provider_oriented_code = bytestream2_get_be32(&gb);
-            if (provider_oriented_code != 0x800)
-                return 0; // ignore
-
-            ret = ff_dovi_rpu_parse(&s->dovi, gb.buffer, 
bytestream2_get_bytes_left(&gb),
-                                    avctx->err_recognition);
-            if (ret < 0) {
-                av_log(avctx, AV_LOG_WARNING, "Error parsing DOVI OBU.\n");
-                return 0; // ignore
-            }
-
-            ret = ff_dovi_attach_side_data(&s->dovi, frame);
-            if (ret < 0)
-                return ret;
-            break;
-        }
-        default:
-            break;
-        }
-        break;
-    case ITU_T_T35_COUNTRY_CODE_UK:
-        bytestream2_skip(&gb, 1); // t35_uk_country_code_second_octet
-
-        provider_code = bytestream2_get_be16(&gb);
-        switch (provider_code) {
-        case ITU_T_T35_PROVIDER_CODE_VNOVA: {
-            AVFrameSideData *sd;
-            if (bytestream2_get_bytes_left(&gb) < 2)
-                return AVERROR_INVALIDDATA;
-
-            ret = ff_frame_new_side_data(avctx, frame, AV_FRAME_DATA_LCEVC,
-                                         bytestream2_get_bytes_left(&gb), &sd);
-            if (ret < 0)
-                return ret;
-            if (!sd)
-                break;
-
-            bytestream2_get_bufferu(&gb, sd->data, sd->size);
-            break;
-        }
-        default:
-            break;
-        }
-        break;
-    default:
-        // ignore unsupported provider codes
-        break;
-    }
+    ret = ff_itut_t35_parse_payload_to_frame(avctx, &itut35, &aux, frame);
+    if (ret < 0)
+        return ret;
 
     return 0;
 }
-- 
2.52.0


>From 60ba2d8517fa785646621b155b4b98f2cf6440fd Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
Date: Fri, 29 May 2026 12:13:25 -0300
Subject: [PATCH 3/4] avcodec/libdav1d: use the ITU-T T35 parsing helpers

Signed-off-by: James Almer <[email protected]>
---
 libavcodec/Makefile   |   2 +-
 libavcodec/libdav1d.c | 133 +++---------------------------------------
 2 files changed, 10 insertions(+), 125 deletions(-)

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 7bd0c0b6bd..3439e6a1e4 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1176,7 +1176,7 @@ OBJS-$(CONFIG_LIBARIBB24_DECODER)         += libaribb24.o 
ass.o
 OBJS-$(CONFIG_LIBARIBCAPTION_DECODER)     += libaribcaption.o ass.o
 OBJS-$(CONFIG_LIBCODEC2_DECODER)          += libcodec2.o
 OBJS-$(CONFIG_LIBCODEC2_ENCODER)          += libcodec2.o
-OBJS-$(CONFIG_LIBDAV1D_DECODER)           += libdav1d.o av1_parse.o
+OBJS-$(CONFIG_LIBDAV1D_DECODER)           += libdav1d.o av1_parse.o itut35.o
 OBJS-$(CONFIG_LIBDAVS2_DECODER)           += libdavs2.o
 OBJS-$(CONFIG_LIBFDK_AAC_DECODER)         += libfdk-aacdec.o
 OBJS-$(CONFIG_LIBFDK_AAC_ENCODER)         += libfdk-aacenc.o
diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c
index 2eaeefc71a..f377f3a3d0 100644
--- a/libavcodec/libdav1d.c
+++ b/libavcodec/libdav1d.c
@@ -364,134 +364,19 @@ static int 
libdav1d_receive_frame_internal(AVCodecContext *c, Dav1dPicture *p)
 static int parse_itut_t35_metadata(Libdav1dContext *dav1d, Dav1dPicture *p,
                                    const Dav1dITUTT35 *itut_t35, 
AVCodecContext *c,
                                    AVFrame *frame) {
-    GetByteContext gb;
-    int provider_code, country_code;
+    FFITUTT35 itut35 = { .country_code = itut_t35->country_code };
+    FFITUTT35Aux aux = { .dovi = &dav1d->dovi };
     int res;
 
-    bytestream2_init(&gb, itut_t35->payload, itut_t35->payload_size);
+    res = ff_itut_t35_parse_buffer(&itut35, itut_t35->payload, 
itut_t35->payload_size,
+                                   FF_ITUT_T35_FLAG_COUNTRY_CODE);
+    if (res <= 0)
+        return res;
 
-    country_code = itut_t35->country_code;
-    switch (country_code) {
-    case ITU_T_T35_COUNTRY_CODE_US:
-        if (bytestream2_get_bytes_left(&gb) < 2)
-            return AVERROR_INVALIDDATA;
-        provider_code = bytestream2_get_be16u(&gb);
+    res = ff_itut_t35_parse_payload_to_frame(c, &itut35, &aux, frame);
+    if (res < 0)
+        return res;
 
-        switch (provider_code) {
-        case ITU_T_T35_PROVIDER_CODE_ATSC: {
-            uint32_t user_identifier = bytestream2_get_be32(&gb);
-            switch (user_identifier) {
-            case MKBETAG('G', 'A', '9', '4'): { // closed captions
-                AVBufferRef *buf = NULL;
-
-                res = ff_parse_a53_cc(&buf, gb.buffer, 
bytestream2_get_bytes_left(&gb));
-                if (res < 0)
-                    return res;
-                if (!res)
-                    return 0;  // no cc found, ignore
-
-                res = ff_frame_new_side_data_from_buf(c, frame, 
AV_FRAME_DATA_A53_CC, &buf);
-                if (res < 0)
-                    return res;
-
-#if FF_API_CODEC_PROPS
-FF_DISABLE_DEPRECATION_WARNINGS
-                c->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
-                break;
-            }
-            default: // ignore unsupported identifiers
-                break;
-            }
-            break;
-        }
-        case ITU_T_T35_PROVIDER_CODE_SAMSUNG: {
-            AVDynamicHDRPlus *hdrplus;
-            int provider_oriented_code = bytestream2_get_be16(&gb);
-            int application_identifier = bytestream2_get_byte(&gb);
-
-            if (provider_oriented_code != 1 || application_identifier != 4)
-                return 0; // ignore
-
-            hdrplus = av_dynamic_hdr_plus_create_side_data(frame);
-            if (!hdrplus)
-                return AVERROR(ENOMEM);
-
-            res = av_dynamic_hdr_plus_from_t35(hdrplus, gb.buffer,
-                                                
bytestream2_get_bytes_left(&gb));
-            if (res < 0)
-                return res;
-            break;
-        }
-        case ITU_T_T35_PROVIDER_CODE_DOLBY: {
-            int provider_oriented_code = bytestream2_get_be32(&gb);
-            if (provider_oriented_code != 0x800)
-                return 0; // ignore
-
-            res = ff_dovi_rpu_parse(&dav1d->dovi, gb.buffer, 
bytestream2_get_bytes_left(&gb),
-                                    c->err_recognition);
-            if (res < 0) {
-                av_log(c, AV_LOG_WARNING, "Error parsing DOVI OBU.\n");
-                return 0; // ignore
-            }
-
-            res = ff_dovi_attach_side_data(&dav1d->dovi, frame);
-            if (res < 0)
-                return res;
-            break;
-        }
-        case ITU_T_T35_PROVIDER_CODE_SMPTE: {
-            AVDynamicHDRSmpte2094App5 *hdr_smpte2094_app5;
-            int provider_oriented_code = bytestream2_get_be16(&gb);
-            if (provider_oriented_code != 1)
-                return 0; // ignore
-
-            hdr_smpte2094_app5 = 
av_dynamic_hdr_smpte2094_app5_create_side_data(frame);
-            if (!hdr_smpte2094_app5)
-                return AVERROR(ENOMEM);
-
-            res = av_dynamic_hdr_smpte2094_app5_from_t35(hdr_smpte2094_app5, 
gb.buffer,
-                                                         
bytestream2_get_bytes_left(&gb));
-            if (res < 0)
-                return res;
-            break;
-        }
-        default:
-            break;
-        }
-        break;
-    case ITU_T_T35_COUNTRY_CODE_UK:
-        bytestream2_skipu(&gb, 1); // t35_uk_country_code_second_octet
-        if (bytestream2_get_bytes_left(&gb) < 2)
-            return AVERROR_INVALIDDATA;
-
-        provider_code = bytestream2_get_be16u(&gb);
-        switch (provider_code) {
-        case ITU_T_T35_PROVIDER_CODE_VNOVA: {
-            AVFrameSideData *sd;
-            if (bytestream2_get_bytes_left(&gb) < 2)
-                return AVERROR_INVALIDDATA;
-
-            res = ff_frame_new_side_data(c, frame, AV_FRAME_DATA_LCEVC,
-                                         bytestream2_get_bytes_left(&gb), &sd);
-            if (res < 0)
-                return res;
-            if (!sd)
-                break;
-
-            bytestream2_get_bufferu(&gb, sd->data, sd->size);
-            break;
-        }
-        default:
-            break;
-        }
-        break;
-
-    default:
-        // ignore unsupported provider codes
-        break;
-    }
     return 0;
 }
 
-- 
2.52.0


>From fcca7432aae9b815446a2e5965a6f711386a8c95 Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
Date: Fri, 29 May 2026 14:08:57 -0300
Subject: [PATCH 4/4] avcodec/libaomdec: use the ITU-T T35 parsing helpers

Signed-off-by: James Almer <[email protected]>
---
 libavcodec/Makefile    |  2 +-
 libavcodec/libaomdec.c | 40 ++++++++++++++--------------------------
 2 files changed, 15 insertions(+), 27 deletions(-)

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 3439e6a1e4..baf642f390 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1170,7 +1170,7 @@ OBJS-$(CONFIG_ALAC_AT_ENCODER)            += 
audiotoolboxenc.o
 OBJS-$(CONFIG_ILBC_AT_ENCODER)            += audiotoolboxenc.o
 OBJS-$(CONFIG_PCM_ALAW_AT_ENCODER)        += audiotoolboxenc.o
 OBJS-$(CONFIG_PCM_MULAW_AT_ENCODER)       += audiotoolboxenc.o
-OBJS-$(CONFIG_LIBAOM_AV1_DECODER)         += libaomdec.o libaom.o
+OBJS-$(CONFIG_LIBAOM_AV1_DECODER)         += libaomdec.o libaom.o itut35.o
 OBJS-$(CONFIG_LIBAOM_AV1_ENCODER)         += libaomenc.o libaom.o
 OBJS-$(CONFIG_LIBARIBB24_DECODER)         += libaribb24.o ass.o
 OBJS-$(CONFIG_LIBARIBCAPTION_DECODER)     += libaribcaption.o ass.o
diff --git a/libavcodec/libaomdec.c b/libavcodec/libaomdec.c
index 79b299bac8..50bfdb693b 100644
--- a/libavcodec/libaomdec.c
+++ b/libavcodec/libaomdec.c
@@ -143,40 +143,28 @@ static int set_pix_fmt(AVCodecContext *avctx, struct 
aom_image *img)
     }
 }
 
-static int decode_metadata_itu_t_t35(AVFrame *frame,
+static int decode_metadata_itu_t_t35(AVCodecContext *avctx, AVFrame *frame,
                                      const uint8_t *buffer, size_t buffer_size)
 {
+    FFITUTT35 itut35 = { 0 };
+    int ret;
+
     if (buffer_size < 6)
         return AVERROR(EINVAL);
 
-    GetByteContext bc;
-    bytestream2_init(&bc, buffer, buffer_size);
+    ret = ff_itut_t35_parse_buffer(&itut35, buffer, buffer_size, 0);
+    if (ret <= 0)
+        return ret;
 
-    const int country_code = bytestream2_get_byteu(&bc);
-    const int provider_code = bytestream2_get_be16u(&bc);
-    const int provider_oriented_code = bytestream2_get_be16u(&bc);
-    const int application_identifier = bytestream2_get_byteu(&bc);
-
-    // See "HDR10+ AV1 Metadata Handling Specification" v1.0.1, Section 2.1.
-    if (country_code == ITU_T_T35_COUNTRY_CODE_US
-        && provider_code == ITU_T_T35_PROVIDER_CODE_SAMSUNG
-        && provider_oriented_code == 0x0001
-        && application_identifier == 0x04) {
-        // HDR10+
-        AVDynamicHDRPlus *hdr_plus = 
av_dynamic_hdr_plus_create_side_data(frame);
-        if (!hdr_plus)
-            return AVERROR(ENOMEM);
-
-        int res = av_dynamic_hdr_plus_from_t35(hdr_plus, bc.buffer,
-                                               
bytestream2_get_bytes_left(&bc));
-        if (res < 0)
-            return res;
-    }
+    ret = ff_itut_t35_parse_payload_to_frame(avctx, &itut35, NULL, frame);
+    if (ret < 0)
+        return ret;
 
     return 0;
 }
 
-static int decode_metadata(AVFrame *frame, const struct aom_image *img)
+static int decode_metadata(AVCodecContext *avctx, AVFrame *frame,
+                           const struct aom_image *img)
 {
     const size_t num_metadata = aom_img_num_metadata(img);
     for (size_t i = 0; i < num_metadata; ++i) {
@@ -186,7 +174,7 @@ static int decode_metadata(AVFrame *frame, const struct 
aom_image *img)
 
         switch (metadata->type) {
         case OBU_METADATA_TYPE_ITUT_T35: {
-            int res = decode_metadata_itu_t_t35(frame, metadata->payload, 
metadata->sz);
+            int res = decode_metadata_itu_t_t35(avctx, frame, 
metadata->payload, metadata->sz);
             if (res < 0)
                 return res;
             break;
@@ -276,7 +264,7 @@ static int aom_decode(AVCodecContext *avctx, AVFrame 
*picture,
             av_image_copy(picture->data, picture->linesize, planes,
                           stride, avctx->pix_fmt, img->d_w, img->d_h);
         }
-        ret = decode_metadata(picture, img);
+        ret = decode_metadata(avctx, picture, img);
         if (ret < 0) {
             av_log(avctx, AV_LOG_ERROR, "Failed to decode metadata\n");
             return ret;
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to