/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 | } |