FFmpeg
Loading...
Searching...
No Matches
side_data.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 <stdio.h>
20#include <string.h>
21
22#include "libavutil/avassert.h"
23#include "libavutil/buffer.h"
24#include "libavutil/dict.h"
25#include "libavutil/display.h"
27#include "libavutil/error.h"
28#include "libavutil/frame.h"
29#include "libavutil/macros.h"
30#include "libavutil/mem.h"
32#include "libavutil/spherical.h"
33#include "libavutil/stereo3d.h"
34
35typedef struct Set {
37 int nb_sd;
38} Set;
39
40/* Every entry below carries a payload laid out as AVFrameSideDataType
41 * documents for its type: a producer owes that layout even when no consumer
42 * reads the buffer back. The small number that identifies an entry in the
43 * reference output therefore lives in the metadata dictionary, which
44 * av_frame_side_data_clone() copies along with the buffer. */
45static void set_marker(AVFrameSideData *sd, int marker)
46{
47 char value[16];
48
49 snprintf(value, sizeof(value), "%d", marker);
50 av_assert0(av_dict_set(&sd->metadata, "marker", value, 0) >= 0);
51}
52
54 const void *payload, size_t size, int marker)
55{
56 AVFrameSideData *sd = av_frame_side_data_new(&s->sd, &s->nb_sd, type,
57 size, 0);
58
59 av_assert0(sd && sd->size == size);
60 memcpy(sd->data, payload, size);
61 set_marker(sd, marker);
62 return sd;
63}
64
65static AVBufferRef *payload_buffer(const void *payload, size_t size)
66{
68
69 av_assert0(buf);
70 memcpy(buf->data, payload, size);
71 return buf;
72}
73
74static const char *entry_marker(const AVFrameSideData *sd)
75{
76 const AVDictionaryEntry *e = av_dict_get(sd->metadata, "marker", NULL, 0);
77
78 return e ? e->value : "none";
79}
80
81static void print_set(const char *label, const Set *s)
82{
83 printf("%s: n=%d\n", label, s->nb_sd);
84 for (int i = 0; i < s->nb_sd; i++)
85 printf(" [%d] %s marker=%s\n", i,
86 av_frame_side_data_name(s->sd[i]->type),
87 entry_marker(s->sd[i]));
88}
89
90/* Dumps a set by looking each type up instead of walking the array. Removal is
91 * documented to drop the matching entries, not to keep the survivors where
92 * they were, so printing by index would tie the reference to the current habit
93 * of moving the last entry into the freed slot. */
94static void print_lookup(const char *label, const Set *s,
95 const enum AVFrameSideDataType *types, size_t nb_types)
96{
97 printf("%s: n=%d\n", label, s->nb_sd);
98 for (size_t i = 0; i < nb_types; i++) {
99 const AVFrameSideData *sd =
100 av_frame_side_data_get(s->sd, s->nb_sd, types[i]);
101 const char *name = av_frame_side_data_name(types[i]);
102
103 if (sd)
104 printf(" %s: marker=%s\n", name, entry_marker(sd));
105 else
106 printf(" %s: absent\n", name);
107 }
108}
109
110int main(void)
111{
112 /* desc / name accessors. */
113 printf("Testing av_frame_side_data_desc() / av_frame_side_data_name()\n");
114 static const enum AVFrameSideDataType known[] = {
115 AV_FRAME_DATA_STEREO3D, /* PROP_GLOBAL */
116 AV_FRAME_DATA_DYNAMIC_HDR_PLUS, /* PROP_COLOR_DEPENDENT */
117 AV_FRAME_DATA_SPHERICAL, /* PROP_GLOBAL|SIZE_DEPENDENT */
118 AV_FRAME_DATA_DOWNMIX_INFO, /* PROP_CHANNEL_DEPENDENT */
119 AV_FRAME_DATA_SEI_UNREGISTERED, /* PROP_MULTI */
120 };
121 for (size_t i = 0; i < FF_ARRAY_ELEMS(known); i++) {
123 const char *n = av_frame_side_data_name(known[i]);
124 /* Compare content: the API only promises a string identifying the
125 * type, not the descriptor's own pointer. */
126 printf(" type=%d name_match=%s props=0x%x\n", known[i],
127 d && n && !strcmp(d->name, n) ? "yes" : "no",
128 d ? d->props : 0);
129 }
130
131 /* Invalid / unmapped types must return NULL (sd_props gap). */
132 {
134 printf(" invalid type desc=%s name=%s\n",
135 av_frame_side_data_desc(bad) ? "non-null" : "null",
136 av_frame_side_data_name(bad) ? "non-null" : "null");
137 }
138
139 /* Payloads. The two structs are allocated through their public
140 * allocators because their sizes are not part of the public ABI. */
141 size_t stereo3d_size, spherical_size;
142 AVStereo3D *stereo3d = av_stereo3d_alloc_size(&stereo3d_size);
143 AVSphericalMapping *spherical = av_spherical_alloc(&spherical_size);
144 /* 16 bytes of uuid_iso_iec_11578 followed by user_data_payload_byte. */
145 uint8_t udu[16 + 8] = {
146 0x9a, 0x21, 0xf3, 0x4d, 0x6b, 0x1c, 0x47, 0x8e,
147 0xa5, 0x30, 0xc2, 0x7f, 0x11, 0x8d, 0x46, 0x02,
148 'p', 'a', 'y', 'l', 'o', 'a', 'd', '1',
149 };
150 int32_t displaymatrix[9];
151 /* src_x = dst_x + motion_x / motion_scale, likewise for y. */
152 AVMotionVector mvs[2] = {
153 { .source = -1, .w = 16, .h = 16, .src_x = 32, .src_y = 48,
154 .dst_x = 40, .dst_y = 48, .motion_x = -8, .motion_y = 0,
155 .motion_scale = 1 },
156 { .source = 1, .w = 8, .h = 8, .src_x = 64, .src_y = 64,
157 .dst_x = 64, .dst_y = 72, .motion_x = 0, .motion_y = -8,
158 .motion_scale = 1 },
159 };
160 /* The mix levels are absolute linear scale factors, not dB. */
161 AVDownmixInfo downmix = {
162 .preferred_downmix_type = AV_DOWNMIX_TYPE_LTRT,
163 .center_mix_level = 0.5,
164 .center_mix_level_ltrt = 0.625,
165 .surround_mix_level = 0.25,
166 .surround_mix_level_ltrt = 0.375,
167 .lfe_mix_level = 0.125,
168 };
169
170 av_assert0(stereo3d && spherical);
171
172 stereo3d->type = AV_STEREO3D_SIDEBYSIDE;
173 stereo3d->view = AV_STEREO3D_VIEW_PACKED;
175 stereo3d->baseline = 65000;
176
178 spherical->yaw = 90 << 16;
179
180 av_display_rotation_set(displaymatrix, 90.0);
181
182 /* Populate a set with several types, one of them MULTI. */
183 Set set = { 0 };
184 new_entry(&set, AV_FRAME_DATA_STEREO3D, stereo3d, stereo3d_size, 100);
185 new_entry(&set, AV_FRAME_DATA_DOWNMIX_INFO, &downmix, sizeof(downmix),
186 200);
187 new_entry(&set, AV_FRAME_DATA_SEI_UNREGISTERED, udu, sizeof(udu), 1);
188 udu[sizeof(udu) - 1] = '2';
189 new_entry(&set, AV_FRAME_DATA_SEI_UNREGISTERED, udu, sizeof(udu), 2);
190 new_entry(&set, AV_FRAME_DATA_SPHERICAL, spherical, spherical_size, 300);
191 /* Entries are appended, so this dump is the insertion order by
192 * construction and shows both MULTI entries. */
193 print_set("\nInitial set", &set);
194
195 /* Types probed by every dump below. */
196 static const enum AVFrameSideDataType probed[] = {
203 };
204
205 /* get / get_c: present and missing types. */
206 printf("\nTesting av_frame_side_data_get()\n");
207 {
208 const AVFrameSideData *got =
210 printf(" stereo3d: %s marker=%s payload_match=%s\n",
211 got ? "found" : "missing", got ? entry_marker(got) : "none",
212 got && got->size == stereo3d_size &&
213 !memcmp(got->data, stereo3d, stereo3d_size) ? "yes" : "no");
214 got = av_frame_side_data_get(set.sd, set.nb_sd,
216 printf(" mastering (absent): %s\n", got ? "FAIL" : "null");
217 }
218
219 /* remove by type clears all matching entries (including duplicates). */
220 printf("\nTesting av_frame_side_data_remove()\n");
223 print_lookup(" after remove SEI_UNREGISTERED", &set,
224 probed, FF_ARRAY_ELEMS(probed));
225
226 /* remove_by_props: PROP_GLOBAL drops STEREO3D and SPHERICAL. */
227 printf("\nTesting av_frame_side_data_remove_by_props()\n");
230 print_lookup(" after remove_by_props(GLOBAL)", &set,
231 probed, FF_ARRAY_ELEMS(probed));
232
233 /* Clone: copy remaining entry into a second set. */
234 printf("\nTesting av_frame_side_data_clone()\n");
235 Set dst = { 0 };
236 if (set.nb_sd > 0) {
237 int ret = av_frame_side_data_clone(&dst.sd, &dst.nb_sd,
238 set.sd[0], 0);
239 printf(" clone into empty: ret=%d nb=%d marker=%s\n", ret, dst.nb_sd,
240 dst.nb_sd ? entry_marker(dst.sd[0]) : "none");
241
242 /* Same type again without REPLACE must fail with EEXIST. */
243 ret = av_frame_side_data_clone(&dst.sd, &dst.nb_sd, set.sd[0], 0);
244 printf(" clone duplicate no REPLACE: ret==AVERROR(EEXIST)=%s\n",
245 ret == AVERROR(EEXIST) ? "yes" : "no");
246
247 /* With REPLACE, clone replaces the existing entry in place. */
248 ret = av_frame_side_data_clone(&dst.sd, &dst.nb_sd, set.sd[0],
250 printf(" clone REPLACE: ret=%d nb=%d\n", ret, dst.nb_sd);
251
252 /* Invalid args. */
253 ret = av_frame_side_data_clone(NULL, &dst.nb_sd, set.sd[0], 0);
254 printf(" clone NULL sd: ret==AVERROR(EINVAL)=%s\n",
255 ret == AVERROR(EINVAL) ? "yes" : "no");
256 }
257
258 /* add: buffer ownership transfer and NEW_REF. */
259 printf("\nTesting av_frame_side_data_add()\n");
260 {
261 AVBufferRef *buf = payload_buffer(displaymatrix, sizeof(displaymatrix));
262
263 AVFrameSideData *sd_added =
264 av_frame_side_data_add(&dst.sd, &dst.nb_sd,
267 printf(" add (move): added=%s pbuf_nulled=%s\n",
268 sd_added ? "yes" : "no", buf == NULL ? "yes" : "no");
269 if (sd_added)
270 set_marker(sd_added, 999);
271
272 /* NEW_REF: the caller retains its reference. */
273 AVBufferRef *keep = payload_buffer(mvs, sizeof(mvs));
274 sd_added = av_frame_side_data_add(&dst.sd, &dst.nb_sd,
277 printf(" add (NEW_REF): added=%s caller_ref_kept=%s nb_mvs=%d\n",
278 sd_added ? "yes" : "no", keep ? "yes" : "no",
279 sd_added ? (int)(sd_added->size / sizeof(AVMotionVector)) : -1);
280 if (sd_added)
281 set_marker(sd_added, 42);
282 av_buffer_unref(&keep);
283
284 /* REPLACE on existing entry: same type, payload swaps in place. */
285 int32_t replacement[9];
286 av_display_rotation_set(replacement, 180.0);
287 AVBufferRef *repl = payload_buffer(replacement, sizeof(replacement));
288 sd_added = av_frame_side_data_add(&dst.sd, &dst.nb_sd,
291 if (sd_added)
292 set_marker(sd_added, 1234);
293 {
294 const AVFrameSideData *after =
297 printf(" add (REPLACE existing): added=%s marker=%s"
298 " payload_match=%s\n",
299 sd_added ? "yes" : "no",
300 after ? entry_marker(after) : "none",
301 after && after->size == sizeof(replacement) &&
302 !memcmp(after->data, replacement, sizeof(replacement)) ?
303 "yes" : "no");
304 }
305 }
306
307 /* clone with UNIQUE: existing same-type entry is removed first. dst
308 * already has a set.sd[0]->type entry from the REPLACE clone above. */
309 printf("\nTesting av_frame_side_data_clone() UNIQUE\n");
310 if (set.nb_sd > 0) {
311 int before = dst.nb_sd;
312 int ret = av_frame_side_data_clone(&dst.sd, &dst.nb_sd, set.sd[0],
314 printf(" clone UNIQUE: ret=%d before=%d after=%d\n",
315 ret, before, dst.nb_sd);
316 }
317
318 print_lookup("\nFinal dst", &dst, probed, FF_ARRAY_ELEMS(probed));
319
320 av_frame_side_data_free(&dst.sd, &dst.nb_sd);
321 av_frame_side_data_free(&set.sd, &set.nb_sd);
322 printf("\nfree: set_nb=%d dst_nb=%d\n", set.nb_sd, dst.nb_sd);
323
324 av_free(stereo3d);
325 av_free(spherical);
326
327 return 0;
328}
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
int32_t
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
refcounted data buffer API
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
__device__ int printf(const char *,...)
Public dictionary API.
Display matrix.
audio downmix medatata
error code definitions
double value
Definition eval.c:102
reference-counted frame API
@ AV_DOWNMIX_TYPE_LTRT
Lt/Rt 2-channel downmix, Dolby Surround compatible.
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
AVBufferRef * av_buffer_alloc(size_t size)
Allocate an AVBuffer of the given size using av_malloc().
Definition buffer.c:77
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition dict.c:60
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition dict.c:86
#define AVERROR(e)
Definition error.h:45
AVFrameSideData * av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd, enum AVFrameSideDataType type, size_t size, unsigned int flags)
Add new side data entry to an array.
Definition side_data.c:204
void av_frame_side_data_free(AVFrameSideData ***sd, int *nb_sd)
Free all side data entries and their contents, then zeroes out the values which the pointers are poin...
Definition side_data.c:139
#define AV_FRAME_SIDE_DATA_FLAG_REPLACE
Don't add a new entry if another of the same type exists.
Definition frame.h:1098
#define AV_FRAME_SIDE_DATA_FLAG_NEW_REF
Create a new reference to the passed in buffer instead of taking ownership of it.
Definition frame.h:1103
AVFrameSideData * av_frame_side_data_add(AVFrameSideData ***sd, int *nb_sd, enum AVFrameSideDataType type, AVBufferRef **pbuf, unsigned int flags)
Add a new side data entry to an array from an existing AVBufferRef.
Definition side_data.c:229
void av_frame_side_data_remove_by_props(AVFrameSideData ***sd, int *nb_sd, int props)
Remove and free all side data instances that match any of the given side data properties.
Definition side_data.c:123
void av_frame_side_data_remove(AVFrameSideData ***sd, int *nb_sd, enum AVFrameSideDataType type)
Remove and free all side data instances of the given type from an array.
Definition side_data.c:108
const AVSideDataDescriptor * av_frame_side_data_desc(enum AVFrameSideDataType type)
Definition side_data.c:68
int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd, const AVFrameSideData *src, unsigned int flags)
Add a new side data entry to an array based on existing side data, taking a reference towards the con...
Definition side_data.c:254
AVFrameSideDataType
Definition frame.h:49
#define AV_FRAME_SIDE_DATA_FLAG_UNIQUE
Remove existing entries before adding new ones.
Definition frame.h:1093
static const AVFrameSideData * av_frame_side_data_get(AVFrameSideData *const *sd, const int nb_sd, enum AVFrameSideDataType type)
Wrapper around av_frame_side_data_get_c() to workaround the limitation that for any type T the conver...
Definition frame.h:1196
const char * av_frame_side_data_name(enum AVFrameSideDataType type)
Definition side_data.c:76
@ AV_SIDE_DATA_PROP_GLOBAL
The side data type can be used in stream-global structures.
Definition frame.h:341
@ AV_FRAME_DATA_SPHERICAL
The data represents the AVSphericalMapping structure defined in libavutil/spherical....
Definition frame.h:131
@ AV_FRAME_DATA_DISPLAYMATRIX
This side data contains a 3x3 transformation matrix describing an affine transformation that needs to...
Definition frame.h:85
@ AV_FRAME_DATA_SEI_UNREGISTERED
User data unregistered metadata associated with a video frame.
Definition frame.h:178
@ AV_FRAME_DATA_DYNAMIC_HDR_PLUS
HDR dynamic metadata associated with a video frame.
Definition frame.h:159
@ AV_FRAME_DATA_MASTERING_DISPLAY_METADATA
Mastering display metadata associated with a video frame.
Definition frame.h:120
@ AV_FRAME_DATA_DOWNMIX_INFO
Metadata relevant to a downmix procedure.
Definition frame.h:73
@ AV_FRAME_DATA_STEREO3D
Stereoscopic 3d metadata.
Definition frame.h:64
@ AV_FRAME_DATA_MOTION_VECTORS
Motion vectors exported by some codecs (on demand through the export_mvs flag set in the libavcodec A...
Definition frame.h:97
void av_display_rotation_set(int32_t matrix[9], double angle)
Initialize a transformation matrix describing a pure clockwise rotation by the specified angle (in de...
Definition display.c:51
AVSphericalMapping * av_spherical_alloc(size_t *size)
Allocate a AVSphericalVideo structure and initialize its fields to default values.
Definition spherical.c:26
@ AV_SPHERICAL_EQUIRECTANGULAR
Video represents a sphere mapped on a flat surface using equirectangular projection.
Definition spherical.h:52
AVStereo3D * av_stereo3d_alloc_size(size_t *size)
Allocate an AVStereo3D structure and set its fields to default values.
Definition stereo3d.c:39
@ AV_STEREO3D_SIDEBYSIDE
Views are next to each other.
Definition stereo3d.h:64
@ AV_PRIMARY_EYE_LEFT
Left eye.
Definition stereo3d.h:183
@ AV_STEREO3D_VIEW_PACKED
Frame contains two packed views.
Definition stereo3d.h:153
cl_device_type type
static int bad(InterplayACMContext *s, unsigned ind, unsigned col)
Stereoscopic video.
Utility Preprocessor macros.
Memory handling functions.
const char * name
Definition qsvenc.c:142
#define FF_ARRAY_ELEMS(a)
#define snprintf
Definition snprintf.h:34
Spherical video.
A reference to a data buffer.
Definition buffer.h:82
uint8_t * data
The data buffer.
Definition buffer.h:90
char * value
Definition dict.h:92
This structure describes optional metadata relevant to a downmix procedure.
Structure to hold side data for an AVFrame.
Definition frame.h:327
AVDictionary * metadata
Definition frame.h:331
size_t size
Definition frame.h:330
uint8_t * data
Definition frame.h:329
This struct describes the properties of a side data type.
Definition frame.h:375
unsigned props
Side data property flags, a combination of AVSideDataProps values.
Definition frame.h:384
const char * name
Human-readable side data description.
Definition frame.h:379
This structure describes how to handle spherical videos, outlining information about projection,...
Definition spherical.h:100
enum AVSphericalProjection projection
Projection type.
Definition spherical.h:104
int32_t yaw
Rotation around the up vector [-180, 180].
Definition spherical.h:144
Stereo 3D type: this structure describes how two videos are packed within a single video surface,...
Definition stereo3d.h:203
enum AVStereo3DType type
How views are packed within the video.
Definition stereo3d.h:207
uint32_t baseline
The distance between the centres of the lenses of the camera system, in micrometers.
Definition stereo3d.h:228
enum AVStereo3DPrimaryEye primary_eye
Which eye is the primary eye when rendering in 2D.
Definition stereo3d.h:222
enum AVStereo3DView view
Determines which views are packed.
Definition stereo3d.h:217
int nb_sd
Definition side_data.c:37
AVFrameSideData ** sd
Definition side_data.c:36
#define av_free(p)
static const char * entry_marker(const AVFrameSideData *sd)
Definition side_data.c:74
static AVFrameSideData * new_entry(Set *s, enum AVFrameSideDataType type, const void *payload, size_t size, int marker)
Definition side_data.c:53
int main(void)
Definition side_data.c:110
static void print_lookup(const char *label, const Set *s, const enum AVFrameSideDataType *types, size_t nb_types)
Definition side_data.c:94
static void print_set(const char *label, const Set *s)
Definition side_data.c:81
static AVBufferRef * payload_buffer(const void *payload, size_t size)
Definition side_data.c:65
static void set_marker(AVFrameSideData *sd, int marker)
Definition side_data.c:45
static void set(uint8_t *a[], int ch, int index, int ch_count, enum AVSampleFormat f, double v)
Definition swresample.c:55
int size