Message ID | 20200329171534.25441-3-zane@zanevaniperen.com |
---|---|
State | Superseded |
Headers | show |
Series | Pro Pinball Series Soundbank demuxer + decoder. | expand |
Context | Check | Description |
---|---|---|
andriy/ffmpeg-patchwork | success | Make fate finished |
Quoting Zane van Iperen (2020-03-29 19:18:20) > Signed-off-by: Zane van Iperen <zane@zanevaniperen.com> > +static int pp_bnk_read_header(AVFormatContext *s) > +{ > + int ret; > + AVStream *st; > + AVCodecParameters *par; > + PPBnkCtx *ctx = s->priv_data; > + uint8_t buf[FFMAX(PP_BNK_FILE_HEADER_SIZE, PP_BNK_TRACK_SIZE)]; > + PPBnkHeader hdr; > + > + if ((ret = avio_read(s->pb, buf, PP_BNK_FILE_HEADER_SIZE)) < 0) > + return ret; > + else if (ret != PP_BNK_FILE_HEADER_SIZE) > + return AVERROR(EIO); > + > + pp_bnk_parse_header(&hdr, buf); > + > + if (hdr.track_count == 0 || hdr.track_count > INT_MAX) > + return AVERROR_INVALIDDATA; > + > + if (hdr.sample_rate == 0 || hdr.sample_rate > INT_MAX) > + return AVERROR_INVALIDDATA; > + > + if (hdr.always1 != 1) { > + avpriv_request_sample(s, "Non-one header value"); > + return AVERROR_PATCHWELCOME; > + } > + > + ctx->track_count = hdr.track_count; > + if ((ret = av_reallocp_array(&ctx->tracks, hdr.track_count, sizeof(PPBnkCtxTrack)))) Why realloc? Seems this is only allocated once. > + return ret; > + > + /* Parse and validate each track. */ > + for (int i = 0; i < hdr.track_count; i++) { > + PPBnkTrack e; > + > + if ((ret = avio_read(s->pb, buf, PP_BNK_TRACK_SIZE)) < 0) { > + av_freep(&ctx->tracks); You are duplicating this free at too many places. Would be better to have a cleanup block at the end and jump to that. > + return ret; > + } else if (ret != PP_BNK_TRACK_SIZE) { > + av_freep(&ctx->tracks); > + return AVERROR(EIO); > + } > + > + pp_bnk_parse_track(&e, buf); > + > + /* The individual sample rates of all tracks must match that of the file header. */ > + if (e.sample_rate != hdr.sample_rate) { > + av_freep(&ctx->tracks); > + return AVERROR_INVALIDDATA; > + } > + > + ctx->tracks[i].data_offset = avio_tell(s->pb); > + ctx->tracks[i].data_size = e.size; > + > + /* Skip over the data to the next stream header. */ > + avio_skip(s->pb, e.size); > + } > + > + /* Build the streams. */ > + for (int i = 0; i < hdr.track_count; i++) { > + nit: unnecessary empty line > + if (!(st = avformat_new_stream(s, NULL))) { > + av_freep(&ctx->tracks); > + return AVERROR(ENOMEM); > + } > + > + par = st->codecpar; > + par->codec_type = AVMEDIA_TYPE_AUDIO; > + par->codec_id = AV_CODEC_ID_ADPCM_IMA_CUNNING; > + par->format = AV_SAMPLE_FMT_S16; > + par->channel_layout = AV_CH_LAYOUT_MONO; > + par->channels = 1; > + par->sample_rate = hdr.sample_rate; > + par->bits_per_coded_sample = 4; > + par->bits_per_raw_sample = 16; > + par->block_align = 1; > + par->bit_rate = par->sample_rate * par->bits_per_coded_sample; > + > + avpriv_set_pts_info(st, 64, 1, par->sample_rate); > + st->start_time = 0; > + st->duration = ctx->tracks[i].data_size * 2; > + } > + > + /* Seek to the start of the first stream. */ > + if ((ret = avio_seek(s->pb, ctx->tracks[0].data_offset, SEEK_SET)) < 0) { > + av_freep(&ctx->tracks); > + return ret; > + } else if (ret != ctx->tracks[0].data_offset) { > + av_freep(&ctx->tracks); > + return AVERROR(EIO); > + } > + > + return 0; > +} > + > +static int pp_bnk_read_packet(AVFormatContext *s, AVPacket *pkt) > +{ > + int64_t ret; > + int size; > + PPBnkCtx *ctx = s->priv_data; > + PPBnkCtxTrack *trk = ctx->tracks + ctx->current_track; > + > + av_assert0(ctx->bytes_read <= trk->data_size); > + > + if (ctx->bytes_read == trk->data_size) { > + nit: unnecessary empty line Otherwise looks ok, but would be nice to have some tests.
On Mon, 06 Apr 2020 15:00:01 +0200 "Anton Khirnov" <anton@khirnov.net> wrote: > Quoting Zane van Iperen (2020-03-29 19:18:20) > > Signed-off-by: Zane van Iperen <zane@zanevaniperen.com> > > +static int pp_bnk_read_header(AVFormatContext *s) > > +{ > > + int ret; > > + AVStream *st; > > + AVCodecParameters *par; > > + PPBnkCtx *ctx = s->priv_data; > > + uint8_t buf[FFMAX(PP_BNK_FILE_HEADER_SIZE, PP_BNK_TRACK_SIZE)]; > > + PPBnkHeader hdr; > > + > > + if ((ret = avio_read(s->pb, buf, PP_BNK_FILE_HEADER_SIZE)) < 0) > > + return ret; > > + else if (ret != PP_BNK_FILE_HEADER_SIZE) > > + return AVERROR(EIO); > > + > > + pp_bnk_parse_header(&hdr, buf); > > + > > + if (hdr.track_count == 0 || hdr.track_count > INT_MAX) > > + return AVERROR_INVALIDDATA; > > + > > + if (hdr.sample_rate == 0 || hdr.sample_rate > INT_MAX) > > + return AVERROR_INVALIDDATA; > > + > > + if (hdr.always1 != 1) { > > + avpriv_request_sample(s, "Non-one header value"); > > + return AVERROR_PATCHWELCOME; > > + } > > + > > + ctx->track_count = hdr.track_count; > > + if ((ret = av_reallocp_array(&ctx->tracks, hdr.track_count, > > sizeof(PPBnkCtxTrack)))) > > Why realloc? Seems this is only allocated once. Good question. Fixed. > > + return ret; > > + > > + /* Parse and validate each track. */ > > + for (int i = 0; i < hdr.track_count; i++) { > > + PPBnkTrack e; > > + > > + if ((ret = avio_read(s->pb, buf, PP_BNK_TRACK_SIZE)) < 0) { > > + av_freep(&ctx->tracks); > > You are duplicating this free at too many places. Would be better to > have a cleanup block at the end and jump to that. > I did that originally, however it's at the awkward spot where doing that causes the code to be larger than the way it is currently. I'll change it. > > + return ret; > > + } else if (ret != PP_BNK_TRACK_SIZE) { > > + av_freep(&ctx->tracks); > > + return AVERROR(EIO); > > + } > > + > > + pp_bnk_parse_track(&e, buf); > > + > > + /* The individual sample rates of all tracks must match > > that of the file header. */ > > + if (e.sample_rate != hdr.sample_rate) { > > + av_freep(&ctx->tracks); > > + return AVERROR_INVALIDDATA; > > + } > > + > > + ctx->tracks[i].data_offset = avio_tell(s->pb); > > + ctx->tracks[i].data_size = e.size; > > + > > + /* Skip over the data to the next stream header. */ > > + avio_skip(s->pb, e.size); > > + } > > + > > + /* Build the streams. */ > > + for (int i = 0; i < hdr.track_count; i++) { > > + > > nit: unnecessary empty line > Nit picked. > > + if (!(st = avformat_new_stream(s, NULL))) { > > + av_freep(&ctx->tracks); > > + return AVERROR(ENOMEM); > > + } > > + > > + par = st->codecpar; > > + par->codec_type = AVMEDIA_TYPE_AUDIO; > > + par->codec_id = > > AV_CODEC_ID_ADPCM_IMA_CUNNING; > > + par->format = AV_SAMPLE_FMT_S16; > > + par->channel_layout = AV_CH_LAYOUT_MONO; > > + par->channels = 1; > > + par->sample_rate = hdr.sample_rate; > > + par->bits_per_coded_sample = 4; > > + par->bits_per_raw_sample = 16; > > + par->block_align = 1; > > + par->bit_rate = par->sample_rate * > > par->bits_per_coded_sample; + > > + avpriv_set_pts_info(st, 64, 1, par->sample_rate); > > + st->start_time = 0; > > + st->duration = ctx->tracks[i].data_size * 2; > > + } > > + > > + /* Seek to the start of the first stream. */ > > + if ((ret = avio_seek(s->pb, ctx->tracks[0].data_offset, > > SEEK_SET)) < 0) { > > + av_freep(&ctx->tracks); > > + return ret; > > + } else if (ret != ctx->tracks[0].data_offset) { > > + av_freep(&ctx->tracks); > > + return AVERROR(EIO); > > + } > > + > > + return 0; > > +} > > + > > +static int pp_bnk_read_packet(AVFormatContext *s, AVPacket *pkt) > > +{ > > + int64_t ret; > > + int size; > > + PPBnkCtx *ctx = s->priv_data; > > + PPBnkCtxTrack *trk = ctx->tracks + ctx->current_track; > > + > > + av_assert0(ctx->bytes_read <= trk->data_size); > > + > > + if (ctx->bytes_read == trk->data_size) { > > + > > nit: unnecessary empty line Fixed. > > Otherwise looks ok, but would be nice to have some tests. > I have tests ready, the plan was to send them if merged (and after samples are uploaded) to avoid https://patchwork.ffmpeg.org/ failures. Should I include them in this irregardless? Zane > -- > Anton Khirnov > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
On 4/6/20, Zane van Iperen <zane@zanevaniperen.com> wrote: > On Mon, 06 Apr 2020 15:00:01 +0200 > "Anton Khirnov" <anton@khirnov.net> wrote: > >> Quoting Zane van Iperen (2020-03-29 19:18:20) >> > Signed-off-by: Zane van Iperen <zane@zanevaniperen.com> >> > +static int pp_bnk_read_header(AVFormatContext *s) >> > +{ >> > + int ret; >> > + AVStream *st; >> > + AVCodecParameters *par; >> > + PPBnkCtx *ctx = s->priv_data; >> > + uint8_t buf[FFMAX(PP_BNK_FILE_HEADER_SIZE, PP_BNK_TRACK_SIZE)]; >> > + PPBnkHeader hdr; >> > + >> > + if ((ret = avio_read(s->pb, buf, PP_BNK_FILE_HEADER_SIZE)) < 0) >> > + return ret; >> > + else if (ret != PP_BNK_FILE_HEADER_SIZE) >> > + return AVERROR(EIO); >> > + >> > + pp_bnk_parse_header(&hdr, buf); >> > + >> > + if (hdr.track_count == 0 || hdr.track_count > INT_MAX) >> > + return AVERROR_INVALIDDATA; >> > + >> > + if (hdr.sample_rate == 0 || hdr.sample_rate > INT_MAX) >> > + return AVERROR_INVALIDDATA; >> > + >> > + if (hdr.always1 != 1) { >> > + avpriv_request_sample(s, "Non-one header value"); >> > + return AVERROR_PATCHWELCOME; >> > + } >> > + >> > + ctx->track_count = hdr.track_count; >> > + if ((ret = av_reallocp_array(&ctx->tracks, hdr.track_count, >> > sizeof(PPBnkCtxTrack)))) >> >> Why realloc? Seems this is only allocated once. > > Good question. Fixed. > > >> > + return ret; >> > + >> > + /* Parse and validate each track. */ >> > + for (int i = 0; i < hdr.track_count; i++) { >> > + PPBnkTrack e; >> > + >> > + if ((ret = avio_read(s->pb, buf, PP_BNK_TRACK_SIZE)) < 0) { >> > + av_freep(&ctx->tracks); >> >> You are duplicating this free at too many places. Would be better to >> have a cleanup block at the end and jump to that. >> > > I did that originally, however it's at the awkward spot where doing > that causes the code to be larger than the way it is currently. > > I'll change it. > >> > + return ret; >> > + } else if (ret != PP_BNK_TRACK_SIZE) { >> > + av_freep(&ctx->tracks); >> > + return AVERROR(EIO); >> > + } >> > + >> > + pp_bnk_parse_track(&e, buf); >> > + >> > + /* The individual sample rates of all tracks must match >> > that of the file header. */ >> > + if (e.sample_rate != hdr.sample_rate) { >> > + av_freep(&ctx->tracks); >> > + return AVERROR_INVALIDDATA; >> > + } >> > + >> > + ctx->tracks[i].data_offset = avio_tell(s->pb); >> > + ctx->tracks[i].data_size = e.size; >> > + >> > + /* Skip over the data to the next stream header. */ >> > + avio_skip(s->pb, e.size); >> > + } >> > + >> > + /* Build the streams. */ >> > + for (int i = 0; i < hdr.track_count; i++) { >> > + >> >> nit: unnecessary empty line >> > > Nit picked. > >> > + if (!(st = avformat_new_stream(s, NULL))) { >> > + av_freep(&ctx->tracks); >> > + return AVERROR(ENOMEM); >> > + } >> > + >> > + par = st->codecpar; >> > + par->codec_type = AVMEDIA_TYPE_AUDIO; >> > + par->codec_id = >> > AV_CODEC_ID_ADPCM_IMA_CUNNING; >> > + par->format = AV_SAMPLE_FMT_S16; >> > + par->channel_layout = AV_CH_LAYOUT_MONO; >> > + par->channels = 1; >> > + par->sample_rate = hdr.sample_rate; >> > + par->bits_per_coded_sample = 4; >> > + par->bits_per_raw_sample = 16; >> > + par->block_align = 1; >> > + par->bit_rate = par->sample_rate * >> > par->bits_per_coded_sample; + >> > + avpriv_set_pts_info(st, 64, 1, par->sample_rate); >> > + st->start_time = 0; >> > + st->duration = ctx->tracks[i].data_size * 2; >> > + } >> > + >> > + /* Seek to the start of the first stream. */ >> > + if ((ret = avio_seek(s->pb, ctx->tracks[0].data_offset, >> > SEEK_SET)) < 0) { >> > + av_freep(&ctx->tracks); >> > + return ret; >> > + } else if (ret != ctx->tracks[0].data_offset) { >> > + av_freep(&ctx->tracks); >> > + return AVERROR(EIO); >> > + } >> > + >> > + return 0; >> > +} >> > + >> > +static int pp_bnk_read_packet(AVFormatContext *s, AVPacket *pkt) >> > +{ >> > + int64_t ret; >> > + int size; >> > + PPBnkCtx *ctx = s->priv_data; >> > + PPBnkCtxTrack *trk = ctx->tracks + ctx->current_track; >> > + >> > + av_assert0(ctx->bytes_read <= trk->data_size); >> > + >> > + if (ctx->bytes_read == trk->data_size) { >> > + >> >> nit: unnecessary empty line > > Fixed. > >> >> Otherwise looks ok, but would be nice to have some tests. >> > > I have tests ready, the plan was to send them if merged (and after > samples are uploaded) to avoid https://patchwork.ffmpeg.org/ failures. > > Should I include them in this irregardless? No, Never in same patch. > > Zane > >> -- >> Anton Khirnov >> _______________________________________________ >> ffmpeg-devel mailing list >> ffmpeg-devel@ffmpeg.org >> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel >> >> To unsubscribe, visit link above, or email >> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
diff --git a/Changelog b/Changelog index 4bcd109f64..8e19a71e1a 100644 --- a/Changelog +++ b/Changelog @@ -56,6 +56,7 @@ version <next>: - CRI HCA demuxer - overlay_cuda filter - Cunning Developments ADPCM decoder +- Pro Pinball Series Soundbank demuxer version 4.2: diff --git a/libavformat/Makefile b/libavformat/Makefile index 8fd0d43721..9df99133fa 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -428,6 +428,7 @@ OBJS-$(CONFIG_PCM_VIDC_DEMUXER) += pcmdec.o pcm.o OBJS-$(CONFIG_PCM_VIDC_MUXER) += pcmenc.o rawenc.o OBJS-$(CONFIG_PJS_DEMUXER) += pjsdec.o subtitles.o OBJS-$(CONFIG_PMP_DEMUXER) += pmpdec.o +OBJS-$(CONFIG_PP_BNK_DEMUXER) += pp_bnk.o OBJS-$(CONFIG_PVA_DEMUXER) += pva.o OBJS-$(CONFIG_PVF_DEMUXER) += pvfdec.o pcm.o OBJS-$(CONFIG_QCP_DEMUXER) += qcp.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 39d2c352f5..3919c9e4c1 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -341,6 +341,7 @@ extern AVInputFormat ff_pcm_u8_demuxer; extern AVOutputFormat ff_pcm_u8_muxer; extern AVInputFormat ff_pjs_demuxer; extern AVInputFormat ff_pmp_demuxer; +extern AVInputFormat ff_pp_bnk_demuxer; extern AVOutputFormat ff_psp_muxer; extern AVInputFormat ff_pva_demuxer; extern AVInputFormat ff_pvf_demuxer; diff --git a/libavformat/pp_bnk.c b/libavformat/pp_bnk.c new file mode 100644 index 0000000000..592d25ab52 --- /dev/null +++ b/libavformat/pp_bnk.c @@ -0,0 +1,263 @@ +/* + * Pro Pinball Series Soundbank (44c, 22c, 11c, 5c) demuxer. + * + * Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "avformat.h" +#include "internal.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/avassert.h" +#include "libavutil/internal.h" + +#define PP_BNK_MAX_READ_SIZE 4096 +#define PP_BNK_FILE_HEADER_SIZE 20 +#define PP_BNK_TRACK_SIZE 20 + +typedef struct PPBnkHeader { + uint32_t bank_id; /*< Bank ID, useless for our purposes. */ + uint32_t sample_rate; /*< Sample rate of the contained tracks. */ + uint32_t always1; /*< Unknown, always seems to be 1. */ + uint32_t track_count; /*< Number of tracks in the file. */ + uint32_t flags; /*< Flags. 2 == music, 0 == sfx. */ +} PPBnkHeader; + +typedef struct PPBnkTrack { + uint32_t id; /*< Track ID. Usually track[i].id == track[i-1].id + 1, but not always */ + uint32_t size; /*< Size of the data in bytes. */ + uint32_t sample_rate; /*< Sample rate. */ + uint32_t always1_1; /*< Unknown, always seems to be 1. */ + uint32_t always1_2; /*< Unknown, always seems to be 1. */ +} PPBnkTrack; + +typedef struct PPBnkCtxTrack { + int64_t data_offset; + uint32_t data_size; +} PPBnkCtxTrack; + +typedef struct PPBnkCtx { + int track_count; + PPBnkCtxTrack *tracks; + uint32_t current_track; + uint32_t bytes_read; +} PPBnkCtx; + + +enum { + PP_BNK_FLAG_PERSIST = (1 << 0), /*< This is a large file, keep in memory. */ + PP_BNK_FLAG_MUSIC = (1 << 1), /*< This is music. */ + PP_BNK_FLAG_MASK = (PP_BNK_FLAG_PERSIST | PP_BNK_FLAG_MUSIC) +}; + +static void pp_bnk_parse_header(PPBnkHeader *hdr, const uint8_t *buf) +{ + hdr->bank_id = AV_RL32(buf + 0); + hdr->sample_rate = AV_RL32(buf + 4); + hdr->always1 = AV_RL32(buf + 8); + hdr->track_count = AV_RL32(buf + 12); + hdr->flags = AV_RL32(buf + 16); +} + +static void pp_bnk_parse_track(PPBnkTrack *trk, const uint8_t *buf) +{ + trk->id = AV_RL32(buf + 0); + trk->size = AV_RL32(buf + 4); + trk->sample_rate = AV_RL32(buf + 8); + trk->always1_1 = AV_RL32(buf + 12); + trk->always1_2 = AV_RL32(buf + 16); +} + +static int pp_bnk_probe(const AVProbeData *p) +{ + uint32_t sample_rate = AV_RL32(p->buf + 4); + uint32_t track_count = AV_RL32(p->buf + 12); + uint32_t flags = AV_RL32(p->buf + 16); + + if (track_count == 0 || sample_rate == 0) + return 0; + + /* Sometimes we have the first track header, so check that too. */ + if (p->buf_size >= 32 && AV_RL32(p->buf + 28) != sample_rate) + return 0; + + /* These limits are based on analysing the game files. */ + if (track_count > 113) + return 10; + + if (sample_rate != 5512 && sample_rate != 11025 && + sample_rate != 22050 && sample_rate != 44100) + return 10; + + if ((flags & ~PP_BNK_FLAG_MASK) != 0) + return 10; + + return AVPROBE_SCORE_MAX / 4 + 1; +} + +static int pp_bnk_read_header(AVFormatContext *s) +{ + int ret; + AVStream *st; + AVCodecParameters *par; + PPBnkCtx *ctx = s->priv_data; + uint8_t buf[FFMAX(PP_BNK_FILE_HEADER_SIZE, PP_BNK_TRACK_SIZE)]; + PPBnkHeader hdr; + + if ((ret = avio_read(s->pb, buf, PP_BNK_FILE_HEADER_SIZE)) < 0) + return ret; + else if (ret != PP_BNK_FILE_HEADER_SIZE) + return AVERROR(EIO); + + pp_bnk_parse_header(&hdr, buf); + + if (hdr.track_count == 0 || hdr.track_count > INT_MAX) + return AVERROR_INVALIDDATA; + + if (hdr.sample_rate == 0 || hdr.sample_rate > INT_MAX) + return AVERROR_INVALIDDATA; + + if (hdr.always1 != 1) { + avpriv_request_sample(s, "Non-one header value"); + return AVERROR_PATCHWELCOME; + } + + ctx->track_count = hdr.track_count; + if ((ret = av_reallocp_array(&ctx->tracks, hdr.track_count, sizeof(PPBnkCtxTrack)))) + return ret; + + /* Parse and validate each track. */ + for (int i = 0; i < hdr.track_count; i++) { + PPBnkTrack e; + + if ((ret = avio_read(s->pb, buf, PP_BNK_TRACK_SIZE)) < 0) { + av_freep(&ctx->tracks); + return ret; + } else if (ret != PP_BNK_TRACK_SIZE) { + av_freep(&ctx->tracks); + return AVERROR(EIO); + } + + pp_bnk_parse_track(&e, buf); + + /* The individual sample rates of all tracks must match that of the file header. */ + if (e.sample_rate != hdr.sample_rate) { + av_freep(&ctx->tracks); + return AVERROR_INVALIDDATA; + } + + ctx->tracks[i].data_offset = avio_tell(s->pb); + ctx->tracks[i].data_size = e.size; + + /* Skip over the data to the next stream header. */ + avio_skip(s->pb, e.size); + } + + /* Build the streams. */ + for (int i = 0; i < hdr.track_count; i++) { + + if (!(st = avformat_new_stream(s, NULL))) { + av_freep(&ctx->tracks); + return AVERROR(ENOMEM); + } + + par = st->codecpar; + par->codec_type = AVMEDIA_TYPE_AUDIO; + par->codec_id = AV_CODEC_ID_ADPCM_IMA_CUNNING; + par->format = AV_SAMPLE_FMT_S16; + par->channel_layout = AV_CH_LAYOUT_MONO; + par->channels = 1; + par->sample_rate = hdr.sample_rate; + par->bits_per_coded_sample = 4; + par->bits_per_raw_sample = 16; + par->block_align = 1; + par->bit_rate = par->sample_rate * par->bits_per_coded_sample; + + avpriv_set_pts_info(st, 64, 1, par->sample_rate); + st->start_time = 0; + st->duration = ctx->tracks[i].data_size * 2; + } + + /* Seek to the start of the first stream. */ + if ((ret = avio_seek(s->pb, ctx->tracks[0].data_offset, SEEK_SET)) < 0) { + av_freep(&ctx->tracks); + return ret; + } else if (ret != ctx->tracks[0].data_offset) { + av_freep(&ctx->tracks); + return AVERROR(EIO); + } + + return 0; +} + +static int pp_bnk_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + int64_t ret; + int size; + PPBnkCtx *ctx = s->priv_data; + PPBnkCtxTrack *trk = ctx->tracks + ctx->current_track; + + av_assert0(ctx->bytes_read <= trk->data_size); + + if (ctx->bytes_read == trk->data_size) { + + if (ctx->current_track == ctx->track_count - 1) + return AVERROR_EOF; + + trk++; + + if ((ret = avio_seek(s->pb, trk->data_offset, SEEK_SET)) < 0) + return ret; + else if (ret != trk->data_offset) + return AVERROR(EIO); + + ctx->bytes_read = 0; + ctx->current_track++; + } + + size = FFMIN(trk->data_size - ctx->bytes_read, PP_BNK_MAX_READ_SIZE); + + if ((ret = av_get_packet(s->pb, pkt, size)) < 0) + return ret; + else if (ret != size) + return AVERROR_INVALIDDATA; + + ctx->bytes_read += ret; + + pkt->stream_index = ctx->current_track; + pkt->duration = ret * 2; + return 0; +} + +static int pp_bnk_read_close(AVFormatContext *s) +{ + PPBnkCtx *ctx = s->priv_data; + + av_freep(&ctx->tracks); + + return 0; +} + +AVInputFormat ff_pp_bnk_demuxer = { + .name = "pp_bnk", + .long_name = NULL_IF_CONFIG_SMALL("Pro Pinball Series Soundbank"), + .priv_data_size = sizeof(PPBnkCtx), + .read_probe = pp_bnk_probe, + .read_header = pp_bnk_read_header, + .read_packet = pp_bnk_read_packet, + .read_close = pp_bnk_read_close +}; diff --git a/libavformat/version.h b/libavformat/version.h index 18c2f5fec2..493a0b337f 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -32,7 +32,7 @@ // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium) // Also please add any ticket numbers that you believe might be affected here #define LIBAVFORMAT_VERSION_MAJOR 58 -#define LIBAVFORMAT_VERSION_MINOR 42 +#define LIBAVFORMAT_VERSION_MINOR 43 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
Signed-off-by: Zane van Iperen <zane@zanevaniperen.com> --- Changelog | 1 + libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/pp_bnk.c | 263 +++++++++++++++++++++++++++++++++++++++ libavformat/version.h | 2 +- 5 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 libavformat/pp_bnk.c