FFmpeg  4.4
aaxdec.c
Go to the documentation of this file.
1 /*
2  * AAX demuxer
3  * Copyright (c) 2020 Paul B Mahol
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 "avformat.h"
25 #include "internal.h"
26 
27 typedef struct AAXColumn {
30  const char *name;
31  uint32_t offset;
32  int size;
33 } AAXColumn;
34 
35 typedef struct AAXSegment {
36  int64_t start;
37  int64_t end;
38 } AAXSegment;
39 
40 typedef struct AAXContext {
41  int64_t table_size;
42  uint16_t version;
43  int64_t rows_offset;
44  int64_t strings_offset;
45  int64_t data_offset;
46  int64_t name_offset;
47  uint16_t columns;
48  uint16_t row_width;
49  uint32_t nb_segments;
50  int64_t schema_offset;
51  int64_t strings_size;
52  char *string_table;
53 
54  uint32_t current_segment;
55 
58 } AAXContext;
59 
60 static int aax_probe(const AVProbeData *p)
61 {
62  if (AV_RB32(p->buf) != MKBETAG('@','U','T','F'))
63  return 0;
64  if (AV_RB32(p->buf + 4) == 0)
65  return 0;
66  if (AV_RB16(p->buf + 8) > 1)
67  return 0;
68  if (AV_RB32(p->buf + 28) < 1)
69  return 0;
70 
71  return AVPROBE_SCORE_MAX;
72 }
73 
74 enum ColumnFlag {
78  COLUMN_FLAG_UNDEFINED = 0x8 /* shouldn't exist */
79 };
80 
81 enum ColumnType {
94  COLUMN_TYPE_UINT128 = 0x0c, /* for GUIDs */
96 };
97 
98 static int64_t get_pts(AVFormatContext *s, int64_t pos, int size)
99 {
100  AAXContext *a = s->priv_data;
101  int64_t pts = 0;
102 
103  for (int seg = 0; seg < a->current_segment; seg++)
104  pts += (a->segments[seg].end - a->segments[seg].start) / size;
105 
106  pts += ((pos - a->segments[a->current_segment].start) / size);
107 
108  return pts;
109 }
110 
112 {
113  AAXContext *a = s->priv_data;
114  AVIOContext *pb = s->pb;
115  AVCodecParameters *par;
116  AVStream *st;
117  int64_t column_offset = 0;
118  int ret, extradata_size;
119  char *codec;
120 
121  avio_skip(pb, 4);
122  a->table_size = avio_rb32(pb) + 8LL;
123  a->version = avio_rb16(pb);
124  a->rows_offset = avio_rb16(pb) + 8LL;
125  a->strings_offset = avio_rb32(pb) + 8LL;
126  a->data_offset = avio_rb32(pb) + 8LL;
127  a->name_offset = avio_rb32(pb);
128  a->columns = avio_rb16(pb);
129  a->row_width = avio_rb16(pb);
130  a->nb_segments = avio_rb32(pb);
131 
132  if (a->nb_segments < 1)
133  return AVERROR_INVALIDDATA;
134 
135  a->schema_offset = 0x20;
136  a->strings_size = a->data_offset - a->strings_offset;
137 
138  if (a->rows_offset > a->table_size ||
139  a->strings_offset > a->table_size ||
140  a->data_offset > a->table_size)
141  return AVERROR_INVALIDDATA;
142  if (a->strings_size <= 0 || a->name_offset >= a->strings_size ||
143  a->strings_size > UINT16_MAX)
144  return AVERROR_INVALIDDATA;
145  if (a->columns <= 0)
146  return AVERROR_INVALIDDATA;
147 
148  a->segments = av_calloc(a->nb_segments, sizeof(*a->segments));
149  if (!a->segments)
150  return AVERROR(ENOMEM);
151 
152  a->xcolumns = av_calloc(a->columns, sizeof(*a->xcolumns));
153  if (!a->xcolumns) {
154  ret = AVERROR(ENOMEM);
155  goto fail;
156  }
157 
158  a->string_table = av_calloc(a->strings_size + 1, sizeof(*a->string_table));
159  if (!a->string_table) {
160  ret = AVERROR(ENOMEM);
161  goto fail;
162  }
163 
164  for (int c = 0; c < a->columns; c++) {
165  uint8_t info = avio_r8(pb);
166  uint32_t offset = avio_rb32(pb);
167  int value_size;
168 
169  if (offset >= a->strings_size) {
170  ret = AVERROR_INVALIDDATA;
171  goto fail;
172  }
173 
174  a->xcolumns[c].flag = info >> 4;
175  a->xcolumns[c].type = info & 0x0F;
176 
177  switch (a->xcolumns[c].type) {
178  case COLUMN_TYPE_UINT8:
179  case COLUMN_TYPE_SINT8:
180  value_size = 0x01;
181  break;
182  case COLUMN_TYPE_UINT16:
183  case COLUMN_TYPE_SINT16:
184  value_size = 0x02;
185  break;
186  case COLUMN_TYPE_UINT32:
187  case COLUMN_TYPE_SINT32:
188  case COLUMN_TYPE_FLOAT:
189  case COLUMN_TYPE_STRING:
190  value_size = 0x04;
191  break;
192  case COLUMN_TYPE_VLDATA:
193  value_size = 0x08;
194  break;
195  case COLUMN_TYPE_UINT128:
196  value_size = 0x10;
197  break;
198  default:
199  ret = AVERROR_INVALIDDATA;
200  goto fail;
201  }
202 
203  a->xcolumns[c].size = value_size;
204 
205  if (a->xcolumns[c].flag & COLUMN_FLAG_NAME)
206  a->xcolumns[c].name = a->string_table + offset;
207 
208  if (a->xcolumns[c].flag & COLUMN_FLAG_DEFAULT) {
209  /* data is found relative to columns start */
210  a->xcolumns[c].offset = avio_tell(pb) - a->schema_offset;
211  avio_skip(pb, value_size);
212  }
213 
214  if (a->xcolumns[c].flag & COLUMN_FLAG_ROW) {
215  /* data is found relative to row start */
216  a->xcolumns[c].offset = column_offset;
217  column_offset += value_size;
218  }
219  }
220 
221  avio_seek(pb, a->strings_offset, SEEK_SET);
222  ret = avio_read(pb, a->string_table, a->strings_size);
223  if (ret != a->strings_size) {
224  if (ret < 0)
225  goto fail;
226  ret = AVERROR(EIO);
227  goto fail;
228  }
229 
230  for (int c = 0; c < a->columns; c++) {
231  int64_t data_offset = 0;
232  int64_t col_offset;
233  int flag, type;
234 
235  if (!a->xcolumns[c].name || strcmp(a->xcolumns[c].name, "data"))
236  continue;
237 
238  type = a->xcolumns[c].type;
239  flag = a->xcolumns[c].flag;
240  col_offset = a->xcolumns[c].offset;
241 
242  for (uint64_t r = 0; r < a->nb_segments; r++) {
243  if (flag & COLUMN_FLAG_DEFAULT) {
244  data_offset = a->schema_offset + col_offset;
245  } else if (flag & COLUMN_FLAG_ROW) {
246  data_offset = a->rows_offset + r * a->row_width + col_offset;
247  } else {
248  ret = AVERROR_INVALIDDATA;
249  goto fail;
250  }
251 
252  avio_seek(pb, data_offset, SEEK_SET);
253  if (type == COLUMN_TYPE_VLDATA) {
254  int64_t start, size;
255 
256  start = avio_rb32(pb);
257  size = avio_rb32(pb);
258  a->segments[r].start = start + a->data_offset;
259  a->segments[r].end = a->segments[r].start + size;
260  } else {
261  ret = AVERROR_INVALIDDATA;
262  goto fail;
263  }
264  }
265  }
266 
267  if (!a->segments[0].end) {
268  ret = AVERROR_INVALIDDATA;
269  goto fail;
270  }
271 
272  st = avformat_new_stream(s, NULL);
273  if (!st) {
274  ret = AVERROR(ENOMEM);
275  goto fail;
276  }
277  st->start_time = 0;
278  par = s->streams[0]->codecpar;
280 
281  codec = a->string_table + a->name_offset;
282  if (!strcmp(codec, "AAX")) {
284  avio_seek(pb, a->segments[0].start, SEEK_SET);
285  if (avio_rb16(pb) != 0x8000) {
286  ret = AVERROR_INVALIDDATA;
287  goto fail;
288  }
289  extradata_size = avio_rb16(pb) + 4;
290  if (extradata_size < 12) {
291  ret = AVERROR_INVALIDDATA;
292  goto fail;
293  }
294  avio_seek(pb, -4, SEEK_CUR);
295  ret = ff_get_extradata(s, par, pb, extradata_size);
296  if (ret < 0) {
297  goto fail;
298  }
299  par->channels = AV_RB8 (par->extradata + 7);
300  par->sample_rate = AV_RB32(par->extradata + 8);
301  if (!par->channels || !par->sample_rate) {
302  ret = AVERROR_INVALIDDATA;
303  goto fail;
304  }
305 
306  avpriv_set_pts_info(st, 64, 32, par->sample_rate);
307  /*} else if (!strcmp(codec, "HCA") ){
308  par->codec_id = AV_CODEC_ID_HCA;*/
309  } else {
310  ret = AVERROR_INVALIDDATA;
311  goto fail;
312  }
313 
314  return 0;
315 fail:
316  av_freep(&a->string_table);
317  av_freep(&a->xcolumns);
318  av_freep(&a->segments);
319 
320  return ret;
321 }
322 
324 {
325  AAXContext *a = s->priv_data;
326  AVCodecParameters *par = s->streams[0]->codecpar;
327  AVIOContext *pb = s->pb;
328  const int size = 18 * par->channels;
329  int ret, extradata_size = 0;
330  uint8_t *extradata = NULL;
331  int skip = 0;
332 
333  if (avio_feof(pb))
334  return AVERROR_EOF;
335 
336  pkt->pos = avio_tell(pb);
337 
338  for (uint32_t seg = 0; seg < a->nb_segments; seg++) {
339  int64_t start = a->segments[seg].start;
340  int64_t end = a->segments[seg].end;
341 
342  if (pkt->pos >= start && pkt->pos <= end) {
343  a->current_segment = seg;
344  if (par->codec_id == AV_CODEC_ID_ADPCM_ADX)
345  skip = (end - start) - ((end - start) / size) * size;
346  break;
347  }
348  }
349 
350  if (pkt->pos >= a->segments[a->current_segment].end - skip) {
351  if (a->current_segment + 1 == a->nb_segments)
352  return AVERROR_EOF;
353  a->current_segment++;
354  avio_seek(pb, a->segments[a->current_segment].start, SEEK_SET);
355 
356  if (par->codec_id == AV_CODEC_ID_ADPCM_ADX) {
357  if (avio_rb16(pb) != 0x8000)
358  return AVERROR_INVALIDDATA;
359  extradata_size = avio_rb16(pb) + 4;
360  avio_seek(pb, -4, SEEK_CUR);
361  if (extradata_size < 12)
362  return AVERROR_INVALIDDATA;
363  extradata = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
364  if (!extradata)
365  return AVERROR(ENOMEM);
366  if (avio_read(pb, extradata, extradata_size) != extradata_size) {
367  av_free(extradata);
368  return AVERROR(EIO);
369  }
370  memset(extradata + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
371  }
372  }
373 
374  ret = av_get_packet(pb, pkt, size);
375  if (ret != size) {
376  av_free(extradata);
377  return ret < 0 ? ret : AVERROR(EIO);
378  }
379  pkt->duration = 1;
380  pkt->stream_index = 0;
381  pkt->pts = get_pts(s, pkt->pos, size);
382 
383  if (extradata) {
384  ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, extradata, extradata_size);
385  if (ret < 0) {
386  av_free(extradata);
387  return ret;
388  }
389  }
390 
391  return ret;
392 }
393 
395 {
396  AAXContext *a = s->priv_data;
397 
398  av_freep(&a->segments);
399  av_freep(&a->xcolumns);
400  av_freep(&a->string_table);
401 
402  return 0;
403 }
404 
406  .name = "aax",
407  .long_name = NULL_IF_CONFIG_SMALL("CRI AAX"),
408  .priv_data_size = sizeof(AAXContext),
413  .extensions = "aax",
415 };
ColumnFlag
Definition: aaxdec.c:74
@ COLUMN_FLAG_NAME
Definition: aaxdec.c:75
@ COLUMN_FLAG_ROW
Definition: aaxdec.c:77
@ COLUMN_FLAG_UNDEFINED
Definition: aaxdec.c:78
@ COLUMN_FLAG_DEFAULT
Definition: aaxdec.c:76
ColumnType
Definition: aaxdec.c:81
@ COLUMN_TYPE_SINT32
Definition: aaxdec.c:87
@ COLUMN_TYPE_DOUBLE
Definition: aaxdec.c:91
@ COLUMN_TYPE_UINT128
Definition: aaxdec.c:94
@ COLUMN_TYPE_UINT16
Definition: aaxdec.c:84
@ COLUMN_TYPE_UINT8
Definition: aaxdec.c:82
@ COLUMN_TYPE_SINT64
Definition: aaxdec.c:89
@ COLUMN_TYPE_UINT32
Definition: aaxdec.c:86
@ COLUMN_TYPE_STRING
Definition: aaxdec.c:92
@ COLUMN_TYPE_VLDATA
Definition: aaxdec.c:93
@ COLUMN_TYPE_UNDEFINED
Definition: aaxdec.c:95
@ COLUMN_TYPE_SINT16
Definition: aaxdec.c:85
@ COLUMN_TYPE_UINT64
Definition: aaxdec.c:88
@ COLUMN_TYPE_FLOAT
Definition: aaxdec.c:90
@ COLUMN_TYPE_SINT8
Definition: aaxdec.c:83
AVInputFormat ff_aax_demuxer
Definition: aaxdec.c:405
static int aax_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: aaxdec.c:323
static int aax_read_close(AVFormatContext *s)
Definition: aaxdec.c:394
static int aax_probe(const AVProbeData *p)
Definition: aaxdec.c:60
static int64_t get_pts(AVFormatContext *s, int64_t pos, int size)
Definition: aaxdec.c:98
static int aax_read_header(AVFormatContext *s)
Definition: aaxdec.c:111
uint8_t
simple assert() macros that are a bit more flexible than ISO C assert().
Main libavformat public API header.
#define AVPROBE_SCORE_MAX
maximum score
Definition: avformat.h:453
int av_get_packet(AVIOContext *s, AVPacket *pkt, int size)
Allocate and read the payload of a packet and initialize its fields with default values.
Definition: utils.c:310
#define AVFMT_GENERIC_INDEX
Use generic index building code.
Definition: avformat.h:463
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:253
unsigned int avio_rb16(AVIOContext *s)
Definition: aviobuf.c:766
int avio_feof(AVIOContext *s)
Similar to feof() but also returns nonzero on read errors.
Definition: aviobuf.c:364
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:557
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition: aviobuf.c:337
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:633
unsigned int avio_rb32(AVIOContext *s)
Definition: aviobuf.c:781
int avio_r8(AVIOContext *s)
Definition: aviobuf.c:624
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
Definition: avio_reading.c:42
#define AV_RB32
Definition: intreadwrite.h:130
#define AV_RB16
Definition: intreadwrite.h:53
#define flag(name)
Definition: cbs_av1.c:553
#define flags(name, subs,...)
Definition: cbs_av1.c:561
#define s(width, name)
Definition: cbs_vp9.c:257
#define fail()
Definition: checkasm.h:133
#define MKBETAG(a, b, c, d)
Definition: common.h:479
#define NULL
Definition: coverity.c:32
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:527
@ AV_CODEC_ID_ADPCM_ADX
Definition: codec_id.h:362
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding.
Definition: avcodec.h:215
FF_ENABLE_DEPRECATION_WARNINGS int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type, uint8_t *data, size_t size)
Wrap an existing array as a packet side data.
Definition: avpacket.c:309
@ AV_PKT_DATA_NEW_EXTRADATA
The AV_PKT_DATA_NEW_EXTRADATA is used to notify the codec or the format that the extradata buffer was...
Definition: packet.h:55
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4505
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
#define AVERROR_EOF
End of file.
Definition: error.h:55
#define AVERROR(e)
Definition: error.h:43
void * av_calloc(size_t nmemb, size_t size)
Non-inlined equivalent of av_mallocz_array().
Definition: mem.c:245
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
cl_device_type type
#define AV_RB8(x)
Definition: intreadwrite.h:395
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: utils.c:4941
int ff_get_extradata(AVFormatContext *s, AVCodecParameters *par, AVIOContext *pb, int size)
Allocate extradata with additional AV_INPUT_BUFFER_PADDING_SIZE at end which is always set to 0 and f...
Definition: utils.c:3330
static int read_probe(const AVProbeData *pd)
Definition: jvdec.c:55
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
static av_cold int read_close(AVFormatContext *ctx)
Definition: libcdio.c:145
unsigned int pos
Definition: spdifenc.c:412
uint8_t flag
Definition: aaxdec.c:28
uint32_t offset
Definition: aaxdec.c:31
uint8_t type
Definition: aaxdec.c:29
int size
Definition: aaxdec.c:32
const char * name
Definition: aaxdec.c:30
int64_t rows_offset
Definition: aaxdec.c:43
uint16_t columns
Definition: aaxdec.c:47
uint16_t version
Definition: aaxdec.c:42
AAXColumn * xcolumns
Definition: aaxdec.c:56
uint32_t current_segment
Definition: aaxdec.c:54
char * string_table
Definition: aaxdec.c:52
int64_t strings_size
Definition: aaxdec.c:51
int64_t strings_offset
Definition: aaxdec.c:44
uint32_t nb_segments
Definition: aaxdec.c:49
int64_t data_offset
Definition: aaxdec.c:45
int64_t table_size
Definition: aaxdec.c:41
int64_t schema_offset
Definition: aaxdec.c:50
int64_t name_offset
Definition: aaxdec.c:46
uint16_t row_width
Definition: aaxdec.c:48
AAXSegment * segments
Definition: aaxdec.c:57
int64_t end
Definition: aaxdec.c:37
int64_t start
Definition: aaxdec.c:36
This struct describes the properties of an encoded stream.
Definition: codec_par.h:52
int channels
Audio only.
Definition: codec_par.h:166
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:56
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: codec_par.h:74
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:60
int sample_rate
Audio only.
Definition: codec_par.h:170
Format I/O context.
Definition: avformat.h:1232
Bytestream IO Context.
Definition: avio.h:161
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:645
This structure stores compressed data.
Definition: packet.h:346
int stream_index
Definition: packet.h:371
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: packet.h:387
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:362
int64_t pos
byte position in stream, -1 if unknown
Definition: packet.h:389
This structure contains the data a format has to probe a file.
Definition: avformat.h:441
unsigned char * buf
Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero.
Definition: avformat.h:443
Stream structure.
Definition: avformat.h:873
int64_t start_time
Decoding: pts of the first frame of the stream in presentation order, in stream time base.
Definition: avformat.h:912
#define av_free(p)
#define av_freep(p)
#define av_malloc(s)
AVPacket * pkt
Definition: movenc.c:59
static int64_t pts
int size
const char * r
Definition: vf_curves.c:116
static const uint8_t offset[127][2]
Definition: vf_spp.c:107
static double c[64]