Updated VGMStream to r1050-873-ga4cf9afd.

CQTexperiment
Christopher Snowhill 2017-12-17 20:35:01 -08:00
parent df85ce80cd
commit cf8fd45f02
16 changed files with 107 additions and 91 deletions

View File

@ -18,6 +18,8 @@ int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, m
}
data->channels_per_frame = info.channels;
data->samples_per_frame = info.frame_samples;
data->bitrate_per_frame = info.bit_rate;
data->sample_rate_per_frame = info.sample_rate;
/* extra checks per type */
@ -50,6 +52,7 @@ int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, m
break;
case MPEG_P3D:
case MPEG_SCD:
if (data->config.interleave <= 0)
goto fail; /* needs external fixed size */
break;
@ -94,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,
@ -102,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;
@ -119,17 +131,28 @@ 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;
case MPEG_P3D: /* fixed interleave, not frame-aligned (ie. blocks may end/start in part of a frame) */
current_data_size = data->config.interleave / 4; /* to ensure we don't feed mpg123 too much */
current_interleave = data->config.interleave; /* fixed interleave (0x400) */
//todo: last block is smaller that interleave, not sure how it's divided
case MPEG_SCD:
current_interleave = data->config.interleave;
#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)
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;
default: /* standard frames (CBR or VBR) */
@ -143,19 +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 */
/* 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;

View File

@ -150,6 +150,8 @@ int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *
}
// todo rarely there is a block between granules (ex. EAL3 v2P in FIFA 2016)
/* get second frame/granule (MPEG1 only) if first granule was found */
granule_found = 0;
while (eaf_0.common_size && eaf_0.mpeg1 && !granule_found) {
@ -665,6 +667,7 @@ static int ealayer3_skip_data(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, i
if (!ok) goto fail;
stream->offset += eaf.eaframe_size;
//;VGM_LOG("s%i: skipping %x, now at %lx\n", num_stream,eaf.eaframe_size,stream->offset);
}
//;VGM_LOG("s%i: skipped %i frames, now at %lx\n", num_stream,skips,stream->offset);

View File

@ -166,9 +166,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:
@ -382,7 +379,7 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data
/* extra EOF check for edge cases when the caller tries to read more samples than possible */
if (!ms->buffer_full && stream->offset >= stream_size) {
VGM_LOG("MPEG: EOF found but more data is requested\n");
VGM_LOG("MPEG: EOF found but more data is requested in stream %i\n", num_stream);
goto decode_fail;
}
@ -602,7 +599,12 @@ long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data *data) {
return (int64_t)bytes * data->mi.rate * 8 / (data->mi.bitrate * 1000);
}
else {
return 0; /* a bit too complex for what is worth */
/* needed for SCD */
if (data->streams_size && data->bitrate_per_frame) {
return (int64_t)(bytes / data->streams_size) * data->sample_rate_per_frame * 8 / (data->bitrate_per_frame * 1000);
}
return 0;
}
}

View File

@ -162,6 +162,7 @@ static const char* extension_list[] = {
"leg",
"lmp4", //fake extension, for MP4s
"logg", //fake extension, for OGGs
"lopus", //fake extension, for OPUS
"lpcm",
"lps",
"lsf",
@ -569,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[] = {

View File

@ -2,7 +2,7 @@
#include "../coding/coding.h"
#include "../vgmstream.h"
/* EA "SNS "blocks (most common in .SNS) */
/* EA SNS/SPS blocks */
void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream) {
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
uint32_t block_size, block_samples;
@ -21,16 +21,10 @@ void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream) {
return;
}
/* 0x80: last block
* 0x40: new block for some codecs?
* 0x08: ?
* 0x04: new block for some codecs?
* 0x01: last block for some codecs?
* 0x00: none? */
if (block_size & 0xFF000000) {
//VGM_ASSERT(!(block_size & 0x80000000), "EA SNS: unknown flag found at %lx\n", block_offset);
block_size &= 0x00FFFFFF;
}
/* At 0x00(1): block flag
* - in SNS: 0x00=normal block, 0x80=last block (not mandatory)
* - in SPS: 0x48=header, 0x44=normal block, 0x45=last block (empty) */
block_size &= 0x00FFFFFF;
for (i = 0; i < vgmstream->channels; i++) {
off_t channel_start = 0x00;

View File

@ -3,7 +3,9 @@
/* Tests each start/mult/add vs derived key8/9 (if provided), as most where brute forced.
* Mainly for debugging purposes (info from VGAudio / ADX_Decoder) */
* Ie. uncommenting this and adding a new key8/key9 + compiling with VGM_DEBUG_OUTPUT
* will print its derived key (useful as games often use the same key for hca and adx type 9).
* Mainly for debugging purposes (info from VGAudio / ADX_Decoder). */
//#define ADX_VERIFY_DERIVED_KEYS 1
@ -199,6 +201,9 @@ static const adxkey_info adxkey9_list[] = {
/* Yuuki Yuuna wa Yuusha de aru - Hanayui no Kirameki / Yuyuyui (iOS/Android) */
{0x3f10,0x3651,0x6d31, NULL,4867249871962584729}, // 438BF1F883653699
// Super Robot Wars X-Omega (voices) [iOS/Android]
{0x5152,0x7979,0x152b, NULL,165521992944278}, // 0000968A97978A96
};
static const int adxkey8_list_count = sizeof(adxkey8_list) / sizeof(adxkey8_list[0]);

View File

@ -48,12 +48,10 @@ VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE * streamFile) {
if (!check_extensions(streamFile,"sps"))
goto fail;
/* Very hacky but the original check for 0x48000000 rejected some playable files */
if (((read_16bitBE(0x00,streamFile) & 0xFFFFFF00) != 0x4800) &&
((read_8bit(0x00, streamFile) & 0xFFFFFF00) != 0x00))
/* SPS block start: 0x00(1): block flag (header=0x48); 0x01(3): block size (usually 0x0c-0x14) */
if (read_8bit(0x00, streamFile) != 0x48)
goto fail;
start_offset = read_8bit(0x03, streamFile);
start_offset = read_32bitBE(0x00, streamFile) & 0x00FFFFFF;
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, 0x04, start_offset, meta_EA_SPS);
if (!vgmstream) goto fail;

View File

@ -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 */

View File

@ -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

View File

@ -144,6 +144,9 @@ static const hcakey_info hcakey_list[] = {
// Pro Evolution Soccer 2018 / Winning Eleven 2018 (Android)
{14121473}, // 0000000000D77A01
// Kirara Fantasia (Android/iOS)
{51408295487268137}, // 00B6A3928706E529
};

View File

@ -11,7 +11,7 @@ VGMSTREAM * init_vgmstream_nsw_opus(STREAMFILE *streamFile) {
off_t offset = 0;
/* check extension, case insensitive */
if ( !check_extensions(streamFile,"opus")) /* no relation to Ogg Opus */
if ( !check_extensions(streamFile,"opus,lopus")) /* no relation to Ogg Opus */
goto fail;
/* variations, maybe custom */

View File

@ -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

View File

@ -12,9 +12,9 @@ static void scd_ogg_decrypt_v3_callback(void *ptr, size_t size, size_t nmemb, vo
VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset, tables_offset, headers_offset, meta_offset, post_meta_offset, stream_size;
off_t start_offset, tables_offset, headers_offset, meta_offset, post_meta_offset;
int headers_entries;
int32_t loop_start, loop_end;
int32_t stream_size, loop_start, loop_end;
int target_stream = streamFile->stream_index;
int loop_flag = 0, channel_count, codec_id, sample_rate;
@ -80,7 +80,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
meta_offset = read_32bit(headers_offset + (target_stream-1)*4,streamFile);
/** stream header **/
stream_size = read_32bit(meta_offset+0x00, streamFile);
stream_size = read_32bit(meta_offset+0x00,streamFile);
channel_count = read_32bit(meta_offset+0x04,streamFile);
sample_rate = read_32bit(meta_offset+0x08,streamFile);
codec_id = read_32bit(meta_offset+0x0c,streamFile);
@ -200,33 +200,33 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
}
break;
case 0x06: /* OGG [Final Fantasy XIII-2 (PS3), Final Fantasy XIV (PC)] */
case 0x06: /* OGG [Final Fantasy XIII-2 (PC), Final Fantasy XIV (PC)] */
goto fail; /* handled above */
#ifdef VGM_USE_MPEG
case 0x07: { /* MPEG [Final Fantasy XIII (PS3)] */
mpeg_codec_data *mpeg_data = NULL;
mpeg_custom_config cfg = {0};
/* Drakengard 3, some Kingdom Hearts */
if (vgmstream->sample_rate == 47999)
vgmstream->sample_rate = 48000;
if (vgmstream->sample_rate == 44099)
vgmstream->sample_rate = 44100;
cfg.interleave = 0x800; /* for multistream [Final Fantasy XIII-2 (PS3)], otherwise ignored */
cfg.data_size = stream_size;
mpeg_data = init_mpeg_codec_data(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels);
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;
vgmstream->layout_type = layout_none;
/* some Drakengard 3, Kingdom Hearts HD have adjusted sample rate (47999, 44099), for looping? */
vgmstream->num_samples = mpeg_bytes_to_samples(stream_size, mpeg_data);
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data);
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data);
//todo find if this actually helps
vgmstream->num_samples -= vgmstream->num_samples%576;
if (loop_flag) {
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data);
vgmstream->loop_start_sample -= vgmstream->loop_start_sample%576;
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data);
vgmstream->loop_end_sample -= vgmstream->loop_end_sample%576;
}
vgmstream->interleave_block_size = 0;
vgmstream->loop_start_sample -= vgmstream->loop_start_sample%576;
vgmstream->loop_end_sample -= vgmstream->loop_end_sample%576;
break;
}
#endif

View File

@ -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

View File

@ -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);

View File

@ -262,9 +262,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.
@ -888,6 +885,7 @@ typedef enum {
MPEG_XVAG, /* N streams of fixed interleave (frame-aligned, several data-frames of fixed size) */
MPEG_FSB, /* N streams of 1 data-frame+padding (=interleave) */
MPEG_P3D, /* N streams of fixed interleave (not frame-aligned) */
MPEG_SCD, /* N streams of fixed interleave (not frame-aligned) */
MPEG_EA, /* 1 stream (maybe N streams in absolute offsets?) */
MPEG_EAL31, /* EALayer3 v1 (SCHl), custom frames with v1 header */
MPEG_EAL31b, /* EALayer3 v1 (SNS), custom frames with v1 header + minor changes */
@ -902,6 +900,7 @@ typedef struct {
int channels; /* max channels */
int fsb_padding; /* fsb padding mode */
int chunk_size; /* size of a data portion */
int data_size; /* playable size */
int interleave; /* size of stream interleave */
int encryption; /* encryption mode */
int big_endian;
@ -947,6 +946,9 @@ typedef struct {
/* for internal use, assumed to be constant for all frames */
int channels_per_frame;
int samples_per_frame;
/* for some calcs */
int bitrate_per_frame;
int sample_rate_per_frame;
/* custom MPEG internals */
int custom; /* flag */