FFmpeg
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_h266.h"
24 #include "cbs_sei.h"
25 
26 static void cbs_free_user_data_registered(void *opaque, uint8_t *data)
27 {
30  av_free(udr);
31 }
32 
33 static void cbs_free_user_data_unregistered(void *opaque, uint8_t *data)
34 {
37  av_free(udu);
38 }
39 
42 {
43  void (*free_func)(void*, uint8_t*);
44 
45  av_assert0(message->payload == NULL &&
46  message->payload_ref == NULL);
47  message->payload_type = desc->type;
48 
50  free_func = &cbs_free_user_data_registered;
51  else if (desc->type == SEI_TYPE_USER_DATA_UNREGISTERED)
53  else
54  free_func = NULL;
55 
56  if (free_func) {
57  message->payload = av_mallocz(desc->size);
58  if (!message->payload)
59  return AVERROR(ENOMEM);
60  message->payload_ref =
61  av_buffer_create(message->payload, desc->size,
62  free_func, NULL, 0);
63  } else {
64  message->payload_ref = av_buffer_alloc(desc->size);
65  }
66  if (!message->payload_ref) {
67  av_freep(&message->payload);
68  return AVERROR(ENOMEM);
69  }
70  message->payload = message->payload_ref->data;
71 
72  return 0;
73 }
74 
76 {
77  void *ptr;
78  int old_count = list->nb_messages_allocated;
79 
80  av_assert0(list->nb_messages <= old_count);
81  if (list->nb_messages + 1 > old_count) {
82  int new_count = 2 * old_count + 1;
83 
84  ptr = av_realloc_array(list->messages,
85  new_count, sizeof(*list->messages));
86  if (!ptr)
87  return AVERROR(ENOMEM);
88 
89  list->messages = ptr;
90  list->nb_messages_allocated = new_count;
91 
92  // Zero the newly-added entries.
93  memset(list->messages + old_count, 0,
94  (new_count - old_count) * sizeof(*list->messages));
95  }
96  ++list->nb_messages;
97  return 0;
98 }
99 
101 {
102  for (int i = 0; i < list->nb_messages; i++) {
103  SEIRawMessage *message = &list->messages[i];
104  av_buffer_unref(&message->payload_ref);
105  av_buffer_unref(&message->extension_data_ref);
106  }
107  av_free(list->messages);
108 }
109 
112  int prefix,
113  CodedBitstreamUnit **sei_unit)
114 {
115  CodedBitstreamUnit *unit;
116  int sei_type, highest_vcl_type, err, i, position;
117 
118  switch (ctx->codec->codec_id) {
119  case AV_CODEC_ID_H264:
120  // (We can ignore auxiliary slices because we only have prefix
121  // SEI in H.264 and an auxiliary picture must always follow a
122  // primary picture.)
123  highest_vcl_type = H264_NAL_IDR_SLICE;
124  if (prefix)
125  sei_type = H264_NAL_SEI;
126  else
127  return AVERROR(EINVAL);
128  break;
129  case AV_CODEC_ID_H265:
130  highest_vcl_type = HEVC_NAL_RSV_VCL31;
131  if (prefix)
132  sei_type = HEVC_NAL_SEI_PREFIX;
133  else
134  sei_type = HEVC_NAL_SEI_SUFFIX;
135  break;
136  case AV_CODEC_ID_H266:
137  highest_vcl_type = VVC_RSV_IRAP_11;
138  if (prefix)
139  sei_type = VVC_PREFIX_SEI_NUT;
140  else
141  sei_type = VVC_SUFFIX_SEI_NUT;
142  break;
143  default:
144  return AVERROR(EINVAL);
145  }
146 
147  // Find an existing SEI NAL unit of the right type.
148  unit = NULL;
149  for (i = 0; i < au->nb_units; i++) {
150  if (au->units[i].type == sei_type) {
151  unit = &au->units[i];
152  break;
153  }
154  }
155 
156  if (unit) {
157  *sei_unit = unit;
158  return 0;
159  }
160 
161  // Need to add a new SEI NAL unit ...
162  if (prefix) {
163  // ... before the first VCL NAL unit.
164  for (i = 0; i < au->nb_units; i++) {
165  if (au->units[i].type < highest_vcl_type)
166  break;
167  }
168  position = i;
169  } else {
170  // ... after the last VCL NAL unit.
171  for (i = au->nb_units - 1; i >= 0; i--) {
172  if (au->units[i].type < highest_vcl_type)
173  break;
174  }
175  if (i < 0) {
176  // No VCL units; just put it at the end.
177  position = au->nb_units;
178  } else {
179  position = i + 1;
180  }
181  }
182 
183  err = ff_cbs_insert_unit_content(au, position, sei_type,
184  NULL, NULL);
185  if (err < 0)
186  return err;
187  unit = &au->units[position];
188  unit->type = sei_type;
189 
190  err = ff_cbs_alloc_unit_content(ctx, unit);
191  if (err < 0)
192  return err;
193 
194  switch (ctx->codec->codec_id) {
195  case AV_CODEC_ID_H264:
196  {
197  H264RawSEI sei = {
198  .nal_unit_header = {
199  .nal_ref_idc = 0,
200  .nal_unit_type = sei_type,
201  },
202  };
203  memcpy(unit->content, &sei, sizeof(sei));
204  }
205  break;
206  case AV_CODEC_ID_H265:
207  {
208  H265RawSEI sei = {
209  .nal_unit_header = {
210  .nal_unit_type = sei_type,
211  .nuh_layer_id = 0,
212  .nuh_temporal_id_plus1 = 1,
213  },
214  };
215  memcpy(unit->content, &sei, sizeof(sei));
216  }
217  break;
218  case AV_CODEC_ID_H266:
219  {
220  H266RawSEI sei = {
221  .nal_unit_header = {
222  .nal_unit_type = sei_type,
223  .nuh_layer_id = 0,
224  .nuh_temporal_id_plus1 = 1,
225  },
226  };
227  memcpy(unit->content, &sei, sizeof(sei));
228  }
229  break;
230  default:
231  av_assert0(0);
232  }
233 
234  *sei_unit = unit;
235  return 0;
236 }
237 
239  CodedBitstreamUnit *unit,
241 {
242  switch (ctx->codec->codec_id) {
243  case AV_CODEC_ID_H264:
244  {
245  H264RawSEI *sei = unit->content;
246  if (unit->type != H264_NAL_SEI)
247  return AVERROR(EINVAL);
248  *list = &sei->message_list;
249  }
250  break;
251  case AV_CODEC_ID_H265:
252  {
253  H265RawSEI *sei = unit->content;
254  if (unit->type != HEVC_NAL_SEI_PREFIX &&
255  unit->type != HEVC_NAL_SEI_SUFFIX)
256  return AVERROR(EINVAL);
257  *list = &sei->message_list;
258  }
259  break;
260  case AV_CODEC_ID_H266:
261  {
262  H266RawSEI *sei = unit->content;
263  if (unit->type != VVC_PREFIX_SEI_NUT &&
264  unit->type != VVC_SUFFIX_SEI_NUT)
265  return AVERROR(EINVAL);
266  *list = &sei->message_list;
267  }
268  break;
269  default:
270  return AVERROR(EINVAL);
271  }
272 
273  return 0;
274 }
275 
278  int prefix,
279  uint32_t payload_type,
280  void *payload_data,
281  AVBufferRef *payload_buf)
282 {
284  CodedBitstreamUnit *unit;
287  AVBufferRef *payload_ref;
288  int err;
289 
290  desc = ff_cbs_sei_find_type(ctx, payload_type);
291  if (!desc)
292  return AVERROR(EINVAL);
293 
294  // Find an existing SEI unit or make a new one to add to.
295  err = cbs_sei_get_unit(ctx, au, prefix, &unit);
296  if (err < 0)
297  return err;
298 
299  // Find the message list inside the codec-dependent unit.
300  err = cbs_sei_get_message_list(ctx, unit, &list);
301  if (err < 0)
302  return err;
303 
304  // Add a new message to the message list.
305  err = ff_cbs_sei_list_add(list);
306  if (err < 0)
307  return err;
308 
309  if (payload_buf) {
310  payload_ref = av_buffer_ref(payload_buf);
311  if (!payload_ref)
312  return AVERROR(ENOMEM);
313  } else {
314  payload_ref = NULL;
315  }
316 
317  message = &list->messages[list->nb_messages - 1];
318 
319  message->payload_type = payload_type;
320  message->payload = payload_data;
321  message->payload_ref = payload_ref;
322 
323  return 0;
324 }
325 
328  uint32_t payload_type,
329  SEIRawMessage **iter)
330 {
331  int err, i, j, found;
332 
333  found = 0;
334  for (i = 0; i < au->nb_units; i++) {
335  CodedBitstreamUnit *unit = &au->units[i];
337 
338  err = cbs_sei_get_message_list(ctx, unit, &list);
339  if (err < 0)
340  continue;
341 
342  for (j = 0; j < list->nb_messages; j++) {
343  SEIRawMessage *message = &list->messages[j];
344 
345  if (message->payload_type == payload_type) {
346  if (!*iter || found) {
347  *iter = message;
348  return 0;
349  }
350  if (message == *iter)
351  found = 1;
352  }
353  }
354  }
355 
356  return AVERROR(ENOENT);
357 }
358 
360  int position)
361 {
363 
364  av_assert0(0 <= position && position < list->nb_messages);
365 
366  message = &list->messages[position];
367  av_buffer_unref(&message->payload_ref);
368  av_buffer_unref(&message->extension_data_ref);
369 
370  --list->nb_messages;
371 
372  if (list->nb_messages > 0) {
373  memmove(list->messages + position,
374  list->messages + position + 1,
375  (list->nb_messages - position) * sizeof(*list->messages));
376  }
377 }
378 
381  uint32_t payload_type)
382 {
383  int err, i, j;
384 
385  for (i = 0; i < au->nb_units; i++) {
386  CodedBitstreamUnit *unit = &au->units[i];
388 
389  err = cbs_sei_get_message_list(ctx, unit, &list);
390  if (err < 0)
391  continue;
392 
393  for (j = list->nb_messages - 1; j >= 0; j--) {
394  if (list->messages[j].payload_type == payload_type)
396  }
397  }
398 }
SEIRawUserDataRegistered::data_ref
AVBufferRef * data_ref
Definition: cbs_sei.h:39
ff_cbs_sei_add_message
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:276
VVC_RSV_IRAP_11
@ VVC_RSV_IRAP_11
Definition: vvc.h:40
cbs_h266.h
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
SEIRawUserDataRegistered
Definition: cbs_sei.h:35
message
Definition: api-threadmessage-test.c:46
cbs_h264.h
CodedBitstreamUnit::content
void * content
Pointer to the decomposed form of this unit.
Definition: cbs.h:107
SEIRawMessage
Definition: cbs_sei.h:74
cbs_free_user_data_unregistered
static void cbs_free_user_data_unregistered(void *opaque, uint8_t *data)
Definition: cbs_sei.c:33
H265RawSEI
Definition: cbs_h265.h:673
ff_cbs_sei_delete_message_type
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:379
CodedBitstreamContext
Context structure for coded bitstream operations.
Definition: cbs.h:219
cbs_sei_get_message_list
static int cbs_sei_get_message_list(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, SEIRawMessageList **list)
Definition: cbs_sei.c:238
data
const char data[16]
Definition: mxf.c:148
CodedBitstreamUnit::type
CodedBitstreamUnitType type
Codec-specific type of this unit.
Definition: cbs.h:74
cbs.h
cbs_h265.h
av_buffer_ref
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:103
cbs_free_user_data_registered
static void cbs_free_user_data_registered(void *opaque, uint8_t *data)
Definition: cbs_sei.c:26
CodedBitstreamUnit
Coded bitstream unit structure.
Definition: cbs.h:70
VVC_SUFFIX_SEI_NUT
@ VVC_SUFFIX_SEI_NUT
Definition: vvc.h:53
SEIRawUserDataUnregistered
Definition: cbs_sei.h:43
CodedBitstreamFragment::units
CodedBitstreamUnit * units
Pointer to an array of units of length nb_units_allocated.
Definition: cbs.h:168
VVC_PREFIX_SEI_NUT
@ VVC_PREFIX_SEI_NUT
Definition: vvc.h:52
H266RawSEI
Definition: cbs_h266.h:859
CodedBitstreamFragment
Coded bitstream fragment structure, combining one or more units.
Definition: cbs.h:122
HEVC_NAL_RSV_VCL31
@ HEVC_NAL_RSV_VCL31
Definition: hevc.h:60
av_realloc_array
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:215
SEIRawMessageList
Definition: cbs_sei.h:84
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
ctx
AVFormatContext * ctx
Definition: movenc.c:48
SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35
@ SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35
Definition: sei.h:34
cbs_internal.h
ff_cbs_sei_alloc_message_payload
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:40
AV_CODEC_ID_H264
@ AV_CODEC_ID_H264
Definition: codec_id.h:79
NULL
#define NULL
Definition: coverity.c:32
av_buffer_unref
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:139
cbs_sei.h
AV_CODEC_ID_H266
#define AV_CODEC_ID_H266
Definition: codec_id.h:251
ff_cbs_insert_unit_content
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:775
SEIMessageTypeDescriptor
Definition: cbs_sei.h:119
H264_NAL_SEI
@ H264_NAL_SEI
Definition: h264.h:40
list
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining list
Definition: filter_design.txt:25
HEVC_NAL_SEI_SUFFIX
@ HEVC_NAL_SEI_SUFFIX
Definition: hevc.h:69
sei
static int FUNC() sei(CodedBitstreamContext *ctx, RWContext *rw, H264RawSEI *current)
Definition: cbs_h264_syntax_template.c:825
av_buffer_create
AVBufferRef * av_buffer_create(uint8_t *data, size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:55
H264_NAL_IDR_SLICE
@ H264_NAL_IDR_SLICE
Definition: h264.h:39
av_buffer_alloc
AVBufferRef * av_buffer_alloc(size_t size)
Allocate an AVBuffer of the given size using av_malloc().
Definition: buffer.c:77
ff_cbs_sei_find_type
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:2239
cbs_sei_delete_message
static void cbs_sei_delete_message(SEIRawMessageList *list, int position)
Definition: cbs_sei.c:359
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:244
ff_cbs_sei_find_message
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:326
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:254
H264RawSEI
Definition: cbs_h264.h:305
ff_cbs_alloc_unit_content
int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit)
Allocate a new internal content buffer matching the type of the unit.
Definition: cbs.c:913
SEI_TYPE_USER_DATA_UNREGISTERED
@ SEI_TYPE_USER_DATA_UNREGISTERED
Definition: sei.h:35
AV_CODEC_ID_H265
#define AV_CODEC_ID_H265
Definition: codec_id.h:227
cbs_sei_get_unit
static int cbs_sei_get_unit(CodedBitstreamContext *ctx, CodedBitstreamFragment *au, int prefix, CodedBitstreamUnit **sei_unit)
Definition: cbs_sei.c:110
desc
const char * desc
Definition: libsvtav1.c:83
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
message
static int FUNC() message(CodedBitstreamContext *ctx, RWContext *rw, SEIRawMessage *current)
Definition: cbs_sei_syntax_template.c:164
ff_cbs_sei_list_add
int ff_cbs_sei_list_add(SEIRawMessageList *list)
Allocate a new empty SEI message in a message list.
Definition: cbs_sei.c:75
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
SEIRawUserDataUnregistered::data_ref
AVBufferRef * data_ref
Definition: cbs_sei.h:46
ff_cbs_sei_free_message_list
void ff_cbs_sei_free_message_list(SEIRawMessageList *list)
Free all SEI messages in a message list.
Definition: cbs_sei.c:100
HEVC_NAL_SEI_PREFIX
@ HEVC_NAL_SEI_PREFIX
Definition: hevc.h:68
CodedBitstreamFragment::nb_units
int nb_units
Number of units in this fragment.
Definition: cbs.h:153