Coverage Report

Created: 2026-04-01 07:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/cbs_sei.c
Line
Count
Source
1
/*
2
 * This file is part of FFmpeg.
3
 *
4
 * FFmpeg is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2.1 of the License, or (at your option) any later version.
8
 *
9
 * FFmpeg is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with FFmpeg; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
 */
18
19
#include "libavutil/mem.h"
20
#include "cbs.h"
21
#include "cbs_internal.h"
22
#include "cbs_h264.h"
23
#include "cbs_h265.h"
24
#include "cbs_h266.h"
25
#include "cbs_sei.h"
26
#include "libavutil/refstruct.h"
27
28
1.23M
#define HEADER(name) do { \
29
1.23M
        ff_cbs_trace_header(ctx, name); \
30
1.23M
    } while (0)
31
32
1.59G
#define CHECK(call) do { \
33
2.43G
        err = (call); \
34
1.59G
        if (err < 0) \
35
1.59G
            return err; \
36
1.59G
    } while (0)
37
38
1.23M
#define FUNC_NAME2(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name
39
1.23M
#define FUNC_NAME1(rw, codec, name) FUNC_NAME2(rw, codec, name)
40
155M
#define FUNC_NAME2_EXPORT(rw, codec, name) ff_cbs_ ## codec ## _ ## rw ## _ ## name
41
155M
#define FUNC_NAME1_EXPORT(rw, codec, name) FUNC_NAME2_EXPORT(rw, codec, name)
42
1.23M
#define FUNC_SEI(name)  FUNC_NAME1(READWRITE, sei,  name)
43
155M
#define FUNC_SEI_EXPORT(name)  FUNC_NAME1_EXPORT(READWRITE, sei,  name)
44
45
#define SEI_FUNC(name, args) \
46
static int FUNC_SEI(name) args;  \
47
static int FUNC_SEI(name ## _internal)(CodedBitstreamContext *ctx, \
48
                                       RWContext *rw, void *cur,   \
49
1.23M
                                       SEIMessageState *state)     \
50
1.23M
{ \
51
1.23M
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
1.23M
} \
cbs_sei.c:cbs_sei_read_film_grain_characteristics_internal
Line
Count
Source
49
12.8k
                                       SEIMessageState *state)     \
50
12.8k
{ \
51
12.8k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
12.8k
} \
cbs_sei.c:cbs_sei_write_film_grain_characteristics_internal
Line
Count
Source
49
12.6k
                                       SEIMessageState *state)     \
50
12.6k
{ \
51
12.6k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
12.6k
} \
cbs_sei.c:cbs_sei_read_display_orientation_internal
Line
Count
Source
49
2.89k
                                       SEIMessageState *state)     \
50
2.89k
{ \
51
2.89k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
2.89k
} \
cbs_sei.c:cbs_sei_write_display_orientation_internal
Line
Count
Source
49
1.50k
                                       SEIMessageState *state)     \
50
1.50k
{ \
51
1.50k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
1.50k
} \
cbs_sei.c:cbs_sei_read_frame_field_information_internal
Line
Count
Source
49
2.66k
                                       SEIMessageState *state)     \
50
2.66k
{ \
51
2.66k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
2.66k
} \
cbs_sei.c:cbs_sei_write_frame_field_information_internal
Line
Count
Source
49
1.61k
                                       SEIMessageState *state)     \
50
1.61k
{ \
51
1.61k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
1.61k
} \
cbs_sei.c:cbs_sei_read_filler_payload_internal
Line
Count
Source
49
18.7k
                                       SEIMessageState *state)     \
50
18.7k
{ \
51
18.7k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
18.7k
} \
cbs_sei.c:cbs_sei_write_filler_payload_internal
Line
Count
Source
49
9.69k
                                       SEIMessageState *state)     \
50
9.69k
{ \
51
9.69k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
9.69k
} \
cbs_sei.c:cbs_sei_read_user_data_registered_internal
Line
Count
Source
49
543k
                                       SEIMessageState *state)     \
50
543k
{ \
51
543k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
543k
} \
cbs_sei.c:cbs_sei_write_user_data_registered_internal
Line
Count
Source
49
351k
                                       SEIMessageState *state)     \
50
351k
{ \
51
351k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
351k
} \
cbs_sei.c:cbs_sei_read_user_data_unregistered_internal
Line
Count
Source
49
85.2k
                                       SEIMessageState *state)     \
50
85.2k
{ \
51
85.2k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
85.2k
} \
cbs_sei.c:cbs_sei_write_user_data_unregistered_internal
Line
Count
Source
49
13.7k
                                       SEIMessageState *state)     \
50
13.7k
{ \
51
13.7k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
13.7k
} \
cbs_sei.c:cbs_sei_read_frame_packing_arrangement_internal
Line
Count
Source
49
26.8k
                                       SEIMessageState *state)     \
50
26.8k
{ \
51
26.8k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
26.8k
} \
cbs_sei.c:cbs_sei_write_frame_packing_arrangement_internal
Line
Count
Source
49
13.6k
                                       SEIMessageState *state)     \
50
13.6k
{ \
51
13.6k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
13.6k
} \
cbs_sei.c:cbs_sei_read_decoded_picture_hash_internal
Line
Count
Source
49
19.9k
                                       SEIMessageState *state)     \
50
19.9k
{ \
51
19.9k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
19.9k
} \
cbs_sei.c:cbs_sei_write_decoded_picture_hash_internal
Line
Count
Source
49
5.79k
                                       SEIMessageState *state)     \
50
5.79k
{ \
51
5.79k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
5.79k
} \
cbs_sei.c:cbs_sei_read_mastering_display_colour_volume_internal
Line
Count
Source
49
42.1k
                                       SEIMessageState *state)     \
50
42.1k
{ \
51
42.1k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
42.1k
} \
cbs_sei.c:cbs_sei_write_mastering_display_colour_volume_internal
Line
Count
Source
49
7.22k
                                       SEIMessageState *state)     \
50
7.22k
{ \
51
7.22k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
7.22k
} \
cbs_sei.c:cbs_sei_read_content_light_level_info_internal
Line
Count
Source
49
22.5k
                                       SEIMessageState *state)     \
50
22.5k
{ \
51
22.5k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
22.5k
} \
cbs_sei.c:cbs_sei_write_content_light_level_info_internal
Line
Count
Source
49
9.13k
                                       SEIMessageState *state)     \
50
9.13k
{ \
51
9.13k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
9.13k
} \
cbs_sei.c:cbs_sei_read_alternative_transfer_characteristics_internal
Line
Count
Source
49
5.13k
                                       SEIMessageState *state)     \
50
5.13k
{ \
51
5.13k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
5.13k
} \
cbs_sei.c:cbs_sei_write_alternative_transfer_characteristics_internal
Line
Count
Source
49
2.51k
                                       SEIMessageState *state)     \
50
2.51k
{ \
51
2.51k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
2.51k
} \
cbs_sei.c:cbs_sei_read_ambient_viewing_environment_internal
Line
Count
Source
49
20.7k
                                       SEIMessageState *state)     \
50
20.7k
{ \
51
20.7k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
20.7k
} \
cbs_sei.c:cbs_sei_write_ambient_viewing_environment_internal
Line
Count
Source
49
2.11k
                                       SEIMessageState *state)     \
50
2.11k
{ \
51
2.11k
    return FUNC_SEI(name)(ctx, rw, cur, state); \
52
2.11k
} \
53
static int FUNC_SEI(name) args
54
55
#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
56
57
#define u(width, name, range_min, range_max) \
58
1.06M
        xu(width, name, current->name, range_min, range_max, 0, )
59
229k
#define flag(name) ub(1, name)
60
#define ue(name, range_min, range_max) \
61
40.4k
        xue(name, current->name, range_min, range_max, 0, )
62
#define i(width, name, range_min, range_max) \
63
        xi(width, name, current->name, range_min, range_max, 0, )
64
#define ib(width, name) \
65
        xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), 0, )
66
#define se(name, range_min, range_max) \
67
        xse(name, current->name, range_min, range_max, 0, )
68
69
#define us(width, name, range_min, range_max, subs, ...) \
70
2.16M
        xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__)
71
#define ubs(width, name, subs, ...) \
72
403k
        xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__)
73
#define flags(name, subs, ...) \
74
44.2k
        xu(1, name, current->name, 0, 1, subs, __VA_ARGS__)
75
#define ues(name, range_min, range_max, subs, ...) \
76
        xue(name, current->name, range_min, range_max, subs, __VA_ARGS__)
77
#define is(width, name, range_min, range_max, subs, ...) \
78
        xi(width, name, current->name, range_min, range_max, subs, __VA_ARGS__)
79
#define ibs(width, name, subs, ...) \
80
        xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), subs, __VA_ARGS__)
81
#define ses(name, range_min, range_max, subs, ...) \
82
267k
        xse(name, current->name, range_min, range_max, subs, __VA_ARGS__)
83
84
598M
#define fixed(width, name, value) do { \
85
404M
        av_unused uint32_t fixed_value = value; \
86
404M
        xu(width, name, fixed_value, value, value, 0, ); \
87
404M
    } while (0)
88
89
90
#define READ
91
#define READWRITE read
92
#define RWContext GetBitContext
93
94
367k
#define ub(width, name) do { \
95
367k
        uint32_t value; \
96
367k
        CHECK(ff_cbs_read_simple_unsigned(ctx, rw, width, #name, \
97
367k
                                          &value)); \
98
367k
        current->name = value; \
99
346k
    } while (0)
100
303M
#define xu(width, name, var, range_min, range_max, subs, ...) do { \
101
297M
        uint32_t value; \
102
297M
        CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
103
297M
                                   SUBSCRIPTS(subs, __VA_ARGS__), \
104
297M
                                   &value, range_min, range_max)); \
105
297M
        var = value; \
106
297M
    } while (0)
107
26.8k
#define xue(name, var, range_min, range_max, subs, ...) do { \
108
26.8k
        uint32_t value; \
109
26.8k
        CHECK(ff_cbs_read_ue_golomb(ctx, rw, #name, \
110
26.8k
                                 SUBSCRIPTS(subs, __VA_ARGS__), \
111
26.8k
                                 &value, range_min, range_max)); \
112
26.8k
        var = value; \
113
25.4k
    } while (0)
114
#define xi(width, name, var, range_min, range_max, subs, ...) do { \
115
        int32_t value; \
116
        CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \
117
                                 SUBSCRIPTS(subs, __VA_ARGS__), \
118
                                 &value, range_min, range_max)); \
119
        var = value; \
120
    } while (0)
121
130k
#define xse(name, var, range_min, range_max, subs, ...) do { \
122
106k
        int32_t value; \
123
106k
        CHECK(ff_cbs_read_se_golomb(ctx, rw, #name, \
124
106k
                                 SUBSCRIPTS(subs, __VA_ARGS__), \
125
106k
                                 &value, range_min, range_max)); \
126
106k
        var = value; \
127
105k
    } while (0)
128
129
130
#define infer(name, value) do { \
131
        current->name = value; \
132
    } while (0)
133
134
#define more_rbsp_data(var) ((var) = ff_cbs_h2645_read_more_rbsp_data(rw))
135
136
84.7M
#define bit_position(rw)   (get_bits_count(rw))
137
126M
#define byte_alignment(rw) (get_bits_count(rw) % 8)
138
139
/* The CBS SEI code uses the refstruct API for the allocation
140
 * of its child buffers. */
141
42.8M
#define allocate(name, size) do { \
142
42.8M
        name  = av_refstruct_allocz(size + \
143
42.8M
                                        AV_INPUT_BUFFER_PADDING_SIZE); \
144
42.8M
        if (!name) \
145
42.8M
            return AVERROR(ENOMEM); \
146
42.8M
    } while (0)
147
148
#define FUNC(name) FUNC_SEI_EXPORT(name)
149
#include "cbs_sei_syntax_template.c"
150
#undef FUNC
151
152
#undef READ
153
#undef READWRITE
154
#undef RWContext
155
#undef ub
156
#undef xu
157
#undef xi
158
#undef xue
159
#undef xse
160
#undef infer
161
#undef more_rbsp_data
162
#undef bit_position
163
#undef byte_alignment
164
#undef allocate
165
166
167
#define WRITE
168
#define READWRITE write
169
#define RWContext PutBitContext
170
171
166k
#define ub(width, name) do { \
172
166k
        uint32_t value = current->name; \
173
166k
        CHECK(ff_cbs_write_simple_unsigned(ctx, rw, width, #name, \
174
166k
                                           value)); \
175
166k
    } while (0)
176
924M
#define xu(width, name, var, range_min, range_max, subs, ...) do { \
177
921M
        uint32_t value = var; \
178
921M
        CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
179
921M
                                    SUBSCRIPTS(subs, __VA_ARGS__), \
180
921M
                                    value, range_min, range_max)); \
181
921M
    } while (0)
182
13.6k
#define xue(name, var, range_min, range_max, subs, ...) do { \
183
13.6k
        uint32_t value = var; \
184
13.6k
        CHECK(ff_cbs_write_ue_golomb(ctx, rw, #name, \
185
13.6k
                                  SUBSCRIPTS(subs, __VA_ARGS__), \
186
13.6k
                                  value, range_min, range_max)); \
187
13.6k
    } while (0)
188
#define xi(width, name, var, range_min, range_max, subs, ...) do { \
189
        int32_t value = var; \
190
        CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \
191
                                  SUBSCRIPTS(subs, __VA_ARGS__), \
192
                                  value, range_min, range_max)); \
193
    } while (0)
194
194k
#define xse(name, var, range_min, range_max, subs, ...) do { \
195
161k
        int32_t value = var; \
196
161k
        CHECK(ff_cbs_write_se_golomb(ctx, rw, #name, \
197
161k
                                  SUBSCRIPTS(subs, __VA_ARGS__), \
198
161k
                                  value, range_min, range_max)); \
199
161k
    } while (0)
200
201
#define infer(name, value) do { \
202
        if (current->name != (value)) { \
203
            av_log(ctx->log_ctx, AV_LOG_ERROR, \
204
                   "%s does not match inferred value: " \
205
                   "%"PRId64", but should be %"PRId64".\n", \
206
                   #name, (int64_t)current->name, (int64_t)(value)); \
207
            return AVERROR_INVALIDDATA; \
208
        } \
209
    } while (0)
210
211
#define more_rbsp_data(var) (var)
212
213
304M
#define bit_position(rw)   (put_bits_count(rw))
214
648M
#define byte_alignment(rw) (put_bits_count(rw) % 8)
215
216
140M
#define allocate(name, size) do { \
217
140M
        if (!name) { \
218
0
            av_log(ctx->log_ctx, AV_LOG_ERROR, "%s must be set " \
219
0
                   "for writing.\n", #name); \
220
0
            return AVERROR_INVALIDDATA; \
221
0
        } \
222
140M
    } while (0)
223
224
155M
#define FUNC(name) FUNC_SEI_EXPORT(name)
225
#include "cbs_sei_syntax_template.c"
226
#undef FUNC
227
228
static void cbs_free_user_data_registered(AVRefStructOpaque unused, void *obj)
229
543k
{
230
543k
    SEIRawUserDataRegistered *udr = obj;
231
543k
    av_refstruct_unref(&udr->data_ref);
232
543k
}
233
234
static void cbs_free_user_data_unregistered(AVRefStructOpaque unused, void *obj)
235
85.2k
{
236
85.2k
    SEIRawUserDataUnregistered *udu = obj;
237
85.2k
    av_refstruct_unref(&udu->data_ref);
238
85.2k
}
239
240
int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message,
241
                                     const SEIMessageTypeDescriptor *desc)
242
42.5M
{
243
42.5M
    void (*free_func)(AVRefStructOpaque, void*);
244
245
42.5M
    av_assert0(message->payload     == NULL &&
246
42.5M
               message->payload_ref == NULL);
247
42.5M
    message->payload_type = desc->type;
248
249
42.5M
    if (desc->type == SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35)
250
543k
        free_func = &cbs_free_user_data_registered;
251
41.9M
    else if (desc->type == SEI_TYPE_USER_DATA_UNREGISTERED)
252
85.2k
        free_func = &cbs_free_user_data_unregistered;
253
41.9M
    else {
254
41.9M
        free_func = NULL;
255
41.9M
    }
256
257
42.5M
    message->payload_ref = av_refstruct_alloc_ext(desc->size, 0,
258
42.5M
                                                  NULL, free_func);
259
42.5M
    if (!message->payload_ref)
260
0
        return AVERROR(ENOMEM);
261
42.5M
    message->payload = message->payload_ref;
262
263
42.5M
    return 0;
264
42.5M
}
265
266
int ff_cbs_sei_list_add(SEIRawMessageList *list)
267
47.2M
{
268
47.2M
    void *ptr;
269
47.2M
    int old_count = list->nb_messages_allocated;
270
271
47.2M
    av_assert0(list->nb_messages <= old_count);
272
47.2M
    if (list->nb_messages + 1 > old_count) {
273
905k
        int new_count = 2 * old_count + 1;
274
275
905k
        ptr = av_realloc_array(list->messages,
276
905k
                               new_count, sizeof(*list->messages));
277
905k
        if (!ptr)
278
0
            return AVERROR(ENOMEM);
279
280
905k
        list->messages = ptr;
281
905k
        list->nb_messages_allocated = new_count;
282
283
        // Zero the newly-added entries.
284
905k
        memset(list->messages + old_count, 0,
285
905k
               (new_count - old_count) * sizeof(*list->messages));
286
905k
    }
287
47.2M
    ++list->nb_messages;
288
47.2M
    return 0;
289
47.2M
}
290
291
void ff_cbs_sei_free_message_list(SEIRawMessageList *list)
292
594k
{
293
47.8M
    for (int i = 0; i < list->nb_messages; i++) {
294
47.2M
        SEIRawMessage *message = &list->messages[i];
295
47.2M
        av_refstruct_unref(&message->payload_ref);
296
47.2M
        av_refstruct_unref(&message->extension_data);
297
47.2M
    }
298
594k
    av_free(list->messages);
299
594k
}
300
301
static int cbs_sei_get_unit(CodedBitstreamContext *ctx,
302
                            CodedBitstreamFragment *au,
303
                            int prefix,
304
                            CodedBitstreamUnit **sei_unit)
305
0
{
306
0
    CodedBitstreamUnit *unit;
307
0
    int sei_type, highest_vcl_type, err, i, position;
308
309
0
    switch (ctx->codec->codec_id) {
310
0
    case AV_CODEC_ID_H264:
311
        // (We can ignore auxiliary slices because we only have prefix
312
        // SEI in H.264 and an auxiliary picture must always follow a
313
        // primary picture.)
314
0
        highest_vcl_type = H264_NAL_IDR_SLICE;
315
0
        if (prefix)
316
0
            sei_type = H264_NAL_SEI;
317
0
        else
318
0
            return AVERROR(EINVAL);
319
0
        break;
320
0
    case AV_CODEC_ID_H265:
321
0
        highest_vcl_type = HEVC_NAL_RSV_VCL31;
322
0
        if (prefix)
323
0
            sei_type = HEVC_NAL_SEI_PREFIX;
324
0
        else
325
0
            sei_type = HEVC_NAL_SEI_SUFFIX;
326
0
        break;
327
0
    case AV_CODEC_ID_H266:
328
0
        highest_vcl_type = VVC_RSV_IRAP_11;
329
0
        if (prefix)
330
0
            sei_type = VVC_PREFIX_SEI_NUT;
331
0
        else
332
0
            sei_type = VVC_SUFFIX_SEI_NUT;
333
0
        break;
334
0
    default:
335
0
        return AVERROR(EINVAL);
336
0
    }
337
338
    // Find an existing SEI NAL unit of the right type.
339
0
    unit = NULL;
340
0
    for (i = 0; i < au->nb_units; i++) {
341
0
        if (au->units[i].type == sei_type) {
342
0
            unit = &au->units[i];
343
0
            break;
344
0
        }
345
0
    }
346
347
0
    if (unit) {
348
0
        *sei_unit = unit;
349
0
        return 0;
350
0
    }
351
352
    // Need to add a new SEI NAL unit ...
353
0
    if (prefix) {
354
        // ... before the first VCL NAL unit.
355
0
        for (i = 0; i < au->nb_units; i++) {
356
0
            if (au->units[i].type < highest_vcl_type)
357
0
                break;
358
0
        }
359
0
        position = i;
360
0
    } else {
361
        // ... after the last VCL NAL unit.
362
0
        for (i = au->nb_units - 1; i >= 0; i--) {
363
0
            if (au->units[i].type < highest_vcl_type)
364
0
                break;
365
0
        }
366
0
        if (i < 0) {
367
            // No VCL units; just put it at the end.
368
0
            position = au->nb_units;
369
0
        } else {
370
0
            position = i + 1;
371
0
        }
372
0
    }
373
374
0
    err = ff_cbs_insert_unit_content(au, position, sei_type,
375
0
                                     NULL, NULL);
376
0
    if (err < 0)
377
0
        return err;
378
0
    unit = &au->units[position];
379
0
    unit->type = sei_type;
380
381
0
    err = ff_cbs_alloc_unit_content(ctx, unit);
382
0
    if (err < 0)
383
0
        return err;
384
385
0
    switch (ctx->codec->codec_id) {
386
0
    case AV_CODEC_ID_H264:
387
0
        {
388
0
            H264RawSEI sei = {
389
0
                .nal_unit_header = {
390
0
                    .nal_ref_idc   = 0,
391
0
                    .nal_unit_type = sei_type,
392
0
                },
393
0
            };
394
0
            memcpy(unit->content, &sei, sizeof(sei));
395
0
        }
396
0
        break;
397
0
    case AV_CODEC_ID_H265:
398
0
        {
399
0
            H265RawSEI sei = {
400
0
                .nal_unit_header = {
401
0
                    .nal_unit_type         = sei_type,
402
0
                    .nuh_layer_id          = 0,
403
0
                    .nuh_temporal_id_plus1 = 1,
404
0
                },
405
0
            };
406
0
            memcpy(unit->content, &sei, sizeof(sei));
407
0
        }
408
0
        break;
409
0
    case AV_CODEC_ID_H266:
410
0
        {
411
0
            H266RawSEI sei = {
412
0
                .nal_unit_header = {
413
0
                    .nal_unit_type         = sei_type,
414
0
                    .nuh_layer_id          = 0,
415
0
                    .nuh_temporal_id_plus1 = 1,
416
0
                },
417
0
            };
418
0
            memcpy(unit->content, &sei, sizeof(sei));
419
0
        }
420
0
        break;
421
0
    default:
422
0
        av_assert0(0);
423
0
    }
424
425
0
    *sei_unit = unit;
426
0
    return 0;
427
0
}
428
429
static int cbs_sei_get_message_list(CodedBitstreamContext *ctx,
430
                                    CodedBitstreamUnit *unit,
431
                                    SEIRawMessageList **list)
432
0
{
433
0
    switch (ctx->codec->codec_id) {
434
0
    case AV_CODEC_ID_H264:
435
0
        {
436
0
            H264RawSEI *sei = unit->content;
437
0
            if (unit->type != H264_NAL_SEI)
438
0
                return AVERROR(EINVAL);
439
0
            *list = &sei->message_list;
440
0
        }
441
0
        break;
442
0
    case AV_CODEC_ID_H265:
443
0
        {
444
0
            H265RawSEI *sei = unit->content;
445
0
            if (unit->type != HEVC_NAL_SEI_PREFIX &&
446
0
                unit->type != HEVC_NAL_SEI_SUFFIX)
447
0
                return AVERROR(EINVAL);
448
0
            *list = &sei->message_list;
449
0
        }
450
0
        break;
451
0
    case AV_CODEC_ID_H266:
452
0
        {
453
0
            H266RawSEI *sei = unit->content;
454
0
            if (unit->type != VVC_PREFIX_SEI_NUT &&
455
0
                unit->type != VVC_SUFFIX_SEI_NUT)
456
0
                return AVERROR(EINVAL);
457
0
            *list = &sei->message_list;
458
0
        }
459
0
        break;
460
0
    default:
461
0
        return AVERROR(EINVAL);
462
0
    }
463
464
0
    return 0;
465
0
}
466
467
int ff_cbs_sei_add_message(CodedBitstreamContext *ctx,
468
                           CodedBitstreamFragment *au,
469
                           int prefix,
470
                           uint32_t     payload_type,
471
                           void        *payload_data,
472
                           void        *payload_ref)
473
0
{
474
0
    const SEIMessageTypeDescriptor *desc;
475
0
    CodedBitstreamUnit *unit;
476
0
    SEIRawMessageList *list;
477
0
    SEIRawMessage *message;
478
0
    int err;
479
480
0
    desc = ff_cbs_sei_find_type(ctx, payload_type);
481
0
    if (!desc)
482
0
        return AVERROR(EINVAL);
483
484
    // Find an existing SEI unit or make a new one to add to.
485
0
    err = cbs_sei_get_unit(ctx, au, prefix, &unit);
486
0
    if (err < 0)
487
0
        return err;
488
489
    // Find the message list inside the codec-dependent unit.
490
0
    err = cbs_sei_get_message_list(ctx, unit, &list);
491
0
    if (err < 0)
492
0
        return err;
493
494
    // Add a new message to the message list.
495
0
    err = ff_cbs_sei_list_add(list);
496
0
    if (err < 0)
497
0
        return err;
498
499
0
    if (payload_ref) {
500
        /* The following just increments payload_ref's refcount,
501
         * so that payload_ref is now owned by us. */
502
0
        payload_ref = av_refstruct_ref(payload_ref);
503
0
    }
504
505
0
    message = &list->messages[list->nb_messages - 1];
506
507
0
    message->payload_type = payload_type;
508
0
    message->payload      = payload_data;
509
0
    message->payload_ref  = payload_ref;
510
511
0
    return 0;
512
0
}
513
514
int ff_cbs_sei_find_message(CodedBitstreamContext *ctx,
515
                            CodedBitstreamFragment *au,
516
                            uint32_t payload_type,
517
                            SEIRawMessage **iter)
518
0
{
519
0
    int err, i, j, found;
520
521
0
    found = 0;
522
0
    for (i = 0; i < au->nb_units; i++) {
523
0
        CodedBitstreamUnit *unit = &au->units[i];
524
0
        SEIRawMessageList *list;
525
526
0
        err = cbs_sei_get_message_list(ctx, unit, &list);
527
0
        if (err < 0)
528
0
            continue;
529
530
0
        for (j = 0; j < list->nb_messages; j++) {
531
0
            SEIRawMessage *message = &list->messages[j];
532
533
0
            if (message->payload_type == payload_type) {
534
0
                if (!*iter || found) {
535
0
                    *iter = message;
536
0
                    return 0;
537
0
                }
538
0
                if (message == *iter)
539
0
                    found = 1;
540
0
            }
541
0
        }
542
0
    }
543
544
0
    return AVERROR(ENOENT);
545
0
}
546
547
static void cbs_sei_delete_message(SEIRawMessageList *list,
548
                                   int position)
549
0
{
550
0
    SEIRawMessage *message;
551
552
0
    av_assert0(0 <= position && position < list->nb_messages);
553
554
0
    message = &list->messages[position];
555
0
    av_refstruct_unref(&message->payload_ref);
556
0
    av_refstruct_unref(&message->extension_data);
557
558
0
    --list->nb_messages;
559
560
0
    if (list->nb_messages > 0) {
561
0
        memmove(list->messages + position,
562
0
                list->messages + position + 1,
563
0
                (list->nb_messages - position) * sizeof(*list->messages));
564
0
    }
565
0
}
566
567
void ff_cbs_sei_delete_message_type(CodedBitstreamContext *ctx,
568
                                    CodedBitstreamFragment *au,
569
                                    uint32_t payload_type)
570
0
{
571
0
    int err, i, j;
572
573
0
    for (i = 0; i < au->nb_units; i++) {
574
0
        CodedBitstreamUnit *unit = &au->units[i];
575
0
        SEIRawMessageList *list;
576
577
0
        err = cbs_sei_get_message_list(ctx, unit, &list);
578
0
        if (err < 0)
579
0
            continue;
580
581
0
        for (j = list->nb_messages - 1; j >= 0; j--) {
582
0
            if (list->messages[j].payload_type == payload_type)
583
0
                cbs_sei_delete_message(list, j);
584
0
        }
585
0
    }
586
0
}
587
588
// Macro for the read/write pair.
589
#define SEI_MESSAGE_RW(codec, name) \
590
    .read  = cbs_ ## codec ## _read_  ## name ## _internal, \
591
    .write = cbs_ ## codec ## _write_ ## name ## _internal
592
593
static const SEIMessageTypeDescriptor cbs_sei_common_types[] = {
594
    {
595
        SEI_TYPE_FILLER_PAYLOAD,
596
        1, 1,
597
        sizeof(SEIRawFillerPayload),
598
        SEI_MESSAGE_RW(sei, filler_payload),
599
    },
600
    {
601
        SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35,
602
        1, 1,
603
        sizeof(SEIRawUserDataRegistered),
604
        SEI_MESSAGE_RW(sei, user_data_registered),
605
    },
606
    {
607
        SEI_TYPE_USER_DATA_UNREGISTERED,
608
        1, 1,
609
        sizeof(SEIRawUserDataUnregistered),
610
        SEI_MESSAGE_RW(sei, user_data_unregistered),
611
    },
612
    {
613
        SEI_TYPE_FRAME_PACKING_ARRANGEMENT,
614
        1, 0,
615
        sizeof(SEIRawFramePackingArrangement),
616
        SEI_MESSAGE_RW(sei, frame_packing_arrangement),
617
    },
618
    {
619
        SEI_TYPE_DECODED_PICTURE_HASH,
620
        0, 1,
621
        sizeof(SEIRawDecodedPictureHash),
622
        SEI_MESSAGE_RW(sei, decoded_picture_hash),
623
    },
624
    {
625
        SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME,
626
        1, 0,
627
        sizeof(SEIRawMasteringDisplayColourVolume),
628
        SEI_MESSAGE_RW(sei, mastering_display_colour_volume),
629
    },
630
    {
631
        SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO,
632
        1, 0,
633
        sizeof(SEIRawContentLightLevelInfo),
634
        SEI_MESSAGE_RW(sei, content_light_level_info),
635
    },
636
    {
637
        SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS,
638
        1, 0,
639
        sizeof(SEIRawAlternativeTransferCharacteristics),
640
        SEI_MESSAGE_RW(sei, alternative_transfer_characteristics),
641
    },
642
    {
643
        SEI_TYPE_AMBIENT_VIEWING_ENVIRONMENT,
644
        1, 0,
645
        sizeof(SEIRawAmbientViewingEnvironment),
646
        SEI_MESSAGE_RW(sei, ambient_viewing_environment),
647
    },
648
    SEI_MESSAGE_TYPE_END,
649
};
650
651
static const SEIMessageTypeDescriptor cbs_sei_h274_types[] = {
652
    {
653
        SEI_TYPE_FILM_GRAIN_CHARACTERISTICS,
654
        1, 0,
655
        sizeof(SEIRawFilmGrainCharacteristics),
656
        SEI_MESSAGE_RW(sei, film_grain_characteristics),
657
    },
658
    {
659
        SEI_TYPE_DISPLAY_ORIENTATION,
660
        1, 0,
661
        sizeof(SEIRawDisplayOrientation),
662
        SEI_MESSAGE_RW(sei, display_orientation)
663
    },
664
    {
665
        SEI_TYPE_FRAME_FIELD_INFO,
666
        1, 0,
667
        sizeof(SEIRawFrameFieldInformation),
668
        SEI_MESSAGE_RW(sei, frame_field_information)
669
    },
670
    SEI_MESSAGE_TYPE_END,
671
};
672
673
const SEIMessageTypeDescriptor *ff_cbs_sei_find_type(CodedBitstreamContext *ctx,
674
                                                     int payload_type)
675
202M
{
676
202M
    const SEIMessageTypeDescriptor *codec_list = NULL;
677
202M
    int i;
678
679
202M
    switch (ctx->codec->codec_id) {
680
0
#if CBS_H264
681
194M
    case AV_CODEC_ID_H264:
682
194M
        codec_list = ff_cbs_sei_h264_types;
683
194M
        break;
684
0
#endif
685
0
#if CBS_H265
686
1.96M
    case AV_CODEC_ID_H265:
687
1.96M
        codec_list = ff_cbs_sei_h265_types;
688
1.96M
        break;
689
0
#endif
690
6.51M
    case AV_CODEC_ID_H266:
691
6.51M
        codec_list = cbs_sei_h274_types;
692
6.51M
        break;
693
202M
    }
694
695
438M
    for (i = 0; codec_list && codec_list[i].type >= 0; i++) {
696
429M
        if (codec_list[i].type == payload_type)
697
193M
            return &codec_list[i];
698
429M
    }
699
700
79.0M
    for (i = 0; cbs_sei_common_types[i].type >= 0; i++) {
701
71.4M
        if (cbs_sei_common_types[i].type == payload_type)
702
1.20M
            return &cbs_sei_common_types[i];
703
71.4M
    }
704
705
7.58M
    return NULL;
706
8.78M
}