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 
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 
57  message->payload_ref = ff_refstruct_alloc_ext(desc->size, 0,
58  NULL, free_func);
59  if (!message->payload_ref)
60  return AVERROR(ENOMEM);
61  message->payload = message->payload_ref;
62 
63  return 0;
64 }
65 
67 {
68  void *ptr;
69  int old_count = list->nb_messages_allocated;
70 
71  av_assert0(list->nb_messages <= old_count);
72  if (list->nb_messages + 1 > old_count) {
73  int new_count = 2 * old_count + 1;
74 
75  ptr = av_realloc_array(list->messages,
76  new_count, sizeof(*list->messages));
77  if (!ptr)
78  return AVERROR(ENOMEM);
79 
80  list->messages = ptr;
81  list->nb_messages_allocated = new_count;
82 
83  // Zero the newly-added entries.
84  memset(list->messages + old_count, 0,
85  (new_count - old_count) * sizeof(*list->messages));
86  }
87  ++list->nb_messages;
88  return 0;
89 }
90 
92 {
93  for (int i = 0; i < list->nb_messages; i++) {
94  SEIRawMessage *message = &list->messages[i];
95  ff_refstruct_unref(&message->payload_ref);
96  ff_refstruct_unref(&message->extension_data);
97  }
98  av_free(list->messages);
99 }
100 
103  int prefix,
104  CodedBitstreamUnit **sei_unit)
105 {
106  CodedBitstreamUnit *unit;
107  int sei_type, highest_vcl_type, err, i, position;
108 
109  switch (ctx->codec->codec_id) {
110  case AV_CODEC_ID_H264:
111  // (We can ignore auxiliary slices because we only have prefix
112  // SEI in H.264 and an auxiliary picture must always follow a
113  // primary picture.)
114  highest_vcl_type = H264_NAL_IDR_SLICE;
115  if (prefix)
116  sei_type = H264_NAL_SEI;
117  else
118  return AVERROR(EINVAL);
119  break;
120  case AV_CODEC_ID_H265:
121  highest_vcl_type = HEVC_NAL_RSV_VCL31;
122  if (prefix)
123  sei_type = HEVC_NAL_SEI_PREFIX;
124  else
125  sei_type = HEVC_NAL_SEI_SUFFIX;
126  break;
127  case AV_CODEC_ID_H266:
128  highest_vcl_type = VVC_RSV_IRAP_11;
129  if (prefix)
130  sei_type = VVC_PREFIX_SEI_NUT;
131  else
132  sei_type = VVC_SUFFIX_SEI_NUT;
133  break;
134  default:
135  return AVERROR(EINVAL);
136  }
137 
138  // Find an existing SEI NAL unit of the right type.
139  unit = NULL;
140  for (i = 0; i < au->nb_units; i++) {
141  if (au->units[i].type == sei_type) {
142  unit = &au->units[i];
143  break;
144  }
145  }
146 
147  if (unit) {
148  *sei_unit = unit;
149  return 0;
150  }
151 
152  // Need to add a new SEI NAL unit ...
153  if (prefix) {
154  // ... before the first VCL NAL unit.
155  for (i = 0; i < au->nb_units; i++) {
156  if (au->units[i].type < highest_vcl_type)
157  break;
158  }
159  position = i;
160  } else {
161  // ... after the last VCL NAL unit.
162  for (i = au->nb_units - 1; i >= 0; i--) {
163  if (au->units[i].type < highest_vcl_type)
164  break;
165  }
166  if (i < 0) {
167  // No VCL units; just put it at the end.
168  position = au->nb_units;
169  } else {
170  position = i + 1;
171  }
172  }
173 
174  err = ff_cbs_insert_unit_content(au, position, sei_type,
175  NULL, NULL);
176  if (err < 0)
177  return err;
178  unit = &au->units[position];
179  unit->type = sei_type;
180 
181  err = ff_cbs_alloc_unit_content(ctx, unit);
182  if (err < 0)
183  return err;
184 
185  switch (ctx->codec->codec_id) {
186  case AV_CODEC_ID_H264:
187  {
188  H264RawSEI sei = {
189  .nal_unit_header = {
190  .nal_ref_idc = 0,
191  .nal_unit_type = sei_type,
192  },
193  };
194  memcpy(unit->content, &sei, sizeof(sei));
195  }
196  break;
197  case AV_CODEC_ID_H265:
198  {
199  H265RawSEI sei = {
200  .nal_unit_header = {
201  .nal_unit_type = sei_type,
202  .nuh_layer_id = 0,
203  .nuh_temporal_id_plus1 = 1,
204  },
205  };
206  memcpy(unit->content, &sei, sizeof(sei));
207  }
208  break;
209  case AV_CODEC_ID_H266:
210  {
211  H266RawSEI sei = {
212  .nal_unit_header = {
213  .nal_unit_type = sei_type,
214  .nuh_layer_id = 0,
215  .nuh_temporal_id_plus1 = 1,
216  },
217  };
218  memcpy(unit->content, &sei, sizeof(sei));
219  }
220  break;
221  default:
222  av_assert0(0);
223  }
224 
225  *sei_unit = unit;
226  return 0;
227 }
228 
230  CodedBitstreamUnit *unit,
232 {
233  switch (ctx->codec->codec_id) {
234  case AV_CODEC_ID_H264:
235  {
236  H264RawSEI *sei = unit->content;
237  if (unit->type != H264_NAL_SEI)
238  return AVERROR(EINVAL);
239  *list = &sei->message_list;
240  }
241  break;
242  case AV_CODEC_ID_H265:
243  {
244  H265RawSEI *sei = unit->content;
245  if (unit->type != HEVC_NAL_SEI_PREFIX &&
246  unit->type != HEVC_NAL_SEI_SUFFIX)
247  return AVERROR(EINVAL);
248  *list = &sei->message_list;
249  }
250  break;
251  case AV_CODEC_ID_H266:
252  {
253  H266RawSEI *sei = unit->content;
254  if (unit->type != VVC_PREFIX_SEI_NUT &&
255  unit->type != VVC_SUFFIX_SEI_NUT)
256  return AVERROR(EINVAL);
257  *list = &sei->message_list;
258  }
259  break;
260  default:
261  return AVERROR(EINVAL);
262  }
263 
264  return 0;
265 }
266 
269  int prefix,
270  uint32_t payload_type,
271  void *payload_data,
272  void *payload_ref)
273 {
275  CodedBitstreamUnit *unit;
278  int err;
279 
280  desc = ff_cbs_sei_find_type(ctx, payload_type);
281  if (!desc)
282  return AVERROR(EINVAL);
283 
284  // Find an existing SEI unit or make a new one to add to.
285  err = cbs_sei_get_unit(ctx, au, prefix, &unit);
286  if (err < 0)
287  return err;
288 
289  // Find the message list inside the codec-dependent unit.
290  err = cbs_sei_get_message_list(ctx, unit, &list);
291  if (err < 0)
292  return err;
293 
294  // Add a new message to the message list.
295  err = ff_cbs_sei_list_add(list);
296  if (err < 0)
297  return err;
298 
299  if (payload_ref) {
300  /* The following just increments payload_ref's refcount,
301  * so that payload_ref is now owned by us. */
302  payload_ref = ff_refstruct_ref(payload_ref);
303  }
304 
305  message = &list->messages[list->nb_messages - 1];
306 
307  message->payload_type = payload_type;
308  message->payload = payload_data;
309  message->payload_ref = payload_ref;
310 
311  return 0;
312 }
313 
316  uint32_t payload_type,
317  SEIRawMessage **iter)
318 {
319  int err, i, j, found;
320 
321  found = 0;
322  for (i = 0; i < au->nb_units; i++) {
323  CodedBitstreamUnit *unit = &au->units[i];
325 
326  err = cbs_sei_get_message_list(ctx, unit, &list);
327  if (err < 0)
328  continue;
329 
330  for (j = 0; j < list->nb_messages; j++) {
331  SEIRawMessage *message = &list->messages[j];
332 
333  if (message->payload_type == payload_type) {
334  if (!*iter || found) {
335  *iter = message;
336  return 0;
337  }
338  if (message == *iter)
339  found = 1;
340  }
341  }
342  }
343 
344  return AVERROR(ENOENT);
345 }
346 
348  int position)
349 {
351 
352  av_assert0(0 <= position && position < list->nb_messages);
353 
354  message = &list->messages[position];
355  ff_refstruct_unref(&message->payload_ref);
356  ff_refstruct_unref(&message->extension_data);
357 
358  --list->nb_messages;
359 
360  if (list->nb_messages > 0) {
361  memmove(list->messages + position,
362  list->messages + position + 1,
363  (list->nb_messages - position) * sizeof(*list->messages));
364  }
365 }
366 
369  uint32_t payload_type)
370 {
371  int err, i, j;
372 
373  for (i = 0; i < au->nb_units; i++) {
374  CodedBitstreamUnit *unit = &au->units[i];
376 
377  err = cbs_sei_get_message_list(ctx, unit, &list);
378  if (err < 0)
379  continue;
380 
381  for (j = list->nb_messages - 1; j >= 0; j--) {
382  if (list->messages[j].payload_type == payload_type)
384  }
385  }
386 }
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:267
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:100
H265RawSEI
Definition: cbs_h265.h:739
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:367
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:229
CodedBitstreamUnit::type
CodedBitstreamUnitType type
Codec-specific type of this unit.
Definition: cbs.h:74
cbs.h
H264_NAL_SEI
@ H264_NAL_SEI
Definition: h264.h:40
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
HEVC_NAL_SEI_SUFFIX
@ HEVC_NAL_SEI_SUFFIX
Definition: hevc.h:69
SEIRawUserDataUnregistered
Definition: cbs_sei.h:40
HEVC_NAL_SEI_PREFIX
@ HEVC_NAL_SEI_PREFIX
Definition: hevc.h:68
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:853
CodedBitstreamFragment
Coded bitstream fragment structure, combining one or more units.
Definition: cbs.h:122
av_realloc_array
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:217
SEIRawMessageList
Definition: cbs_sei.h:109
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
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:253
SEIMessageTypeDescriptor
Definition: cbs_sei.h:144
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_RSV_VCL31
@ HEVC_NAL_RSV_VCL31
Definition: hevc.h:60
H264_NAL_IDR_SLICE
@ H264_NAL_IDR_SLICE
Definition: h264.h:39
sei
static int FUNC() sei(CodedBitstreamContext *ctx, RWContext *rw, H264RawSEI *current)
Definition: cbs_h264_syntax_template.c:858
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:2313
cbs_sei_delete_message
static void cbs_sei_delete_message(SEIRawMessageList *list, int position)
Definition: cbs_sei.c:347
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:314
VVC_SUFFIX_SEI_NUT
@ VVC_SUFFIX_SEI_NUT
Definition: vvc.h:53
H264RawSEI
Definition: cbs_h264.h:325
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:229
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:101
desc
const char * desc
Definition: libsvtav1.c:79
mem.h
message
static int FUNC() message(CodedBitstreamContext *ctx, RWContext *rw, SEIRawMessage *current)
Definition: cbs_sei_syntax_template.c:227
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:66
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
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:91
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