tools/sofa2wavs: fix build on Windows
[ffmpeg.git] / libavformat / apv.c
1 /*
2 * APV helper functions for muxers
3 * Copyright (c) 2025 Dawid Kozinski <d.kozinski@samsung.com>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "libavutil/avassert.h"
23 #include "libavutil/intreadwrite.h"
24 #include "libavutil/mem.h"
25
26 #include "apv.h"
27 #include "cbs.h"
28 #include "avformat.h"
29 #include "avio.h"
30 #include "avio_internal.h"
31 #include "libavcodec/cbs_apv.h"
32 #include "libavcodec/packet.h"
33
34 typedef struct APVDecoderFrameInfo {
35 uint8_t color_description_present_flag; // 1 bit
36
37 // The variable indicates whether the capture_time_distance value in the APV bitstream's frame header should be ignored during playback.
38 // If capture_time_distance_ignored is set to true, the capture_time_distance information will not be utilized,
39 // and timing information for playback should be calculated using an alternative method.
40 // If set to false, the capture_time_distance value will be used as is from the frame header.
41 // It is recommended to set this variable to true, allowing the use of MP4 timestamps for playback and recording,
42 // which enables the conventional compression and playback methods based on the timestamp table defined by the ISO-based file format.
43 uint8_t capture_time_distance_ignored; // 1-bit
44
45 uint8_t profile_idc; // 8 bits
46 uint8_t level_idc; // 8 bits
47 uint8_t band_idc; // 8 bits
48 uint32_t frame_width; // 32 bits
49 uint32_t frame_height; // 32 bits
50 uint8_t chroma_format_idc; // 4 bits
51 uint8_t bit_depth_minus8; // 4 bits
52 uint8_t capture_time_distance; // 8 bits
53
54 // if (color_description_present_flag)
55 uint8_t color_primaries; // 8 bits
56 uint8_t transfer_characteristics; // 8 bits
57 uint8_t matrix_coefficients; // 8 bits
58 uint8_t full_range_flag; // 1 bit
59 } APVDecoderFrameInfo;
60
61 typedef struct APVDecoderConfigurationEntry {
62 uint8_t pbu_type; // 8 bits
63 uint8_t number_of_frame_info; // 8 bits
64
65 APVDecoderFrameInfo *frame_info; // An array of size number_of_frame_info storing elements of type APVDecoderFrameInfo*
66 } APVDecoderConfigurationEntry;
67
68 // ISOBMFF binding for APV
69 // @see https://github.com/openapv/openapv/blob/main/readme/apv_isobmff.md
70 typedef struct APVDecoderConfigurationRecord {
71 uint8_t configurationVersion; // 8 bits
72 uint8_t number_of_configuration_entry; // 8 bits
73
74 APVDecoderConfigurationEntry *configuration_entry; // table of size number_of_configuration_entry
75
76 CodedBitstreamContext *cbc;
77 CodedBitstreamFragment frag;
78 } APVDecoderConfigurationRecord;
79
80 void ff_isom_write_apvc(AVIOContext *pb, const APVDecoderConfigurationRecord *apvc, void *logctx)
81 {
82 av_log(logctx, AV_LOG_TRACE, "configurationVersion: %"PRIu8"\n",
83 apvc->configurationVersion);
84
85 av_log(logctx, AV_LOG_TRACE, "number_of_configuration_entry: %"PRIu8"\n",
86 apvc->number_of_configuration_entry);
87
88 for (int i = 0; i < apvc->number_of_configuration_entry; i++) {
89 const APVDecoderConfigurationEntry *configuration_entry = &apvc->configuration_entry[i];
90
91 av_log(logctx, AV_LOG_TRACE, "pbu_type: %"PRIu8"\n",
92 configuration_entry->pbu_type);
93
94 av_log(logctx, AV_LOG_TRACE, "number_of_frame_info: %"PRIu8"\n",
95 configuration_entry->number_of_frame_info);
96
97 for (int j = 0; j < configuration_entry->number_of_frame_info; j++) {
98 const APVDecoderFrameInfo *frame_info = &configuration_entry->frame_info[j];
99
100 av_log(logctx, AV_LOG_TRACE, "color_description_present_flag: %"PRIu8"\n",
101 frame_info->color_description_present_flag);
102
103 av_log(logctx, AV_LOG_TRACE, "capture_time_distance_ignored: %"PRIu8"\n",
104 frame_info->capture_time_distance_ignored);
105
106 av_log(logctx, AV_LOG_TRACE, "profile_idc: %"PRIu8"\n",
107 frame_info->profile_idc);
108
109 av_log(logctx, AV_LOG_TRACE, "level_idc: %"PRIu8"\n",
110 frame_info->level_idc);
111
112 av_log(logctx, AV_LOG_TRACE, "band_idc: %"PRIu8"\n",
113 frame_info->band_idc);
114
115 av_log(logctx, AV_LOG_TRACE, "frame_width: %"PRIu32"\n",
116 frame_info->frame_width);
117
118 av_log(logctx, AV_LOG_TRACE, "frame_height: %"PRIu32"\n",
119 frame_info->frame_height);
120
121 av_log(logctx, AV_LOG_TRACE, "chroma_format_idc: %"PRIu8"\n",
122 frame_info->chroma_format_idc);
123
124 av_log(logctx, AV_LOG_TRACE, "bit_depth_minus8: %"PRIu8"\n",
125 frame_info->bit_depth_minus8);
126
127 av_log(logctx, AV_LOG_TRACE, "capture_time_distance: %"PRIu8"\n",
128 frame_info->capture_time_distance);
129
130 if (frame_info->color_description_present_flag) {
131 av_log(logctx, AV_LOG_TRACE, "color_primaries: %"PRIu8"\n",
132 frame_info->color_primaries);
133
134 av_log(logctx, AV_LOG_TRACE, "transfer_characteristics: %"PRIu8"\n",
135 frame_info->transfer_characteristics);
136
137 av_log(logctx, AV_LOG_TRACE, "matrix_coefficients: %"PRIu8"\n",
138 frame_info->matrix_coefficients);
139
140 av_log(logctx, AV_LOG_TRACE, "full_range_flag: %"PRIu8"\n",
141 frame_info->full_range_flag);
142 }
143 }
144 }
145
146 /* unsigned int(8) configurationVersion = 1; */
147 avio_w8(pb, apvc->configurationVersion);
148
149 avio_w8(pb, apvc->number_of_configuration_entry);
150
151 for (int i = 0; i < apvc->number_of_configuration_entry; i++) {
152 const APVDecoderConfigurationEntry *configuration_entry = &apvc->configuration_entry[i];
153
154 avio_w8(pb, configuration_entry->pbu_type);
155 avio_w8(pb, configuration_entry->number_of_frame_info);
156
157 for (int j = 0; j < configuration_entry->number_of_frame_info; j++) {
158 const APVDecoderFrameInfo *frame_info = &configuration_entry->frame_info[j];
159
160 /* reserved_zero_6bits
161 * unsigned int(1) color_description_present_flag
162 * unsigned int(1) capture_time_distance_ignored */
163 avio_w8(pb, frame_info->color_description_present_flag << 1 |
164 frame_info->capture_time_distance_ignored);
165
166 /* unsigned int(8) profile_idc */
167 avio_w8(pb, frame_info->profile_idc);
168
169 /* unsigned int(8) level_idc */
170 avio_w8(pb, frame_info->level_idc);
171
172 /* unsigned int(8) band_idc */
173 avio_w8(pb, frame_info->band_idc);
174
175 /* unsigned int(32) frame_width_minus1 */
176 avio_wb32(pb, frame_info->frame_width);
177
178 /* unsigned int(32) frame_height_minus1 */
179 avio_wb32(pb, frame_info->frame_height);
180
181 /* unsigned int(4) chroma_format_idc */
182 /* unsigned int(4) bit_depth_minus8 */
183 avio_w8(pb, (frame_info->chroma_format_idc << 4) |
184 frame_info->bit_depth_minus8);
185
186 /* unsigned int(8) capture_time_distance */
187 avio_w8(pb, frame_info->capture_time_distance);
188
189 if (frame_info->color_description_present_flag) {
190 /* unsigned int(8) color_primaries */
191 avio_w8(pb, frame_info->color_primaries);
192
193 /* unsigned int(8) transfer_characteristics */
194 avio_w8(pb, frame_info->transfer_characteristics);
195
196 /* unsigned int(8) matrix_coefficients */
197 avio_w8(pb, frame_info->matrix_coefficients);
198
199 /* unsigned int(1) full_range_flag
200 * reserved_zero_7bits */
201 avio_w8(pb, frame_info->full_range_flag << 7);
202 }
203 }
204 }
205 }
206
207 static const CodedBitstreamUnitType decompose_unit_types[] = {
208 APV_PBU_PRIMARY_FRAME, APV_PBU_NON_PRIMARY_FRAME,
209 APV_PBU_PREVIEW_FRAME, APV_PBU_DEPTH_FRAME, APV_PBU_ALPHA_FRAME
210 };
211
212 static int apv_add_configuration_entry(APVDecoderConfigurationRecord *apvc, int pbu_type)
213 {
214 APVDecoderConfigurationEntry *temp;
215
216 av_assert0(apvc->number_of_configuration_entry < FF_ARRAY_ELEMS(decompose_unit_types));
217 temp = av_realloc_array(apvc->configuration_entry,
218 apvc->number_of_configuration_entry + 1, sizeof(*apvc->configuration_entry));
219
220 if (!temp)
221 return AVERROR(ENOMEM);
222
223 apvc->configuration_entry = temp;
224 memset(&apvc->configuration_entry[apvc->number_of_configuration_entry], 0, sizeof(*apvc->configuration_entry));
225 apvc->configuration_entry[apvc->number_of_configuration_entry].pbu_type = pbu_type;
226 apvc->number_of_configuration_entry++;
227
228 return 0;
229 }
230
231 static int apv_add_frameinfo(APVDecoderConfigurationEntry *configuration_entry,
232 const APVDecoderFrameInfo *frame_info)
233 {
234 APVDecoderFrameInfo *temp;
235
236 if (configuration_entry->number_of_frame_info >= UINT8_MAX)
237 return AVERROR(EINVAL);
238
239 temp = av_realloc_array(configuration_entry->frame_info,
240 configuration_entry->number_of_frame_info + 1, sizeof(*configuration_entry->frame_info));
241
242 if (!temp)
243 return AVERROR(ENOMEM);
244
245 configuration_entry->frame_info = temp;
246 memcpy(&configuration_entry->frame_info[configuration_entry->number_of_frame_info], frame_info, sizeof(*frame_info));
247 configuration_entry->number_of_frame_info++;
248
249 return 0;
250 }
251
252 int ff_isom_parse_apvc(APVDecoderConfigurationRecord *apvc,
253 const AVPacket *pkt, void *logctx)
254 {
255 APVDecoderFrameInfo frame_info;
256 int ret;
257
258 if (pkt->size < 8 || AV_RB32(pkt->data) != APV_SIGNATURE)
259 /* We can't write a valid apvC from the provided data */
260 return AVERROR_INVALIDDATA;
261
262 ret = ff_lavf_cbs_read(apvc->cbc, &apvc->frag, pkt->buf, pkt->data, pkt->size);
263 if (ret < 0) {
264 av_log(logctx, AV_LOG_ERROR, "Failed to parse access unit.\n");
265 return ret;
266 }
267
268 memset(&frame_info, 0, sizeof(frame_info));
269 frame_info.capture_time_distance_ignored = 1;
270
271 for (int i = 0; i < apvc->frag.nb_units; i++) {
272 const CodedBitstreamUnit *pbu = &apvc->frag.units[i];
273 int j;
274
275 switch (pbu->type) {
276 case APV_PBU_PRIMARY_FRAME:
277 case APV_PBU_NON_PRIMARY_FRAME:
278 case APV_PBU_PREVIEW_FRAME:
279 case APV_PBU_DEPTH_FRAME:
280 case APV_PBU_ALPHA_FRAME:
281 break;
282 default:
283 continue;
284 };
285
286 const APVRawFrame *frame = pbu->content;
287 const APVRawFrameHeader *header = &frame->frame_header;
288 const APVRawFrameInfo *info = &header->frame_info;
289 int bit_depth = info->bit_depth_minus8 + 8;
290
291 if (bit_depth < 8 || bit_depth > 16 || bit_depth % 2)
292 break;
293
294 frame_info.profile_idc = info->profile_idc;
295 frame_info.level_idc = info->level_idc;
296 frame_info.band_idc = info->band_idc;
297
298 frame_info.frame_width = info->frame_width;
299 frame_info.frame_height =info->frame_height;
300 frame_info.chroma_format_idc = info->chroma_format_idc;
301 frame_info.bit_depth_minus8 = info->bit_depth_minus8;
302 frame_info.capture_time_distance = info->capture_time_distance;
303
304 frame_info.color_description_present_flag = header->color_description_present_flag;
305 if (frame_info.color_description_present_flag) {
306 frame_info.color_primaries = header->color_primaries;
307 frame_info.transfer_characteristics = header->transfer_characteristics;
308 frame_info.matrix_coefficients = header->matrix_coefficients;
309 frame_info.full_range_flag = header->full_range_flag;
310 } else {
311 frame_info.color_primaries =
312 frame_info.transfer_characteristics =
313 frame_info.matrix_coefficients =
314 frame_info.full_range_flag = 0;
315 }
316
317 for (j = 0; j < apvc->number_of_configuration_entry; j++) {
318 int k;
319
320 if (apvc->configuration_entry[j].pbu_type != pbu->type)
321 continue;
322
323 for (k = 0; k < apvc->configuration_entry[j].number_of_frame_info; k++) {
324 if (!memcmp(&apvc->configuration_entry[j].frame_info[k], &frame_info, sizeof(frame_info)))
325 break;
326 }
327 if (k == apvc->configuration_entry[j].number_of_frame_info) {
328 ret = apv_add_frameinfo(&apvc->configuration_entry[j], &frame_info);
329 if (ret < 0)
330 goto end;
331 }
332 break;
333 }
334
335 if (j == apvc->number_of_configuration_entry) {
336 ret = apv_add_configuration_entry(apvc, pbu->type);
337 if (ret < 0)
338 goto end;
339 ret = apv_add_frameinfo(&apvc->configuration_entry[j], &frame_info);
340 if (ret < 0)
341 goto end;
342 }
343 }
344
345 ret = 0;
346 end:
347 ff_lavf_cbs_fragment_reset(&apvc->frag);
348
349 return ret;
350 }
351
352 int ff_isom_init_apvc(APVDecoderConfigurationRecord **papvc, void *logctx)
353 {
354 APVDecoderConfigurationRecord *apvc = av_mallocz(sizeof(*apvc));
355
356 if (!apvc)
357 return AVERROR(ENOMEM);
358
359 int ret = ff_lavf_cbs_init(&apvc->cbc, AV_CODEC_ID_APV, logctx);
360 if (ret < 0) {
361 av_freep(&apvc);
362 return ret;
363 }
364
365 apvc->cbc->decompose_unit_types = decompose_unit_types;
366 apvc->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types);
367
368 apvc->configurationVersion = 1;
369
370 *papvc = apvc;
371
372 return 0;
373 }
374
375 void ff_isom_close_apvc(APVDecoderConfigurationRecord **papvc)
376 {
377 APVDecoderConfigurationRecord *apvc = *papvc;
378
379 if (!apvc)
380 return;
381
382 for (int i = 0; i < apvc->number_of_configuration_entry; i++)
383 av_freep(&apvc->configuration_entry[i].frame_info);
384 av_freep(&apvc->configuration_entry);
385
386 ff_lavf_cbs_fragment_free(&apvc->frag);
387 ff_lavf_cbs_close(&apvc->cbc);
388
389 av_freep(papvc);
390 }