diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 52ea46e645..c86184f9fd 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -100,9 +100,9 @@ OBJS-$(CONFIG_H264DSP)                 += h264dsp.o h264idct.o
 OBJS-$(CONFIG_H264PARSE)               += h264_parse.o h2645_parse.o h264_ps.o
 OBJS-$(CONFIG_H264PRED)                += h264pred.o
 OBJS-$(CONFIG_H264QPEL)                += h264qpel.o
-OBJS-$(CONFIG_H264_SEI)                += h264_sei.o
+OBJS-$(CONFIG_H264_SEI)                += h264_sei.o h2645_sei.o
 OBJS-$(CONFIG_HEVCPARSE)               += hevc_parse.o h2645_parse.o hevc_ps.o hevc_data.o
-OBJS-$(CONFIG_HEVC_SEI)                += hevc_sei.o dynamic_hdr10_plus.o dynamic_hdr_vivid.o
+OBJS-$(CONFIG_HEVC_SEI)                += hevc_sei.o h2645_sei.o dynamic_hdr10_plus.o dynamic_hdr_vivid.o
 OBJS-$(CONFIG_HPELDSP)                 += hpeldsp.o
 OBJS-$(CONFIG_HUFFMAN)                 += huffman.o
 OBJS-$(CONFIG_HUFFYUVDSP)              += huffyuvdsp.o
diff --git a/libavcodec/h2645_sei.c b/libavcodec/h2645_sei.c
new file mode 100644
index 0000000000..5ff62bfac1
--- /dev/null
+++ b/libavcodec/h2645_sei.c
@@ -0,0 +1,391 @@
+/*
+ * Common H.264 and HEVC Supplementary Enhancement Information messages
+ *
+ * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2012 - 2013 Guillaume Martres
+ * Copyright (C) 2012 - 2013 Gildas Cocherel
+ * Copyright (C) 2013 Vittorio Giovara
+ *
+ * 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 "config_components.h"
+
+#include "libavutil/display.h"
+#include "libavutil/film_grain_params.h"
+#include "libavutil/pixdesc.h"
+
+#include "atsc_a53.h"
+#include "avcodec.h"
+#include "dynamic_hdr10_plus.h"
+#include "dynamic_hdr_vivid.h"
+#include "get_bits.h"
+#include "golomb.h"
+#include "h2645_sei.h"
+
+#define IS_H264(codec_id) (CONFIG_H264_SEI && CONFIG_HEVC_SEI ? codec_id == AV_CODEC_ID_H264 : CONFIG_H264_SEI)
+#define IS_HEVC(codec_id) (CONFIG_H264_SEI && CONFIG_HEVC_SEI ? codec_id == AV_CODEC_ID_HEVC : CONFIG_HEVC_SEI)
+
+#if CONFIG_HEVC_SEI
+static int decode_registered_user_data_dynamic_hdr_plus(HEVCSEIDynamicHDRPlus *s,
+                                                        GetByteContext *gb)
+{
+    size_t meta_size;
+    int err;
+    AVDynamicHDRPlus *metadata = av_dynamic_hdr_plus_alloc(&meta_size);
+    if (!metadata)
+        return AVERROR(ENOMEM);
+
+    err = ff_parse_itu_t_t35_to_dynamic_hdr10_plus(metadata, gb->buffer,
+                                                   bytestream2_get_bytes_left(gb));
+    if (err < 0) {
+        av_free(metadata);
+        return err;
+    }
+
+    av_buffer_unref(&s->info);
+    s->info = av_buffer_create((uint8_t *)metadata, meta_size, NULL, NULL, 0);
+    if (!s->info) {
+        av_free(metadata);
+        return AVERROR(ENOMEM);
+    }
+
+    return 0;
+}
+
+static int decode_registered_user_data_dynamic_hdr_vivid(HEVCSEIDynamicHDRVivid *s,
+                                                         GetByteContext *gb)
+{
+    size_t meta_size;
+    int err;
+    AVDynamicHDRVivid *metadata = av_dynamic_hdr_vivid_alloc(&meta_size);
+    if (!metadata)
+        return AVERROR(ENOMEM);
+
+    err = ff_parse_itu_t_t35_to_dynamic_hdr_vivid(metadata,
+                                                  gb->buffer, bytestream2_get_bytes_left(gb));
+    if (err < 0) {
+        av_free(metadata);
+        return err;
+    }
+
+    av_buffer_unref(&s->info);
+    s->info = av_buffer_create((uint8_t *)metadata, meta_size, NULL, NULL, 0);
+    if (!s->info) {
+        av_free(metadata);
+        return AVERROR(ENOMEM);
+    }
+
+    return 0;
+}
+#endif
+
+static int decode_registered_user_data_afd(H264SEIAFD *h, GetByteContext *gb)
+{
+    int flag;
+
+    if (bytestream2_get_bytes_left(gb) <= 0)
+        return AVERROR_INVALIDDATA;
+
+    flag = !!(bytestream2_get_byteu(gb) & 0x40); // active_format_flag
+
+    if (flag) {
+        if (bytestream2_get_bytes_left(gb) <= 0)
+            return AVERROR_INVALIDDATA;
+        h->active_format_description = bytestream2_get_byteu(gb) & 0xF;
+        h->present                   = 1;
+    }
+
+    return 0;
+}
+
+static int decode_registered_user_data_closed_caption(H2645SEIA53Caption *h,
+                                                      GetByteContext *gb)
+{
+    return ff_parse_a53_cc(&h->buf_ref, gb->buffer,
+                           bytestream2_get_bytes_left(gb));
+}
+
+static int decode_registered_user_data(H2645SEI *h, GetByteContext *gb,
+                                       enum AVCodecID codec_id, void *logctx)
+{
+    int country_code, provider_code;
+
+    if (bytestream2_get_bytes_left(gb) < 3)
+        return AVERROR_INVALIDDATA;
+
+    country_code = bytestream2_get_byteu(gb); // itu_t_t35_country_code
+    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
+    }
+
+    if (country_code != 0xB5 && country_code != 0x26) { // usa_country_code and cn_country_code
+        av_log(logctx, AV_LOG_VERBOSE,
+               "Unsupported User Data Registered ITU-T T35 SEI message (country_code = %d)\n",
+               country_code);
+        return 0;
+    }
+
+    /* itu_t_t35_payload_byte follows */
+    provider_code = bytestream2_get_be16u(gb);
+
+    switch (provider_code) {
+    case 0x31: { // atsc_provider_code
+        uint32_t user_identifier;
+
+        if (bytestream2_get_bytes_left(gb) < 4)
+            return AVERROR_INVALIDDATA;
+
+        user_identifier = bytestream2_get_be32u(gb);
+        switch (user_identifier) {
+        case MKBETAG('D', 'T', 'G', '1'):       // afd_data
+            if (!IS_H264(codec_id))
+                goto unsupported;
+            return decode_registered_user_data_afd(&h->afd, gb);
+        case MKBETAG('G', 'A', '9', '4'):       // closed captions
+            return decode_registered_user_data_closed_caption(&h->a53_caption, gb);
+        default:
+        unsupported:
+            av_log(logctx, AV_LOG_VERBOSE,
+                   "Unsupported User Data Registered ITU-T T35 SEI message (atsc user_identifier = 0x%04x)\n",
+                   user_identifier);
+            break;
+        }
+        break;
+    }
+#if CONFIG_HEVC_SEI
+    case 0x04: { // cuva_provider_code
+        const uint16_t cuva_provider_oriented_code = 0x0005;
+        uint16_t provider_oriented_code;
+
+        if (!IS_HEVC(codec_id))
+            goto unsupported_provider_code;
+
+        if (bytestream2_get_bytes_left(gb) < 2)
+            return AVERROR_INVALIDDATA;
+
+        provider_oriented_code = bytestream2_get_be16u(gb);
+        if (provider_oriented_code == cuva_provider_oriented_code) {
+            return decode_registered_user_data_dynamic_hdr_vivid(&h->dynamic_hdr_vivid, gb);
+        }
+        break;
+    }
+    case 0x3C: { // smpte_provider_code
+        // A/341 Amendment - 2094-40
+        const uint16_t smpte2094_40_provider_oriented_code = 0x0001;
+        const uint8_t smpte2094_40_application_identifier = 0x04;
+        uint16_t provider_oriented_code;
+        uint8_t application_identifier;
+
+        if (!IS_HEVC(codec_id))
+            goto unsupported_provider_code;
+
+        if (bytestream2_get_bytes_left(gb) < 3)
+            return AVERROR_INVALIDDATA;
+
+        provider_oriented_code = bytestream2_get_be16u(gb);
+        application_identifier = bytestream2_get_byteu(gb);
+        if (provider_oriented_code == smpte2094_40_provider_oriented_code &&
+            application_identifier == smpte2094_40_application_identifier) {
+            return decode_registered_user_data_dynamic_hdr_plus(&h->dynamic_hdr_plus, gb);
+        }
+        break;
+    }
+    unsupported_provider_code:
+#endif
+    default:
+        av_log(logctx, AV_LOG_VERBOSE,
+               "Unsupported User Data Registered ITU-T T35 SEI message (provider_code = %d)\n",
+               provider_code);
+        break;
+    }
+
+    return 0;
+}
+
+static int decode_unregistered_user_data(H2645SEIUnregistered *h,
+                                         GetByteContext *gb,
+                                         enum AVCodecID codec_id)
+{
+    uint8_t *user_data;
+    int size = bytestream2_get_bytes_left(gb);
+    AVBufferRef *buf_ref, **tmp;
+
+    if (size < 16 || size >= INT_MAX - 1)
+        return AVERROR_INVALIDDATA;
+
+    tmp = av_realloc_array(h->buf_ref, h->nb_buf_ref + 1, sizeof(*h->buf_ref));
+    if (!tmp)
+        return AVERROR(ENOMEM);
+    h->buf_ref = tmp;
+
+    buf_ref = av_buffer_alloc(size + 1);
+    if (!buf_ref)
+        return AVERROR(ENOMEM);
+    user_data = buf_ref->data;
+
+    bytestream2_get_bufferu(gb, user_data, size);
+    user_data[size] = 0;
+    buf_ref->size = size;
+    h->buf_ref[h->nb_buf_ref++] = buf_ref;
+
+    if (IS_H264(codec_id)) {
+        int e, build;
+        e = sscanf(user_data + 16, "x264 - core %d", &build);
+        if (e == 1 && build > 0)
+            h->x264_build = build;
+        if (e == 1 && build == 1 && !strncmp(user_data+16, "x264 - core 0000", 16))
+            h->x264_build = 67;
+    }
+
+    return 0;
+}
+
+static int decode_display_orientation(H2645SEIDisplayOrientation *h,
+                                      GetBitContext *gb)
+{
+    h->present = !get_bits1(gb);  // display_orientation_cancel_flag
+
+    if (h->present) {
+        h->hflip = get_bits1(gb);     // hor_flip
+        h->vflip = get_bits1(gb);     // ver_flip
+
+        h->anticlockwise_rotation = get_bits(gb, 16);
+        // This is followed by display_orientation_repetition_period
+        // and display_orientation_extension_flag for H.264
+        // and by display_orientation_persistence_flag for HEVC.
+    }
+
+    return 0;
+}
+
+static int decode_frame_packing_arrangement(H2645SEIFramePacking *h,
+                                            GetBitContext *gb,
+                                            enum AVCodecID codec_id)
+{
+    h->arrangement_id          = get_ue_golomb_long(gb);
+    h->arrangement_cancel_flag = get_bits1(gb);
+    h->present = !h->arrangement_cancel_flag;
+
+    if (h->present) {
+        h->arrangement_type              = get_bits(gb, 7);
+        h->quincunx_sampling_flag        = get_bits1(gb);
+        h->content_interpretation_type   = get_bits(gb, 6);
+
+        // spatial_flipping_flag, frame0_flipped_flag, field_views_flag
+        skip_bits(gb, 3);
+        h->current_frame_is_frame0_flag  = get_bits1(gb);
+        // frame0_self_contained_flag, frame1_self_contained_flag
+        skip_bits(gb, 2);
+
+        if (!h->quincunx_sampling_flag && h->arrangement_type != 5)
+            skip_bits(gb, 16);      // frame[01]_grid_position_[xy]
+        skip_bits(gb, 8);           // frame_packing_arrangement_reserved_byte
+        if (IS_H264(codec_id))
+            h->arrangement_repetition_period = get_ue_golomb_long(gb);
+        else
+            skip_bits1(gb); // frame_packing_arrangement_persistence_flag
+    }
+    // H.264: frame_packing_arrangement_extension_flag,
+    // HEVC:  upsampled_aspect_ratio_flag
+    skip_bits1(gb);
+
+    return 0;
+}
+
+static int decode_alternative_transfer(H2645SEIAlternativeTransfer *s,
+                                       GetByteContext *gb)
+{
+    if (bytestream2_get_bytes_left(gb) < 1)
+        return AVERROR_INVALIDDATA;
+
+    s->present = 1;
+    s->preferred_transfer_characteristics = bytestream2_get_byteu(gb);
+
+    return 0;
+}
+
+static int decode_film_grain_characteristics(H2645SEIFilmGrainCharacteristics *h,
+                                             enum AVCodecID codec_id, GetBitContext *gb)
+{
+    h->present = !get_bits1(gb); // film_grain_characteristics_cancel_flag
+
+    if (h->present) {
+        memset(h, 0, sizeof(*h));
+        h->model_id = get_bits(gb, 2);
+        h->separate_colour_description_present_flag = get_bits1(gb);
+        if (h->separate_colour_description_present_flag) {
+            h->bit_depth_luma   = get_bits(gb, 3) + 8;
+            h->bit_depth_chroma = get_bits(gb, 3) + 8;
+            h->full_range       = get_bits1(gb);
+            h->color_primaries  = get_bits(gb, 8);
+            h->transfer_characteristics = get_bits(gb, 8);
+            h->matrix_coeffs    = get_bits(gb, 8);
+        }
+        h->blending_mode_id  = get_bits(gb, 2);
+        h->log2_scale_factor = get_bits(gb, 4);
+        for (int c = 0; c < 3; c++)
+            h->comp_model_present_flag[c] = get_bits1(gb);
+        for (int c = 0; c < 3; c++) {
+            if (h->comp_model_present_flag[c]) {
+                h->num_intensity_intervals[c] = get_bits(gb, 8) + 1;
+                h->num_model_values[c] = get_bits(gb, 3) + 1;
+                if (h->num_model_values[c] > 6)
+                    return AVERROR_INVALIDDATA;
+                for (int i = 0; i < h->num_intensity_intervals[c]; i++) {
+                    h->intensity_interval_lower_bound[c][i] = get_bits(gb, 8);
+                    h->intensity_interval_upper_bound[c][i] = get_bits(gb, 8);
+                    for (int j = 0; j < h->num_model_values[c]; j++)
+                        h->comp_model_value[c][i][j] = get_se_golomb_long(gb);
+                }
+            }
+        }
+        if (IS_HEVC(codec_id))
+            h->persistence_flag = get_bits1(gb);
+        else
+            h->repetition_period = get_ue_golomb_long(gb);
+
+        h->present = 1;
+    }
+
+    return 0;
+}
+
+int ff_h2645_sei_message_decode(H2645SEI *h, enum SEIType type,
+                                enum AVCodecID codec_id, GetBitContext *gb,
+                                GetByteContext *gbyte, void *logctx)
+{
+    switch (type) {
+    case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35:
+        return decode_registered_user_data(h, gbyte, codec_id, logctx);
+    case SEI_TYPE_USER_DATA_UNREGISTERED:
+        return decode_unregistered_user_data(&h->unregistered, gbyte, codec_id);
+    case SEI_TYPE_DISPLAY_ORIENTATION:
+        return decode_display_orientation(&h->display_orientation, gb);
+    case SEI_TYPE_FILM_GRAIN_CHARACTERISTICS:
+        return decode_film_grain_characteristics(&h->film_grain_characteristics, codec_id, gb);
+    case SEI_TYPE_FRAME_PACKING_ARRANGEMENT:
+        return decode_frame_packing_arrangement(&h->frame_packing, gb, codec_id);
+    case SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS:
+        return decode_alternative_transfer(&h->alternative_transfer, gbyte);
+    default:
+        return FF_H2645_SEI_MESSAGE_UNHANDLED;
+    }
+}
diff --git a/libavcodec/h2645_sei.h b/libavcodec/h2645_sei.h
new file mode 100644
index 0000000000..4128ff7940
--- /dev/null
+++ b/libavcodec/h2645_sei.h
@@ -0,0 +1,133 @@
+/*
+ * 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
+ */
+
+#ifndef AVCODEC_H2645_SEI_H
+#define AVCODEC_H2645_SEI_H
+
+#include <stdint.h>
+
+#include "libavutil/buffer.h"
+#include "libavutil/frame.h"
+
+#include "avcodec.h"
+#include "bytestream.h"
+#include "codec_id.h"
+#include "get_bits.h"
+#include "sei.h"
+
+typedef struct H2645SEIA53Caption {
+    AVBufferRef *buf_ref;
+} H2645SEIA53Caption;
+
+typedef struct H264SEIAFD {
+    int present;
+    uint8_t active_format_description;
+} H264SEIAFD;
+
+typedef struct HEVCSEIDynamicHDRPlus {
+    AVBufferRef *info;
+} HEVCSEIDynamicHDRPlus;
+
+typedef struct HEVCSEIDynamicHDRVivid {
+    AVBufferRef *info;
+} HEVCSEIDynamicHDRVivid;
+
+typedef struct H2645SEIUnregistered {
+    AVBufferRef **buf_ref;
+    unsigned nb_buf_ref;
+    int x264_build;           //< H.264 only
+} H2645SEIUnregistered;
+
+typedef struct H2645SEIFramePacking {
+    int present;
+    int arrangement_id;
+    int arrangement_cancel_flag;  ///< is previous arrangement canceled, -1 if never received (currently H.264 only)
+    int arrangement_type;
+    int arrangement_repetition_period;
+    int content_interpretation_type;
+    int quincunx_sampling_flag;
+    int current_frame_is_frame0_flag;
+} H2645SEIFramePacking;
+
+typedef struct H2645SEIDisplayOrientation {
+    int present;
+    int anticlockwise_rotation;
+    int hflip, vflip;
+} H2645SEIDisplayOrientation;
+
+typedef struct H2645SEIAlternativeTransfer {
+    int present;
+    int preferred_transfer_characteristics;
+} H2645SEIAlternativeTransfer;
+
+typedef struct H2645SEIFilmGrainCharacteristics {
+    int present;
+    int model_id;
+    int separate_colour_description_present_flag;
+    int bit_depth_luma;
+    int bit_depth_chroma;
+    int full_range;
+    int color_primaries;
+    int transfer_characteristics;
+    int matrix_coeffs;
+    int blending_mode_id;
+    int log2_scale_factor;
+    int comp_model_present_flag[3];
+    uint16_t num_intensity_intervals[3];
+    uint8_t num_model_values[3];
+    uint8_t intensity_interval_lower_bound[3][256];
+    uint8_t intensity_interval_upper_bound[3][256];
+    int16_t comp_model_value[3][256][6];
+    int repetition_period;       //< H.264 only
+    int persistence_flag;        //< HEVC  only
+} H2645SEIFilmGrainCharacteristics;
+
+typedef struct H2645SEI {
+    H2645SEIA53Caption a53_caption;
+    H264SEIAFD afd;                              //< H.264 only
+    HEVCSEIDynamicHDRPlus  dynamic_hdr_plus;     //< HEVC only
+    HEVCSEIDynamicHDRVivid dynamic_hdr_vivid;    //< HEVC only
+    H2645SEIUnregistered unregistered;
+    H2645SEIFramePacking frame_packing;
+    H2645SEIDisplayOrientation display_orientation;
+    H2645SEIAlternativeTransfer alternative_transfer;
+    H2645SEIFilmGrainCharacteristics film_grain_characteristics;
+} H2645SEI;
+
+enum {
+    FF_H2645_SEI_MESSAGE_HANDLED = 0,
+    FF_H2645_SEI_MESSAGE_UNHANDLED,
+};
+
+/**
+ * Decode a single SEI message.
+ *
+ * This function may either use gb or gbyte to decode the SEI message.
+ *
+ * @param[in, out] gb    GetBitContext that needs to be at the start
+ *                       of the payload (i.e. after the payload_size bytes);
+ *                       it needs to be initially byte-aligned
+ * @param[in, out] gbyte a GetByteContext for the same data as gb
+ * @return < 0 on error, FF_H2645_SEI_MESSAGE_HANDLED if the SEI message
+ *         has been handled or FF_H2645_SEI_MESSAGE_UNHANDLED if not.
+ */
+int ff_h2645_sei_message_decode(H2645SEI *h, enum SEIType type,
+                                enum AVCodecID codec_id, GetBitContext *gb,
+                                GetByteContext *gbyte, void *logctx);
+
+#endif /* AVCODEC_H2645_SEI_H */
diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
index 50810f1789..3ed23fb9ca 100644
--- a/libavcodec/h264_parser.c
+++ b/libavcodec/h264_parser.c
@@ -274,8 +274,8 @@ static inline int parse_nal_units(AVCodecParserContext *s,
     s->picture_structure = AV_PICTURE_STRUCTURE_UNKNOWN;
 
     ff_h264_sei_uninit(&p->sei);
-    p->sei.frame_packing.arrangement_cancel_flag = -1;
-    p->sei.unregistered.x264_build = -1;
+    p->sei.common.frame_packing.arrangement_cancel_flag = -1;
+    p->sei.common.unregistered.x264_build = -1;
 
     if (!buf_size)
         return 0;
@@ -565,7 +565,7 @@ static inline int parse_nal_units(AVCodecParserContext *s,
             }
             if (sps->timing_info_present_flag) {
                 int64_t den = sps->time_scale;
-                if (p->sei.unregistered.x264_build < 44U)
+                if (p->sei.common.unregistered.x264_build < 44U)
                     den *= 2;
                 av_reduce(&avctx->framerate.den, &avctx->framerate.num,
                           sps->num_units_in_tick * avctx->ticks_per_frame, den, 1 << 30);
diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c
index d62a276779..c62aef9246 100644
--- a/libavcodec/h264_sei.c
+++ b/libavcodec/h264_sei.c
@@ -32,7 +32,6 @@
 #include "libavutil/log.h"
 #include "libavutil/macros.h"
 #include "libavutil/mem.h"
-#include "atsc_a53.h"
 #include "bytestream.h"
 #include "get_bits.h"
 #include "golomb.h"
@@ -55,16 +54,16 @@ void ff_h264_sei_uninit(H264SEIContext *h)
 
     h->picture_timing.present      = 0;
     h->buffering_period.present    = 0;
-    h->frame_packing.present       = 0;
-    h->film_grain_characteristics.present = 0;
-    h->display_orientation.present = 0;
-    h->afd.present                 =  0;
-
-    av_buffer_unref(&h->a53_caption.buf_ref);
-    for (int i = 0; i < h->unregistered.nb_buf_ref; i++)
-        av_buffer_unref(&h->unregistered.buf_ref[i]);
-    h->unregistered.nb_buf_ref = 0;
-    av_freep(&h->unregistered.buf_ref);
+    h->common.frame_packing.present       = 0;
+    h->common.film_grain_characteristics.present = 0;
+    h->common.display_orientation.present = 0;
+    h->common.afd.present                 =  0;
+
+    av_buffer_unref(&h->common.a53_caption.buf_ref);
+    for (int i = 0; i < h->common.unregistered.nb_buf_ref; i++)
+        av_buffer_unref(&h->common.unregistered.buf_ref[i]);
+    h->common.unregistered.nb_buf_ref = 0;
+    av_freep(&h->common.unregistered.buf_ref);
 }
 
 int ff_h264_sei_process_picture_timing(H264SEIPictureTiming *h, const SPS *sps,
@@ -153,123 +152,6 @@ static int decode_picture_timing(H264SEIPictureTiming *h, GetByteContext *gb,
     return 0;
 }
 
-static int decode_registered_user_data_afd(H264SEIAFD *h, GetByteContext *gb)
-{
-    int flag;
-
-    if (bytestream2_get_bytes_left(gb) <= 0)
-        return AVERROR_INVALIDDATA;
-
-    flag = !!(bytestream2_get_byteu(gb) & 0x40); // active_format_flag
-
-    if (flag) {
-        if (bytestream2_get_bytes_left(gb) <= 0)
-            return AVERROR_INVALIDDATA;
-        h->active_format_description = bytestream2_get_byteu(gb) & 0xF;
-        h->present                   = 1;
-    }
-
-    return 0;
-}
-
-static int decode_registered_user_data_closed_caption(H264SEIA53Caption *h,
-                                                      GetByteContext *gb)
-{
-    return ff_parse_a53_cc(&h->buf_ref, gb->buffer,
-                           bytestream2_get_bytes_left(gb));
-}
-
-static int decode_registered_user_data(H264SEIContext *h, GetByteContext *gb,
-                                       void *logctx)
-{
-    int country_code, provider_code;
-
-    if (bytestream2_get_bytes_left(gb) < 3)
-        return AVERROR_INVALIDDATA;
-
-    country_code = bytestream2_get_byteu(gb); // itu_t_t35_country_code
-    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
-    }
-
-    if (country_code != 0xB5) { // usa_country_code
-        av_log(logctx, AV_LOG_VERBOSE,
-               "Unsupported User Data Registered ITU-T T35 SEI message (country_code = %d)\n",
-               country_code);
-        return 0;
-    }
-
-    /* itu_t_t35_payload_byte follows */
-    provider_code = bytestream2_get_be16u(gb);
-
-    switch (provider_code) {
-    case 0x31: { // atsc_provider_code
-        uint32_t user_identifier;
-
-        if (bytestream2_get_bytes_left(gb) < 4)
-            return AVERROR_INVALIDDATA;
-
-        user_identifier = bytestream2_get_be32u(gb);
-        switch (user_identifier) {
-        case MKBETAG('D', 'T', 'G', '1'):       // afd_data
-            return decode_registered_user_data_afd(&h->afd, gb);
-        case MKBETAG('G', 'A', '9', '4'):       // closed captions
-            return decode_registered_user_data_closed_caption(&h->a53_caption, gb);
-        default:
-            av_log(logctx, AV_LOG_VERBOSE,
-                   "Unsupported User Data Registered ITU-T T35 SEI message (atsc user_identifier = 0x%04x)\n",
-                   user_identifier);
-            break;
-        }
-        break;
-    }
-    default:
-        av_log(logctx, AV_LOG_VERBOSE,
-               "Unsupported User Data Registered ITU-T T35 SEI message (provider_code = %d)\n",
-               provider_code);
-        break;
-    }
-
-    return 0;
-}
-
-static int decode_unregistered_user_data(H264SEIUnregistered *h, GetByteContext *gb,
-                                         void *logctx)
-{
-    uint8_t *user_data;
-    int e, build, size = bytestream2_get_bytes_left(gb);
-    AVBufferRef *buf_ref, **tmp;
-
-    if (size < 16 || size >= INT_MAX - 1)
-        return AVERROR_INVALIDDATA;
-
-    tmp = av_realloc_array(h->buf_ref, h->nb_buf_ref + 1, sizeof(*h->buf_ref));
-    if (!tmp)
-        return AVERROR(ENOMEM);
-    h->buf_ref = tmp;
-
-    buf_ref = av_buffer_alloc(size + 1);
-    if (!buf_ref)
-        return AVERROR(ENOMEM);
-    user_data = buf_ref->data;
-
-    bytestream2_get_bufferu(gb, user_data, size);
-    user_data[size] = 0;
-    buf_ref->size = size;
-    h->buf_ref[h->nb_buf_ref++] = buf_ref;
-
-    e = sscanf(user_data + 16, "x264 - core %d", &build);
-    if (e == 1 && build > 0)
-        h->x264_build = build;
-    if (e == 1 && build == 1 && !strncmp(user_data+16, "x264 - core 0000", 16))
-        h->x264_build = 67;
-
-    return 0;
-}
-
 static int decode_recovery_point(H264SEIRecoveryPoint *h, GetBitContext *gb, void *logctx)
 {
     unsigned recovery_frame_cnt = get_ue_golomb_long(gb);
@@ -325,51 +207,6 @@ static int decode_buffering_period(H264SEIBufferingPeriod *h, GetBitContext *gb,
     return 0;
 }
 
-static int decode_frame_packing_arrangement(H264SEIFramePacking *h,
-                                            GetBitContext *gb)
-{
-    h->arrangement_id          = get_ue_golomb_long(gb);
-    h->arrangement_cancel_flag = get_bits1(gb);
-    h->present = !h->arrangement_cancel_flag;
-
-    if (h->present) {
-        h->arrangement_type = get_bits(gb, 7);
-        h->quincunx_sampling_flag         = get_bits1(gb);
-        h->content_interpretation_type    = get_bits(gb, 6);
-
-        // spatial_flipping_flag, frame0_flipped_flag, field_views_flag
-        skip_bits(gb, 3);
-        h->current_frame_is_frame0_flag = get_bits1(gb);
-        // frame0_self_contained_flag, frame1_self_contained_flag
-        skip_bits(gb, 2);
-
-        if (!h->quincunx_sampling_flag && h->arrangement_type != 5)
-            skip_bits(gb, 16);      // frame[01]_grid_position_[xy]
-        skip_bits(gb, 8);           // frame_packing_arrangement_reserved_byte
-        h->arrangement_repetition_period = get_ue_golomb_long(gb);
-    }
-    skip_bits1(gb);                 // frame_packing_arrangement_extension_flag
-
-    return 0;
-}
-
-static int decode_display_orientation(H264SEIDisplayOrientation *h,
-                                      GetBitContext *gb)
-{
-    h->present = !get_bits1(gb);
-
-    if (h->present) {
-        h->hflip = get_bits1(gb);     // hor_flip
-        h->vflip = get_bits1(gb);     // ver_flip
-
-        h->anticlockwise_rotation = get_bits(gb, 16);
-        get_ue_golomb_long(gb);       // display_orientation_repetition_period
-        skip_bits1(gb);               // display_orientation_extension_flag
-    }
-
-    return 0;
-}
-
 static int decode_green_metadata(H264SEIGreenMetaData *h, GetByteContext *gb)
 {
     h->green_metadata_type = bytestream2_get_byte(gb);
@@ -395,57 +232,6 @@ static int decode_green_metadata(H264SEIGreenMetaData *h, GetByteContext *gb)
     return 0;
 }
 
-static int decode_alternative_transfer(H264SEIAlternativeTransfer *h,
-                                       GetByteContext *gb)
-{
-    h->present = 1;
-    h->preferred_transfer_characteristics = bytestream2_get_byte(gb);
-    return 0;
-}
-
-static int decode_film_grain_characteristics(H264SEIFilmGrainCharacteristics *h,
-                                             GetBitContext *gb)
-{
-    h->present = !get_bits1(gb); // film_grain_characteristics_cancel_flag
-
-    if (h->present) {
-        memset(h, 0, sizeof(*h));
-        h->model_id = get_bits(gb, 2);
-        h->separate_colour_description_present_flag = get_bits1(gb);
-        if (h->separate_colour_description_present_flag) {
-            h->bit_depth_luma = get_bits(gb, 3) + 8;
-            h->bit_depth_chroma = get_bits(gb, 3) + 8;
-            h->full_range = get_bits1(gb);
-            h->color_primaries = get_bits(gb, 8);
-            h->transfer_characteristics = get_bits(gb, 8);
-            h->matrix_coeffs = get_bits(gb, 8);
-        }
-        h->blending_mode_id = get_bits(gb, 2);
-        h->log2_scale_factor = get_bits(gb, 4);
-        for (int c = 0; c < 3; c++)
-            h->comp_model_present_flag[c] = get_bits1(gb);
-        for (int c = 0; c < 3; c++) {
-            if (h->comp_model_present_flag[c]) {
-                h->num_intensity_intervals[c] = get_bits(gb, 8) + 1;
-                h->num_model_values[c] = get_bits(gb, 3) + 1;
-                if (h->num_model_values[c] > 6)
-                    return AVERROR_INVALIDDATA;
-                for (int i = 0; i < h->num_intensity_intervals[c]; i++) {
-                    h->intensity_interval_lower_bound[c][i] = get_bits(gb, 8);
-                    h->intensity_interval_upper_bound[c][i] = get_bits(gb, 8);
-                    for (int j = 0; j < h->num_model_values[c]; j++)
-                        h->comp_model_value[c][i][j] = get_se_golomb_long(gb);
-                }
-            }
-        }
-        h->repetition_period = get_ue_golomb_long(gb);
-
-        h->present = 1;
-    }
-
-    return 0;
-}
-
 int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb,
                        const H264ParamSets *ps, void *logctx)
 {
@@ -490,35 +276,20 @@ int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb,
         case SEI_TYPE_PIC_TIMING: // Picture timing SEI
             ret = decode_picture_timing(&h->picture_timing, &gbyte_payload, logctx);
             break;
-        case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35:
-            ret = decode_registered_user_data(h, &gbyte_payload, logctx);
-            break;
-        case SEI_TYPE_USER_DATA_UNREGISTERED:
-            ret = decode_unregistered_user_data(&h->unregistered, &gbyte_payload, logctx);
-            break;
         case SEI_TYPE_RECOVERY_POINT:
             ret = decode_recovery_point(&h->recovery_point, &gb_payload, logctx);
             break;
         case SEI_TYPE_BUFFERING_PERIOD:
             ret = decode_buffering_period(&h->buffering_period, &gb_payload, ps, logctx);
             break;
-        case SEI_TYPE_FRAME_PACKING_ARRANGEMENT:
-            ret = decode_frame_packing_arrangement(&h->frame_packing, &gb_payload);
-            break;
-        case SEI_TYPE_DISPLAY_ORIENTATION:
-            ret = decode_display_orientation(&h->display_orientation, &gb_payload);
-            break;
         case SEI_TYPE_GREEN_METADATA:
             ret = decode_green_metadata(&h->green_metadata, &gbyte_payload);
             break;
-        case SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS:
-            ret = decode_alternative_transfer(&h->alternative_transfer, &gbyte_payload);
-            break;
-        case SEI_TYPE_FILM_GRAIN_CHARACTERISTICS:
-            ret = decode_film_grain_characteristics(&h->film_grain_characteristics, &gb_payload);
-            break;
         default:
-            av_log(logctx, AV_LOG_DEBUG, "unknown SEI type %d\n", type);
+            ret = ff_h2645_sei_message_decode(&h->common, type, AV_CODEC_ID_H264,
+                                              &gb_payload, &gbyte_payload, logctx);
+            if (ret == FF_H2645_SEI_MESSAGE_UNHANDLED)
+                av_log(logctx, AV_LOG_DEBUG, "unknown SEI type %d\n", type);
         }
         if (ret < 0 && ret != AVERROR_PS_NOT_FOUND)
             return ret;
@@ -536,7 +307,7 @@ int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb,
     return master_ret;
 }
 
-const char *ff_h264_sei_stereo_mode(const H264SEIFramePacking *h)
+const char *ff_h264_sei_stereo_mode(const H2645SEIFramePacking *h)
 {
     if (h->arrangement_cancel_flag == 0) {
         switch (h->arrangement_type) {
diff --git a/libavcodec/h264_sei.h b/libavcodec/h264_sei.h
index d7866f42ad..7a53d01ac5 100644
--- a/libavcodec/h264_sei.h
+++ b/libavcodec/h264_sei.h
@@ -20,6 +20,7 @@
 #define AVCODEC_H264_SEI_H
 
 #include "get_bits.h"
+#include "h2645_sei.h"
 #include "h264_ps.h"
 #include "sei.h"
 
@@ -99,21 +100,6 @@ typedef struct H264SEIPictureTiming {
     int timecode_cnt;
 } H264SEIPictureTiming;
 
-typedef struct H264SEIAFD {
-    int present;
-    uint8_t active_format_description;
-} H264SEIAFD;
-
-typedef struct H264SEIA53Caption {
-    AVBufferRef *buf_ref;
-} H264SEIA53Caption;
-
-typedef struct H264SEIUnregistered {
-    int x264_build;
-    AVBufferRef **buf_ref;
-    int nb_buf_ref;
-} H264SEIUnregistered;
-
 typedef struct H264SEIRecoveryPoint {
     /**
      * recovery_frame_cnt
@@ -130,23 +116,6 @@ typedef struct H264SEIBufferingPeriod {
     int initial_cpb_removal_delay[32];  ///< Initial timestamps for CPBs
 } H264SEIBufferingPeriod;
 
-typedef struct H264SEIFramePacking {
-    int present;
-    int arrangement_id;
-    int arrangement_cancel_flag;  ///< is previous arrangement canceled, -1 if never received
-    H264_SEI_FpaType arrangement_type;
-    int arrangement_repetition_period;
-    int content_interpretation_type;
-    int quincunx_sampling_flag;
-    int current_frame_is_frame0_flag;
-} H264SEIFramePacking;
-
-typedef struct H264SEIDisplayOrientation {
-    int present;
-    int anticlockwise_rotation;
-    int hflip, vflip;
-} H264SEIDisplayOrientation;
-
 typedef struct H264SEIGreenMetaData {
     uint8_t green_metadata_type;
     uint8_t period_type;
@@ -160,44 +129,12 @@ typedef struct H264SEIGreenMetaData {
     uint16_t xsd_metric_value;
 } H264SEIGreenMetaData;
 
-typedef struct H264SEIAlternativeTransfer {
-    int present;
-    int preferred_transfer_characteristics;
-} H264SEIAlternativeTransfer;
-
-typedef struct H264SEIFilmGrainCharacteristics {
-    int present;
-    int model_id;
-    int separate_colour_description_present_flag;
-    int bit_depth_luma;
-    int bit_depth_chroma;
-    int full_range;
-    int color_primaries;
-    int transfer_characteristics;
-    int matrix_coeffs;
-    int blending_mode_id;
-    int log2_scale_factor;
-    int comp_model_present_flag[3];
-    uint16_t num_intensity_intervals[3];
-    uint8_t num_model_values[3];
-    uint8_t intensity_interval_lower_bound[3][256];
-    uint8_t intensity_interval_upper_bound[3][256];
-    int16_t comp_model_value[3][256][6];
-    int repetition_period;
-} H264SEIFilmGrainCharacteristics;
-
 typedef struct H264SEIContext {
+    H2645SEI common;
     H264SEIPictureTiming picture_timing;
-    H264SEIAFD afd;
-    H264SEIA53Caption a53_caption;
-    H264SEIUnregistered unregistered;
     H264SEIRecoveryPoint recovery_point;
     H264SEIBufferingPeriod buffering_period;
-    H264SEIFramePacking frame_packing;
-    H264SEIDisplayOrientation display_orientation;
     H264SEIGreenMetaData green_metadata;
-    H264SEIAlternativeTransfer alternative_transfer;
-    H264SEIFilmGrainCharacteristics film_grain_characteristics;
 } H264SEIContext;
 
 struct H264ParamSets;
@@ -213,7 +150,7 @@ void ff_h264_sei_uninit(H264SEIContext *h);
 /**
  * Get stereo_mode string from the h264 frame_packing_arrangement
  */
-const char *ff_h264_sei_stereo_mode(const H264SEIFramePacking *h);
+const char *ff_h264_sei_stereo_mode(const H2645SEIFramePacking *h);
 
 /**
  * Parse the contents of a picture timing message given an active SPS.
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index d56722a5c2..a6d8d2bdac 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -433,29 +433,30 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
 
     h->frame_recovered       = h1->frame_recovered;
 
-    ret = av_buffer_replace(&h->sei.a53_caption.buf_ref, h1->sei.a53_caption.buf_ref);
+    ret = av_buffer_replace(&h->sei.common.a53_caption.buf_ref,
+                            h1->sei.common.a53_caption.buf_ref);
     if (ret < 0)
         return ret;
 
-    for (i = 0; i < h->sei.unregistered.nb_buf_ref; i++)
-        av_buffer_unref(&h->sei.unregistered.buf_ref[i]);
-    h->sei.unregistered.nb_buf_ref = 0;
+    for (i = 0; i < h->sei.common.unregistered.nb_buf_ref; i++)
+        av_buffer_unref(&h->sei.common.unregistered.buf_ref[i]);
+    h->sei.common.unregistered.nb_buf_ref = 0;
 
-    if (h1->sei.unregistered.nb_buf_ref) {
-        ret = av_reallocp_array(&h->sei.unregistered.buf_ref,
-                                h1->sei.unregistered.nb_buf_ref,
-                                sizeof(*h->sei.unregistered.buf_ref));
+    if (h1->sei.common.unregistered.nb_buf_ref) {
+        ret = av_reallocp_array(&h->sei.common.unregistered.buf_ref,
+                                h1->sei.common.unregistered.nb_buf_ref,
+                                sizeof(*h->sei.common.unregistered.buf_ref));
         if (ret < 0)
             return ret;
 
-        for (i = 0; i < h1->sei.unregistered.nb_buf_ref; i++) {
-            h->sei.unregistered.buf_ref[i] = av_buffer_ref(h1->sei.unregistered.buf_ref[i]);
-            if (!h->sei.unregistered.buf_ref[i])
+        for (i = 0; i < h1->sei.common.unregistered.nb_buf_ref; i++) {
+            h->sei.common.unregistered.buf_ref[i] = av_buffer_ref(h1->sei.common.unregistered.buf_ref[i]);
+            if (!h->sei.common.unregistered.buf_ref[i])
                 return AVERROR(ENOMEM);
-            h->sei.unregistered.nb_buf_ref++;
+            h->sei.common.unregistered.nb_buf_ref++;
         }
     }
-    h->sei.unregistered.x264_build = h1->sei.unregistered.x264_build;
+    h->sei.common.unregistered.x264_build = h1->sei.common.unregistered.x264_build;
 
     if (!h->cur_pic_ptr)
         return 0;
@@ -528,7 +529,7 @@ static int h264_frame_start(H264Context *h)
     pic->f->crop_top    = h->crop_top;
     pic->f->crop_bottom = h->crop_bottom;
 
-    pic->needs_fg = h->sei.film_grain_characteristics.present && !h->avctx->hwaccel &&
+    pic->needs_fg = h->sei.common.film_grain_characteristics.present && !h->avctx->hwaccel &&
         !(h->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN);
 
     if ((ret = alloc_picture(h, pic)) < 0)
@@ -579,8 +580,8 @@ static int h264_frame_start(H264Context *h)
 
     h->mb_aff_frame = h->ps.sps->mb_aff && (h->picture_structure == PICT_FRAME);
 
-    if (h->sei.unregistered.x264_build >= 0)
-        h->x264_build = h->sei.unregistered.x264_build;
+    if (h->sei.common.unregistered.x264_build >= 0)
+        h->x264_build = h->sei.common.unregistered.x264_build;
 
     assert(h->cur_pic_ptr->long_ref == 0);
 
@@ -1114,10 +1115,10 @@ static int h264_init_ps(H264Context *h, const H264SliceContext *sl, int first_sl
             }
         }
 
-        if (h->sei.alternative_transfer.present &&
-            av_color_transfer_name(h->sei.alternative_transfer.preferred_transfer_characteristics) &&
-            h->sei.alternative_transfer.preferred_transfer_characteristics != AVCOL_TRC_UNSPECIFIED) {
-            h->avctx->color_trc = h->sei.alternative_transfer.preferred_transfer_characteristics;
+        if (h->sei.common.alternative_transfer.present &&
+            av_color_transfer_name(h->sei.common.alternative_transfer.preferred_transfer_characteristics) &&
+            h->sei.common.alternative_transfer.preferred_transfer_characteristics != AVCOL_TRC_UNSPECIFIED) {
+            h->avctx->color_trc = h->sei.common.alternative_transfer.preferred_transfer_characteristics;
         }
     }
     h->avctx->chroma_sample_location = sps->chroma_location;
@@ -1243,11 +1244,11 @@ static int h264_export_frame_props(H264Context *h)
         }
     }
 
-    if (h->sei.frame_packing.present &&
-        h->sei.frame_packing.arrangement_type <= 6 &&
-        h->sei.frame_packing.content_interpretation_type > 0 &&
-        h->sei.frame_packing.content_interpretation_type < 3) {
-        H264SEIFramePacking *fp = &h->sei.frame_packing;
+    if (h->sei.common.frame_packing.present &&
+        h->sei.common.frame_packing.arrangement_type <= 6 &&
+        h->sei.common.frame_packing.content_interpretation_type > 0 &&
+        h->sei.common.frame_packing.content_interpretation_type < 3) {
+        H2645SEIFramePacking *fp = &h->sei.common.frame_packing;
         AVStereo3D *stereo = av_stereo3d_create_side_data(out);
         if (stereo) {
         switch (fp->arrangement_type) {
@@ -1289,11 +1290,11 @@ static int h264_export_frame_props(H264Context *h)
         }
     }
 
-    if (h->sei.display_orientation.present &&
-        (h->sei.display_orientation.anticlockwise_rotation ||
-         h->sei.display_orientation.hflip ||
-         h->sei.display_orientation.vflip)) {
-        H264SEIDisplayOrientation *o = &h->sei.display_orientation;
+    if (h->sei.common.display_orientation.present &&
+        (h->sei.common.display_orientation.anticlockwise_rotation ||
+         h->sei.common.display_orientation.hflip ||
+         h->sei.common.display_orientation.vflip)) {
+        H2645SEIDisplayOrientation *o = &h->sei.common.display_orientation;
         double angle = o->anticlockwise_rotation * 360 / (double) (1 << 16);
         AVFrameSideData *rotation = av_frame_new_side_data(out,
                                                            AV_FRAME_DATA_DISPLAYMATRIX,
@@ -1314,18 +1315,18 @@ static int h264_export_frame_props(H264Context *h)
         }
     }
 
-    if (h->sei.afd.present) {
+    if (h->sei.common.afd.present) {
         AVFrameSideData *sd = av_frame_new_side_data(out, AV_FRAME_DATA_AFD,
                                                      sizeof(uint8_t));
 
         if (sd) {
-            *sd->data = h->sei.afd.active_format_description;
-            h->sei.afd.present = 0;
+            *sd->data = h->sei.common.afd.active_format_description;
+            h->sei.common.afd.present = 0;
         }
     }
 
-    if (h->sei.a53_caption.buf_ref) {
-        H264SEIA53Caption *a53 = &h->sei.a53_caption;
+    if (h->sei.common.a53_caption.buf_ref) {
+        H2645SEIA53Caption *a53 = &h->sei.common.a53_caption;
 
         AVFrameSideData *sd = av_frame_new_side_data_from_buf(out, AV_FRAME_DATA_A53_CC, a53->buf_ref);
         if (!sd)
@@ -1335,8 +1336,8 @@ static int h264_export_frame_props(H264Context *h)
         h->avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
     }
 
-    for (int i = 0; i < h->sei.unregistered.nb_buf_ref; i++) {
-        H264SEIUnregistered *unreg = &h->sei.unregistered;
+    for (int i = 0; i < h->sei.common.unregistered.nb_buf_ref; i++) {
+        H2645SEIUnregistered *unreg = &h->sei.common.unregistered;
 
         if (unreg->buf_ref[i]) {
             AVFrameSideData *sd = av_frame_new_side_data_from_buf(out,
@@ -1347,10 +1348,10 @@ static int h264_export_frame_props(H264Context *h)
             unreg->buf_ref[i] = NULL;
         }
     }
-    h->sei.unregistered.nb_buf_ref = 0;
+    h->sei.common.unregistered.nb_buf_ref = 0;
 
-    if (h->sei.film_grain_characteristics.present) {
-        H264SEIFilmGrainCharacteristics *fgc = &h->sei.film_grain_characteristics;
+    if (h->sei.common.film_grain_characteristics.present) {
+        H2645SEIFilmGrainCharacteristics *fgc = &h->sei.common.film_grain_characteristics;
         AVFilmGrainParams *fgp = av_film_grain_params_create_side_data(out);
         if (!fgp)
             return AVERROR(ENOMEM);
diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c
index d80bc6b17f..49f4db90e3 100644
--- a/libavcodec/h264dec.c
+++ b/libavcodec/h264dec.c
@@ -296,8 +296,8 @@ static int h264_init_context(AVCodecContext *avctx, H264Context *h)
     h->recovery_frame        = -1;
     h->frame_recovered       = 0;
     h->poc.prev_frame_num    = -1;
-    h->sei.frame_packing.arrangement_cancel_flag = -1;
-    h->sei.unregistered.x264_build = -1;
+    h->sei.common.frame_packing.arrangement_cancel_flag = -1;
+    h->sei.common.unregistered.x264_build = -1;
 
     h->next_outputed_poc = INT_MIN;
     for (i = 0; i < FF_ARRAY_ELEMS(h->last_pocs); i++)
@@ -848,7 +848,7 @@ static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp)
     if (srcp->needs_fg && (ret = av_frame_copy_props(dst, srcp->f)) < 0)
         return ret;
 
-    av_dict_set(&dst->metadata, "stereo_mode", ff_h264_sei_stereo_mode(&h->sei.frame_packing), 0);
+    av_dict_set(&dst->metadata, "stereo_mode", ff_h264_sei_stereo_mode(&h->sei.common.frame_packing), 0);
 
     if (srcp->sei_recovery_frame_cnt == 0)
         dst->key_frame = 1;
diff --git a/libavcodec/hevc_sei.c b/libavcodec/hevc_sei.c
index 631373e06f..b0a4a8b035 100644
--- a/libavcodec/hevc_sei.c
+++ b/libavcodec/hevc_sei.c
@@ -22,10 +22,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include "atsc_a53.h"
 #include "bytestream.h"
-#include "dynamic_hdr10_plus.h"
-#include "dynamic_hdr_vivid.h"
 #include "golomb.h"
 #include "hevc_ps.h"
 #include "hevc_sei.h"
@@ -98,38 +95,6 @@ static int decode_nal_sei_content_light_info(HEVCSEIContentLight *s,
     return  0;
 }
 
-static int decode_nal_sei_frame_packing_arrangement(HEVCSEIFramePacking *s, GetBitContext *gb)
-{
-    get_ue_golomb_long(gb);             // frame_packing_arrangement_id
-    s->present = !get_bits1(gb);
-
-    if (s->present) {
-        s->arrangement_type               = get_bits(gb, 7);
-        s->quincunx_subsampling           = get_bits1(gb);
-        s->content_interpretation_type    = get_bits(gb, 6);
-
-        // spatial_flipping_flag, frame0_flipped_flag, field_views_flag
-        skip_bits(gb, 3);
-        s->current_frame_is_frame0_flag = get_bits1(gb);
-    }
-    return 0;
-}
-
-static int decode_nal_sei_display_orientation(HEVCSEIDisplayOrientation *s, GetBitContext *gb)
-{
-    s->present = !get_bits1(gb);
-
-    if (s->present) {
-        s->hflip = get_bits1(gb);     // hor_flip
-        s->vflip = get_bits1(gb);     // ver_flip
-
-        s->anticlockwise_rotation = get_bits(gb, 16);
-        // skip_bits1(gb);     // display_orientation_persistence_flag
-    }
-
-    return 0;
-}
-
 static int decode_nal_sei_pic_timing(HEVCSEI *s, GetBitContext *gb,
                                      const HEVCParamSets *ps, void *logctx)
 {
@@ -161,182 +126,6 @@ static int decode_nal_sei_pic_timing(HEVCSEI *s, GetBitContext *gb,
     return 0;
 }
 
-static int decode_registered_user_data_closed_caption(HEVCSEIA53Caption *s,
-                                                      GetByteContext *gb)
-{
-    int ret;
-
-    ret = ff_parse_a53_cc(&s->buf_ref, gb->buffer,
-                          bytestream2_get_bytes_left(gb));
-    if (ret < 0)
-        return ret;
-
-    return 0;
-}
-
-static int decode_nal_sei_user_data_unregistered(HEVCSEIUnregistered *s,
-                                                 GetByteContext *gb)
-{
-    AVBufferRef *buf_ref, **tmp;
-    int size = bytestream2_get_bytes_left(gb);
-
-    if (size < 16 || size >= INT_MAX - 1)
-       return AVERROR_INVALIDDATA;
-
-    tmp = av_realloc_array(s->buf_ref, s->nb_buf_ref + 1, sizeof(*s->buf_ref));
-    if (!tmp)
-        return AVERROR(ENOMEM);
-    s->buf_ref = tmp;
-
-    buf_ref = av_buffer_alloc(size + 1);
-    if (!buf_ref)
-        return AVERROR(ENOMEM);
-
-    bytestream2_get_bufferu(gb, buf_ref->data, size);
-    buf_ref->data[size] = 0;
-    buf_ref->size = size;
-    s->buf_ref[s->nb_buf_ref++] = buf_ref;
-
-    return 0;
-}
-
-static int decode_registered_user_data_dynamic_hdr_plus(HEVCSEIDynamicHDRPlus *s,
-                                                        GetByteContext *gb)
-{
-    size_t meta_size;
-    int err;
-    AVDynamicHDRPlus *metadata = av_dynamic_hdr_plus_alloc(&meta_size);
-    if (!metadata)
-        return AVERROR(ENOMEM);
-
-    err = ff_parse_itu_t_t35_to_dynamic_hdr10_plus(metadata, gb->buffer,
-                                                   bytestream2_get_bytes_left(gb));
-    if (err < 0) {
-        av_free(metadata);
-        return err;
-    }
-
-    av_buffer_unref(&s->info);
-    s->info = av_buffer_create((uint8_t *)metadata, meta_size, NULL, NULL, 0);
-    if (!s->info) {
-        av_free(metadata);
-        return AVERROR(ENOMEM);
-    }
-
-    return 0;
-}
-
-static int decode_registered_user_data_dynamic_hdr_vivid(HEVCSEIDynamicHDRVivid *s,
-                                                         GetByteContext *gb)
-{
-    size_t meta_size;
-    int err;
-    AVDynamicHDRVivid *metadata = av_dynamic_hdr_vivid_alloc(&meta_size);
-    if (!metadata)
-        return AVERROR(ENOMEM);
-
-    err = ff_parse_itu_t_t35_to_dynamic_hdr_vivid(metadata,
-                                                  gb->buffer, bytestream2_get_bytes_left(gb));
-    if (err < 0) {
-        av_free(metadata);
-        return err;
-    }
-
-    av_buffer_unref(&s->info);
-    s->info = av_buffer_create((uint8_t *)metadata, meta_size, NULL, NULL, 0);
-    if (!s->info) {
-        av_free(metadata);
-        return AVERROR(ENOMEM);
-    }
-
-    return 0;
-}
-
-static int decode_nal_sei_user_data_registered_itu_t_t35(HEVCSEI *s, GetByteContext *gb,
-                                                         void *logctx)
-{
-    int country_code, provider_code;
-
-    if (bytestream2_get_bytes_left(gb) < 3)
-        return AVERROR_INVALIDDATA;
-
-    country_code = bytestream2_get_byteu(gb);
-    if (country_code == 0xFF) {
-        if (bytestream2_get_bytes_left(gb) < 3)
-            return AVERROR_INVALIDDATA;
-
-        bytestream2_skipu(gb, 1);
-    }
-
-    if (country_code != 0xB5 && country_code != 0x26) { // usa_country_code and cn_country_code
-        av_log(logctx, AV_LOG_VERBOSE,
-               "Unsupported User Data Registered ITU-T T35 SEI message (country_code = 0x%x)\n",
-               country_code);
-        return 0;
-    }
-
-    provider_code = bytestream2_get_be16u(gb);
-
-    switch (provider_code) {
-    case 0x04: { // cuva_provider_code
-        const uint16_t cuva_provider_oriented_code = 0x0005;
-        uint16_t provider_oriented_code;
-
-        if (bytestream2_get_bytes_left(gb) < 2)
-            return AVERROR_INVALIDDATA;
-
-        provider_oriented_code = bytestream2_get_be16u(gb);
-        if (provider_oriented_code == cuva_provider_oriented_code) {
-            return decode_registered_user_data_dynamic_hdr_vivid(&s->dynamic_hdr_vivid, gb);
-        }
-        break;
-    }
-    case 0x3C: { // smpte_provider_code
-        // A/341 Amendment - 2094-40
-        const uint16_t smpte2094_40_provider_oriented_code = 0x0001;
-        const uint8_t smpte2094_40_application_identifier = 0x04;
-        uint16_t provider_oriented_code;
-        uint8_t application_identifier;
-
-        if (bytestream2_get_bytes_left(gb) < 3)
-            return AVERROR_INVALIDDATA;
-
-        provider_oriented_code = bytestream2_get_be16u(gb);
-        application_identifier = bytestream2_get_byteu(gb);
-        if (provider_oriented_code == smpte2094_40_provider_oriented_code &&
-            application_identifier == smpte2094_40_application_identifier) {
-            return decode_registered_user_data_dynamic_hdr_plus(&s->dynamic_hdr_plus, gb);
-        }
-        break;
-    }
-    case 0x31: { // atsc_provider_code
-        uint32_t user_identifier;
-
-        if (bytestream2_get_bytes_left(gb) < 4)
-            return AVERROR_INVALIDDATA;
-
-        user_identifier = bytestream2_get_be32u(gb);
-        switch (user_identifier) {
-        case MKBETAG('G', 'A', '9', '4'):
-            return decode_registered_user_data_closed_caption(&s->a53_caption, gb);
-        default:
-            av_log(logctx, AV_LOG_VERBOSE,
-                   "Unsupported User Data Registered ITU-T T35 SEI message (atsc user_identifier = 0x%04x)\n",
-                   user_identifier);
-            break;
-        }
-        break;
-    }
-    default:
-        av_log(logctx, AV_LOG_VERBOSE,
-               "Unsupported User Data Registered ITU-T T35 SEI message (provider_code = %d)\n",
-               provider_code);
-        break;
-    }
-
-    return 0;
-}
-
 static int decode_nal_sei_active_parameter_sets(HEVCSEI *s, GetBitContext *gb, void *logctx)
 {
     int num_sps_ids_minus1;
@@ -362,18 +151,6 @@ static int decode_nal_sei_active_parameter_sets(HEVCSEI *s, GetBitContext *gb, v
     return 0;
 }
 
-static int decode_nal_sei_alternative_transfer(HEVCSEIAlternativeTransfer *s,
-                                               GetByteContext *gb)
-{
-    if (bytestream2_get_bytes_left(gb) < 1)
-        return AVERROR_INVALIDDATA;
-
-    s->present = 1;
-    s->preferred_transfer_characteristics = bytestream2_get_byteu(gb);
-
-    return 0;
-}
-
 static int decode_nal_sei_timecode(HEVCSEITimeCode *s, GetBitContext *gb)
 {
     s->num_clock_ts = get_bits(gb, 2);
@@ -420,49 +197,6 @@ static int decode_nal_sei_timecode(HEVCSEITimeCode *s, GetBitContext *gb)
     return 0;
 }
 
-static int decode_film_grain_characteristics(HEVCSEIFilmGrainCharacteristics *h,
-                                             GetBitContext *gb)
-{
-    h->present = !get_bits1(gb); // film_grain_characteristics_cancel_flag
-
-    if (h->present) {
-        memset(h, 0, sizeof(*h));
-        h->model_id = get_bits(gb, 2);
-        h->separate_colour_description_present_flag = get_bits1(gb);
-        if (h->separate_colour_description_present_flag) {
-            h->bit_depth_luma = get_bits(gb, 3) + 8;
-            h->bit_depth_chroma = get_bits(gb, 3) + 8;
-            h->full_range = get_bits1(gb);
-            h->color_primaries = get_bits(gb, 8);
-            h->transfer_characteristics = get_bits(gb, 8);
-            h->matrix_coeffs = get_bits(gb, 8);
-        }
-        h->blending_mode_id = get_bits(gb, 2);
-        h->log2_scale_factor = get_bits(gb, 4);
-        for (int c = 0; c < 3; c++)
-            h->comp_model_present_flag[c] = get_bits1(gb);
-        for (int c = 0; c < 3; c++) {
-            if (h->comp_model_present_flag[c]) {
-                h->num_intensity_intervals[c] = get_bits(gb, 8) + 1;
-                h->num_model_values[c] = get_bits(gb, 3) + 1;
-                if (h->num_model_values[c] > 6)
-                    return AVERROR_INVALIDDATA;
-                for (int i = 0; i < h->num_intensity_intervals[c]; i++) {
-                    h->intensity_interval_lower_bound[c][i] = get_bits(gb, 8);
-                    h->intensity_interval_upper_bound[c][i] = get_bits(gb, 8);
-                    for (int j = 0; j < h->num_model_values[c]; j++)
-                        h->comp_model_value[c][i][j] = get_se_golomb_long(gb);
-                }
-            }
-        }
-        h->persistence_flag = get_bits1(gb);
-
-        h->present = 1;
-    }
-
-    return 0;
-}
-
 static int decode_nal_sei_prefix(GetBitContext *gb, GetByteContext *gbyte,
                                  void *logctx, HEVCSEI *s,
                                  const HEVCParamSets *ps, int type)
@@ -470,10 +204,6 @@ static int decode_nal_sei_prefix(GetBitContext *gb, GetByteContext *gbyte,
     switch (type) {
     case 256:  // Mismatched value from HM 8.1
         return decode_nal_sei_decoded_picture_hash(&s->picture_hash, gbyte);
-    case SEI_TYPE_FRAME_PACKING_ARRANGEMENT:
-        return decode_nal_sei_frame_packing_arrangement(&s->frame_packing, gb);
-    case SEI_TYPE_DISPLAY_ORIENTATION:
-        return decode_nal_sei_display_orientation(&s->display_orientation, gb);
     case SEI_TYPE_PIC_TIMING:
         return decode_nal_sei_pic_timing(s, gb, ps, logctx);
     case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME:
@@ -482,19 +212,15 @@ static int decode_nal_sei_prefix(GetBitContext *gb, GetByteContext *gbyte,
         return decode_nal_sei_content_light_info(&s->content_light, gbyte);
     case SEI_TYPE_ACTIVE_PARAMETER_SETS:
         return decode_nal_sei_active_parameter_sets(s, gb, logctx);
-    case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35:
-        return decode_nal_sei_user_data_registered_itu_t_t35(s, gbyte, logctx);
-    case SEI_TYPE_USER_DATA_UNREGISTERED:
-        return decode_nal_sei_user_data_unregistered(&s->unregistered, gbyte);
-    case SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS:
-        return decode_nal_sei_alternative_transfer(&s->alternative_transfer, gbyte);
     case SEI_TYPE_TIME_CODE:
         return decode_nal_sei_timecode(&s->timecode, gb);
-    case SEI_TYPE_FILM_GRAIN_CHARACTERISTICS:
-        return decode_film_grain_characteristics(&s->film_grain_characteristics, gb);
-    default:
-        av_log(logctx, AV_LOG_DEBUG, "Skipped PREFIX SEI %d\n", type);
-        return 0;
+    default: {
+        int ret = ff_h2645_sei_message_decode(&s->common, type, AV_CODEC_ID_HEVC,
+                                              gb, gbyte, logctx);
+        if (ret == FF_H2645_SEI_MESSAGE_UNHANDLED)
+            av_log(logctx, AV_LOG_DEBUG, "Skipped PREFIX SEI %d\n", type);
+        return ret;
+    }
     }
 }
 
@@ -569,12 +295,12 @@ int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEI *s,
 
 void ff_hevc_reset_sei(HEVCSEI *s)
 {
-    av_buffer_unref(&s->a53_caption.buf_ref);
-
-    for (int i = 0; i < s->unregistered.nb_buf_ref; i++)
-        av_buffer_unref(&s->unregistered.buf_ref[i]);
-    s->unregistered.nb_buf_ref = 0;
-    av_freep(&s->unregistered.buf_ref);
-    av_buffer_unref(&s->dynamic_hdr_plus.info);
-    av_buffer_unref(&s->dynamic_hdr_vivid.info);
+    av_buffer_unref(&s->common.a53_caption.buf_ref);
+
+    for (int i = 0; i < s->common.unregistered.nb_buf_ref; i++)
+        av_buffer_unref(&s->common.unregistered.buf_ref[i]);
+    s->common.unregistered.nb_buf_ref = 0;
+    av_freep(&s->common.unregistered.buf_ref);
+    av_buffer_unref(&s->common.dynamic_hdr_plus.info);
+    av_buffer_unref(&s->common.dynamic_hdr_vivid.info);
 }
diff --git a/libavcodec/hevc_sei.h b/libavcodec/hevc_sei.h
index ef987f6781..8ea0245802 100644
--- a/libavcodec/hevc_sei.h
+++ b/libavcodec/hevc_sei.h
@@ -27,6 +27,7 @@
 
 #include "get_bits.h"
 #include "hevc.h"
+#include "h2645_sei.h"
 #include "sei.h"
 
 
@@ -48,25 +49,10 @@ typedef struct HEVCSEIFramePacking {
     int current_frame_is_frame0_flag;
 } HEVCSEIFramePacking;
 
-typedef struct HEVCSEIDisplayOrientation {
-    int present;
-    int anticlockwise_rotation;
-    int hflip, vflip;
-} HEVCSEIDisplayOrientation;
-
 typedef struct HEVCSEIPictureTiming {
     int picture_struct;
 } HEVCSEIPictureTiming;
 
-typedef struct HEVCSEIA53Caption {
-    AVBufferRef *buf_ref;
-} HEVCSEIA53Caption;
-
-typedef struct HEVCSEIUnregistered {
-    AVBufferRef **buf_ref;
-    int nb_buf_ref;
-} HEVCSEIUnregistered;
-
 typedef struct HEVCSEIMasteringDisplay {
     int present;
     uint16_t display_primaries[3][2];
@@ -75,14 +61,6 @@ typedef struct HEVCSEIMasteringDisplay {
     uint32_t min_luminance;
 } HEVCSEIMasteringDisplay;
 
-typedef struct HEVCSEIDynamicHDRPlus {
-    AVBufferRef *info;
-} HEVCSEIDynamicHDRPlus;
-
-typedef struct HEVCSEIDynamicHDRVivid {
-    AVBufferRef *info;
-} HEVCSEIDynamicHDRVivid;
-
 typedef struct HEVCSEIContentLight {
     int present;
     uint16_t max_content_light_level;
@@ -114,42 +92,14 @@ typedef struct HEVCSEITimeCode {
     int32_t  time_offset_value[3];
 } HEVCSEITimeCode;
 
-typedef struct HEVCSEIFilmGrainCharacteristics {
-    int present;
-    int model_id;
-    int separate_colour_description_present_flag;
-    int bit_depth_luma;
-    int bit_depth_chroma;
-    int full_range;
-    int color_primaries;
-    int transfer_characteristics;
-    int matrix_coeffs;
-    int blending_mode_id;
-    int log2_scale_factor;
-    int comp_model_present_flag[3];
-    uint16_t num_intensity_intervals[3];
-    uint8_t num_model_values[3];
-    uint8_t intensity_interval_lower_bound[3][256];
-    uint8_t intensity_interval_upper_bound[3][256];
-    int16_t comp_model_value[3][256][6];
-    int persistence_flag;
-} HEVCSEIFilmGrainCharacteristics;
-
 typedef struct HEVCSEI {
+    H2645SEI common;
     HEVCSEIPictureHash picture_hash;
-    HEVCSEIFramePacking frame_packing;
-    HEVCSEIDisplayOrientation display_orientation;
     HEVCSEIPictureTiming picture_timing;
-    HEVCSEIA53Caption a53_caption;
-    HEVCSEIUnregistered unregistered;
     HEVCSEIMasteringDisplay mastering_display;
-    HEVCSEIDynamicHDRPlus dynamic_hdr_plus;
-    HEVCSEIDynamicHDRVivid dynamic_hdr_vivid;
     HEVCSEIContentLight content_light;
     int active_seq_parameter_set_id;
-    HEVCSEIAlternativeTransfer alternative_transfer;
     HEVCSEITimeCode timecode;
-    HEVCSEIFilmGrainCharacteristics film_grain_characteristics;
 } HEVCSEI;
 
 struct HEVCParamSets;
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index f222f20706..69e65482dd 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -382,16 +382,16 @@ static int export_stream_params_from_sei(HEVCContext *s)
 {
     AVCodecContext *avctx = s->avctx;
 
-    if (s->sei.a53_caption.buf_ref)
+    if (s->sei.common.a53_caption.buf_ref)
         s->avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
 
-    if (s->sei.alternative_transfer.present &&
-        av_color_transfer_name(s->sei.alternative_transfer.preferred_transfer_characteristics) &&
-        s->sei.alternative_transfer.preferred_transfer_characteristics != AVCOL_TRC_UNSPECIFIED) {
-        avctx->color_trc = s->sei.alternative_transfer.preferred_transfer_characteristics;
+    if (s->sei.common.alternative_transfer.present &&
+        av_color_transfer_name(s->sei.common.alternative_transfer.preferred_transfer_characteristics) &&
+        s->sei.common.alternative_transfer.preferred_transfer_characteristics != AVCOL_TRC_UNSPECIFIED) {
+        avctx->color_trc = s->sei.common.alternative_transfer.preferred_transfer_characteristics;
     }
 
-    if (s->sei.film_grain_characteristics.present)
+    if (s->sei.common.film_grain_characteristics.present)
         avctx->properties |= FF_CODEC_PROPERTY_FILM_GRAIN;
 
     return 0;
@@ -2731,18 +2731,18 @@ static int set_side_data(HEVCContext *s)
     AVFrame *out = s->ref->frame;
     int ret;
 
-    if (s->sei.frame_packing.present &&
-        s->sei.frame_packing.arrangement_type >= 3 &&
-        s->sei.frame_packing.arrangement_type <= 5 &&
-        s->sei.frame_packing.content_interpretation_type > 0 &&
-        s->sei.frame_packing.content_interpretation_type < 3) {
+    if (s->sei.common.frame_packing.present &&
+        s->sei.common.frame_packing.arrangement_type >= 3 &&
+        s->sei.common.frame_packing.arrangement_type <= 5 &&
+        s->sei.common.frame_packing.content_interpretation_type > 0 &&
+        s->sei.common.frame_packing.content_interpretation_type < 3) {
         AVStereo3D *stereo = av_stereo3d_create_side_data(out);
         if (!stereo)
             return AVERROR(ENOMEM);
 
-        switch (s->sei.frame_packing.arrangement_type) {
+        switch (s->sei.common.frame_packing.arrangement_type) {
         case 3:
-            if (s->sei.frame_packing.quincunx_subsampling)
+            if (s->sei.common.frame_packing.quincunx_sampling_flag)
                 stereo->type = AV_STEREO3D_SIDEBYSIDE_QUINCUNX;
             else
                 stereo->type = AV_STEREO3D_SIDEBYSIDE;
@@ -2755,21 +2755,21 @@ static int set_side_data(HEVCContext *s)
             break;
         }
 
-        if (s->sei.frame_packing.content_interpretation_type == 2)
+        if (s->sei.common.frame_packing.content_interpretation_type == 2)
             stereo->flags = AV_STEREO3D_FLAG_INVERT;
 
-        if (s->sei.frame_packing.arrangement_type == 5) {
-            if (s->sei.frame_packing.current_frame_is_frame0_flag)
+        if (s->sei.common.frame_packing.arrangement_type == 5) {
+            if (s->sei.common.frame_packing.current_frame_is_frame0_flag)
                 stereo->view = AV_STEREO3D_VIEW_LEFT;
             else
                 stereo->view = AV_STEREO3D_VIEW_RIGHT;
         }
     }
 
-    if (s->sei.display_orientation.present &&
-        (s->sei.display_orientation.anticlockwise_rotation ||
-         s->sei.display_orientation.hflip || s->sei.display_orientation.vflip)) {
-        double angle = s->sei.display_orientation.anticlockwise_rotation * 360 / (double) (1 << 16);
+    if (s->sei.common.display_orientation.present &&
+        (s->sei.common.display_orientation.anticlockwise_rotation ||
+         s->sei.common.display_orientation.hflip || s->sei.common.display_orientation.vflip)) {
+        double angle = s->sei.common.display_orientation.anticlockwise_rotation * 360 / (double) (1 << 16);
         AVFrameSideData *rotation = av_frame_new_side_data(out,
                                                            AV_FRAME_DATA_DISPLAYMATRIX,
                                                            sizeof(int32_t) * 9);
@@ -2784,12 +2784,12 @@ static int set_side_data(HEVCContext *s)
          * an arbitatry axis and O(phi) is the proper rotation by phi)
          * we can create display matrices as desired by negating
          * the degree once for every flip applied. */
-        angle = -angle * (1 - 2 * !!s->sei.display_orientation.hflip)
-                       * (1 - 2 * !!s->sei.display_orientation.vflip);
+        angle = -angle * (1 - 2 * !!s->sei.common.display_orientation.hflip)
+                       * (1 - 2 * !!s->sei.common.display_orientation.vflip);
         av_display_rotation_set((int32_t *)rotation->data, angle);
         av_display_matrix_flip((int32_t *)rotation->data,
-                               s->sei.display_orientation.hflip,
-                               s->sei.display_orientation.vflip);
+                               s->sei.common.display_orientation.hflip,
+                               s->sei.common.display_orientation.vflip);
     }
 
     // Decrement the mastering display flag when IRAP frame has no_rasl_output_flag=1
@@ -2861,8 +2861,8 @@ static int set_side_data(HEVCContext *s)
                metadata->MaxCLL, metadata->MaxFALL);
     }
 
-    if (s->sei.a53_caption.buf_ref) {
-        HEVCSEIA53Caption *a53 = &s->sei.a53_caption;
+    if (s->sei.common.a53_caption.buf_ref) {
+        H2645SEIA53Caption *a53 = &s->sei.common.a53_caption;
 
         AVFrameSideData *sd = av_frame_new_side_data_from_buf(out, AV_FRAME_DATA_A53_CC, a53->buf_ref);
         if (!sd)
@@ -2870,8 +2870,8 @@ static int set_side_data(HEVCContext *s)
         a53->buf_ref = NULL;
     }
 
-    for (int i = 0; i < s->sei.unregistered.nb_buf_ref; i++) {
-        HEVCSEIUnregistered *unreg = &s->sei.unregistered;
+    for (int i = 0; i < s->sei.common.unregistered.nb_buf_ref; i++) {
+        H2645SEIUnregistered *unreg = &s->sei.common.unregistered;
 
         if (unreg->buf_ref[i]) {
             AVFrameSideData *sd = av_frame_new_side_data_from_buf(out,
@@ -2882,7 +2882,7 @@ static int set_side_data(HEVCContext *s)
             unreg->buf_ref[i] = NULL;
         }
     }
-    s->sei.unregistered.nb_buf_ref = 0;
+    s->sei.common.unregistered.nb_buf_ref = 0;
 
     if (s->sei.timecode.present) {
         uint32_t *tc_sd;
@@ -2910,8 +2910,8 @@ static int set_side_data(HEVCContext *s)
         s->sei.timecode.num_clock_ts = 0;
     }
 
-    if (s->sei.film_grain_characteristics.present) {
-        HEVCSEIFilmGrainCharacteristics *fgc = &s->sei.film_grain_characteristics;
+    if (s->sei.common.film_grain_characteristics.present) {
+        H2645SEIFilmGrainCharacteristics *fgc = &s->sei.common.film_grain_characteristics;
         AVFilmGrainParams *fgp = av_film_grain_params_create_side_data(out);
         if (!fgp)
             return AVERROR(ENOMEM);
@@ -2965,8 +2965,8 @@ static int set_side_data(HEVCContext *s)
         fgc->present = fgc->persistence_flag;
     }
 
-    if (s->sei.dynamic_hdr_plus.info) {
-        AVBufferRef *info_ref = av_buffer_ref(s->sei.dynamic_hdr_plus.info);
+    if (s->sei.common.dynamic_hdr_plus.info) {
+        AVBufferRef *info_ref = av_buffer_ref(s->sei.common.dynamic_hdr_plus.info);
         if (!info_ref)
             return AVERROR(ENOMEM);
 
@@ -2987,8 +2987,8 @@ static int set_side_data(HEVCContext *s)
     if ((ret = ff_dovi_attach_side_data(&s->dovi_ctx, out)) < 0)
         return ret;
 
-    if (s->sei.dynamic_hdr_vivid.info) {
-        AVBufferRef *info_ref = av_buffer_ref(s->sei.dynamic_hdr_vivid.info);
+    if (s->sei.common.dynamic_hdr_vivid.info) {
+        AVBufferRef *info_ref = av_buffer_ref(s->sei.common.dynamic_hdr_vivid.info);
         if (!info_ref)
             return AVERROR(ENOMEM);
 
@@ -3034,7 +3034,7 @@ static int hevc_frame_start(HEVCContext *s)
 
     s->ref->frame->key_frame = IS_IRAP(s);
 
-    s->ref->needs_fg = s->sei.film_grain_characteristics.present &&
+    s->ref->needs_fg = s->sei.common.film_grain_characteristics.present &&
         !(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN) &&
         !s->avctx->hwaccel;
 
@@ -3745,30 +3745,32 @@ static int hevc_update_thread_context(AVCodecContext *dst,
         s->max_ra = INT_MAX;
     }
 
-    ret = av_buffer_replace(&s->sei.a53_caption.buf_ref, s0->sei.a53_caption.buf_ref);
+    ret = av_buffer_replace(&s->sei.common.a53_caption.buf_ref,
+                            s0->sei.common.a53_caption.buf_ref);
     if (ret < 0)
         return ret;
 
-    for (i = 0; i < s->sei.unregistered.nb_buf_ref; i++)
-        av_buffer_unref(&s->sei.unregistered.buf_ref[i]);
-    s->sei.unregistered.nb_buf_ref = 0;
+    for (i = 0; i < s->sei.common.unregistered.nb_buf_ref; i++)
+        av_buffer_unref(&s->sei.common.unregistered.buf_ref[i]);
+    s->sei.common.unregistered.nb_buf_ref = 0;
 
-    if (s0->sei.unregistered.nb_buf_ref) {
-        ret = av_reallocp_array(&s->sei.unregistered.buf_ref,
-                                s0->sei.unregistered.nb_buf_ref,
-                                sizeof(*s->sei.unregistered.buf_ref));
+    if (s0->sei.common.unregistered.nb_buf_ref) {
+        ret = av_reallocp_array(&s->sei.common.unregistered.buf_ref,
+                                s0->sei.common.unregistered.nb_buf_ref,
+                                sizeof(*s->sei.common.unregistered.buf_ref));
         if (ret < 0)
             return ret;
 
-        for (i = 0; i < s0->sei.unregistered.nb_buf_ref; i++) {
-            s->sei.unregistered.buf_ref[i] = av_buffer_ref(s0->sei.unregistered.buf_ref[i]);
-            if (!s->sei.unregistered.buf_ref[i])
+        for (i = 0; i < s0->sei.common.unregistered.nb_buf_ref; i++) {
+            s->sei.common.unregistered.buf_ref[i] = av_buffer_ref(s0->sei.common.unregistered.buf_ref[i]);
+            if (!s->sei.common.unregistered.buf_ref[i])
                 return AVERROR(ENOMEM);
-            s->sei.unregistered.nb_buf_ref++;
+            s->sei.common.unregistered.nb_buf_ref++;
         }
     }
 
-    ret = av_buffer_replace(&s->sei.dynamic_hdr_plus.info, s0->sei.dynamic_hdr_plus.info);
+    ret = av_buffer_replace(&s->sei.common.dynamic_hdr_plus.info,
+                            s0->sei.common.dynamic_hdr_plus.info);
     if (ret < 0)
         return ret;
 
@@ -3780,15 +3782,16 @@ static int hevc_update_thread_context(AVCodecContext *dst,
     if (ret < 0)
         return ret;
 
-    ret = av_buffer_replace(&s->sei.dynamic_hdr_vivid.info, s0->sei.dynamic_hdr_vivid.info);
+    ret = av_buffer_replace(&s->sei.common.dynamic_hdr_vivid.info,
+                            s0->sei.common.dynamic_hdr_vivid.info);
     if (ret < 0)
         return ret;
 
-    s->sei.frame_packing        = s0->sei.frame_packing;
-    s->sei.display_orientation  = s0->sei.display_orientation;
+    s->sei.common.frame_packing        = s0->sei.common.frame_packing;
+    s->sei.common.display_orientation  = s0->sei.common.display_orientation;
+    s->sei.common.alternative_transfer = s0->sei.common.alternative_transfer;
     s->sei.mastering_display    = s0->sei.mastering_display;
     s->sei.content_light        = s0->sei.content_light;
-    s->sei.alternative_transfer = s0->sei.alternative_transfer;
 
     ret = export_stream_params_from_sei(s);
     if (ret < 0)
