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