From a3b991ac3f7c66cf6da9055d2f4da324c02ee170 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 17 Dec 2017 19:25:10 +0100 Subject: [PATCH] Modify SCD/P3D/FSB/XVAG interleave and fix short last interleave Previously, the streams' offsets needed to be pre-adjusted with the interleave; now assumes all streams start in the same offset (first stream). This simplifies short last interleaves (SCD/P3D) and makes layout_mpeg_custom unnecessary (also allows theoretical variable-sized interleaves). --- src/coding/mpeg_custom_utils.c | 67 ++++++++++++++++------------------ src/coding/mpeg_decoder.c | 3 -- src/formats.c | 3 -- src/meta/fsb.c | 8 +--- src/meta/fsb5.c | 5 +-- src/meta/p3d.c | 9 ++--- src/meta/sqex_scd.c | 8 ++-- src/meta/xvag.c | 18 +++------ src/vgmstream.c | 3 -- src/vgmstream.h | 3 -- 10 files changed, 46 insertions(+), 81 deletions(-) diff --git a/src/coding/mpeg_custom_utils.c b/src/coding/mpeg_custom_utils.c index 54fe8c56..f225f931 100644 --- a/src/coding/mpeg_custom_utils.c +++ b/src/coding/mpeg_custom_utils.c @@ -97,7 +97,9 @@ int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d mpeg_frame_info info; size_t current_data_size = 0; size_t current_padding = 0; - size_t current_interleave = 0; + size_t current_interleave_pre = 0; /* interleaved data size before current stream */ + size_t current_interleave_post = 0; /* interleaved data size after current stream */ + size_t current_interleave = 0; /* interleave in this block (usually this + pre + post = interleave*streams = block) */ /* Get data size to give to the decoder, per stream. Usually 1 frame at a time, @@ -105,11 +107,18 @@ int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d switch(data->type) { case MPEG_XVAG: /* frames of fixed size (though we could read frame info too) */ - current_data_size = data->config.chunk_size; current_interleave = data->config.interleave; /* big interleave */ + current_interleave_pre = current_interleave*num_stream; + current_interleave_post = current_interleave*(data->streams_size-1) - current_interleave_pre; + + current_data_size = data->config.chunk_size; break; case MPEG_FSB: /* frames with padding + interleave */ + current_interleave = data->config.interleave; /* constant for multi-stream FSbs (1 frame + padding) */ + current_interleave_pre = current_interleave*num_stream; + current_interleave_post = current_interleave*(data->streams_size-1) - current_interleave_pre; + if ( !mpeg_get_frame_info(stream->streamfile, stream->offset, &info) ) goto fail; current_data_size = info.frame_size; @@ -122,9 +131,6 @@ int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d : 0; } - /* frame interleave (ie. read 1 data-frame, skip 1 data-frame per stream) */ - current_interleave = data->config.interleave; /* constant for multi-stream FSbs */ - VGM_ASSERT(data->streams_size > 1 && current_interleave != current_data_size+current_padding, "MPEG FSB: %i streams with non-constant interleave found @ 0x%08lx\n", data->streams_size, stream->offset); break; @@ -132,18 +138,20 @@ int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d case MPEG_P3D: /* fixed interleave, not frame-aligned (ie. blocks may end/start in part of a frame) */ case MPEG_SCD: current_interleave = data->config.interleave; -#if 0 //todo + +#if 1 /* check if current interleave block is short */ { off_t block_offset = stream->offset - stream->channel_start_offset; size_t next_block = data->streams_size*data->config.interleave; - if (data->config.data_size && block_offset + next_block >= data->config.data_size) { - size_t short_interleave = (data->config.data_size % next_block) / data->streams_size; - current_interleave = short_interleave; - } + if (data->config.data_size && block_offset + next_block >= data->config.data_size) + current_interleave = (data->config.data_size % next_block) / data->streams_size; /* short_interleave*/ } #endif + current_interleave_pre = current_interleave*num_stream; + current_interleave_post = current_interleave*(data->streams_size-1) - current_interleave_pre; + current_data_size = current_interleave; break; @@ -158,39 +166,26 @@ int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d goto fail; } + /* This assumes all streams' offsets start in the first stream, and advances + * the 'full interleaved block' at once, ex: + * start at s0=0x00, s1=0x00, interleave=0x40 (block = 0x40*2=0x80) + * @0x00 read 0x40 of s0, skip 0x40 of s1 (block of 0x80 done) > new offset = 0x80 + * @0x00 skip 0x40 of s0, read 0x40 of s1 (block of 0x80 done) > new offset = 0x800 + */ - /* read single frame */ - ms->bytes_in_buffer = read_streamfile(ms->buffer,stream->offset, current_data_size, stream->streamfile); + /* read chunk (skipping other interleaves if needed) */ + ms->bytes_in_buffer = read_streamfile(ms->buffer,stream->offset + current_interleave_pre, current_data_size, stream->streamfile); - /* update offsets */ + /* update offsets and skip other streams */ stream->offset += current_data_size + current_padding; - /* skip interleave once block is done, if defined */ - if (current_interleave && ((stream->offset - stream->channel_start_offset) % current_interleave == 0)) { - stream->offset += current_interleave * (data->streams_size-1); /* skip a block each stream */ - -#if 0 //todo fix last block interleave - int i; - - /* skip other blocks one by one (to handle if next last block has short interleave) */ - for (i = 0; i < data->streams_size - 1; i++) { - off_t block_offset = stream->offset - stream->channel_start_offset; - size_t next_block = data->streams_size*data->config.interleave; - - if (data->config.data_size && block_offset + next_block >= data->config.data_size) { - /* other stream's data is in last block (short interleave) */ - size_t short_interleave = (data->config.data_size % next_block) / data->streams_size; - stream->offset += short_interleave; - } - else { - /* other stream's data is in normal block (regular interleave) */ - stream->offset += current_interleave; - } - } -#endif + /* skip rest of block (interleave per stream) once this stream's interleaved data is done, if defined */ + if (current_interleave && ((stream->offset - stream->channel_start_offset + current_interleave_pre + current_interleave_post) % current_interleave == 0)) { + stream->offset += current_interleave_pre + current_interleave_post; } + return 1; fail: return 0; diff --git a/src/coding/mpeg_decoder.c b/src/coding/mpeg_decoder.c index 6a528072..ba8aeea9 100644 --- a/src/coding/mpeg_decoder.c +++ b/src/coding/mpeg_decoder.c @@ -167,9 +167,6 @@ mpeg_codec_data *init_mpeg_custom_codec_data(STREAMFILE *streamFile, off_t start } - /* write output */ - config->interleave = data->config.interleave; /* for FSB */ - return data; fail: diff --git a/src/formats.c b/src/formats.c index 1e630a73..f3572d48 100644 --- a/src/formats.c +++ b/src/formats.c @@ -570,9 +570,6 @@ static const layout_info layout_info_list[] = { #ifdef VGM_USE_VORBIS {layout_ogg_vorbis, "Ogg"}, #endif -#ifdef VGM_USE_MPEG - {layout_mpeg_custom, "Custom MPEG Audio"}, -#endif }; static const meta_info meta_info_list[] = { diff --git a/src/meta/fsb.c b/src/meta/fsb.c index cdce31cb..388cad2e 100644 --- a/src/meta/fsb.c +++ b/src/meta/fsb.c @@ -287,9 +287,8 @@ VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) { if (fsbh.mode & FSOUND_MPEG) { /* FSB3: ?; FSB4: Shatter, Way of the Samurai 3/4, Forza Horizon 1/2, Dragon Age Origins */ #if defined(VGM_USE_MPEG) - mpeg_custom_config cfg; + mpeg_custom_config cfg = {0}; - memset(&cfg, 0, sizeof(mpeg_custom_config)); cfg.fsb_padding = (vgmstream->channels > 2 ? 16 : (fsbh.flags & FMOD_FSB_SOURCE_MPEG_PADDED4 ? 4 : (fsbh.flags & FMOD_FSB_SOURCE_MPEG_PADDED ? 2 : 0))); @@ -299,10 +298,7 @@ VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) { vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg); if (!vgmstream->codec_data) goto fail; - - /* both to setup initial interleave in vgmstream_open_stream */ - vgmstream->interleave_block_size = cfg.interleave; - vgmstream->layout_type = layout_mpeg_custom; + vgmstream->layout_type = layout_none; #else goto fail; /* FFmpeg can't properly read FSB4 or FMOD's 0-padded MPEG data @ start_offset */ diff --git a/src/meta/fsb5.c b/src/meta/fsb5.c index eb8f0d37..c648db71 100644 --- a/src/meta/fsb5.c +++ b/src/meta/fsb5.c @@ -265,10 +265,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) { vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, StartOffset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg); if (!vgmstream->codec_data) goto fail; - - /* both to setup initial interleave in vgmstream_open_stream */ - vgmstream->interleave_block_size = cfg.interleave; - vgmstream->layout_type = layout_mpeg_custom; + vgmstream->layout_type = layout_none; break; } #endif diff --git a/src/meta/p3d.c b/src/meta/p3d.c index 5556fc18..752e6014 100644 --- a/src/meta/p3d.c +++ b/src/meta/p3d.c @@ -145,18 +145,15 @@ VGMSTREAM * init_vgmstream_p3d(STREAMFILE *streamFile) { #ifdef VGM_USE_MPEG case 0x6D703300: { /* "mp3\0" (PS3) */ - mpeg_custom_config cfg; + mpeg_custom_config cfg = {0}; - memset(&cfg, 0, sizeof(mpeg_custom_config)); cfg.interleave = 0x400; + cfg.data_size = data_size; /* block_size * 3 = frame size (0x60*3=0x120 or 0x40*3=0xC0) but doesn't seem to have any significance) */ vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_P3D, &cfg); if (!vgmstream->codec_data) goto fail; - - /* both to setup initial interleave in vgmstream_open_stream */ - vgmstream->interleave_block_size = cfg.interleave; - vgmstream->layout_type = layout_mpeg_custom; + vgmstream->layout_type = layout_none; break; } #endif diff --git a/src/meta/sqex_scd.c b/src/meta/sqex_scd.c index 92790102..bfa98052 100644 --- a/src/meta/sqex_scd.c +++ b/src/meta/sqex_scd.c @@ -208,7 +208,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) { mpeg_codec_data *mpeg_data = NULL; mpeg_custom_config cfg = {0}; - cfg.interleave = 0x800; /* for multistream [Final Fantasy XIII-2 (PS3)] */ + cfg.interleave = 0x800; /* for multistream [Final Fantasy XIII-2 (PS3)], otherwise ignored */ cfg.data_size = stream_size; /* Drakengard 3, some Kingdom Hearts */ @@ -221,11 +221,9 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) { mpeg_data = init_mpeg_custom_codec_data(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_SCD, &cfg); if (!mpeg_data) goto fail; vgmstream->codec_data = mpeg_data; - /* to setup initial interleave in vgmstream_open_stream */ - vgmstream->layout_type = layout_mpeg_custom; - vgmstream->interleave_block_size = cfg.interleave; + vgmstream->layout_type = layout_none; - vgmstream->num_samples = mpeg_bytes_to_samples(stream_size, mpeg_data); + vgmstream->num_samples = mpeg_bytes_to_samples(stream_size, mpeg_data); //todo test/fix vgmstream->num_samples -= vgmstream->num_samples%576; if (loop_flag) { vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data); diff --git a/src/meta/xvag.c b/src/meta/xvag.c index 987db2f1..c187aebf 100644 --- a/src/meta/xvag.c +++ b/src/meta/xvag.c @@ -82,25 +82,19 @@ VGMSTREAM * init_vgmstream_xvag(STREAMFILE *streamFile) { #ifdef VGM_USE_MPEG case 0x08: { /* MPEG: The Last of Us, Uncharted 3, Medieval Moves */ - mpeg_custom_config cfg; - int fixed_frame_size; - - memset(&cfg, 0, sizeof(mpeg_custom_config)); + mpeg_custom_config cfg = {0}; /* "mpin": mpeg info */ /* 0x00/04: mpeg version/layer? other: unknown or repeats of "fmat" */ - if (!find_chunk(streamFile, 0x6D70696E,first_offset,0, &chunk_offset,NULL, !little_endian, 1)) goto fail; /*"mpin"*/ - fixed_frame_size = read_32bit(chunk_offset+0x1c,streamFile); + if (!find_chunk(streamFile, 0x6D70696E,first_offset,0, &chunk_offset,NULL, !little_endian, 1)) + goto fail; /*"mpin"*/ - cfg.chunk_size = fixed_frame_size; - cfg.interleave = fixed_frame_size * multiplier; + cfg.chunk_size = read_32bit(chunk_offset+0x1c,streamFile); /* fixed frame size */ + cfg.interleave = cfg.chunk_size * multiplier; vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_XVAG, &cfg); if (!vgmstream->codec_data) goto fail; - - /* both to setup initial interleave in vgmstream_open_stream */ - vgmstream->interleave_block_size = cfg.interleave; - vgmstream->layout_type = layout_mpeg_custom; + vgmstream->layout_type = layout_none; break; } #endif diff --git a/src/vgmstream.c b/src/vgmstream.c index b5bb594e..c3001d21 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -922,9 +922,6 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre break; #ifdef VGM_USE_VORBIS case layout_ogg_vorbis: -#endif -#ifdef VGM_USE_MPEG - case layout_mpeg_custom: #endif case layout_none: render_vgmstream_nolayout(buffer,sample_count,vgmstream); diff --git a/src/vgmstream.h b/src/vgmstream.h index 44233193..4d7d2a6c 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -254,9 +254,6 @@ typedef enum { #ifdef VGM_USE_VORBIS layout_ogg_vorbis, /* ogg vorbis file */ #endif -#ifdef VGM_USE_MPEG - layout_mpeg_custom, /* usually straight data but may setup offset/interleave somehow */ -#endif } layout_t; /* The meta type specifies how we know what we know about the file.