FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/fsb.c
Date: 2024-04-19 17:50:32
Exec Total Coverage
Lines: 3 124 2.4%
Functions: 1 3 33.3%
Branches: 1 70 1.4%

Line Branch Exec Source
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 "demux.h"
27 #include "internal.h"
28
29 7125 static int fsb_probe(const AVProbeData *p)
30 {
31
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 7125 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
7125 if (memcmp(p->buf, "FSB", 3) || p->buf[3] - '0' < 1 || p->buf[3] - '0' > 5)
32 7125 return 0;
33 if (AV_RL32(p->buf + 4) != 1)
34 return 0;
35 return AVPROBE_SCORE_MAX;
36 }
37
38 static int fsb_read_header(AVFormatContext *s)
39 {
40 AVIOContext *pb = s->pb;
41 unsigned format, version, c;
42 int64_t offset;
43 AVCodecParameters *par;
44 AVStream *st = avformat_new_stream(s, NULL);
45 int ret;
46
47 avio_skip(pb, 3); // "FSB"
48 version = avio_r8(pb) - '0';
49 if (version != 4 && version != 3) {
50 avpriv_request_sample(s, "version %d", version);
51 return AVERROR_PATCHWELCOME;
52 }
53
54 avio_skip(pb, 4);
55
56 if (!st)
57 return AVERROR(ENOMEM);
58 par = st->codecpar;
59 par->codec_type = AVMEDIA_TYPE_AUDIO;
60 par->codec_tag = 0;
61
62 if (version == 3) {
63 offset = avio_rl32(pb) + 0x18;
64 avio_skip(pb, 44);
65 st->duration = avio_rl32(pb);
66 avio_skip(pb, 12);
67 format = avio_rl32(pb);
68 par->sample_rate = avio_rl32(pb);
69 if (par->sample_rate <= 0)
70 return AVERROR_INVALIDDATA;
71 avio_skip(pb, 6);
72 par->ch_layout.nb_channels = avio_rl16(pb);
73 if (!par->ch_layout.nb_channels)
74 return AVERROR_INVALIDDATA;
75
76 if (format & 0x00000100) {
77 par->codec_id = AV_CODEC_ID_PCM_S16LE;
78 par->block_align = 4096 * par->ch_layout.nb_channels;
79 } else if (format & 0x00400000) {
80 par->bits_per_coded_sample = 4;
81 par->codec_id = AV_CODEC_ID_ADPCM_IMA_WAV;
82 par->block_align = 36 * par->ch_layout.nb_channels;
83 } else if (format & 0x00800000) {
84 par->codec_id = AV_CODEC_ID_ADPCM_PSX;
85 par->block_align = 16 * par->ch_layout.nb_channels;
86 } else if (format & 0x02000000) {
87 par->codec_id = AV_CODEC_ID_ADPCM_THP;
88 par->block_align = 8 * par->ch_layout.nb_channels;
89 if (par->ch_layout.nb_channels > INT_MAX / 32)
90 return AVERROR_INVALIDDATA;
91 ret = ff_alloc_extradata(par, 32 * par->ch_layout.nb_channels);
92 if (ret < 0)
93 return ret;
94 avio_seek(pb, 0x68, SEEK_SET);
95 for (c = 0; c < par->ch_layout.nb_channels; c++) {
96 avio_read(pb, par->extradata + 32 * c, 32);
97 avio_skip(pb, 14);
98 }
99 } else {
100 avpriv_request_sample(s, "format 0x%X", format);
101 return AVERROR_PATCHWELCOME;
102 }
103 } else if (version == 4) {
104 offset = avio_rl32(pb) + 0x30;
105 avio_skip(pb, 80);
106 st->duration = avio_rl32(pb);
107
108 format = avio_rb32(pb);
109 switch(format) {
110 case 0x40001001:
111 case 0x00001005:
112 case 0x40001081:
113 case 0x40200001:
114 par->codec_id = AV_CODEC_ID_XMA2;
115 break;
116 case 0x40000802:
117 par->codec_id = AV_CODEC_ID_ADPCM_THP;
118 break;
119 default:
120 avpriv_request_sample(s, "format 0x%X", format);
121 return AVERROR_PATCHWELCOME;
122 }
123
124 par->sample_rate = avio_rl32(pb);
125 if (par->sample_rate <= 0)
126 return AVERROR_INVALIDDATA;
127 avio_skip(pb, 6);
128
129 par->ch_layout.nb_channels = avio_rl16(pb);
130 if (!par->ch_layout.nb_channels)
131 return AVERROR_INVALIDDATA;
132
133 switch (par->codec_id) {
134 case AV_CODEC_ID_XMA2:
135 ret = ff_alloc_extradata(par, 34);
136 if (ret < 0)
137 return ret;
138 memset(par->extradata, 0, 34);
139 par->block_align = 2048;
140 break;
141 case AV_CODEC_ID_ADPCM_THP:
142 if (par->ch_layout.nb_channels > INT_MAX / 32)
143 return AVERROR_INVALIDDATA;
144 ret = ff_alloc_extradata(par, 32 * par->ch_layout.nb_channels);
145 if (ret < 0)
146 return ret;
147 avio_seek(pb, 0x80, SEEK_SET);
148 for (c = 0; c < par->ch_layout.nb_channels; c++) {
149 avio_read(pb, par->extradata + 32 * c, 32);
150 avio_skip(pb, 14);
151 }
152 par->block_align = 8 * par->ch_layout.nb_channels;
153 break;
154 }
155 } else {
156 av_assert0(0);
157 }
158
159 avio_skip(pb, offset - avio_tell(pb));
160
161 avpriv_set_pts_info(st, 64, 1, par->sample_rate);
162
163 return 0;
164 }
165
166 static 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
203 const FFInputFormat ff_fsb_demuxer = {
204 .p.name = "fsb",
205 .p.long_name = NULL_IF_CONFIG_SMALL("FMOD Sample Bank"),
206 .p.extensions = "fsb",
207 .p.flags = AVFMT_GENERIC_INDEX,
208 .read_probe = fsb_probe,
209 .read_header = fsb_read_header,
210 .read_packet = fsb_read_packet,
211 };
212