xref: /third_party/ffmpeg/libavformat/fsb.c (revision cabdff1a)
1/*
2 * FSB demuxer
3 * Copyright (c) 2015 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 "avio.h"
26#include "internal.h"
27
28static int fsb_probe(const AVProbeData *p)
29{
30    if (memcmp(p->buf, "FSB", 3) || p->buf[3] - '0' < 1 || p->buf[3] - '0' > 5)
31        return 0;
32    if (AV_RL32(p->buf + 4) != 1)
33        return 0;
34    return AVPROBE_SCORE_MAX;
35}
36
37static int fsb_read_header(AVFormatContext *s)
38{
39    AVIOContext *pb = s->pb;
40    unsigned format, version, c;
41    int64_t offset;
42    AVCodecParameters *par;
43    AVStream *st = avformat_new_stream(s, NULL);
44    int ret;
45
46    avio_skip(pb, 3); // "FSB"
47    version = avio_r8(pb) - '0';
48    if (version != 4 && version != 3) {
49        avpriv_request_sample(s, "version %d", version);
50        return AVERROR_PATCHWELCOME;
51    }
52
53    avio_skip(pb, 4);
54
55    if (!st)
56        return AVERROR(ENOMEM);
57    par = st->codecpar;
58    par->codec_type  = AVMEDIA_TYPE_AUDIO;
59    par->codec_tag   = 0;
60
61    if (version == 3) {
62        offset = avio_rl32(pb) + 0x18;
63        avio_skip(pb, 44);
64        st->duration = avio_rl32(pb);
65        avio_skip(pb, 12);
66        format = avio_rl32(pb);
67        par->sample_rate = avio_rl32(pb);
68        if (par->sample_rate <= 0)
69            return AVERROR_INVALIDDATA;
70        avio_skip(pb, 6);
71        par->ch_layout.nb_channels = avio_rl16(pb);
72        if (!par->ch_layout.nb_channels)
73            return AVERROR_INVALIDDATA;
74
75        if (format & 0x00000100) {
76            par->codec_id    = AV_CODEC_ID_PCM_S16LE;
77            par->block_align = 4096 * par->ch_layout.nb_channels;
78        } else if (format & 0x00400000) {
79            par->bits_per_coded_sample = 4;
80            par->codec_id    = AV_CODEC_ID_ADPCM_IMA_WAV;
81            par->block_align = 36 * par->ch_layout.nb_channels;
82        } else if (format & 0x00800000) {
83            par->codec_id    = AV_CODEC_ID_ADPCM_PSX;
84            par->block_align = 16 * par->ch_layout.nb_channels;
85        } else if (format & 0x02000000) {
86            par->codec_id    = AV_CODEC_ID_ADPCM_THP;
87            par->block_align = 8 * par->ch_layout.nb_channels;
88            if (par->ch_layout.nb_channels > INT_MAX / 32)
89                return AVERROR_INVALIDDATA;
90            ret = ff_alloc_extradata(par, 32 * par->ch_layout.nb_channels);
91            if (ret < 0)
92                return ret;
93            avio_seek(pb, 0x68, SEEK_SET);
94            for (c = 0; c < par->ch_layout.nb_channels; c++) {
95                avio_read(pb, par->extradata + 32 * c, 32);
96                avio_skip(pb, 14);
97            }
98        } else {
99            avpriv_request_sample(s, "format 0x%X", format);
100            return AVERROR_PATCHWELCOME;
101        }
102    } else if (version == 4) {
103        offset = avio_rl32(pb) + 0x30;
104        avio_skip(pb, 80);
105        st->duration = avio_rl32(pb);
106
107        format = avio_rb32(pb);
108        switch(format) {
109        case 0x40001001:
110        case 0x00001005:
111        case 0x40001081:
112        case 0x40200001:
113            par->codec_id = AV_CODEC_ID_XMA2;
114            break;
115        case 0x40000802:
116            par->codec_id = AV_CODEC_ID_ADPCM_THP;
117            break;
118        default:
119            avpriv_request_sample(s, "format 0x%X", format);
120            return AVERROR_PATCHWELCOME;
121        }
122
123        par->sample_rate = avio_rl32(pb);
124        if (par->sample_rate <= 0)
125            return AVERROR_INVALIDDATA;
126        avio_skip(pb, 6);
127
128        par->ch_layout.nb_channels = avio_rl16(pb);
129        if (!par->ch_layout.nb_channels)
130            return AVERROR_INVALIDDATA;
131
132        switch (par->codec_id) {
133        case AV_CODEC_ID_XMA2:
134            ret = ff_alloc_extradata(par, 34);
135            if (ret < 0)
136                return ret;
137            memset(par->extradata, 0, 34);
138            par->block_align = 2048;
139            break;
140        case AV_CODEC_ID_ADPCM_THP:
141            if (par->ch_layout.nb_channels > INT_MAX / 32)
142                return AVERROR_INVALIDDATA;
143            ret = ff_alloc_extradata(par, 32 * par->ch_layout.nb_channels);
144            if (ret < 0)
145                return ret;
146            avio_seek(pb, 0x80, SEEK_SET);
147            for (c = 0; c < par->ch_layout.nb_channels; c++) {
148                avio_read(pb, par->extradata + 32 * c, 32);
149                avio_skip(pb, 14);
150            }
151            par->block_align = 8 * par->ch_layout.nb_channels;
152            break;
153        }
154    } else {
155        av_assert0(0);
156    }
157
158    avio_skip(pb, offset - avio_tell(pb));
159    ffformatcontext(s)->data_offset = avio_tell(pb);
160
161    avpriv_set_pts_info(st, 64, 1, par->sample_rate);
162
163    return 0;
164}
165
166static int fsb_read_packet(AVFormatContext *s, AVPacket *pkt)
167{
168    AVCodecParameters *par = s->streams[0]->codecpar;
169    int64_t pos;
170    int ret;
171
172    if (avio_feof(s->pb))
173        return AVERROR_EOF;
174
175    pos = avio_tell(s->pb);
176    if (par->codec_id == AV_CODEC_ID_ADPCM_THP &&
177        par->ch_layout.nb_channels > 1) {
178        int i, ch;
179
180        ret = av_new_packet(pkt, par->block_align);
181        if (ret < 0)
182            return ret;
183        for (i = 0; i < 4; i++) {
184            for (ch = 0; ch < par->ch_layout.nb_channels; ch++) {
185                pkt->data[ch * 8 + i * 2 + 0] = avio_r8(s->pb);
186                pkt->data[ch * 8 + i * 2 + 1] = avio_r8(s->pb);
187            }
188        }
189        ret = 0;
190    } else {
191        ret = av_get_packet(s->pb, pkt, par->block_align);
192    }
193
194    if (par->codec_id == AV_CODEC_ID_XMA2 && pkt->size >= 1)
195        pkt->duration = (pkt->data[0] >> 2) * 512;
196
197    pkt->pos = pos;
198    pkt->stream_index = 0;
199
200    return ret;
201}
202
203const AVInputFormat ff_fsb_demuxer = {
204    .name        = "fsb",
205    .long_name   = NULL_IF_CONFIG_SMALL("FMOD Sample Bank"),
206    .read_probe  = fsb_probe,
207    .read_header = fsb_read_header,
208    .read_packet = fsb_read_packet,
209    .extensions  = "fsb",
210    .flags       = AVFMT_GENERIC_INDEX,
211};
212