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/intreadwrite.h"
23 #include "avformat.h"
24 #include "avio_internal.h"
25 #include "demux.h"
26 #include "internal.h"
27 
28 typedef struct AAXColumn {
29     uint8_t flag;
30     uint8_t type;
31     const char *name;
32     uint32_t offset;
33     int size;
34 } AAXColumn;
35 
36 typedef struct AAXSegment {
37     int64_t start;
38     int64_t end;
39 } AAXSegment;
40 
41 typedef struct AAXContext {
42     int64_t table_size;
43     uint16_t version;
44     int64_t rows_offset;
45     int64_t strings_offset;
46     int64_t data_offset;
47     int64_t name_offset;
48     uint16_t columns;
49     uint16_t row_width;
50     uint32_t nb_segments;
51     int64_t schema_offset;
52     int64_t strings_size;
53     char *string_table;
54 
55     uint32_t current_segment;
56 
57     AAXColumn *xcolumns;
58     AAXSegment *segments;
59 } AAXContext;
60 
aax_probe(const AVProbeData *p)61 static int aax_probe(const AVProbeData *p)
62 {
63     if (AV_RB32(p->buf) != MKBETAG('@','U','T','F'))
64         return 0;
65     if (AV_RB32(p->buf + 4) == 0)
66         return 0;
67     if (AV_RB16(p->buf + 8) > 1)
68         return 0;
69     if (AV_RB32(p->buf + 28) < 1)
70         return 0;
71 
72     return AVPROBE_SCORE_MAX;
73 }
74 
75 enum ColumnFlag {
76     COLUMN_FLAG_NAME            = 0x1,
77     COLUMN_FLAG_DEFAULT         = 0x2,
78     COLUMN_FLAG_ROW             = 0x4,
79     COLUMN_FLAG_UNDEFINED       = 0x8 /* shouldn't exist */
80 };
81 
82 enum ColumnType {
83     COLUMN_TYPE_UINT8           = 0x00,
84     COLUMN_TYPE_SINT8           = 0x01,
85     COLUMN_TYPE_UINT16          = 0x02,
86     COLUMN_TYPE_SINT16          = 0x03,
87     COLUMN_TYPE_UINT32          = 0x04,
88     COLUMN_TYPE_SINT32          = 0x05,
89     COLUMN_TYPE_UINT64          = 0x06,
90     COLUMN_TYPE_SINT64          = 0x07,
91     COLUMN_TYPE_FLOAT           = 0x08,
92     COLUMN_TYPE_DOUBLE          = 0x09,
93     COLUMN_TYPE_STRING          = 0x0a,
94     COLUMN_TYPE_VLDATA          = 0x0b,
95     COLUMN_TYPE_UINT128         = 0x0c, /* for GUIDs */
96     COLUMN_TYPE_UNDEFINED       = -1
97 };
98 
get_pts(AVFormatContext *s, int64_t pos, int size)99 static int64_t get_pts(AVFormatContext *s, int64_t pos, int size)
100 {
101     AAXContext *a = s->priv_data;
102     int64_t pts = 0;
103 
104     for (int seg = 0; seg < a->current_segment; seg++)
105         pts += (a->segments[seg].end - a->segments[seg].start) / size;
106 
107     pts += ((pos - a->segments[a->current_segment].start) / size);
108 
109     return pts;
110 }
111 
aax_read_header(AVFormatContext *s)112 static int aax_read_header(AVFormatContext *s)
113 {
114     AAXContext *a = s->priv_data;
115     AVIOContext *pb = s->pb;
116     AVCodecParameters *par;
117     AVStream *st;
118     int64_t column_offset = 0;
119     int ret, extradata_size;
120     char *codec;
121     int64_t ret64;
122 
123     avio_skip(pb, 4);
124     a->table_size      = avio_rb32(pb) + 8LL;
125     a->version         = avio_rb16(pb);
126     a->rows_offset     = avio_rb16(pb) + 8LL;
127     a->strings_offset  = avio_rb32(pb) + 8LL;
128     a->data_offset     = avio_rb32(pb) + 8LL;
129     a->name_offset     = avio_rb32(pb);
130     a->columns         = avio_rb16(pb);
131     a->row_width       = avio_rb16(pb);
132     a->nb_segments     = avio_rb32(pb);
133 
134     if (a->nb_segments < 1)
135         return AVERROR_INVALIDDATA;
136 
137     a->schema_offset   = 0x20;
138     a->strings_size    = a->data_offset - a->strings_offset;
139 
140     if (a->rows_offset > a->table_size ||
141         a->strings_offset > a->table_size ||
142         a->data_offset > a->table_size)
143         return AVERROR_INVALIDDATA;
144     if (a->strings_size <= 0 || a->name_offset >= a->strings_size ||
145         a->strings_size > UINT16_MAX)
146         return AVERROR_INVALIDDATA;
147     if (a->columns <= 0)
148         return AVERROR_INVALIDDATA;
149 
150     a->segments = av_calloc(a->nb_segments, sizeof(*a->segments));
151     if (!a->segments)
152         return AVERROR(ENOMEM);
153 
154     a->xcolumns = av_calloc(a->columns, sizeof(*a->xcolumns));
155     if (!a->xcolumns)
156         return AVERROR(ENOMEM);
157 
158     a->string_table = av_calloc(a->strings_size + 1, sizeof(*a->string_table));
159     if (!a->string_table)
160         return AVERROR(ENOMEM);
161 
162     for (int c = 0; c < a->columns; c++) {
163         uint8_t info = avio_r8(pb);
164         uint32_t offset = avio_rb32(pb);
165         int value_size;
166 
167         if (offset >= a->strings_size)
168             return AVERROR_INVALIDDATA;
169 
170         a->xcolumns[c].flag = info >>   4;
171         a->xcolumns[c].type = info & 0x0F;
172 
173         switch (a->xcolumns[c].type) {
174         case COLUMN_TYPE_UINT8:
175         case COLUMN_TYPE_SINT8:
176             value_size = 0x01;
177             break;
178         case COLUMN_TYPE_UINT16:
179         case COLUMN_TYPE_SINT16:
180             value_size = 0x02;
181             break;
182         case COLUMN_TYPE_UINT32:
183         case COLUMN_TYPE_SINT32:
184         case COLUMN_TYPE_FLOAT:
185         case COLUMN_TYPE_STRING:
186             value_size = 0x04;
187             break;
188         case COLUMN_TYPE_VLDATA:
189             value_size = 0x08;
190             break;
191         case COLUMN_TYPE_UINT128:
192             value_size = 0x10;
193             break;
194         default:
195             return AVERROR_INVALIDDATA;
196         }
197 
198         a->xcolumns[c].size = value_size;
199 
200         if (a->xcolumns[c].flag & COLUMN_FLAG_NAME)
201             a->xcolumns[c].name = a->string_table + offset;
202 
203         if (a->xcolumns[c].flag & COLUMN_FLAG_DEFAULT) {
204             /* data is found relative to columns start */
205             a->xcolumns[c].offset = avio_tell(pb) - a->schema_offset;
206             avio_skip(pb, value_size);
207         }
208 
209         if (a->xcolumns[c].flag & COLUMN_FLAG_ROW) {
210             /* data is found relative to row start */
211             a->xcolumns[c].offset = column_offset;
212             column_offset += value_size;
213         }
214     }
215 
216     ret = ret64 = avio_seek(pb, a->strings_offset, SEEK_SET);
217     if (ret64 < 0)
218         return ret;
219 
220     ret = ffio_read_size(pb, a->string_table, a->strings_size);
221     if (ret < 0)
222         return ret;
223 
224     for (int c = 0; c < a->columns; c++) {
225         int64_t data_offset = 0;
226         int64_t col_offset;
227         int flag, type;
228 
229         if (!a->xcolumns[c].name || strcmp(a->xcolumns[c].name, "data"))
230             continue;
231 
232         type = a->xcolumns[c].type;
233         flag = a->xcolumns[c].flag;
234         col_offset = a->xcolumns[c].offset;
235 
236         for (uint64_t r = 0; r < a->nb_segments; r++) {
237             if (flag & COLUMN_FLAG_DEFAULT) {
238                 data_offset = a->schema_offset + col_offset;
239             } else if (flag & COLUMN_FLAG_ROW) {
240                 data_offset = a->rows_offset + r * a->row_width + col_offset;
241             } else
242                 return AVERROR_INVALIDDATA;
243 
244             ret = ret64 = avio_seek(pb, data_offset, SEEK_SET);
245             if (ret64 < 0)
246                 return ret;
247 
248             if (type == COLUMN_TYPE_VLDATA) {
249                 int64_t start, size;
250 
251                 start = avio_rb32(pb);
252                 size  = avio_rb32(pb);
253                 if (!size)
254                     return AVERROR_INVALIDDATA;
255                 a->segments[r].start = start + a->data_offset;
256                 a->segments[r].end   = a->segments[r].start + size;
257                 if (r &&
258                     a->segments[r].start < a->segments[r-1].end &&
259                     a->segments[r].end   > a->segments[r-1].start)
260                     return AVERROR_INVALIDDATA;
261             } else
262                 return AVERROR_INVALIDDATA;
263         }
264     }
265 
266     if (!a->segments[0].end)
267         return AVERROR_INVALIDDATA;
268 
269     st = avformat_new_stream(s, NULL);
270     if (!st)
271         return AVERROR(ENOMEM);
272     st->start_time = 0;
273     par = s->streams[0]->codecpar;
274     par->codec_type = AVMEDIA_TYPE_AUDIO;
275 
276     codec = a->string_table + a->name_offset;
277     if (!strcmp(codec, "AAX")) {
278         par->codec_id = AV_CODEC_ID_ADPCM_ADX;
279         ret64 = avio_seek(pb, a->segments[0].start, SEEK_SET);
280         if (ret64 < 0 || avio_rb16(pb) != 0x8000)
281             return AVERROR_INVALIDDATA;
282         extradata_size = avio_rb16(pb) + 4;
283         if (extradata_size < 12)
284             return AVERROR_INVALIDDATA;
285         avio_seek(pb, -4, SEEK_CUR);
286         ret = ff_get_extradata(s, par, pb, extradata_size);
287         if (ret < 0)
288             return ret;
289         par->ch_layout.nb_channels = AV_RB8 (par->extradata + 7);
290         par->sample_rate = AV_RB32(par->extradata + 8);
291         if (!par->ch_layout.nb_channels || !par->sample_rate)
292             return AVERROR_INVALIDDATA;
293 
294         avpriv_set_pts_info(st, 64, 32, par->sample_rate);
295   /*} else if (!strcmp(codec, "HCA") ){
296         par->codec_id = AV_CODEC_ID_HCA;*/
297     } else {
298         return AVERROR_INVALIDDATA;
299     }
300 
301     return 0;
302 }
303 
aax_read_packet(AVFormatContext *s, AVPacket *pkt)304 static int aax_read_packet(AVFormatContext *s, AVPacket *pkt)
305 {
306     AAXContext *a = s->priv_data;
307     AVCodecParameters *par = s->streams[0]->codecpar;
308     AVIOContext *pb = s->pb;
309     const int size = 18 * par->ch_layout.nb_channels;
310     int ret, extradata_size = 0;
311     uint8_t *extradata = NULL;
312     int skip = 0;
313 
314     if (avio_feof(pb))
315         return AVERROR_EOF;
316 
317     pkt->pos = avio_tell(pb);
318 
319     for (uint32_t seg = 0; seg < a->nb_segments; seg++) {
320         int64_t start = a->segments[seg].start;
321         int64_t end   = a->segments[seg].end;
322 
323         if (pkt->pos >= start && pkt->pos <= end) {
324             a->current_segment = seg;
325             if (par->codec_id == AV_CODEC_ID_ADPCM_ADX)
326                 skip = (end - start) - ((end - start) / size) * size;
327             break;
328         }
329     }
330 
331     if (pkt->pos >= a->segments[a->current_segment].end - skip) {
332         if (a->current_segment + 1 == a->nb_segments)
333             return AVERROR_EOF;
334         a->current_segment++;
335         avio_seek(pb, a->segments[a->current_segment].start, SEEK_SET);
336 
337         if (par->codec_id == AV_CODEC_ID_ADPCM_ADX) {
338             if (avio_rb16(pb) != 0x8000)
339                 return AVERROR_INVALIDDATA;
340             extradata_size = avio_rb16(pb) + 4;
341             avio_seek(pb, -4, SEEK_CUR);
342             if (extradata_size < 12)
343                 return AVERROR_INVALIDDATA;
344             extradata = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
345             if (!extradata)
346                 return AVERROR(ENOMEM);
347             if (avio_read(pb, extradata, extradata_size) != extradata_size) {
348                 av_free(extradata);
349                 return AVERROR(EIO);
350             }
351             memset(extradata + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
352         }
353     }
354 
355     ret = av_get_packet(pb, pkt, size);
356     if (ret != size) {
357         av_free(extradata);
358         return ret < 0 ? ret : AVERROR(EIO);
359     }
360     pkt->duration = 1;
361     pkt->stream_index = 0;
362     pkt->pts = get_pts(s, pkt->pos, size);
363 
364     if (extradata) {
365         ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, extradata, extradata_size);
366         if (ret < 0) {
367             av_free(extradata);
368             return ret;
369         }
370     }
371 
372     return ret;
373 }
374 
aax_read_close(AVFormatContext *s)375 static int aax_read_close(AVFormatContext *s)
376 {
377     AAXContext *a = s->priv_data;
378 
379     av_freep(&a->segments);
380     av_freep(&a->xcolumns);
381     av_freep(&a->string_table);
382 
383     return 0;
384 }
385 
386 const AVInputFormat ff_aax_demuxer = {
387     .name           = "aax",
388     .long_name      = NULL_IF_CONFIG_SMALL("CRI AAX"),
389     .priv_data_size = sizeof(AAXContext),
390     .flags_internal = FF_FMT_INIT_CLEANUP,
391     .read_probe     = aax_probe,
392     .read_header    = aax_read_header,
393     .read_packet    = aax_read_packet,
394     .read_close     = aax_read_close,
395     .extensions     = "aax",
396     .flags          = AVFMT_GENERIC_INDEX,
397 };
398