Browse code

avformat: add FSB demuxer

Signed-off-by: Paul B Mahol <onemda@gmail.com>

Paul B Mahol authored on 2015/10/19 21:42:56
Showing 5 changed files
... ...
@@ -20,7 +20,7 @@ version <next>:
20 20
 - selectivecolor filter
21 21
 - extensive native AAC encoder improvements
22 22
 - ADPCM PSX decoder
23
-- 3dostr, dcstr, genh, vag, xvag, ads, msf, svag & vpk demuxer
23
+- 3dostr, dcstr, fsb, genh, vag, xvag, ads, msf, svag & vpk demuxer
24 24
 - zscale filter
25 25
 - wve demuxer
26 26
 - zero-copy Intel QSV transcoding in ffmpeg
... ...
@@ -170,6 +170,7 @@ OBJS-$(CONFIG_FOURXM_DEMUXER)            += 4xm.o
170 170
 OBJS-$(CONFIG_FRAMECRC_MUXER)            += framecrcenc.o framehash.o
171 171
 OBJS-$(CONFIG_FRAMEMD5_MUXER)            += md5enc.o framehash.o
172 172
 OBJS-$(CONFIG_FRM_DEMUXER)               += frmdec.o
173
+OBJS-$(CONFIG_FSB_DEMUXER)               += fsb.o
173 174
 OBJS-$(CONFIG_GIF_MUXER)                 += gif.o
174 175
 OBJS-$(CONFIG_GIF_DEMUXER)               += gifdec.o
175 176
 OBJS-$(CONFIG_GSM_DEMUXER)               += gsmdec.o
... ...
@@ -138,6 +138,7 @@ void av_register_all(void)
138 138
     REGISTER_MUXER   (FRAMECRC,         framecrc);
139 139
     REGISTER_MUXER   (FRAMEMD5,         framemd5);
140 140
     REGISTER_DEMUXER (FRM,              frm);
141
+    REGISTER_DEMUXER (FSB,              fsb);
141 142
     REGISTER_MUXDEMUX(G722,             g722);
142 143
     REGISTER_MUXDEMUX(G723_1,           g723_1);
143 144
     REGISTER_DEMUXER (G729,             g729);
144 145
new file mode 100644
... ...
@@ -0,0 +1,210 @@
0
+/*
1
+ * FSB demuxer
2
+ * Copyright (c) 2015 Paul B Mahol
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+#include "libavutil/avassert.h"
22
+#include "libavutil/intreadwrite.h"
23
+#include "avformat.h"
24
+#include "avio.h"
25
+#include "internal.h"
26
+
27
+static int fsb_probe(AVProbeData *p)
28
+{
29
+    if (memcmp(p->buf, "FSB", 3) || p->buf[3] - '0' < 1 || p->buf[3] - '0' > 5)
30
+        return 0;
31
+    if (AV_RL32(p->buf + 4) != 1)
32
+        return 0;
33
+    return AVPROBE_SCORE_MAX;
34
+}
35
+
36
+static int fsb_read_header(AVFormatContext *s)
37
+{
38
+    AVIOContext *pb = s->pb;
39
+    unsigned format, version, c;
40
+    int64_t offset;
41
+    AVCodecContext *codec;
42
+    AVStream *st = avformat_new_stream(s, NULL);
43
+
44
+    avio_skip(pb, 3); // "FSB"
45
+    version = avio_r8(pb) - '0';
46
+    if (version != 4 && version != 3) {
47
+        avpriv_request_sample(s, "version %d", version);
48
+        return AVERROR_PATCHWELCOME;
49
+    }
50
+
51
+    avio_skip(pb, 4);
52
+
53
+    if (!st)
54
+        return AVERROR(ENOMEM);
55
+    codec = st->codec;
56
+    codec->codec_type  = AVMEDIA_TYPE_AUDIO;
57
+    codec->codec_tag   = 0;
58
+
59
+    if (version == 3) {
60
+        offset = avio_rl32(pb) + 0x18;
61
+        avio_skip(pb, 44);
62
+        st->duration = avio_rl32(pb);
63
+        avio_skip(pb, 12);
64
+        format = avio_rl32(pb);
65
+        codec->sample_rate = avio_rl32(pb);
66
+        if (codec->sample_rate <= 0)
67
+            return AVERROR_INVALIDDATA;
68
+        avio_skip(pb, 6);
69
+        codec->channels    = avio_rl16(pb);
70
+        if (!codec->channels)
71
+            return AVERROR_INVALIDDATA;
72
+
73
+        if (format & 0x00000100) {
74
+            codec->codec_id    = AV_CODEC_ID_PCM_S16LE;
75
+            codec->block_align = 4096 * codec->channels;
76
+        } else if (format & 0x00400000) {
77
+            codec->bits_per_coded_sample = 4;
78
+            codec->codec_id    = AV_CODEC_ID_ADPCM_IMA_WAV;
79
+            codec->block_align = 36 * codec->channels;
80
+        } else if (format & 0x00800000) {
81
+            codec->codec_id    = AV_CODEC_ID_ADPCM_PSX;
82
+            codec->block_align = 16 * codec->channels;
83
+        } else if (format & 0x02000000) {
84
+            codec->codec_id    = AV_CODEC_ID_ADPCM_THP;
85
+            codec->block_align = 8 * codec->channels;
86
+            if (codec->channels > INT_MAX / 32)
87
+                return AVERROR_INVALIDDATA;
88
+            ff_alloc_extradata(codec, 32 * codec->channels);
89
+            if (!codec->extradata)
90
+                return AVERROR(ENOMEM);
91
+            avio_seek(pb, 0x68, SEEK_SET);
92
+            for (c = 0; c < codec->channels; c++) {
93
+                avio_read(pb, codec->extradata + 32 * c, 32);
94
+                avio_skip(pb, 14);
95
+            }
96
+        } else {
97
+            avpriv_request_sample(s, "format 0x%X", format);
98
+            return AVERROR_PATCHWELCOME;
99
+        }
100
+    } else if (version == 4) {
101
+        offset = avio_rl32(pb) + 0x30;
102
+        avio_skip(pb, 80);
103
+        st->duration = avio_rl32(pb);
104
+
105
+        format = avio_rb32(pb);
106
+        switch(format) {
107
+        case 0x40001001:
108
+        case 0x00001005:
109
+        case 0x40001081:
110
+        case 0x40200001:
111
+            codec->codec_id = AV_CODEC_ID_XMA2;
112
+            break;
113
+        case 0x40000802:
114
+            codec->codec_id = AV_CODEC_ID_ADPCM_THP;
115
+            break;
116
+        default:
117
+            avpriv_request_sample(s, "format 0x%X", format);
118
+            return AVERROR_PATCHWELCOME;
119
+        }
120
+
121
+        codec->sample_rate = avio_rl32(pb);
122
+        if (codec->sample_rate <= 0)
123
+            return AVERROR_INVALIDDATA;
124
+        avio_skip(pb, 6);
125
+
126
+        codec->channels    = avio_rl16(pb);
127
+        if (!codec->channels)
128
+            return AVERROR_INVALIDDATA;
129
+
130
+        switch (codec->codec_id) {
131
+        case AV_CODEC_ID_XMA2:
132
+            ff_alloc_extradata(codec, 34);
133
+            if (!codec->extradata)
134
+                return AVERROR(ENOMEM);
135
+            memset(codec->extradata, 0, 34);
136
+            codec->block_align = 2048;
137
+            break;
138
+        case AV_CODEC_ID_ADPCM_THP:
139
+            if (codec->channels > INT_MAX / 32)
140
+                return AVERROR_INVALIDDATA;
141
+            ff_alloc_extradata(codec, 32 * codec->channels);
142
+            if (!codec->extradata)
143
+                return AVERROR(ENOMEM);
144
+            avio_seek(pb, 0x80, SEEK_SET);
145
+            for (c = 0; c < codec->channels; c++) {
146
+                avio_read(pb, codec->extradata + 32 * c, 32);
147
+                avio_skip(pb, 14);
148
+            }
149
+            codec->block_align = 8 * codec->channels;
150
+            break;
151
+        }
152
+    } else {
153
+        av_assert0(0);
154
+    }
155
+
156
+    avio_skip(pb, offset - avio_tell(pb));
157
+    s->internal->data_offset = avio_tell(pb);
158
+
159
+    avpriv_set_pts_info(st, 64, 1, codec->sample_rate);
160
+
161
+    return 0;
162
+}
163
+
164
+static int fsb_read_packet(AVFormatContext *s, AVPacket *pkt)
165
+{
166
+    AVCodecContext *codec = s->streams[0]->codec;
167
+    int64_t pos;
168
+    int ret;
169
+
170
+    if (avio_feof(s->pb))
171
+        return AVERROR_EOF;
172
+
173
+    pos = avio_tell(s->pb);
174
+    if (codec->codec_id == AV_CODEC_ID_ADPCM_THP &&
175
+               codec->channels > 1) {
176
+        int i, ch;
177
+
178
+        ret = av_new_packet(pkt, codec->block_align);
179
+        if (ret < 0)
180
+            return ret;
181
+        for (i = 0; i < 4; i++) {
182
+            for (ch = 0; ch < codec->channels; ch++) {
183
+                pkt->data[ch * 8 + i * 2 + 0] = avio_r8(s->pb);
184
+                pkt->data[ch * 8 + i * 2 + 1] = avio_r8(s->pb);
185
+            }
186
+        }
187
+        ret = 0;
188
+    } else {
189
+        ret = av_get_packet(s->pb, pkt, codec->block_align);
190
+    }
191
+
192
+    if (codec->codec_id == AV_CODEC_ID_XMA2 && pkt->size >= 1)
193
+        pkt->duration = (pkt->data[0] >> 2) * 512;
194
+
195
+    pkt->pos = pos;
196
+    pkt->stream_index = 0;
197
+
198
+    return ret;
199
+}
200
+
201
+AVInputFormat ff_fsb_demuxer = {
202
+    .name        = "fsb",
203
+    .long_name   = NULL_IF_CONFIG_SMALL("FMOD Sample Bank"),
204
+    .read_probe  = fsb_probe,
205
+    .read_header = fsb_read_header,
206
+    .read_packet = fsb_read_packet,
207
+    .extensions  = "fsb",
208
+    .flags       = AVFMT_GENERIC_INDEX,
209
+};
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/version.h"
31 31
 
32 32
 #define LIBAVFORMAT_VERSION_MAJOR  57
33
-#define LIBAVFORMAT_VERSION_MINOR  17
33
+#define LIBAVFORMAT_VERSION_MINOR  18
34 34
 #define LIBAVFORMAT_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \