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 "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 "refstruct.h"
27 
28 static void cbs_free_user_data_registered(FFRefStructOpaque unused, void *obj)
29 {
30  SEIRawUserDataRegistered *udr = obj;
31  ff_refstruct_unref(&udr->data);
32 }
33 
34 static void cbs_free_user_data_unregistered(FFRefStructOpaque unused, void *obj)
35 {
36  SEIRawUserDataUnregistered *udu = obj;
37  ff_refstruct_unref(&udu->data);
38 }
39 
42 {
43  void (*free_func)(FFRefStructOpaque, void*);
44  unsigned flags = 0;
45 
46  av_assert0(message->payload == NULL &&
47  message->payload_ref == NULL);
48  message->payload_type = desc->type;
49 
51  free_func = &cbs_free_user_data_registered;
52  else if (desc->type == SEI_TYPE_USER_DATA_UNREGISTERED)
54  else {
55  free_func = NULL;
57  }
58 
59  message->payload_ref = ff_refstruct_alloc_ext(desc->size, flags,
60  NULL, free_func);
61  if (!message->payload_ref)
62  return AVERROR(ENOMEM);
63  message->payload = message->payload_ref;
64 
65  return 0;
66 }
67 
69 {
70  void *ptr;
71  int old_count = list->nb_messages_allocated;
72 
73  av_assert0(list->nb_messages <= old_count);
74  if (list->nb_messages + 1 > old_count) {
75  int new_count = 2 * old_count + 1;
76 
77  ptr = av_realloc_array(list->messages,
78  new_count, sizeof(*list->messages));
79  if (!ptr)
80  return AVERROR(ENOMEM);
81 
82  list->messages = ptr;
83  list->nb_messages_allocated = new_count;
84 
85  // Zero the newly-added entries.
86  memset(list->messages + old_count, 0,
87  (new_count - old_count) * sizeof(*list->messages));
88  }
89  ++list->nb_messages;
90  return 0;
91 }
92 
94 {
95  for (int i = 0; i < list->nb_messages; i++) {
96  SEIRawMessage *message = &list->messages[i];
97  ff_refstruct_unref(&message->payload_ref);
98  ff_refstruct_unref(&message->extension_data);
99  }
100  av_free(list->messages);
101 }
102 
105  int prefix,
106  CodedBitstreamUnit **sei_unit)
107 {
108  CodedBitstreamUnit *unit;
109  int sei_type, highest_vcl_type, err, i, position;
110 
111  switch (ctx->codec->codec_id) {
112  case AV_CODEC_ID_H264:
113  // (We can ignore auxiliary slices because we only have prefix
114  // SEI in H.264 and an auxiliary picture must always follow a
115  // primary picture.)
116  highest_vcl_type = H264_NAL_IDR_SLICE;
117  if (prefix)
118  sei_type = H264_NAL_SEI;
119  else
120  return AVERROR(EINVAL);
121  break;
122  case AV_CODEC_ID_H265:
123  highest_vcl_type = HEVC_NAL_RSV_VCL31;
124  if (prefix)
125  sei_type = HEVC_NAL_SEI_PREFIX;
126  else
127  sei_type = HEVC_NAL_SEI_SUFFIX;
128  break;
129  case AV_CODEC_ID_H266:
130  highest_vcl_type = VVC_RSV_IRAP_11;
131  if (prefix)
132  sei_type = VVC_PREFIX_SEI_NUT;
133  else
134  sei_type = VVC_SUFFIX_SEI_NUT;
135  break;
136  default:
137  return AVERROR(EINVAL);
138  }
139 
140  // Find an existing SEI NAL unit of the right type.
141  unit = NULL;
142  for (i = 0; i < au->nb_units; i++) {
143  if (au->units[i].type == sei_type) {
144  unit = &au->units[i];
145  break;
146  }
147  }
148 
149  if (unit) {
150  *sei_unit = unit;
151  return 0;
152  }
153 
154  // Need to add a new SEI NAL unit ...
155  if (prefix) {
156  // ... before the first VCL NAL unit.
157  for (i = 0; i < au->nb_units; i++) {
158  if (au->units[i].type < highest_vcl_type)
159  break;
160  }
161  position = i;
162  } else {
163  // ... after the last VCL NAL unit.
164  for (i = au->nb_units - 1; i >= 0; i--) {
165  if (au->units[i].type < highest_vcl_type)
166  break;
167  }
168  if (i < 0) {
169  // No VCL units; just put it at the end.
170  position = au->nb_units;
171  } else {
172  position = i + 1;
173  }
174  }
175 
176  err = ff_cbs_insert_unit_content(au, position, sei_type,
177  NULL, NULL);
178  if (err < 0)
179  return err;
180  unit = &au->units[position];
181  unit->type = sei_type;
182 
183  err = ff_cbs_alloc_unit_content(ctx, unit);
184  if (err < 0)
185  return err;
186 
187  switch (ctx->codec->codec_id) {
188  case AV_CODEC_ID_H264:
189  {
190  H264RawSEI sei = {
191  .nal_unit_header = {
192  .nal_ref_idc = 0,
193  .nal_unit_type = sei_type,
194  },
195  };
196  memcpy(unit->content, &sei, sizeof(sei));
197  }
198  break;
199  case AV_CODEC_ID_H265:
200  {
201  H265RawSEI sei = {
202  .nal_unit_header = {
203  .nal_unit_type = sei_type,
204  .nuh_layer_id = 0,
205  .nuh_temporal_id_plus1 = 1,
206  },
207  };
208  memcpy(unit->content, &sei, sizeof(sei));
209  }
210  break;
211  case AV_CODEC_ID_H266:
212  {
213  H266RawSEI sei = {
214  .nal_unit_header = {
215  .nal_unit_type = sei_type,
216  .nuh_layer_id = 0,
217  .nuh_temporal_id_plus1 = 1,
218  },
219  };
220  memcpy(unit->content, &sei, sizeof(sei));
221  }
222  break;
223  default:
224  av_assert0(0);
225  }
226 
227  *sei_unit = unit;
228  return 0;
229 }
230 
232  CodedBitstreamUnit *unit,
234 {
235  switch (ctx->codec->codec_id) {
236  case AV_CODEC_ID_H264:
237  {
238  H264RawSEI *sei = unit->content;
239  if (unit->type != H264_NAL_SEI)
240  return AVERROR(EINVAL);
241  *list = &sei->message_list;
242  }
243  break;
244  case AV_CODEC_ID_H265:
245  {
246  H265RawSEI *sei = unit->content;
247  if (unit->type != HEVC_NAL_SEI_PREFIX &&
248  unit->type != HEVC_NAL_SEI_SUFFIX)
249  return AVERROR(EINVAL);
250  *list = &sei->message_list;
251  }
252  break;
253  case AV_CODEC_ID_H266:
254  {
255  H266RawSEI *sei = unit->content;
256  if (unit->type != VVC_PREFIX_SEI_NUT &&
257  unit->type != VVC_SUFFIX_SEI_NUT)
258  return AVERROR(EINVAL);
259  *list = &sei->message_list;
260  }
261  break;
262  default:
263  return AVERROR(EINVAL);
264  }
265 
266  return 0;
267 }
268 
271  int prefix,
272  uint32_t payload_type,
273  void *payload_data,
274  void *payload_ref)
275 {
277  CodedBitstreamUnit *unit;
280  int err;
281 
282  desc = ff_cbs_sei_find_type(ctx, payload_type);
283  if (!desc)
284  return AVERROR(EINVAL);
285 
286  // Find an existing SEI unit or make a new one to add to.
287  err = cbs_sei_get_unit(ctx, au, prefix, &unit);
288  if (err < 0)
289  return err;
290 
291  // Find the message list inside the codec-dependent unit.
292  err = cbs_sei_get_message_list(ctx, unit, &list);
293  if (err < 0)
294  return err;
295 
296  // Add a new message to the message list.
297  err = ff_cbs_sei_list_add(list);
298  if (err < 0)
299  return err;
300 
301  if (payload_ref) {
302  /* The following just increments payload_ref's refcount,
303  * so that payload_ref is now owned by us. */
304  payload_ref = ff_refstruct_ref(payload_ref);
305  }
306 
307  message = &list->messages[list->nb_messages - 1];
308 
309  message->payload_type = payload_type;
310  message->payload = payload_data;
311  message->payload_ref = payload_ref;
312 
313  return 0;
314 }
315 
318  uint32_t payload_type,
319  SEIRawMessage **iter)
320 {
321  int err, i, j, found;
322 
323  found = 0;
324  for (i = 0; i < au->nb_units; i++) {
325  CodedBitstreamUnit *unit = &au->units[i];
327 
328  err = cbs_sei_get_message_list(ctx, unit, &list);
329  if (err < 0)
330  continue;
331 
332  for (j = 0; j < list->nb_messages; j++) {
333  SEIRawMessage *message = &list->messages[j];
334 
335  if (message->payload_type == payload_type) {
336  if (!*iter || found) {
337  *iter = message;
338  return 0;
339  }
340  if (message == *iter)
341  found = 1;
342  }
343  }
344  }
345 
346  return AVERROR(ENOENT);
347 }
348 
350  int position)
351 {
353 
354  av_assert0(0 <= position && position < list->nb_messages);
355 
356  message = &list->messages[position];
357  ff_refstruct_unref(&message->payload_ref);
358  ff_refstruct_unref(&message->extension_data);
359 
360  --list->nb_messages;
361 
362  if (list->nb_messages > 0) {
363  memmove(list->messages + position,
364  list->messages + position + 1,
365  (list->nb_messages - position) * sizeof(*list->messages));
366  }
367 }
368 
371  uint32_t payload_type)
372 {
373  int err, i, j;
374 
375  for (i = 0; i < au->nb_units; i++) {
376  CodedBitstreamUnit *unit = &au->units[i];
378 
379  err = cbs_sei_get_message_list(ctx, unit, &list);
380  if (err < 0)
381  continue;
382 
383  for (j = list->nb_messages - 1; j >= 0; j--) {
384  if (list->messages[j].payload_type == payload_type)
386  }
387  }
388 }
ff_refstruct_ref
void * ff_refstruct_ref(void *obj)
Create a new reference to an object managed via this API, i.e.
Definition: refstruct.c:140
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:33
message
Definition: api-threadmessage-test.c:47
ff_cbs_sei_add_message
int ff_cbs_sei_add_message(CodedBitstreamContext *ctx, CodedBitstreamFragment *au, int prefix, uint32_t payload_type, void *payload_data, void *payload_ref)
Add an SEI message to an access unit.
Definition: cbs_sei.c:269
cbs_h264.h
CodedBitstreamUnit::content
void * content
Pointer to the decomposed form of this unit.
Definition: cbs.h:107
ff_cbs_insert_unit_content
int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, int position, CodedBitstreamUnitType type, void *content, void *content_ref)
Insert a new unit into a fragment with the given content.
Definition: cbs.c:783
ff_refstruct_alloc_ext
static void * ff_refstruct_alloc_ext(size_t size, unsigned flags, void *opaque, void(*free_cb)(FFRefStructOpaque opaque, void *obj))
A wrapper around ff_refstruct_alloc_ext_c() for the common case of a non-const qualified opaque.
Definition: refstruct.h:94
SEIRawMessage
Definition: cbs_sei.h:70
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:369
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:231
CodedBitstreamUnit::type
CodedBitstreamUnitType type
Codec-specific type of this unit.
Definition: cbs.h:74
cbs.h
cbs_h265.h
FFRefStructOpaque
RefStruct is an API for creating reference-counted objects with minimal overhead.
Definition: refstruct.h:58
CodedBitstreamUnit
Coded bitstream unit structure.
Definition: cbs.h:70
SEIRawUserDataUnregistered::data
uint8_t * data
RefStruct reference.
Definition: cbs_sei.h:42
SEIRawUserDataUnregistered
Definition: cbs_sei.h:40
refstruct.h
CodedBitstreamFragment::units
CodedBitstreamUnit * units
Pointer to an array of units of length nb_units_allocated.
Definition: cbs.h:168
H266RawSEI
Definition: cbs_h266.h:861
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:217
SEIRawMessageList
Definition: cbs_sei.h:79
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
H264_NAL_IDR_SLICE
@ H264_NAL_IDR_SLICE
Definition: h264.h:39
ctx
AVFormatContext * ctx
Definition: movenc.c:49
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
cbs_sei.h
AV_CODEC_ID_H266
#define AV_CODEC_ID_H266
Definition: codec_id.h:251
SEIMessageTypeDescriptor
Definition: cbs_sei.h:114
VVC_PREFIX_SEI_NUT
@ VVC_PREFIX_SEI_NUT
Definition: vvc.h:52
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:824
SEIRawUserDataRegistered::data
uint8_t * data
RefStruct reference.
Definition: cbs_sei.h:36
cbs_free_user_data_unregistered
static void cbs_free_user_data_unregistered(FFRefStructOpaque unused, void *obj)
Definition: cbs_sei.c:34
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:2249
cbs_sei_delete_message
static void cbs_sei_delete_message(SEIRawMessageList *list, int position)
Definition: cbs_sei.c:349
H264_NAL_SEI
@ H264_NAL_SEI
Definition: h264.h:40
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
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:316
VVC_SUFFIX_SEI_NUT
@ VVC_SUFFIX_SEI_NUT
Definition: vvc.h:53
H264RawSEI
Definition: cbs_h264.h:305
VVC_RSV_IRAP_11
@ VVC_RSV_IRAP_11
Definition: vvc.h:40
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:923
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_free_user_data_registered
static void cbs_free_user_data_registered(FFRefStructOpaque unused, void *obj)
Definition: cbs_sei.c:28
cbs_sei_get_unit
static int cbs_sei_get_unit(CodedBitstreamContext *ctx, CodedBitstreamFragment *au, int prefix, CodedBitstreamUnit **sei_unit)
Definition: cbs_sei.c:103
desc
const char * desc
Definition: libsvtav1.c:75
mem.h
FF_REFSTRUCT_FLAG_NO_ZEROING
#define FF_REFSTRUCT_FLAG_NO_ZEROING
If this flag is set in ff_refstruct_alloc_ext_c(), the object will not be initially zeroed.
Definition: refstruct.h:67
message
static int FUNC() message(CodedBitstreamContext *ctx, RWContext *rw, SEIRawMessage *current)
Definition: cbs_sei_syntax_template.c:165
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:68
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
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:93
HEVC_NAL_SEI_PREFIX
@ HEVC_NAL_SEI_PREFIX
Definition: hevc.h:68
ff_refstruct_unref
void ff_refstruct_unref(void *objp)
Decrement the reference count of the underlying object and automatically free the object if there are...
Definition: refstruct.c:120
CodedBitstreamFragment::nb_units
int nb_units
Number of units in this fragment.
Definition: cbs.h:153