FFmpeg  4.4.6
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 {
38 } AAXSegment;
39 
40 typedef struct AAXContext {
42  uint16_t version;
47  uint16_t columns;
48  uint16_t row_width;
49  uint32_t nb_segments;
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 
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  int64_t ret64;
121 
122  avio_skip(pb, 4);
123  a->table_size = avio_rb32(pb) + 8LL;
124  a->version = avio_rb16(pb);
125  a->rows_offset = avio_rb16(pb) + 8LL;
126  a->strings_offset = avio_rb32(pb) + 8LL;
127  a->data_offset = avio_rb32(pb) + 8LL;
128  a->name_offset = avio_rb32(pb);
129  a->columns = avio_rb16(pb);
130  a->row_width = avio_rb16(pb);
131  a->nb_segments = avio_rb32(pb);
132 
133  if (a->nb_segments < 1)
134  return AVERROR_INVALIDDATA;
135 
136  a->schema_offset = 0x20;
137  a->strings_size = a->data_offset - a->strings_offset;
138 
139  if (a->rows_offset > a->table_size ||
140  a->strings_offset > a->table_size ||
141  a->data_offset > a->table_size)
142  return AVERROR_INVALIDDATA;
143  if (a->strings_size <= 0 || a->name_offset >= a->strings_size ||
144  a->strings_size > UINT16_MAX)
145  return AVERROR_INVALIDDATA;
146  if (a->columns <= 0)
147  return AVERROR_INVALIDDATA;
148 
149  a->segments = av_calloc(a->nb_segments, sizeof(*a->segments));
150  if (!a->segments)
151  return AVERROR(ENOMEM);
152 
153  a->xcolumns = av_calloc(a->columns, sizeof(*a->xcolumns));
154  if (!a->xcolumns) {
155  ret = AVERROR(ENOMEM);
156  goto fail;
157  }
158 
159  a->string_table = av_calloc(a->strings_size + 1, sizeof(*a->string_table));
160  if (!a->string_table) {
161  ret = AVERROR(ENOMEM);
162  goto fail;
163  }
164 
165  for (int c = 0; c < a->columns; c++) {
166  uint8_t info = avio_r8(pb);
167  uint32_t offset = avio_rb32(pb);
168  int value_size;
169 
170  if (offset >= a->strings_size) {
171  ret = AVERROR_INVALIDDATA;
172  goto fail;
173  }
174 
175  a->xcolumns[c].flag = info >> 4;
176  a->xcolumns[c].type = info & 0x0F;
177 
178  switch (a->xcolumns[c].type) {
179  case COLUMN_TYPE_UINT8:
180  case COLUMN_TYPE_SINT8:
181  value_size = 0x01;
182  break;
183  case COLUMN_TYPE_UINT16:
184  case COLUMN_TYPE_SINT16:
185  value_size = 0x02;
186  break;
187  case COLUMN_TYPE_UINT32:
188  case COLUMN_TYPE_SINT32:
189  case COLUMN_TYPE_FLOAT:
190  case COLUMN_TYPE_STRING:
191  value_size = 0x04;
192  break;
193  case COLUMN_TYPE_VLDATA:
194  value_size = 0x08;
195  break;
196  case COLUMN_TYPE_UINT128:
197  value_size = 0x10;
198  break;
199  default:
200  ret = AVERROR_INVALIDDATA;
201  goto fail;
202  }
203 
204  a->xcolumns[c].size = value_size;
205 
206  if (a->xcolumns[c].flag & COLUMN_FLAG_NAME)
207  a->xcolumns[c].name = a->string_table + offset;
208 
209  if (a->xcolumns[c].flag & COLUMN_FLAG_DEFAULT) {
210  /* data is found relative to columns start */
211  a->xcolumns[c].offset = avio_tell(pb) - a->schema_offset;
212  avio_skip(pb, value_size);
213  }
214 
215  if (a->xcolumns[c].flag & COLUMN_FLAG_ROW) {
216  /* data is found relative to row start */
217  a->xcolumns[c].offset = column_offset;
218  column_offset += value_size;
219  }
220  }
221 
222  ret = ret64 = avio_seek(pb, a->strings_offset, SEEK_SET);
223  if (ret64 < 0)
224  goto fail;
225 
226  ret = avio_read(pb, a->string_table, a->strings_size);
227  if (ret != a->strings_size) {
228  if (ret < 0)
229  goto fail;
230  ret = AVERROR(EIO);
231  goto fail;
232  }
233 
234  for (int c = 0; c < a->columns; c++) {
235  int64_t data_offset = 0;
236  int64_t col_offset;
237  int flag, type;
238 
239  if (!a->xcolumns[c].name || strcmp(a->xcolumns[c].name, "data"))
240  continue;
241 
242  type = a->xcolumns[c].type;
243  flag = a->xcolumns[c].flag;
244  col_offset = a->xcolumns[c].offset;
245 
246  for (uint64_t r = 0; r < a->nb_segments; r++) {
247  if (flag & COLUMN_FLAG_DEFAULT) {
248  data_offset = a->schema_offset + col_offset;
249  } else if (flag & COLUMN_FLAG_ROW) {
250  data_offset = a->rows_offset + r * a->row_width + col_offset;
251  } else {
252  ret = AVERROR_INVALIDDATA;
253  goto fail;
254  }
255 
256  ret = ret64 = avio_seek(pb, data_offset, SEEK_SET);
257  if (ret64 < 0)
258  goto fail;
259 
260  if (type == COLUMN_TYPE_VLDATA) {
261  int64_t start, size;
262 
263  start = avio_rb32(pb);
264  size = avio_rb32(pb);
265  if (!size)
266  return AVERROR_INVALIDDATA;
267  a->segments[r].start = start + a->data_offset;
268  a->segments[r].end = a->segments[r].start + size;
269  } else {
270  ret = AVERROR_INVALIDDATA;
271  goto fail;
272  }
273  }
274  }
275 
276  if (!a->segments[0].end) {
277  ret = AVERROR_INVALIDDATA;
278  goto fail;
279  }
280 
281  st = avformat_new_stream(s, NULL);
282  if (!st) {
283  ret = AVERROR(ENOMEM);
284  goto fail;
285  }
286  st->start_time = 0;
287  par = s->streams[0]->codecpar;
289 
290  codec = a->string_table + a->name_offset;
291  if (!strcmp(codec, "AAX")) {
293  ret64 = avio_seek(pb, a->segments[0].start, SEEK_SET);
294  if (ret64 < 0 || avio_rb16(pb) != 0x8000) {
295  ret = AVERROR_INVALIDDATA;
296  goto fail;
297  }
298  extradata_size = avio_rb16(pb) + 4;
299  if (extradata_size < 12) {
300  ret = AVERROR_INVALIDDATA;
301  goto fail;
302  }
303  avio_seek(pb, -4, SEEK_CUR);
304  ret = ff_get_extradata(s, par, pb, extradata_size);
305  if (ret < 0) {
306  goto fail;
307  }
308  par->channels = AV_RB8 (par->extradata + 7);
309  par->sample_rate = AV_RB32(par->extradata + 8);
310  if (!par->channels || !par->sample_rate) {
311  ret = AVERROR_INVALIDDATA;
312  goto fail;
313  }
314 
315  avpriv_set_pts_info(st, 64, 32, par->sample_rate);
316  /*} else if (!strcmp(codec, "HCA") ){
317  par->codec_id = AV_CODEC_ID_HCA;*/
318  } else {
319  ret = AVERROR_INVALIDDATA;
320  goto fail;
321  }
322 
323  return 0;
324 fail:
325  av_freep(&a->string_table);
326  av_freep(&a->xcolumns);
327  av_freep(&a->segments);
328 
329  return ret;
330 }
331 
333 {
334  AAXContext *a = s->priv_data;
335  AVCodecParameters *par = s->streams[0]->codecpar;
336  AVIOContext *pb = s->pb;
337  const int size = 18 * par->channels;
338  int ret, extradata_size = 0;
339  uint8_t *extradata = NULL;
340  int skip = 0;
341 
342  if (avio_feof(pb))
343  return AVERROR_EOF;
344 
345  pkt->pos = avio_tell(pb);
346 
347  for (uint32_t seg = 0; seg < a->nb_segments; seg++) {
348  int64_t start = a->segments[seg].start;
349  int64_t end = a->segments[seg].end;
350 
351  if (pkt->pos >= start && pkt->pos <= end) {
352  a->current_segment = seg;
353  if (par->codec_id == AV_CODEC_ID_ADPCM_ADX)
354  skip = (end - start) - ((end - start) / size) * size;
355  break;
356  }
357  }
358 
359  if (pkt->pos >= a->segments[a->current_segment].end - skip) {
360  if (a->current_segment + 1 == a->nb_segments)
361  return AVERROR_EOF;
362  a->current_segment++;
363  avio_seek(pb, a->segments[a->current_segment].start, SEEK_SET);
364 
365  if (par->codec_id == AV_CODEC_ID_ADPCM_ADX) {
366  if (avio_rb16(pb) != 0x8000)
367  return AVERROR_INVALIDDATA;
368  extradata_size = avio_rb16(pb) + 4;
369  avio_seek(pb, -4, SEEK_CUR);
370  if (extradata_size < 12)
371  return AVERROR_INVALIDDATA;
372  extradata = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
373  if (!extradata)
374  return AVERROR(ENOMEM);
375  if (avio_read(pb, extradata, extradata_size) != extradata_size) {
376  av_free(extradata);
377  return AVERROR(EIO);
378  }
379  memset(extradata + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
380  }
381  }
382 
383  ret = av_get_packet(pb, pkt, size);
384  if (ret != size) {
385  av_free(extradata);
386  return ret < 0 ? ret : AVERROR(EIO);
387  }
388  pkt->duration = 1;
389  pkt->stream_index = 0;
390  pkt->pts = get_pts(s, pkt->pos, size);
391 
392  if (extradata) {
393  ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, extradata, extradata_size);
394  if (ret < 0) {
395  av_free(extradata);
396  return ret;
397  }
398  }
399 
400  return ret;
401 }
402 
404 {
405  AAXContext *a = s->priv_data;
406 
407  av_freep(&a->segments);
408  av_freep(&a->xcolumns);
409  av_freep(&a->string_table);
410 
411  return 0;
412 }
413 
415  .name = "aax",
416  .long_name = NULL_IF_CONFIG_SMALL("CRI AAX"),
417  .priv_data_size = sizeof(AAXContext),
422  .extensions = "aax",
424 };
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:414
static int aax_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: aaxdec.c:332
static int aax_read_close(AVFormatContext *s)
Definition: aaxdec.c:403
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:564
#define flags(name, subs,...)
Definition: cbs_av1.c:572
#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
long long int64_t
Definition: coverity.c:34
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:545
@ 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:4509
#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:4945
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:3332
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]