FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/pp_bnk.c
Date: 2024-04-25 05:10:44
Exec Total Coverage
Lines: 110 140 78.6%
Functions: 6 7 85.7%
Branches: 66 96 68.8%

Line Branch Exec Source
1 /*
2 * Pro Pinball Series Soundbank (44c, 22c, 11c, 5c) demuxer.
3 *
4 * Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.com)
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22 #include "avformat.h"
23 #include "demux.h"
24 #include "internal.h"
25 #include "libavutil/intreadwrite.h"
26 #include "libavutil/avassert.h"
27 #include "libavutil/channel_layout.h"
28 #include "libavutil/internal.h"
29 #include "libavutil/mem.h"
30
31 #define PP_BNK_MAX_READ_SIZE 4096
32 #define PP_BNK_FILE_HEADER_SIZE 20
33 #define PP_BNK_TRACK_SIZE 20
34
35 typedef struct PPBnkHeader {
36 uint32_t bank_id; /*< Bank ID, useless for our purposes. */
37 uint32_t sample_rate; /*< Sample rate of the contained tracks. */
38 uint32_t always1; /*< Unknown, always seems to be 1. */
39 uint32_t track_count; /*< Number of tracks in the file. */
40 uint32_t flags; /*< Flags. */
41 } PPBnkHeader;
42
43 typedef struct PPBnkTrack {
44 uint32_t id; /*< Track ID. Usually track[i].id == track[i-1].id + 1, but not always */
45 uint32_t size; /*< Size of the data in bytes. */
46 uint32_t sample_rate; /*< Sample rate. */
47 uint32_t always1_1; /*< Unknown, always seems to be 1. */
48 uint32_t always1_2; /*< Unknown, always seems to be 1. */
49 } PPBnkTrack;
50
51 typedef struct PPBnkCtxTrack {
52 int64_t data_offset;
53 uint32_t data_size;
54 uint32_t bytes_read;
55 } PPBnkCtxTrack;
56
57 typedef struct PPBnkCtx {
58 int track_count;
59 PPBnkCtxTrack *tracks;
60 uint32_t current_track;
61 int is_music;
62 } PPBnkCtx;
63
64 enum {
65 PP_BNK_FLAG_PERSIST = (1 << 0), /*< This is a large file, keep in memory. */
66 PP_BNK_FLAG_MUSIC = (1 << 1), /*< This is music. */
67 PP_BNK_FLAG_MASK = (PP_BNK_FLAG_PERSIST | PP_BNK_FLAG_MUSIC)
68 };
69
70 10 static void pp_bnk_parse_header(PPBnkHeader *hdr, const uint8_t *buf)
71 {
72 10 hdr->bank_id = AV_RL32(buf + 0);
73 10 hdr->sample_rate = AV_RL32(buf + 4);
74 10 hdr->always1 = AV_RL32(buf + 8);
75 10 hdr->track_count = AV_RL32(buf + 12);
76 10 hdr->flags = AV_RL32(buf + 16);
77 10 }
78
79 17 static void pp_bnk_parse_track(PPBnkTrack *trk, const uint8_t *buf)
80 {
81 17 trk->id = AV_RL32(buf + 0);
82 17 trk->size = AV_RL32(buf + 4);
83 17 trk->sample_rate = AV_RL32(buf + 8);
84 17 trk->always1_1 = AV_RL32(buf + 12);
85 17 trk->always1_2 = AV_RL32(buf + 16);
86 17 }
87
88 7128 static int pp_bnk_probe(const AVProbeData *p)
89 {
90 7128 uint32_t sample_rate = AV_RL32(p->buf + 4);
91 7128 uint32_t track_count = AV_RL32(p->buf + 12);
92 7128 uint32_t flags = AV_RL32(p->buf + 16);
93
94
4/4
✓ Branch 0 taken 6817 times.
✓ Branch 1 taken 311 times.
✓ Branch 2 taken 932 times.
✓ Branch 3 taken 5885 times.
7128 if (track_count == 0 || track_count > INT_MAX)
95 1243 return 0;
96
97
6/6
✓ Branch 0 taken 5884 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 5875 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 5874 times.
✓ Branch 5 taken 1 times.
5885 if ((sample_rate != 5512) && (sample_rate != 11025) &&
98
2/2
✓ Branch 0 taken 5872 times.
✓ Branch 1 taken 2 times.
5874 (sample_rate != 22050) && (sample_rate != 44100))
99 5872 return 0;
100
101 /* Check the first track header. */
102
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (AV_RL32(p->buf + 28) != sample_rate)
103 3 return 0;
104
105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if ((flags & ~PP_BNK_FLAG_MASK) != 0)
106 return 0;
107
108 10 return AVPROBE_SCORE_MAX / 4 + 1;
109 }
110
111 10 static int pp_bnk_read_header(AVFormatContext *s)
112 {
113 int64_t ret;
114 AVStream *st;
115 AVCodecParameters *par;
116 10 PPBnkCtx *ctx = s->priv_data;
117 uint8_t buf[FFMAX(PP_BNK_FILE_HEADER_SIZE, PP_BNK_TRACK_SIZE)];
118 PPBnkHeader hdr;
119
120
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if ((ret = avio_read(s->pb, buf, PP_BNK_FILE_HEADER_SIZE)) < 0)
121 return ret;
122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 else if (ret != PP_BNK_FILE_HEADER_SIZE)
123 return AVERROR(EIO);
124
125 10 pp_bnk_parse_header(&hdr, buf);
126
127
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (hdr.track_count == 0 || hdr.track_count > INT_MAX)
128 return AVERROR_INVALIDDATA;
129
130
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (hdr.sample_rate == 0 || hdr.sample_rate > INT_MAX)
131 return AVERROR_INVALIDDATA;
132
133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (hdr.always1 != 1) {
134 avpriv_request_sample(s, "Non-one header value");
135 return AVERROR_PATCHWELCOME;
136 }
137
138 10 ctx->track_count = hdr.track_count;
139
140
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (!(ctx->tracks = av_malloc_array(hdr.track_count, sizeof(PPBnkCtxTrack))))
141 return AVERROR(ENOMEM);
142
143 /* Parse and validate each track. */
144
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 4 times.
22 for (int i = 0; i < hdr.track_count; i++) {
145 PPBnkTrack e;
146 18 PPBnkCtxTrack *trk = ctx->tracks + i;
147
148 18 ret = avio_read(s->pb, buf, PP_BNK_TRACK_SIZE);
149
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
18 if (ret < 0 && ret != AVERROR_EOF)
150 return ret;
151
152 /* Short byte-count or EOF, we have a truncated file. */
153
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17 times.
18 if (ret != PP_BNK_TRACK_SIZE) {
154 1 av_log(s, AV_LOG_WARNING, "File truncated at %d/%u track(s)\n",
155 i, hdr.track_count);
156 1 ctx->track_count = i;
157 6 break;
158 }
159
160 17 pp_bnk_parse_track(&e, buf);
161
162 /* The individual sample rates of all tracks must match that of the file header. */
163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (e.sample_rate != hdr.sample_rate)
164 return AVERROR_INVALIDDATA;
165
166
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
17 if (e.always1_1 != 1 || e.always1_2 != 1) {
167 avpriv_request_sample(s, "Non-one track header values");
168 return AVERROR_PATCHWELCOME;
169 }
170
171 17 trk->data_offset = avio_tell(s->pb);
172 17 trk->data_size = e.size;
173 17 trk->bytes_read = 0;
174
175 /*
176 * Skip over the data to the next stream header.
177 * Sometimes avio_skip() doesn't detect EOF. If it doesn't, either:
178 * - the avio_read() above will, or
179 * - pp_bnk_read_packet() will read a truncated last track.
180 */
181
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 12 times.
17 if ((ret = avio_skip(s->pb, e.size)) == AVERROR_EOF) {
182 5 ctx->track_count = i + 1;
183 5 av_log(s, AV_LOG_WARNING,
184 "Track %d has truncated data, assuming track count == %d\n",
185 i, ctx->track_count);
186 5 break;
187
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 } else if (ret < 0) {
188 return ret;
189 }
190 }
191
192 /* File is only a header. */
193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ctx->track_count == 0)
194 return AVERROR_INVALIDDATA;
195
196 21 ctx->is_music = (hdr.flags & PP_BNK_FLAG_MUSIC) &&
197
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
11 (ctx->track_count == 2) &&
198
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 (ctx->tracks[0].data_size == ctx->tracks[1].data_size);
199
200 /* Build the streams. */
201
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 10 times.
26 for (int i = 0; i < (ctx->is_music ? 1 : ctx->track_count); i++) {
202
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if (!(st = avformat_new_stream(s, NULL)))
203 return AVERROR(ENOMEM);
204
205 16 par = st->codecpar;
206 16 par->codec_type = AVMEDIA_TYPE_AUDIO;
207 16 par->codec_id = AV_CODEC_ID_ADPCM_IMA_CUNNING;
208 16 par->format = AV_SAMPLE_FMT_S16P;
209
210 16 av_channel_layout_default(&par->ch_layout, ctx->is_music + 1);
211 16 par->sample_rate = hdr.sample_rate;
212 16 par->bits_per_coded_sample = 4;
213 16 par->block_align = 1;
214 16 par->bit_rate = par->sample_rate * (int64_t)par->bits_per_coded_sample *
215 16 par->ch_layout.nb_channels;
216
217 16 avpriv_set_pts_info(st, 64, 1, par->sample_rate);
218 16 st->start_time = 0;
219 16 st->duration = ctx->tracks[i].data_size * 2;
220 }
221
222 10 return 0;
223 }
224
225 76 static int pp_bnk_read_packet(AVFormatContext *s, AVPacket *pkt)
226 {
227 76 PPBnkCtx *ctx = s->priv_data;
228
229 /*
230 * Read a packet from each track, round-robin style.
231 * This method is nasty, but needed to avoid "Too many packets buffered" errors.
232 */
233
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 20 times.
132 for (int i = 0; i < ctx->track_count; i++, ctx->current_track++)
234 {
235 int64_t ret;
236 int size;
237 PPBnkCtxTrack *trk;
238
239 112 ctx->current_track %= ctx->track_count;
240
241 112 trk = ctx->tracks + ctx->current_track;
242
243
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 73 times.
112 if (trk->bytes_read == trk->data_size)
244 39 continue;
245
246
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 73 times.
73 if ((ret = avio_seek(s->pb, trk->data_offset + trk->bytes_read, SEEK_SET)) < 0)
247 return ret;
248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 else if (ret != trk->data_offset + trk->bytes_read)
249 return AVERROR(EIO);
250
251 73 size = FFMIN(trk->data_size - trk->bytes_read, PP_BNK_MAX_READ_SIZE);
252
253
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 24 times.
73 if (!ctx->is_music) {
254 49 ret = av_get_packet(s->pb, pkt, size);
255
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 44 times.
49 if (ret == AVERROR_EOF) {
256 /* If we've hit EOF, don't attempt this track again. */
257 5 trk->data_size = trk->bytes_read;
258 5 continue;
259 }
260 } else {
261
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
24 if (!pkt->data && (ret = av_new_packet(pkt, size * 2)) < 0)
262 return ret;
263 24 ret = avio_read(s->pb, pkt->data + size * ctx->current_track, size);
264
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
24 if (ret >= 0 && ret != size) {
265 /* Only return stereo packets if both tracks could be read. */
266 ret = AVERROR_EOF;
267 }
268 }
269
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 if (ret < 0)
270 return ret;
271
272 68 trk->bytes_read += ret;
273 68 pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
274 68 pkt->stream_index = ctx->current_track;
275 68 pkt->duration = ret * 2;
276
277
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 44 times.
68 if (ctx->is_music) {
278
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (pkt->stream_index == 0)
279 12 continue;
280
281 12 pkt->stream_index = 0;
282 }
283
284 56 ctx->current_track++;
285 56 return 0;
286 }
287
288 /* If we reach here, we're done. */
289 20 return AVERROR_EOF;
290 }
291
292 10 static int pp_bnk_read_close(AVFormatContext *s)
293 {
294 10 PPBnkCtx *ctx = s->priv_data;
295
296 10 av_freep(&ctx->tracks);
297
298 10 return 0;
299 }
300
301 static int pp_bnk_seek(AVFormatContext *s, int stream_index,
302 int64_t pts, int flags)
303 {
304 PPBnkCtx *ctx = s->priv_data;
305
306 if (pts != 0)
307 return AVERROR(EINVAL);
308
309 if (ctx->is_music) {
310 av_assert0(stream_index == 0);
311 ctx->tracks[0].bytes_read = 0;
312 ctx->tracks[1].bytes_read = 0;
313 } else {
314 ctx->tracks[stream_index].bytes_read = 0;
315 }
316
317 return 0;
318 }
319
320 const FFInputFormat ff_pp_bnk_demuxer = {
321 .p.name = "pp_bnk",
322 .p.long_name = NULL_IF_CONFIG_SMALL("Pro Pinball Series Soundbank"),
323 .priv_data_size = sizeof(PPBnkCtx),
324 .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
325 .read_probe = pp_bnk_probe,
326 .read_header = pp_bnk_read_header,
327 .read_packet = pp_bnk_read_packet,
328 .read_close = pp_bnk_read_close,
329 .read_seek = pp_bnk_seek,
330 };
331