FFmpeg
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
apv.c
Go to the documentation of this file.
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 {
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.
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
60 
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*
67 
68 // ISOBMFF binding for APV
69 // @see https://github.com/openapv/openapv/blob/main/readme/apv_isobmff.md
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 
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",
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 
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 
210 };
211 
213 {
215 
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));
227 
228  return 0;
229 }
230 
231 static int apv_add_frameinfo(APVDecoderConfigurationEntry *configuration_entry,
233 {
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 
253  const AVPacket *pkt, void *logctx)
254 {
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) {
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) {
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;
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 
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 
367 
368  apvc->configurationVersion = 1;
369 
370  *papvc = apvc;
371 
372  return 0;
373 }
374 
376 {
377  APVDecoderConfigurationRecord *apvc = *papvc;
378 
379  if (!apvc)
380  return;
381 
382  for (int i = 0; i < apvc->number_of_configuration_entry; i++)
385 
386  ff_lavf_cbs_fragment_free(&apvc->frag);
387  ff_lavf_cbs_close(&apvc->cbc);
388 
389  av_freep(papvc);
390 }
frame_info
static int FUNC() frame_info(CodedBitstreamContext *ctx, RWContext *rw, APVRawFrameInfo *current)
Definition: cbs_apv_syntax_template.c:63
APVDecoderFrameInfo::band_idc
uint8_t band_idc
Definition: apv.c:47
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
APV_PBU_NON_PRIMARY_FRAME
@ APV_PBU_NON_PRIMARY_FRAME
Definition: apv.h:28
APVDecoderFrameInfo::level_idc
uint8_t level_idc
Definition: apv.c:46
CodedBitstreamUnit::content
void * content
Pointer to the decomposed form of this unit.
Definition: cbs.h:114
AVPacket::data
uint8_t * data
Definition: packet.h:552
CodedBitstreamContext
Context structure for coded bitstream operations.
Definition: cbs.h:226
cbs.h
APVDecoderFrameInfo::bit_depth_minus8
uint8_t bit_depth_minus8
Definition: apv.c:51
decompose_unit_types
static const CodedBitstreamUnitType decompose_unit_types[]
Definition: apv.c:207
CodedBitstreamUnit::type
CodedBitstreamUnitType type
Codec-specific type of this unit.
Definition: cbs.h:81
ff_isom_write_apvc
void ff_isom_write_apvc(AVIOContext *pb, const APVDecoderConfigurationRecord *apvc, void *logctx)
Definition: apv.c:80
bit_depth
static void bit_depth(AudioStatsContext *s, const uint64_t *const mask, uint8_t *depth)
Definition: af_astats.c:246
APV_SIGNATURE
#define APV_SIGNATURE
Definition: apv.h:23
APVDecoderFrameInfo::color_description_present_flag
uint8_t color_description_present_flag
Definition: apv.c:35
CodedBitstreamUnit
Coded bitstream unit structure.
Definition: cbs.h:77
apv_add_configuration_entry
static int apv_add_configuration_entry(APVDecoderConfigurationRecord *apvc, int pbu_type)
Definition: apv.c:212
APVDecoderConfigurationRecord
Definition: apv.c:70
CodedBitstreamFragment::units
CodedBitstreamUnit * units
Pointer to an array of units of length nb_units_allocated.
Definition: cbs.h:175
avassert.h
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:236
pkt
AVPacket * pkt
Definition: movenc.c:60
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
CodedBitstreamFragment
Coded bitstream fragment structure, combining one or more units.
Definition: cbs.h:129
APVDecoderFrameInfo::capture_time_distance_ignored
uint8_t capture_time_distance_ignored
Definition: apv.c:43
intreadwrite.h
APVDecoderFrameInfo::matrix_coefficients
uint8_t matrix_coefficients
Definition: apv.c:57
av_realloc_array
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:217
APVRawFrameInfo
Definition: cbs_apv.h:43
info
MIPS optimizations info
Definition: mips.txt:2
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:41
CodedBitstreamUnitType
uint32_t CodedBitstreamUnitType
The codec-specific type of a bitstream unit.
Definition: cbs.h:54
APVDecoderFrameInfo::color_primaries
uint8_t color_primaries
Definition: apv.c:55
APVDecoderConfigurationEntry
Definition: apv.c:61
APVDecoderConfigurationRecord::configuration_entry
APVDecoderConfigurationEntry * configuration_entry
Definition: apv.c:74
APV_PBU_DEPTH_FRAME
@ APV_PBU_DEPTH_FRAME
Definition: apv.h:30
AVPacket::buf
AVBufferRef * buf
A reference to the reference-counted buffer where the packet data is stored.
Definition: packet.h:535
APVDecoderConfigurationRecord::configurationVersion
uint8_t configurationVersion
Definition: apv.c:71
APVDecoderConfigurationRecord::cbc
CodedBitstreamContext * cbc
Definition: apv.c:76
avio_w8
void avio_w8(AVIOContext *s, int b)
Definition: aviobuf.c:179
APVRawFrame
Definition: cbs_apv.h:101
APVDecoderFrameInfo
Definition: apv.c:34
APV_PBU_PRIMARY_FRAME
@ APV_PBU_PRIMARY_FRAME
Definition: apv.h:27
AVIOContext
Bytestream IO Context.
Definition: avio.h:160
AVPacket::size
int size
Definition: packet.h:553
APVRawFrameHeader
Definition: cbs_apv.h:67
avio.h
AV_RB32
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_RB32
Definition: bytestream.h:96
header
static const uint8_t header[24]
Definition: sdr2.c:68
avio_wb32
void avio_wb32(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:365
APVDecoderFrameInfo::transfer_characteristics
uint8_t transfer_characteristics
Definition: apv.c:56
apv.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
avio_internal.h
packet.h
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:256
APVDecoderFrameInfo::frame_width
uint32_t frame_width
Definition: apv.c:48
ret
ret
Definition: filter_design.txt:187
AV_CODEC_ID_APV
@ AV_CODEC_ID_APV
Definition: codec_id.h:332
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:265
ff_isom_close_apvc
void ff_isom_close_apvc(APVDecoderConfigurationRecord **papvc)
Definition: apv.c:375
avformat.h
APVDecoderFrameInfo::capture_time_distance
uint8_t capture_time_distance
Definition: apv.c:52
APVDecoderConfigurationEntry::number_of_frame_info
uint8_t number_of_frame_info
Definition: apv.c:63
ff_isom_parse_apvc
int ff_isom_parse_apvc(APVDecoderConfigurationRecord *apvc, const AVPacket *pkt, void *logctx)
Definition: apv.c:252
APVDecoderConfigurationEntry::pbu_type
uint8_t pbu_type
Definition: apv.c:62
temp
else temp
Definition: vf_mcdeint.c:271
apv_add_frameinfo
static int apv_add_frameinfo(APVDecoderConfigurationEntry *configuration_entry, const APVDecoderFrameInfo *frame_info)
Definition: apv.c:231
mem.h
APV_PBU_ALPHA_FRAME
@ APV_PBU_ALPHA_FRAME
Definition: apv.h:31
APVDecoderFrameInfo::frame_height
uint32_t frame_height
Definition: apv.c:49
AVPacket
This structure stores compressed data.
Definition: packet.h:529
CodedBitstreamContext::nb_decompose_unit_types
int nb_decompose_unit_types
Length of the decompose_unit_types array.
Definition: cbs.h:259
CodedBitstreamContext::decompose_unit_types
const CodedBitstreamUnitType * decompose_unit_types
Array of unit types which should be decomposed when reading.
Definition: cbs.h:255
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
APVDecoderFrameInfo::profile_idc
uint8_t profile_idc
Definition: apv.c:45
ff_isom_init_apvc
int ff_isom_init_apvc(APVDecoderConfigurationRecord **papvc, void *logctx)
Definition: apv.c:352
APVDecoderFrameInfo::full_range_flag
uint8_t full_range_flag
Definition: apv.c:58
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
APVDecoderConfigurationRecord::frag
CodedBitstreamFragment frag
Definition: apv.c:77
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
APV_PBU_PREVIEW_FRAME
@ APV_PBU_PREVIEW_FRAME
Definition: apv.h:29
APVDecoderConfigurationRecord::number_of_configuration_entry
uint8_t number_of_configuration_entry
Definition: apv.c:72
cbs_apv.h
APVDecoderFrameInfo::chroma_format_idc
uint8_t chroma_format_idc
Definition: apv.c:50
APVDecoderConfigurationEntry::frame_info
APVDecoderFrameInfo * frame_info
Definition: apv.c:65
CodedBitstreamFragment::nb_units
int nb_units
Number of units in this fragment.
Definition: cbs.h:160