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 #include "refstruct.h"
26 
27 static void cbs_free_user_data_registered(FFRefStructOpaque unused, void *obj)
28 {
29  SEIRawUserDataRegistered *udr = obj;
30  ff_refstruct_unref(&udr->data);
31 }
32 
33 static void cbs_free_user_data_unregistered(FFRefStructOpaque unused, void *obj)
34 {
35  SEIRawUserDataUnregistered *udu = obj;
36  ff_refstruct_unref(&udu->data);
37 }
38 
41 {
42  void (*free_func)(FFRefStructOpaque, void*);
43  unsigned flags = 0;
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;
56  }
57 
58  message->payload_ref = ff_refstruct_alloc_ext(desc->size, flags,
59  NULL, free_func);
60  if (!message->payload_ref)
61  return AVERROR(ENOMEM);
62  message->payload = message->payload_ref;
63 
64  return 0;
65 }
66 
68 {
69  void *ptr;
70  int old_count = list->nb_messages_allocated;
71 
72  av_assert0(list->nb_messages <= old_count);
73  if (list->nb_messages + 1 > old_count) {
74  int new_count = 2 * old_count + 1;
75 
76  ptr = av_realloc_array(list->messages,
77  new_count, sizeof(*list->messages));
78  if (!ptr)
79  return AVERROR(ENOMEM);
80 
81  list->messages = ptr;
82  list->nb_messages_allocated = new_count;
83 
84  // Zero the newly-added entries.
85  memset(list->messages + old_count, 0,
86  (new_count - old_count) * sizeof(*list->messages));
87  }
88  ++list->nb_messages;
89  return 0;
90 }
91 
93 {
94  for (int i = 0; i < list->nb_messages; i++) {
95  SEIRawMessage *message = &list->messages[i];
96  ff_refstruct_unref(&message->payload_ref);
97  ff_refstruct_unref(&message->extension_data);
98  }
99  av_free(list->messages);
100 }
101 
104  int prefix,
105  CodedBitstreamUnit **sei_unit)
106 {
107  CodedBitstreamUnit *unit;
108  int sei_type, highest_vcl_type, err, i, position;
109 
110  switch (ctx->codec->codec_id) {
111  case AV_CODEC_ID_H264:
112  // (We can ignore auxiliary slices because we only have prefix
113  // SEI in H.264 and an auxiliary picture must always follow a
114  // primary picture.)
115  highest_vcl_type = H264_NAL_IDR_SLICE;
116  if (prefix)
117  sei_type = H264_NAL_SEI;
118  else
119  return AVERROR(EINVAL);
120  break;
121  case AV_CODEC_ID_H265:
122  highest_vcl_type = HEVC_NAL_RSV_VCL31;
123  if (prefix)
124  sei_type = HEVC_NAL_SEI_PREFIX;
125  else
126  sei_type = HEVC_NAL_SEI_SUFFIX;
127  break;
128  case AV_CODEC_ID_H266:
129  highest_vcl_type = VVC_RSV_IRAP_11;
130  if (prefix)
131  sei_type = VVC_PREFIX_SEI_NUT;
132  else
133  sei_type = VVC_SUFFIX_SEI_NUT;
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_content(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  case AV_CODEC_ID_H266:
211  {
212  H266RawSEI sei = {
213  .nal_unit_header = {
214  .nal_unit_type = sei_type,
215  .nuh_layer_id = 0,
216  .nuh_temporal_id_plus1 = 1,
217  },
218  };
219  memcpy(unit->content, &sei, sizeof(sei));
220  }
221  break;
222  default:
223  av_assert0(0);
224  }
225 
226  *sei_unit = unit;
227  return 0;
228 }
229 
231  CodedBitstreamUnit *unit,
233 {
234  switch (ctx->codec->codec_id) {
235  case AV_CODEC_ID_H264:
236  {
237  H264RawSEI *sei = unit->content;
238  if (unit->type != H264_NAL_SEI)
239  return AVERROR(EINVAL);
240  *list = &sei->message_list;
241  }
242  break;
243  case AV_CODEC_ID_H265:
244  {
245  H265RawSEI *sei = unit->content;
246  if (unit->type != HEVC_NAL_SEI_PREFIX &&
247  unit->type != HEVC_NAL_SEI_SUFFIX)
248  return AVERROR(EINVAL);
249  *list = &sei->message_list;
250  }
251  break;
252  case AV_CODEC_ID_H266:
253  {
254  H266RawSEI *sei = unit->content;
255  if (unit->type != VVC_PREFIX_SEI_NUT &&
256  unit->type != VVC_SUFFIX_SEI_NUT)
257  return AVERROR(EINVAL);
258  *list = &sei->message_list;
259  }
260  break;
261  default:
262  return AVERROR(EINVAL);
263  }
264 
265  return 0;
266 }
267 
270  int prefix,
271  uint32_t payload_type,
272  void *payload_data,
273  void *payload_ref)
274 {
276  CodedBitstreamUnit *unit;
279  int err;
280 
281  desc = ff_cbs_sei_find_type(ctx, payload_type);
282  if (!desc)
283  return AVERROR(EINVAL);
284 
285  // Find an existing SEI unit or make a new one to add to.
286  err = cbs_sei_get_unit(ctx, au, prefix, &unit);
287  if (err < 0)
288  return err;
289 
290  // Find the message list inside the codec-dependent unit.
291  err = cbs_sei_get_message_list(ctx, unit, &list);
292  if (err < 0)
293  return err;
294 
295  // Add a new message to the message list.
296  err = ff_cbs_sei_list_add(list);
297  if (err < 0)
298  return err;
299 
300  if (payload_ref) {
301  /* The following just increments payload_ref's refcount,
302  * so that payload_ref is now owned by us. */
303  payload_ref = ff_refstruct_ref(payload_ref);
304  }
305 
306  message = &list->messages[list->nb_messages - 1];
307 
308  message->payload_type = payload_type;
309  message->payload = payload_data;
310  message->payload_ref = payload_ref;
311 
312  return 0;
313 }
314 
317  uint32_t payload_type,
318  SEIRawMessage **iter)
319 {
320  int err, i, j, found;
321 
322  found = 0;
323  for (i = 0; i < au->nb_units; i++) {
324  CodedBitstreamUnit *unit = &au->units[i];
326 
327  err = cbs_sei_get_message_list(ctx, unit, &list);
328  if (err < 0)
329  continue;
330 
331  for (j = 0; j < list->nb_messages; j++) {
332  SEIRawMessage *message = &list->messages[j];
333 
334  if (message->payload_type == payload_type) {
335  if (!*iter || found) {
336  *iter = message;
337  return 0;
338  }
339  if (message == *iter)
340  found = 1;
341  }
342  }
343  }
344 
345  return AVERROR(ENOENT);
346 }
347 
349  int position)
350 {
352 
353  av_assert0(0 <= position && position < list->nb_messages);
354 
355  message = &list->messages[position];
356  ff_refstruct_unref(&message->payload_ref);
357  ff_refstruct_unref(&message->extension_data);
358 
359  --list->nb_messages;
360 
361  if (list->nb_messages > 0) {
362  memmove(list->messages + position,
363  list->messages + position + 1,
364  (list->nb_messages - position) * sizeof(*list->messages));
365  }
366 }
367 
370  uint32_t payload_type)
371 {
372  int err, i, j;
373 
374  for (i = 0; i < au->nb_units; i++) {
375  CodedBitstreamUnit *unit = &au->units[i];
377 
378  err = cbs_sei_get_message_list(ctx, unit, &list);
379  if (err < 0)
380  continue;
381 
382  for (j = list->nb_messages - 1; j >= 0; j--) {
383  if (list->messages[j].payload_type == payload_type)
385  }
386  }
387 }
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:46
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:268
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:782
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:368
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:230
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:215
SEIRawMessageList
Definition: cbs_sei.h:79
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:39
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
H264_NAL_IDR_SLICE
@ H264_NAL_IDR_SLICE
Definition: h264.h:39
cbs_free_user_data_unregistered
static void cbs_free_user_data_unregistered(FFRefStructOpaque unused, void *obj)
Definition: cbs_sei.c:33
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:2252
cbs_sei_delete_message
static void cbs_sei_delete_message(SEIRawMessageList *list, int position)
Definition: cbs_sei.c:348
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
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:315
VVC_SUFFIX_SEI_NUT
@ VVC_SUFFIX_SEI_NUT
Definition: vvc.h:53
H264RawSEI
Definition: cbs_h264.h:305
H264_NAL_SEI
@ H264_NAL_SEI
Definition: h264.h:40
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:922
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:27
cbs_sei_get_unit
static int cbs_sei_get_unit(CodedBitstreamContext *ctx, CodedBitstreamFragment *au, int prefix, CodedBitstreamUnit **sei_unit)
Definition: cbs_sei.c:102
desc
const char * desc
Definition: libsvtav1.c:75
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:67
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:482
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:92
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