Tweak block parsing to handle better unknown blocks; try to improve EOFs

This commit is contained in:
bnnm 2017-07-09 00:56:27 +02:00
parent a4d1e869cf
commit e96f3c0700
2 changed files with 68 additions and 68 deletions

View File

@ -18,64 +18,59 @@ void ea_schl_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
id = read_32bitBE(block_offset+0x00,streamFile); id = read_32bitBE(block_offset+0x00,streamFile);
block_size = read_32bitLE(block_offset+0x04,streamFile); block_size = read_32bitLE(block_offset+0x04,streamFile);
if (block_size > 0x00F00000) /* size size is always LE, except in early SS/MAC */ if (block_size > 0x00F00000) /* size is always LE, except in early SS/MAC */
block_size = read_32bitBE(block_offset+0x04,streamFile); block_size = read_32bitBE(block_offset+0x04,streamFile);
if (id == 0x5343446C) /* "SCDl" data block found */ /* SCxx blocks have size in the header, but others may not. To simplify we just try to find
* a SCDl (main data) every 0x04. EA sometimes concats many small files, so after a SCEl (end block)
* there may be a new SCHl + SCDl too, so this pretends they are a single stream. */
if (id == 0x5343446C) { /* "SCDl" data block found */
/* use num_samples from header if possible; don't calc as data may have padding (ex. PCM8) or not possible (ex. MP3) */
switch(vgmstream->coding_type) {
case coding_PSX:
block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels);
break;
default:
block_samples = read_32bit(block_offset+0x08,streamFile);
break;
}
/* guard against false positives (happens in "pIQT" blocks) */
if (block_size > 0xFFFF || block_samples > 0xFFFF) { /* observed max is ~0xf00 but who knows */
block_offset += 0x04;
continue;
}
break; break;
block_offset += block_size; /* size includes header */
/* Some EA files concat many small subfiles, for mapped music (.map/lin), so after SCEl
* there may be a new SCHl. We'll find it and pretend they are a single stream. */
if (id == 0x5343456C && block_offset + 0x80 > file_size) { /* "SCEl" end block found with no extra "SCHl" */
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset + block_size;
return;
} }
if (id == 0x5343456C) { /* "SCEl" end block found */ else {
/* Usually there is padding between SCEl and SCHl (aligned to 0x80) */ /* movie "pIQT" may be bigger than what block_size says, but seems to help */
block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* also 32b-aligned */ if (id == 0x5343486C || id == 0x5343436C || id == 0x53434C6C || id == 0x70495154) { /* "SCHl" "SCCl" "SCLl" "SCEl" "pIQT" */
for (i = 0; i < 0x80 / 4; i++) { block_offset += block_size;
id = read_32bitBE(block_offset,streamFile); } else {
if (id == 0x5343486C) /* "SCHl" new header block found */
break; /* next loop will parse and skip it */
block_offset += 0x04; block_offset += 0x04;
} }
}
if (block_offset >= file_size) { if (id == 0x5343456C) { /* "SCEl" end block found */
vgmstream->current_block_offset = block_offset; block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* 32b-aligned, important */
vgmstream->next_block_offset = block_offset + 0x04; /* Usually there is padding between SCEl and SCHl too (aligned to 0x80) */
return; }
}
if (id == 0 || id == 0xFFFFFFFF) { continue;
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset + 0x04;
return; /* probably hit padding or EOF */
} }
} }
/* EOF reads: pretend we have samples to please the layout (unsure if this helps) */
if (block_offset >= file_size) { if (block_offset >= file_size) {
vgmstream->current_block_offset = block_offset; vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset + 0x04; vgmstream->next_block_offset = block_offset + 0x04;
vgmstream->current_block_samples = vgmstream->num_samples;
return; return;
} }
/* use num_samples from header if possible; don't calc as rarely data may have padding (ex. PCM8) or not possible (ex. MP3) */
switch(vgmstream->coding_type) {
case coding_PSX:
block_samples = ps_bytes_to_samples(block_size-0x10, vgmstream->channels);
break;
default:
block_samples = read_32bit(block_offset+0x08,streamFile);
break;
}
/* set new channel offsets and ADPCM history */ /* set new channel offsets and ADPCM history */
/* ADPCM hist could be considered part of the stream/decoder (some EAXA decoders call it "EAXA R1" when it has hist), and BNKs /* ADPCM hist could be considered part of the stream/decoder (some EAXA decoders call it "EAXA R1" when it has hist), and BNKs
* (with no blocks) also have them in the first offset. To simplify and since DSP also have them, we read them here instead. */ * (with no blocks) also have them in the first offset. To simplify and since DSP also have them, we read them here instead. */

View File

@ -296,6 +296,7 @@ static int parse_stream_header(STREAMFILE* streamFile, ea_header* ea, off_t begi
case 0x0B: /* unknown (always 0x02) */ case 0x0B: /* unknown (always 0x02) */
case 0x13: /* effect bus (0..127) */ case 0x13: /* effect bus (0..127) */
case 0x14: /* emdedded user data (free size/value) */ case 0x14: /* emdedded user data (free size/value) */
case 0x1B: /* unknown (movie related?) */
read_patch(streamFile, &offset); read_patch(streamFile, &offset);
break; break;
@ -527,13 +528,13 @@ fail:
* music (.map/lin). We get total possible samples (counting all subfiles) and pretend * music (.map/lin). We get total possible samples (counting all subfiles) and pretend
* they are a single stream. Subfiles always share header, except num_samples. */ * they are a single stream. Subfiles always share header, except num_samples. */
static int get_ea_total_samples(STREAMFILE* streamFile, off_t start_offset, const ea_header* ea) { static int get_ea_total_samples(STREAMFILE* streamFile, off_t start_offset, const ea_header* ea) {
int i, num_samples = 0; int num_samples = 0;
size_t file_size = get_streamfile_size(streamFile); size_t file_size = get_streamfile_size(streamFile);
off_t block_offset = start_offset; off_t block_offset = start_offset;
int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE; int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE;
while (block_offset < file_size) { while (block_offset < file_size) {
uint32_t id, block_size; uint32_t id, block_size, block_samples;
id = read_32bitBE(block_offset+0x00,streamFile); id = read_32bitBE(block_offset+0x00,streamFile);
@ -541,44 +542,48 @@ static int get_ea_total_samples(STREAMFILE* streamFile, off_t start_offset, cons
if (block_size > 0x00F00000) /* size is always LE, except in early SS/MAC */ if (block_size > 0x00F00000) /* size is always LE, except in early SS/MAC */
block_size = read_32bitBE(block_offset+0x04,streamFile); block_size = read_32bitBE(block_offset+0x04,streamFile);
/* SCxx blocks have size in the header, but others may not. To simplify we just try to
* find a SCDl (main data) every 0x04. EA sometimes concats many small files, so after a SCEl (end block)
* there may be a new SCHl + SCDl too, so this pretends they are a single stream. */
if (id == 0x5343446C) { /* "SCDl" data block found */ if (id == 0x5343446C) { /* "SCDl" data block found */
/* use num_samples from header if possible */ /* use num_samples from header if possible */
switch (ea->codec2) { switch (ea->codec2) {
case EA_CODEC2_VAG: /* PS-ADPCM */ case EA_CODEC2_VAG: /* PS-ADPCM */
num_samples += ps_bytes_to_samples(block_size-0x10, ea->channels); block_samples = ps_bytes_to_samples(block_size-0x10, ea->channels);
break; break;
default: default:
num_samples += read_32bit(block_offset+0x08,streamFile); block_samples = read_32bit(block_offset+0x08,streamFile);
break; break;
} }
/* guard against false positives (happens in "pIQT" blocks) */
if (block_size > 0xFFFF || block_samples > 0xFFFF) { /* observed max is ~0xf00 but who knows */
block_offset += 0x04;
continue;
}
num_samples += block_samples;
block_offset += block_size; /* size includes header */
} }
else {
block_offset += block_size; /* size includes header */ /* movie "pIQT" may be bigger than what block_size says, but seems to help */
if (id == 0x5343486C || id == 0x5343436C || id == 0x53434C6C || id == 0x70495154) { /* "SCHl" "SCCl" "SCLl" "SCEl" "pIQT" */
/* EA sometimes concats many small files, so after SCEl there may be a new SCHl. block_offset += block_size;
* We'll find it and pretend they are a single stream. */ } else {
if (id == 0x5343456C && block_offset + 0x80 > file_size)
break;
if (id == 0x5343456C) { /* "SCEl" end block found */
/* Usually there is padding between SCEl and SCHl (aligned to 0x80) */
block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* also 32b-aligned */
for (i = 0; i < 0x80 / 4; i++) {
id = read_32bitBE(block_offset,streamFile);
if (id == 0x5343486C) /* "SCHl" new header block found */
break; /* next loop will parse and skip it */
block_offset += 0x04; block_offset += 0x04;
} }
if (id == 0x5343456C) { /* "SCEl" end block found */
/* Usually there is padding between SCEl and SCHl (aligned to 0x80) */
block_offset += (block_offset % 0x04) == 0 ? 0 : 0x04 - (block_offset % 0x04); /* also 32b-aligned, important */
}
block_offset += 0x04;
continue;
} }
if (block_offset > file_size)
break;
if (id == 0 || id == 0xFFFFFFFF)
return num_samples; /* probably hit padding or EOF */
VGM_ASSERT(id != 0x5343486C && id != 0x5343436C && id != 0x5343446C && id != 0x53434C6C && id != 0x5343456C,
"EA: unknown block id 0x%x at 0x%lx\n", id, block_offset);
} }
return num_samples; return num_samples;