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