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_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);
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 = -1;
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,
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;
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  if (payload_buf) {
266  payload_ref = av_buffer_ref(payload_buf);
267  if (!payload_ref)
268  return AVERROR(ENOMEM);
269  } else {
270  payload_ref = NULL;
271  }
272 
273  // Find an existing SEI unit or make a new one to add to.
274  err = cbs_sei_get_unit(ctx, au, prefix, &unit);
275  if (err < 0)
276  return err;
277 
278  // Find the message list inside the codec-dependent unit.
279  err = cbs_sei_get_message_list(ctx, unit, &list);
280  if (err < 0)
281  return err;
282 
283  // Add a new message to the message list.
284  err = ff_cbs_sei_list_add(list);
285  if (err < 0)
286  return err;
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];
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);
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];
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 }
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
#define NULL
Definition: coverity.c:32
int nb_units
Number of units in this fragment.
Definition: cbs.h:149
static void cbs_free_user_data_registered(void *opaque, uint8_t *data)
Definition: cbs_sei.c:25
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 * data_ref
Definition: cbs_sei.h:39
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
const char * desc
Definition: libsvtav1.c:79
CodedBitstreamUnitType type
Codec-specific type of this unit.
Definition: cbs.h:70
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
AVBufferRef * extension_data_ref
Definition: cbs_sei.h: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
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
SEIRawMessageList message_list
Definition: cbs_h265.h:663
static void cbs_sei_delete_message(SEIRawMessageList *list, int position)
Definition: cbs_sei.c:330
uint8_t
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 cbs_sei_get_message_list(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, SEIRawMessageList **list)
Definition: cbs_sei.c:218
Coded bitstream unit structure.
Definition: cbs.h:66
void * content
Pointer to the decomposed form of this unit.
Definition: cbs.h:103
CodedBitstreamUnit * units
Pointer to an array of units of length nb_units_allocated.
Definition: cbs.h:164
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
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:198
SEIRawMessage * messages
Definition: cbs_sei.h:79
AVBufferRef * av_buffer_create(uint8_t *data, int size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:29
void ff_cbs_sei_free_message_list(SEIRawMessageList *list)
Free all SEI messages in a message list.
Definition: cbs_sei.c:99
typedef void(APIENTRY *FF_PFNGLACTIVETEXTUREPROC)(GLenum texture)
AVFormatContext * ctx
Definition: movenc.c:48
uint32_t payload_type
Definition: cbs_sei.h:69
AVBufferRef * data_ref
Definition: cbs_sei.h:46
#define AV_CODEC_ID_H265
Definition: codec_id.h:224
static int FUNC() message(CodedBitstreamContext *ctx, RWContext *rw, SEIRawMessage *current)
AVBufferRef * payload_ref
Definition: cbs_sei.h:72
AVBufferRef * av_buffer_alloc(int size)
Allocate an AVBuffer of the given size using av_malloc().
Definition: buffer.c:67
static int cbs_sei_get_unit(CodedBitstreamContext *ctx, CodedBitstreamFragment *au, int prefix, CodedBitstreamUnit **sei_unit)
Definition: cbs_sei.c:109
Coded bitstream fragment structure, combining one or more units.
Definition: cbs.h:118
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
uint8_t * data
The data buffer.
Definition: buffer.h:89
SEIRawMessageList message_list
Definition: cbs_h264.h:296
int nb_messages_allocated
Definition: cbs_sei.h:81
int ff_cbs_sei_list_add(SEIRawMessageList *list)
Allocate a new empty SEI message in a message list.
Definition: cbs_sei.c:74
Context structure for coded bitstream operations.
Definition: cbs.h:170
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
enum AVCodecID codec_id
Definition: cbs_internal.h:87
A reference to a data buffer.
Definition: buffer.h:81
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:93
static int FUNC() sei(CodedBitstreamContext *ctx, RWContext *rw, H264RawSEI *current)
void * payload
Definition: cbs_sei.h:71
#define av_free(p)
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
#define av_freep(p)
const struct CodedBitstreamType * codec
Internal codec-specific hooks.
Definition: cbs.h:180
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
static void cbs_free_user_data_unregistered(void *opaque, uint8_t *data)
Definition: cbs_sei.c:32
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
int i
Definition: input.c:407