Add/fix XWMA start and num samples

This commit is contained in:
bnnm 2018-10-07 23:27:31 +02:00
parent edd7226ee0
commit 80aad4f15a
9 changed files with 118 additions and 4 deletions

View File

@ -612,9 +612,10 @@ static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, i
msd->loop_end_sample = loop_end_frame * samples_per_frame + (msd->loop_end_subframe) * samples_per_subframe; msd->loop_end_sample = loop_end_frame * samples_per_frame + (msd->loop_end_subframe) * samples_per_subframe;
} }
//todo apply once FFmpeg decode is ok (must internal skip 64 samples + apply skips + output extra 128 IMDCT samples) and remove skip_samples output //todo apply once FFmpeg decode is ok
// for XMA must internal skip 64 samples + apply skips + output extra 128 IMDCT samples) and remove skip_samples output
#if 0 #if 0
{ if (msd->xma_version == 1 || msd->xma_version == 2) {
msd->num_samples += 128; /* final extra IMDCT samples */ msd->num_samples += 128; /* final extra IMDCT samples */
msd->num_samples -= start_skip; /* can be less but fixed to 512 in practice */ msd->num_samples -= start_skip; /* can be less but fixed to 512 in practice */
msd->num_samples -= end_skip; msd->num_samples -= end_skip;
@ -630,6 +631,14 @@ static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, i
} }
} }
#endif #endif
/* the above can't properly read skips for WMAPro ATM, but should fixed to 1 frame anyway */
if (msd->xma_version == 0) {
msd->num_samples -= samples_per_frame; /* FFmpeg does skip this */
#if 0
msd->num_samples += (samples_per_frame / 2); /* but doesn't add extra samples */
#endif
}
} }
static int wma_get_samples_per_frame(int version, int sample_rate, uint32_t decode_flags) { static int wma_get_samples_per_frame(int version, int sample_rate, uint32_t decode_flags) {
@ -744,6 +753,11 @@ void wma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_ali
} }
msd->num_samples = num_frames * samples_per_frame; msd->num_samples = num_frames * samples_per_frame;
#if 0 //todo apply once FFmpeg decode is ok
msd->num_samples += (samples_per_frame / 2); /* last IMDCT samples */
msd->num_samples -= (samples_per_frame * 2); /* WMA default encoder delay */
#endif
} }

View File

@ -456,8 +456,8 @@ static const char* extension_list[] = {
"xwb", "xwb",
"xmd", "xmd",
"xwc", "xwc",
"xwm", //FFmpeg, not parsed (XWMA) "xwm",
"xwma", //FFmpeg, not parsed (XWMA) "xwma",
"xws", "xws",
"xwv", "xwv",
@ -1088,6 +1088,7 @@ static const meta_info meta_info_list[] = {
{meta_NXA, "Entergram NXA header"}, {meta_NXA, "Entergram NXA header"},
{meta_ADPCM_CAPCOM, "Capcom .ADPCM header"}, {meta_ADPCM_CAPCOM, "Capcom .ADPCM header"},
{meta_UE4OPUS, "Epic Games UE4OPUS header"}, {meta_UE4OPUS, "Epic Games UE4OPUS header"},
{meta_XWMA, "Microsoft XWMA RIFF header"},
}; };

View File

@ -1609,6 +1609,10 @@
<File <File
RelativePath=".\meta\xwc.c" RelativePath=".\meta\xwc.c"
> >
</File>
<File
RelativePath=".\meta\xwma.c"
>
</File> </File>
<File <File
RelativePath=".\meta\ydsp.c" RelativePath=".\meta\ydsp.c"

View File

@ -474,6 +474,7 @@
<ClCompile Include="meta\xmd.c" /> <ClCompile Include="meta\xmd.c" />
<ClCompile Include="meta\xwb.c" /> <ClCompile Include="meta\xwb.c" />
<ClCompile Include="meta\xwc.c" /> <ClCompile Include="meta\xwc.c" />
<ClCompile Include="meta\xwma.c" />
<ClCompile Include="meta\ydsp.c" /> <ClCompile Include="meta\ydsp.c" />
<ClCompile Include="meta\zsd.c" /> <ClCompile Include="meta\zsd.c" />
<ClCompile Include="meta\zwdsp.c" /> <ClCompile Include="meta\zwdsp.c" />

View File

@ -991,6 +991,9 @@
<ClCompile Include="meta\xwc.c"> <ClCompile Include="meta\xwc.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\xwma.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ydsp.c"> <ClCompile Include="meta\ydsp.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>

View File

@ -793,4 +793,6 @@ VGMSTREAM * init_vgmstream_adpcm_capcom(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ue4opus(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_ue4opus(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_xwma(STREAMFILE * streamFile);
#endif /*_META_H*/ #endif /*_META_H*/

87
src/meta/xwma.c Normal file
View File

@ -0,0 +1,87 @@
#include "meta.h"
#include "../coding/coding.h"
/* XWMA - Microsoft WMA container [The Elder Scrolls: Skyrim (PC/X360), Hydrophobia (PC)] */
VGMSTREAM * init_vgmstream_xwma(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t fmt_offset, data_offset, first_offset = 0xc;
size_t fmt_size, data_size;
int loop_flag, channel_count;
/* checks */
/* .xwma: standard
* .xwm: The Elder Scrolls: Skyrim (PC), Blade Arcus from Shining (PC) */
if (!check_extensions(streamFile, "xwma,xwm"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x52494646) /* "RIFF" */
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x58574D41) /* "XWMA" */
goto fail;
if ( !find_chunk_le(streamFile, 0x666d7420,first_offset,0, &fmt_offset,&fmt_size) ) /* "fmt "*/
goto fail;
if ( !find_chunk_le(streamFile, 0x64617461,first_offset,0, &data_offset,&data_size) ) /* "data"*/
goto fail;
channel_count = read_16bitLE(fmt_offset+0x02,streamFile);
loop_flag = 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitLE(fmt_offset+0x04, streamFile);
vgmstream->meta_type = meta_XWMA;
/* the main purpose of this meta is redoing the XWMA header to:
* - redo header to fix XWMA with buggy bit rates so FFmpeg can play them ok
* - skip seek table to fix FFmpeg buggy XWMA seeking (see init_seek)
* - read num_samples correctly
*/
#ifdef VGM_USE_FFMPEG
{
uint8_t buf[0x100];
int bytes, avg_bps, block_align, wma_codec;
avg_bps = read_32bitLE(fmt_offset+0x08, streamFile);
block_align = (uint16_t)read_16bitLE(fmt_offset+0x0c, streamFile);
wma_codec = (uint16_t)read_16bitLE(fmt_offset+0x00, streamFile);
bytes = ffmpeg_make_riff_xwma(buf,0x100, wma_codec, data_size, vgmstream->channels, vgmstream->sample_rate, avg_bps, block_align);
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, data_offset,data_size);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
/* manually find total samples, why don't they put this in the header is beyond me */
{
ms_sample_data msd = {0};
msd.channels = vgmstream->channels;
msd.data_offset = data_offset;
msd.data_size = data_size;
if (wma_codec == 0x0162)
wmapro_get_samples(&msd, streamFile, block_align, vgmstream->sample_rate,0x00E0);
else
wma_get_samples(&msd, streamFile, block_align, vgmstream->sample_rate,0x001F);
vgmstream->num_samples = msd.num_samples;
if (vgmstream->num_samples == 0)
vgmstream->num_samples = (int32_t)((ffmpeg_codec_data*)vgmstream->codec_data)->totalSamples; /* from avg-br */
//num_samples seem to be found in the last "seek" table entry too, as: entry / channels / 2
}
}
#else
goto fail;
#endif
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -441,6 +441,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_utk, init_vgmstream_utk,
init_vgmstream_adpcm_capcom, init_vgmstream_adpcm_capcom,
init_vgmstream_ue4opus, init_vgmstream_ue4opus,
init_vgmstream_xwma,
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ /* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */

View File

@ -698,6 +698,7 @@ typedef enum {
meta_NXA, meta_NXA,
meta_ADPCM_CAPCOM, meta_ADPCM_CAPCOM,
meta_UE4OPUS, meta_UE4OPUS,
meta_XWMA,
} meta_t; } meta_t;