FFmpeg  4.4.4
cbs_sei.c
Go to the documentation of this file.
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 static void cbs_free_user_data_registered(void *opaque, uint8_t *data)
26 {
29  av_free(udr);
30 }
31 
32 static void cbs_free_user_data_unregistered(void *opaque, uint8_t *data)
33 {
36  av_free(udu);
37 }
38 
41 {
42  void (*free_func)(void*, uint8_t*);
43 
44  av_assert0(message->payload == NULL &&
45  message->payload_ref == NULL);
46  message->payload_type = desc->type;
47 
49  free_func = &cbs_free_user_data_registered;
50  else if (desc->type == SEI_TYPE_USER_DATA_UNREGISTERED)
52  else
53  free_func = NULL;
54 
55  if (free_func) {
56  message->payload = av_mallocz(desc->size);
57  if (!message->payload)
58  return AVERROR(ENOMEM);
59  message->payload_ref =
60  av_buffer_create(message->payload, desc->size,
61  free_func, NULL, 0);
62  } else {
63  message->payload_ref = av_buffer_alloc(desc->size);
64  }
65  if (!message->payload_ref) {
66  av_freep(&message->payload);
67  return AVERROR(ENOMEM);
68  }
69  message->payload = message->payload_ref->data;
70 
71  return 0;
72 }
73 
75 {
76  void *ptr;
77  int old_count = list->nb_messages_allocated;
78 
79  av_assert0(list->nb_messages <= old_count);
80  if (list->nb_messages + 1 > old_count) {
81  int new_count = 2 * old_count + 1;
82 
83  ptr = av_realloc_array(list->messages,
84  new_count, sizeof(*list->messages));
85  if (!ptr)
86  return AVERROR(ENOMEM);
87 
88  list->messages = ptr;
89  list->nb_messages_allocated = new_count;
90 
91  // Zero the newly-added entries.
92  memset(list->messages + old_count, 0,
93  (new_count - old_count) * sizeof(*list->messages));
94  }
95  ++list->nb_messages;
96  return 0;
97 }
98 
100 {
101  for (int i = 0; i < list->nb_messages; i++) {
102  SEIRawMessage *message = &list->messages[i];
103  av_buffer_unref(&message->payload_ref);
104  av_buffer_unref(&message->extension_data_ref);
105  }
106  av_free(list->messages);
107 }
108 
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 
219  CodedBitstreamUnit *unit,
220  SEIRawMessageList **list)
221 {
222  switch (ctx->codec->codec_id) {
223  case AV_CODEC_ID_H264:
224  {
225  H264RawSEI *sei = unit->content;
226  if (unit->type != H264_NAL_SEI)
227  return AVERROR(EINVAL);
228  *list = &sei->message_list;
229  }
230  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  return 0;
245 }
246 
249  int prefix,
250  uint32_t payload_type,
251  void *payload_data,
252  AVBufferRef *payload_buf)
253 {
255  CodedBitstreamUnit *unit;
256  SEIRawMessageList *list;
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 
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 
331  int position)
332 {
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 
352  uint32_t payload_type)
353 {
354  int err, i, j;
355 
356  for (i = 0; i < au->nb_units; i++) {
357  CodedBitstreamUnit *unit = &au->units[i];
358  SEIRawMessageList *list;
359 
360  err = cbs_sei_get_message_list(ctx, unit, &list);
361  if (err < 0)
362  continue;
363 
364  for (j = list->nb_messages - 1; j >= 0; j--) {
365  if (list->messages[j].payload_type == payload_type)
366  cbs_sei_delete_message(list, j);
367  }
368  }
369 }
uint8_t
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, int position, CodedBitstreamUnitType type, void *content, AVBufferRef *content_buf)
Insert a new unit into a fragment with the given content.
Definition: cbs.c:737
int ff_cbs_alloc_unit_content2(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit)
Allocate a new internal content buffer matching the type of the unit.
Definition: cbs.c:869
const SEIMessageTypeDescriptor * ff_cbs_sei_find_type(CodedBitstreamContext *ctx, int payload_type)
Find the type descriptor for the given payload type.
Definition: cbs_h2645.c:1640
static int FUNC() sei(CodedBitstreamContext *ctx, RWContext *rw, H264RawSEI *current)
static void cbs_sei_delete_message(SEIRawMessageList *list, int position)
Definition: cbs_sei.c:330
static void cbs_free_user_data_registered(void *opaque, uint8_t *data)
Definition: cbs_sei.c:25
void ff_cbs_sei_free_message_list(SEIRawMessageList *list)
Free all SEI messages in a message list.
Definition: cbs_sei.c:99
int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message, const SEIMessageTypeDescriptor *desc)
Allocate a new payload for the given SEI message.
Definition: cbs_sei.c:39
static void cbs_free_user_data_unregistered(void *opaque, uint8_t *data)
Definition: cbs_sei.c:32
void ff_cbs_sei_delete_message_type(CodedBitstreamContext *ctx, CodedBitstreamFragment *au, uint32_t payload_type)
Delete all messages with the given payload type from an access unit.
Definition: cbs_sei.c:350
static int cbs_sei_get_message_list(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, SEIRawMessageList **list)
Definition: cbs_sei.c:218
int ff_cbs_sei_list_add(SEIRawMessageList *list)
Allocate a new empty SEI message in a message list.
Definition: cbs_sei.c:74
int ff_cbs_sei_add_message(CodedBitstreamContext *ctx, CodedBitstreamFragment *au, int prefix, uint32_t payload_type, void *payload_data, AVBufferRef *payload_buf)
Add an SEI message to an access unit.
Definition: cbs_sei.c:247
static int cbs_sei_get_unit(CodedBitstreamContext *ctx, CodedBitstreamFragment *au, int prefix, CodedBitstreamUnit **sei_unit)
Definition: cbs_sei.c:109
int ff_cbs_sei_find_message(CodedBitstreamContext *ctx, CodedBitstreamFragment *au, uint32_t payload_type, SEIRawMessage **iter)
Iterate over messages with the given payload type in an access unit.
Definition: cbs_sei.c:297
static int FUNC() message(CodedBitstreamContext *ctx, RWContext *rw, SEIRawMessage *current)
#define AV_CODEC_ID_H265
Definition: codec_id.h:224
#define NULL
Definition: coverity.c:32
@ AV_CODEC_ID_H264
Definition: codec_id.h:76
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition: buffer.c:125
AVBufferRef * av_buffer_create(uint8_t *data, buffer_size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:29
AVBufferRef * av_buffer_alloc(buffer_size_t size)
Allocate an AVBuffer of the given size using av_malloc().
Definition: buffer.c:67
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:93
#define AVERROR(e)
Definition: error.h:43
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:237
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Allocate, reallocate, or free an array.
Definition: mem.c:198
@ H264_NAL_SEI
Definition: h264.h:40
@ H264_NAL_IDR_SLICE
Definition: h264.h:39
int i
Definition: input.c:407
@ HEVC_NAL_SEI_SUFFIX
Definition: hevc.h:69
@ HEVC_NAL_RSV_VCL31
Definition: hevc.h:60
@ HEVC_NAL_SEI_PREFIX
Definition: hevc.h:68
const char * desc
Definition: libsvtav1.c:79
const char data[16]
Definition: mxf.c:142
typedef void(RENAME(mix_any_func_type))
@ SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35
Definition: sei.h:34
@ SEI_TYPE_USER_DATA_UNREGISTERED
Definition: sei.h:35
A reference to a data buffer.
Definition: buffer.h:84
Context structure for coded bitstream operations.
Definition: cbs.h:170
Coded bitstream fragment structure, combining one or more units.
Definition: cbs.h:118
CodedBitstreamUnit * units
Pointer to an array of units of length nb_units_allocated.
Definition: cbs.h:164
int nb_units
Number of units in this fragment.
Definition: cbs.h:149
Coded bitstream unit structure.
Definition: cbs.h:66
void * content
Pointer to the decomposed form of this unit.
Definition: cbs.h:103
CodedBitstreamUnitType type
Codec-specific type of this unit.
Definition: cbs.h:70
int nb_messages_allocated
Definition: cbs_sei.h:81
SEIRawMessage * messages
Definition: cbs_sei.h:79
uint32_t payload_type
Definition: cbs_sei.h:69
AVBufferRef * data_ref
Definition: cbs_sei.h:39
AVBufferRef * data_ref
Definition: cbs_sei.h:46
#define av_free(p)
#define av_freep(p)
AVFormatContext * ctx
Definition: movenc.c:48