FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/cbs_sei.c
Date: 2021-09-24 20:55:06
Exec Total Coverage
Lines: 59 183 32.2%
Branches: 25 103 24.3%

Line Branch Exec 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 "cbs.h"
20 #include "cbs_internal.h"
21 #include "cbs_h264.h"
22 #include "cbs_h265.h"
23 #include "cbs_sei.h"
24
25 25 static void cbs_free_user_data_registered(void *opaque, uint8_t *data)
26 {
27 25 SEIRawUserDataRegistered *udr = (SEIRawUserDataRegistered*)data;
28 25 av_buffer_unref(&udr->data_ref);
29 25 av_free(udr);
30 25 }
31
32 static void cbs_free_user_data_unregistered(void *opaque, uint8_t *data)
33 {
34 SEIRawUserDataUnregistered *udu = (SEIRawUserDataUnregistered*)data;
35 av_buffer_unref(&udu->data_ref);
36 av_free(udu);
37 }
38
39 1895 int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message,
40 const SEIMessageTypeDescriptor *desc)
41 {
42 void (*free_func)(void*, uint8_t*);
43
44
2/4
✓ Branch 0 taken 1895 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1895 times.
1895 av_assert0(message->payload == NULL &&
45 message->payload_ref == NULL);
46 1895 message->payload_type = desc->type;
47
48
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 1870 times.
1895 if (desc->type == SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35)
49 25 free_func = &cbs_free_user_data_registered;
50
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1870 times.
1870 else if (desc->type == SEI_TYPE_USER_DATA_UNREGISTERED)
51 free_func = &cbs_free_user_data_unregistered;
52 else
53 1870 free_func = NULL;
54
55
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 1870 times.
1895 if (free_func) {
56 25 message->payload = av_mallocz(desc->size);
57
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (!message->payload)
58 return AVERROR(ENOMEM);
59 25 message->payload_ref =
60 25 av_buffer_create(message->payload, desc->size,
61 free_func, NULL, 0);
62 } else {
63 1870 message->payload_ref = av_buffer_alloc(desc->size);
64 }
65
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1895 times.
1895 if (!message->payload_ref) {
66 av_freep(&message->payload);
67 return AVERROR(ENOMEM);
68 }
69 1895 message->payload = message->payload_ref->data;
70
71 1895 return 0;
72 }
73
74 1900 int ff_cbs_sei_list_add(SEIRawMessageList *list)
75 {
76 void *ptr;
77 1900 int old_count = list->nb_messages_allocated;
78
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1900 times.
1900 av_assert0(list->nb_messages <= old_count);
80
2/2
✓ Branch 0 taken 1891 times.
✓ Branch 1 taken 9 times.
1900 if (list->nb_messages + 1 > old_count) {
81 1891 int new_count = 2 * old_count + 1;
82
83 1891 ptr = av_realloc_array(list->messages,
84 new_count, sizeof(*list->messages));
85
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1891 times.
1891 if (!ptr)
86 return AVERROR(ENOMEM);
87
88 1891 list->messages = ptr;
89 1891 list->nb_messages_allocated = new_count;
90
91 // Zero the newly-added entries.
92 1891 memset(list->messages + old_count, 0,
93 1891 (new_count - old_count) * sizeof(*list->messages));
94 }
95 1900 ++list->nb_messages;
96 1900 return 0;
97 }
98
99 1880 void ff_cbs_sei_free_message_list(SEIRawMessageList *list)
100 {
101
2/2
✓ Branch 0 taken 1900 times.
✓ Branch 1 taken 1880 times.
3780 for (int i = 0; i < list->nb_messages; i++) {
102 1900 SEIRawMessage *message = &list->messages[i];
103 1900 av_buffer_unref(&message->payload_ref);
104 1900 av_buffer_unref(&message->extension_data_ref);
105 }
106 1880 av_free(list->messages);
107 1880 }
108
109 static int cbs_sei_get_unit(CodedBitstreamContext *ctx,
110 CodedBitstreamFragment *au,
111 int prefix,
112 CodedBitstreamUnit **sei_unit)
113 {
114 CodedBitstreamUnit *unit;
115 int sei_type, highest_vcl_type, err, i, position;
116
117 switch (ctx->codec->codec_id) {
118 case AV_CODEC_ID_H264:
119 // (We can ignore auxiliary slices because we only have prefix
120 // SEI in H.264 and an auxiliary picture must always follow a
121 // primary picture.)
122 highest_vcl_type = H264_NAL_IDR_SLICE;
123 if (prefix)
124 sei_type = H264_NAL_SEI;
125 else
126 return AVERROR(EINVAL);
127 break;
128 case AV_CODEC_ID_H265:
129 highest_vcl_type = HEVC_NAL_RSV_VCL31;
130 if (prefix)
131 sei_type = HEVC_NAL_SEI_PREFIX;
132 else
133 sei_type = HEVC_NAL_SEI_SUFFIX;
134 break;
135 default:
136 return AVERROR(EINVAL);
137 }
138
139 // Find an existing SEI NAL unit of the right type.
140 unit = NULL;
141 for (i = 0; i < au->nb_units; i++) {
142 if (au->units[i].type == sei_type) {
143 unit = &au->units[i];
144 break;
145 }
146 }
147
148 if (unit) {
149 *sei_unit = unit;
150 return 0;
151 }
152
153 // Need to add a new SEI NAL unit ...
154 if (prefix) {
155 // ... before the first VCL NAL unit.
156 for (i = 0; i < au->nb_units; i++) {
157 if (au->units[i].type < highest_vcl_type)
158 break;
159 }
160 position = i;
161 } else {
162 // ... after the last VCL NAL unit.
163 for (i = au->nb_units - 1; i >= 0; i--) {
164 if (au->units[i].type < highest_vcl_type)
165 break;
166 }
167 if (i < 0) {
168 // No VCL units; just put it at the end.
169 position = au->nb_units;
170 } else {
171 position = i + 1;
172 }
173 }
174
175 err = ff_cbs_insert_unit_content(au, position, sei_type,
176 NULL, NULL);
177 if (err < 0)
178 return err;
179 unit = &au->units[position];
180 unit->type = sei_type;
181
182 err = ff_cbs_alloc_unit_content2(ctx, unit);
183 if (err < 0)
184 return err;
185
186 switch (ctx->codec->codec_id) {
187 case AV_CODEC_ID_H264:
188 {
189 H264RawSEI sei = {
190 .nal_unit_header = {
191 .nal_ref_idc = 0,
192 .nal_unit_type = sei_type,
193 },
194 };
195 memcpy(unit->content, &sei, sizeof(sei));
196 }
197 break;
198 case AV_CODEC_ID_H265:
199 {
200 H265RawSEI sei = {
201 .nal_unit_header = {
202 .nal_unit_type = sei_type,
203 .nuh_layer_id = 0,
204 .nuh_temporal_id_plus1 = 1,
205 },
206 };
207 memcpy(unit->content, &sei, sizeof(sei));
208 }
209 break;
210 default:
211 av_assert0(0);
212 }
213
214 *sei_unit = unit;
215 return 0;
216 }
217
218 104 static int cbs_sei_get_message_list(CodedBitstreamContext *ctx,
219 CodedBitstreamUnit *unit,
220 SEIRawMessageList **list)
221 {
222
1/3
✓ Branch 0 taken 104 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
104 switch (ctx->codec->codec_id) {
223 104 case AV_CODEC_ID_H264:
224 {
225 104 H264RawSEI *sei = unit->content;
226
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 61 times.
104 if (unit->type != H264_NAL_SEI)
227 43 return AVERROR(EINVAL);
228 61 *list = &sei->message_list;
229 }
230 61 break;
231 case AV_CODEC_ID_H265:
232 {
233 H265RawSEI *sei = unit->content;
234 if (unit->type != HEVC_NAL_SEI_PREFIX &&
235 unit->type != HEVC_NAL_SEI_SUFFIX)
236 return AVERROR(EINVAL);
237 *list = &sei->message_list;
238 }
239 break;
240 default:
241 return AVERROR(EINVAL);
242 }
243
244 61 return 0;
245 }
246
247 int ff_cbs_sei_add_message(CodedBitstreamContext *ctx,
248 CodedBitstreamFragment *au,
249 int prefix,
250 uint32_t payload_type,
251 void *payload_data,
252 AVBufferRef *payload_buf)
253 {
254 const SEIMessageTypeDescriptor *desc;
255 CodedBitstreamUnit *unit;
256 SEIRawMessageList *list;
257 SEIRawMessage *message;
258 AVBufferRef *payload_ref;
259 int err;
260
261 desc = ff_cbs_sei_find_type(ctx, payload_type);
262 if (!desc)
263 return AVERROR(EINVAL);
264
265 // Find an existing SEI unit or make a new one to add to.
266 err = cbs_sei_get_unit(ctx, au, prefix, &unit);
267 if (err < 0)
268 return err;
269
270 // Find the message list inside the codec-dependent unit.
271 err = cbs_sei_get_message_list(ctx, unit, &list);
272 if (err < 0)
273 return err;
274
275 // Add a new message to the message list.
276 err = ff_cbs_sei_list_add(list);
277 if (err < 0)
278 return err;
279
280 if (payload_buf) {
281 payload_ref = av_buffer_ref(payload_buf);
282 if (!payload_ref)
283 return AVERROR(ENOMEM);
284 } else {
285 payload_ref = NULL;
286 }
287
288 message = &list->messages[list->nb_messages - 1];
289
290 message->payload_type = payload_type;
291 message->payload = payload_data;
292 message->payload_ref = payload_ref;
293
294 return 0;
295 }
296
297 int ff_cbs_sei_find_message(CodedBitstreamContext *ctx,
298 CodedBitstreamFragment *au,
299 uint32_t payload_type,
300 SEIRawMessage **iter)
301 {
302 int err, i, j, found;
303
304 found = 0;
305 for (i = 0; i < au->nb_units; i++) {
306 CodedBitstreamUnit *unit = &au->units[i];
307 SEIRawMessageList *list;
308
309 err = cbs_sei_get_message_list(ctx, unit, &list);
310 if (err < 0)
311 continue;
312
313 for (j = 0; j < list->nb_messages; j++) {
314 SEIRawMessage *message = &list->messages[j];
315
316 if (message->payload_type == payload_type) {
317 if (!*iter || found) {
318 *iter = message;
319 return 0;
320 }
321 if (message == *iter)
322 found = 1;
323 }
324 }
325 }
326
327 return AVERROR(ENOENT);
328 }
329
330 static void cbs_sei_delete_message(SEIRawMessageList *list,
331 int position)
332 {
333 SEIRawMessage *message;
334
335 av_assert0(0 <= position && position < list->nb_messages);
336
337 message = &list->messages[position];
338 av_buffer_unref(&message->payload_ref);
339 av_buffer_unref(&message->extension_data_ref);
340
341 --list->nb_messages;
342
343 if (list->nb_messages > 0) {
344 memmove(list->messages + position,
345 list->messages + position + 1,
346 (list->nb_messages - position) * sizeof(*list->messages));
347 }
348 }
349
350 40 void ff_cbs_sei_delete_message_type(CodedBitstreamContext *ctx,
351 CodedBitstreamFragment *au,
352 uint32_t payload_type)
353 {
354 int err, i, j;
355
356
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 40 times.
144 for (i = 0; i < au->nb_units; i++) {
357 104 CodedBitstreamUnit *unit = &au->units[i];
358 SEIRawMessageList *list;
359
360 104 err = cbs_sei_get_message_list(ctx, unit, &list);
361
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 61 times.
104 if (err < 0)
362 43 continue;
363
364
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 61 times.
122 for (j = list->nb_messages - 1; j >= 0; j--) {
365
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 if (list->messages[j].payload_type == payload_type)
366 cbs_sei_delete_message(list, j);
367 }
368 }
369 40 }
370