| Line | Branch | Exec | Source |
|---|---|---|---|
| 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" | ||
| 26 | #include "libavutil/downmix_info.h" | ||
| 27 | #include "libavutil/error.h" | ||
| 28 | #include "libavutil/frame.h" | ||
| 29 | #include "libavutil/macros.h" | ||
| 30 | #include "libavutil/mem.h" | ||
| 31 | #include "libavutil/motion_vector.h" | ||
| 32 | #include "libavutil/spherical.h" | ||
| 33 | #include "libavutil/stereo3d.h" | ||
| 34 | |||
| 35 | typedef struct Set { | ||
| 36 | AVFrameSideData **sd; | ||
| 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. */ | ||
| 45 | 8 | static void set_marker(AVFrameSideData *sd, int marker) | |
| 46 | { | ||
| 47 | char value[16]; | ||
| 48 | |||
| 49 | 8 | snprintf(value, sizeof(value), "%d", marker); | |
| 50 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
|
8 | av_assert0(av_dict_set(&sd->metadata, "marker", value, 0) >= 0); |
| 51 | 8 | } | |
| 52 | |||
| 53 | 5 | static AVFrameSideData *new_entry(Set *s, enum AVFrameSideDataType type, | |
| 54 | const void *payload, size_t size, int marker) | ||
| 55 | { | ||
| 56 | 5 | AVFrameSideData *sd = av_frame_side_data_new(&s->sd, &s->nb_sd, type, | |
| 57 | size, 0); | ||
| 58 | |||
| 59 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | av_assert0(sd && sd->size == size); |
| 60 | 5 | memcpy(sd->data, payload, size); | |
| 61 | 5 | set_marker(sd, marker); | |
| 62 | 5 | return sd; | |
| 63 | } | ||
| 64 | |||
| 65 | 3 | static AVBufferRef *payload_buffer(const void *payload, size_t size) | |
| 66 | { | ||
| 67 | 3 | AVBufferRef *buf = av_buffer_alloc(size); | |
| 68 | |||
| 69 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | av_assert0(buf); |
| 70 | 3 | memcpy(buf->data, payload, size); | |
| 71 | 3 | return buf; | |
| 72 | } | ||
| 73 | |||
| 74 | 15 | static const char *entry_marker(const AVFrameSideData *sd) | |
| 75 | { | ||
| 76 | 15 | const AVDictionaryEntry *e = av_dict_get(sd->metadata, "marker", NULL, 0); | |
| 77 | |||
| 78 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | return e ? e->value : "none"; |
| 79 | } | ||
| 80 | |||
| 81 | 1 | static void print_set(const char *label, const Set *s) | |
| 82 | { | ||
| 83 | 1 | printf("%s: n=%d\n", label, s->nb_sd); | |
| 84 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
|
6 | for (int i = 0; i < s->nb_sd; i++) |
| 85 | 5 | printf(" [%d] %s marker=%s\n", i, | |
| 86 | 5 | av_frame_side_data_name(s->sd[i]->type), | |
| 87 | 5 | entry_marker(s->sd[i])); | |
| 88 | 1 | } | |
| 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. */ | ||
| 94 | 3 | static void print_lookup(const char *label, const Set *s, | |
| 95 | const enum AVFrameSideDataType *types, size_t nb_types) | ||
| 96 | { | ||
| 97 | 3 | printf("%s: n=%d\n", label, s->nb_sd); | |
| 98 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 3 times.
|
21 | for (size_t i = 0; i < nb_types; i++) { |
| 99 | const AVFrameSideData *sd = | ||
| 100 | 18 | av_frame_side_data_get(s->sd, s->nb_sd, types[i]); | |
| 101 | 18 | const char *name = av_frame_side_data_name(types[i]); | |
| 102 | |||
| 103 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 11 times.
|
18 | if (sd) |
| 104 | 7 | printf(" %s: marker=%s\n", name, entry_marker(sd)); | |
| 105 | else | ||
| 106 | 11 | printf(" %s: absent\n", name); | |
| 107 | } | ||
| 108 | 3 | } | |
| 109 | |||
| 110 | 1 | int main(void) | |
| 111 | { | ||
| 112 | /* desc / name accessors. */ | ||
| 113 | 1 | 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 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
|
6 | for (size_t i = 0; i < FF_ARRAY_ELEMS(known); i++) { |
| 122 | 5 | const AVSideDataDescriptor *d = av_frame_side_data_desc(known[i]); | |
| 123 | 5 | 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 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
10 | printf(" type=%d name_match=%s props=0x%x\n", known[i], |
| 127 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | 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 | { | ||
| 133 | 1 | enum AVFrameSideDataType bad = (enum AVFrameSideDataType)-1; | |
| 134 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
2 | printf(" invalid type desc=%s name=%s\n", |
| 135 | 1 | av_frame_side_data_desc(bad) ? "non-null" : "null", | |
| 136 | 1 | 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 | 1 | AVStereo3D *stereo3d = av_stereo3d_alloc_size(&stereo3d_size); | |
| 143 | 1 | AVSphericalMapping *spherical = av_spherical_alloc(&spherical_size); | |
| 144 | /* 16 bytes of uuid_iso_iec_11578 followed by user_data_payload_byte. */ | ||
| 145 | 1 | 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 | 1 | 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 | 1 | 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 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | av_assert0(stereo3d && spherical); |
| 171 | |||
| 172 | 1 | stereo3d->type = AV_STEREO3D_SIDEBYSIDE; | |
| 173 | 1 | stereo3d->view = AV_STEREO3D_VIEW_PACKED; | |
| 174 | 1 | stereo3d->primary_eye = AV_PRIMARY_EYE_LEFT; | |
| 175 | 1 | stereo3d->baseline = 65000; | |
| 176 | |||
| 177 | 1 | spherical->projection = AV_SPHERICAL_EQUIRECTANGULAR; | |
| 178 | 1 | spherical->yaw = 90 << 16; | |
| 179 | |||
| 180 | 1 | av_display_rotation_set(displaymatrix, 90.0); | |
| 181 | |||
| 182 | /* Populate a set with several types, one of them MULTI. */ | ||
| 183 | 1 | Set set = { 0 }; | |
| 184 | 1 | new_entry(&set, AV_FRAME_DATA_STEREO3D, stereo3d, stereo3d_size, 100); | |
| 185 | 1 | new_entry(&set, AV_FRAME_DATA_DOWNMIX_INFO, &downmix, sizeof(downmix), | |
| 186 | 200); | ||
| 187 | 1 | new_entry(&set, AV_FRAME_DATA_SEI_UNREGISTERED, udu, sizeof(udu), 1); | |
| 188 | 1 | udu[sizeof(udu) - 1] = '2'; | |
| 189 | 1 | new_entry(&set, AV_FRAME_DATA_SEI_UNREGISTERED, udu, sizeof(udu), 2); | |
| 190 | 1 | 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 | 1 | print_set("\nInitial set", &set); | |
| 194 | |||
| 195 | /* Types probed by every dump below. */ | ||
| 196 | static const enum AVFrameSideDataType probed[] = { | ||
| 197 | AV_FRAME_DATA_STEREO3D, | ||
| 198 | AV_FRAME_DATA_DOWNMIX_INFO, | ||
| 199 | AV_FRAME_DATA_SEI_UNREGISTERED, | ||
| 200 | AV_FRAME_DATA_SPHERICAL, | ||
| 201 | AV_FRAME_DATA_DISPLAYMATRIX, | ||
| 202 | AV_FRAME_DATA_MOTION_VECTORS, | ||
| 203 | }; | ||
| 204 | |||
| 205 | /* get / get_c: present and missing types. */ | ||
| 206 | 1 | printf("\nTesting av_frame_side_data_get()\n"); | |
| 207 | { | ||
| 208 | const AVFrameSideData *got = | ||
| 209 | 1 | av_frame_side_data_get(set.sd, set.nb_sd, AV_FRAME_DATA_STEREO3D); | |
| 210 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
3 | printf(" stereo3d: %s marker=%s payload_match=%s\n", |
| 211 | 1 | got ? "found" : "missing", got ? entry_marker(got) : "none", | |
| 212 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | got && got->size == stereo3d_size && |
| 213 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | !memcmp(got->data, stereo3d, stereo3d_size) ? "yes" : "no"); |
| 214 | 1 | got = av_frame_side_data_get(set.sd, set.nb_sd, | |
| 215 | AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); | ||
| 216 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | printf(" mastering (absent): %s\n", got ? "FAIL" : "null"); |
| 217 | } | ||
| 218 | |||
| 219 | /* remove by type clears all matching entries (including duplicates). */ | ||
| 220 | 1 | printf("\nTesting av_frame_side_data_remove()\n"); | |
| 221 | 1 | av_frame_side_data_remove(&set.sd, &set.nb_sd, | |
| 222 | AV_FRAME_DATA_SEI_UNREGISTERED); | ||
| 223 | 1 | 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 | 1 | printf("\nTesting av_frame_side_data_remove_by_props()\n"); | |
| 228 | 1 | av_frame_side_data_remove_by_props(&set.sd, &set.nb_sd, | |
| 229 | AV_SIDE_DATA_PROP_GLOBAL); | ||
| 230 | 1 | 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 | 1 | printf("\nTesting av_frame_side_data_clone()\n"); | |
| 235 | 1 | Set dst = { 0 }; | |
| 236 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (set.nb_sd > 0) { |
| 237 | 1 | int ret = av_frame_side_data_clone(&dst.sd, &dst.nb_sd, | |
| 238 | 1 | set.sd[0], 0); | |
| 239 | 1 | printf(" clone into empty: ret=%d nb=%d marker=%s\n", ret, dst.nb_sd, | |
| 240 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | dst.nb_sd ? entry_marker(dst.sd[0]) : "none"); |
| 241 | |||
| 242 | /* Same type again without REPLACE must fail with EEXIST. */ | ||
| 243 | 1 | ret = av_frame_side_data_clone(&dst.sd, &dst.nb_sd, set.sd[0], 0); | |
| 244 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | 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 | 1 | ret = av_frame_side_data_clone(&dst.sd, &dst.nb_sd, set.sd[0], | |
| 249 | AV_FRAME_SIDE_DATA_FLAG_REPLACE); | ||
| 250 | 1 | printf(" clone REPLACE: ret=%d nb=%d\n", ret, dst.nb_sd); | |
| 251 | |||
| 252 | /* Invalid args. */ | ||
| 253 | 1 | ret = av_frame_side_data_clone(NULL, &dst.nb_sd, set.sd[0], 0); | |
| 254 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | 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 | 1 | printf("\nTesting av_frame_side_data_add()\n"); | |
| 260 | { | ||
| 261 | 1 | AVBufferRef *buf = payload_buffer(displaymatrix, sizeof(displaymatrix)); | |
| 262 | |||
| 263 | AVFrameSideData *sd_added = | ||
| 264 | 1 | av_frame_side_data_add(&dst.sd, &dst.nb_sd, | |
| 265 | AV_FRAME_DATA_DISPLAYMATRIX, | ||
| 266 | &buf, AV_FRAME_SIDE_DATA_FLAG_UNIQUE); | ||
| 267 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | printf(" add (move): added=%s pbuf_nulled=%s\n", |
| 268 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | sd_added ? "yes" : "no", buf == NULL ? "yes" : "no"); |
| 269 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (sd_added) |
| 270 | 1 | set_marker(sd_added, 999); | |
| 271 | |||
| 272 | /* NEW_REF: the caller retains its reference. */ | ||
| 273 | 1 | AVBufferRef *keep = payload_buffer(mvs, sizeof(mvs)); | |
| 274 | 1 | sd_added = av_frame_side_data_add(&dst.sd, &dst.nb_sd, | |
| 275 | AV_FRAME_DATA_MOTION_VECTORS, &keep, | ||
| 276 | AV_FRAME_SIDE_DATA_FLAG_NEW_REF); | ||
| 277 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
2 | printf(" add (NEW_REF): added=%s caller_ref_kept=%s nb_mvs=%d\n", |
| 278 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | sd_added ? "yes" : "no", keep ? "yes" : "no", |
| 279 | 1 | sd_added ? (int)(sd_added->size / sizeof(AVMotionVector)) : -1); | |
| 280 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (sd_added) |
| 281 | 1 | set_marker(sd_added, 42); | |
| 282 | 1 | av_buffer_unref(&keep); | |
| 283 | |||
| 284 | /* REPLACE on existing entry: same type, payload swaps in place. */ | ||
| 285 | int32_t replacement[9]; | ||
| 286 | 1 | av_display_rotation_set(replacement, 180.0); | |
| 287 | 1 | AVBufferRef *repl = payload_buffer(replacement, sizeof(replacement)); | |
| 288 | 1 | sd_added = av_frame_side_data_add(&dst.sd, &dst.nb_sd, | |
| 289 | AV_FRAME_DATA_DISPLAYMATRIX, &repl, | ||
| 290 | AV_FRAME_SIDE_DATA_FLAG_REPLACE); | ||
| 291 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (sd_added) |
| 292 | 1 | set_marker(sd_added, 1234); | |
| 293 | { | ||
| 294 | const AVFrameSideData *after = | ||
| 295 | 1 | av_frame_side_data_get(dst.sd, dst.nb_sd, | |
| 296 | AV_FRAME_DATA_DISPLAYMATRIX); | ||
| 297 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
3 | printf(" add (REPLACE existing): added=%s marker=%s" |
| 298 | " payload_match=%s\n", | ||
| 299 | sd_added ? "yes" : "no", | ||
| 300 | 1 | after ? entry_marker(after) : "none", | |
| 301 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | after && after->size == sizeof(replacement) && |
| 302 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | !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 | 1 | printf("\nTesting av_frame_side_data_clone() UNIQUE\n"); | |
| 310 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (set.nb_sd > 0) { |
| 311 | 1 | int before = dst.nb_sd; | |
| 312 | 1 | int ret = av_frame_side_data_clone(&dst.sd, &dst.nb_sd, set.sd[0], | |
| 313 | AV_FRAME_SIDE_DATA_FLAG_UNIQUE); | ||
| 314 | 1 | printf(" clone UNIQUE: ret=%d before=%d after=%d\n", | |
| 315 | ret, before, dst.nb_sd); | ||
| 316 | } | ||
| 317 | |||
| 318 | 1 | print_lookup("\nFinal dst", &dst, probed, FF_ARRAY_ELEMS(probed)); | |
| 319 | |||
| 320 | 1 | av_frame_side_data_free(&dst.sd, &dst.nb_sd); | |
| 321 | 1 | av_frame_side_data_free(&set.sd, &set.nb_sd); | |
| 322 | 1 | printf("\nfree: set_nb=%d dst_nb=%d\n", set.nb_sd, dst.nb_sd); | |
| 323 | |||
| 324 | 1 | av_free(stereo3d); | |
| 325 | 1 | av_free(spherical); | |
| 326 | |||
| 327 | 1 | return 0; | |
| 328 | } | ||
| 329 |