Add .vid VID1 and XBOX-IMA/DSP/PCM [Enter the Matrix (GC/Xbox)]

This commit is contained in:
bnnm 2020-03-08 22:15:06 +01:00
parent e3727da3b7
commit 7fc20cb49f
11 changed files with 201 additions and 57 deletions

View File

@ -58,11 +58,18 @@ int vorbis_custom_parse_packet_vid1(VGMSTREAMCHANNEL *stream, vorbis_custom_code
/* test block start */
if (read_32bitBE(stream->offset + 0x00,stream->streamfile) == 0x4652414D && /* "FRAM" */
read_32bitBE(stream->offset + 0x20,stream->streamfile) == 0x41554444) { /* "AUDD" */
data->block_offset = stream->offset;
data->block_size = read_32bitBE(stream->offset + 0x2c,stream->streamfile);
stream->offset += 0x34; /* actual start, rest is chunk sizes and maybe granule info */
if (read_32bitBE(stream->offset + 0x00,stream->streamfile) == 0x4652414D) { /* "FRAM" */
stream->offset += 0x20;
if (read_32bitBE(stream->offset + 0x00,stream->streamfile) == 0x56494444) { /* "VIDD"*/
stream->offset += read_32bitBE(stream->offset + 0x04, stream->streamfile);
}
if (read_32bitBE(stream->offset + 0x00,stream->streamfile) == 0x41554444) { /* "AUDD" */
data->block_offset = stream->offset;
data->block_size = read_32bitBE(stream->offset + 0x0c,stream->streamfile);
stream->offset += 0x14; /* actual start, rest is chunk sizes and maybe granule info */
}
}
@ -78,7 +85,7 @@ int vorbis_custom_parse_packet_vid1(VGMSTREAMCHANNEL *stream, vorbis_custom_code
//todo: sometimes there are short packets like 01be590000 and Vorbis complains and skips, no idea
/* test block end (weird size calc but seems ok) */
if ((stream->offset - (data->block_offset + 0x34)) >= (data->block_size - 0x06)) {
if ((stream->offset - (data->block_offset + 0x14)) >= (data->block_size - 0x06)) {
stream->offset = data->block_offset + read_32bitBE(data->block_offset + 0x04,stream->streamfile);
}

View File

@ -516,6 +516,7 @@ static const char* extension_list[] = {
"vgm", //txth/reserved [Maximo (PS2)]
"vgs",
"vgv",
"vid",
"vig",
"vis",
"vms",
@ -845,6 +846,7 @@ static const layout_info layout_info_list[] = {
{layout_blocked_h4m, "blocked (H4M)"},
{layout_blocked_xa_aiff, "blocked (XA AIFF)"},
{layout_blocked_vs_square, "blocked (Square VS)"},
{layout_blocked_vid1, "blocked (VID1)"},
};
static const meta_info meta_info_list[] = {
@ -1175,7 +1177,7 @@ static const meta_info meta_info_list[] = {
{meta_VXN, "Gameloft VXN header"},
{meta_EA_SNR_SNS, "Electronic Arts SNR+SNS header"},
{meta_EA_SPS, "Electronic Arts SPS header"},
{meta_NGC_VID1, "Neversoft VID1 header"},
{meta_VID1, "Factor 5 VID1 header"},
{meta_PC_FLX, "Ultima IX .FLX header"},
{meta_MOGG, "Harmonix Music Systems MOGG Vorbis"},
{meta_OGG_VORBIS, "Ogg Vorbis header"},

View File

@ -205,6 +205,9 @@ void block_update(off_t block_offset, VGMSTREAM * vgmstream) {
case layout_blocked_vs_square:
block_update_vs_square(block_offset,vgmstream);
break;
case layout_blocked_vid1:
block_update_vid1(block_offset,vgmstream);
break;
default: /* not a blocked layout */
break;
}

61
src/layout/blocked_vid1.c Normal file
View File

@ -0,0 +1,61 @@
#include "layout.h"
#include "../vgmstream.h"
/* blocks with video and audio */
void block_update_vid1(off_t block_offset, VGMSTREAM* vgmstream) {
STREAMFILE* sf = vgmstream->ch[0].streamfile;
int ch;
int channels = vgmstream->channels;
uint32_t (*read_u32)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_u32be : read_u32le;
size_t audd_size = 0, data_size = 0;
if (read_u32(block_offset + 0x00, sf) != 0x4652414D) { /* "FRAM" */
/* signal EOF, as files ends with padding */
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset;
vgmstream->current_block_size = 0;
vgmstream->current_block_samples = -1;
return;
}
block_offset += 0x20;
if (read_u32(block_offset + 0x00, sf) == 0x56494444) { /* "VIDD"*/
block_offset += read_u32(block_offset + 0x04, sf);
}
if (read_u32(block_offset + 0x00, sf) == 0x41554444) { /* "AUDD" */
audd_size = read_u32(block_offset + 0x04, sf);
data_size = read_u32(block_offset + 0x0c, sf);
}
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset + audd_size;
vgmstream->current_block_size = (data_size / channels);
vgmstream->current_block_samples = 0;
for (ch = 0; ch < vgmstream->channels; ch++) {
off_t interleave, head_size;
switch(vgmstream->coding_type) {
case coding_PCM16_int:
interleave = 0x02 * ch;
head_size = 0x10;
break;
case coding_XBOX_IMA:
interleave = 0x00;
head_size = 0x10;
break;
case coding_NGC_DSP:
interleave = (data_size / channels) * ch;
head_size = 0x20;
break;
default:
interleave = 0;
head_size = 0x10;
break;
}
vgmstream->ch[ch].offset = block_offset + head_size + interleave;
}
}

View File

@ -46,6 +46,7 @@ void block_update_sthd(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_h4m(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_xa_aiff(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_vs_square(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_vid1(off_t block_offset, VGMSTREAM* vgmstream);
/* other layouts */
void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream);

View File

@ -2278,6 +2278,10 @@
RelativePath=".\layout\blocked_vgs.c"
>
</File>
<File
RelativePath=".\layout\blocked_vid1.c"
>
</File>
<File
RelativePath=".\layout\blocked_vs_square.c"
>

View File

@ -615,6 +615,7 @@
<ClCompile Include="layout\blocked_awc.c" />
<ClCompile Include="layout\blocked_ea_1snh.c" />
<ClCompile Include="layout\blocked_vgs.c" />
<ClCompile Include="layout\blocked_vid1.c" />
<ClCompile Include="layout\blocked_vs_square.c" />
<ClCompile Include="layout\blocked_vawx.c" />
<ClCompile Include="layout\blocked_xvag.c" />

View File

@ -1354,6 +1354,9 @@
<ClCompile Include="layout\blocked_vgs.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\blocked_vid1.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\blocked_vs_square.c">
<Filter>layout\Source Files</Filter>
</ClCompile>

View File

@ -1,74 +1,134 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
/* VID1 - from Neversoft games (Gun, Tony Hawk's American Wasteland GC) */
VGMSTREAM * init_vgmstream_ngc_vid1(STREAMFILE *streamFile) {
/* VID1 - Factor 5/DivX format GC/Xbox games [Gun (GC), Tony Hawk's American Wasteland (GC), Enter The Matrix (Xbox)]*/
VGMSTREAM * init_vgmstream_ngc_vid1(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, header_offset, header_size;
int loop_flag = 0, channel_count;
off_t start_offset, header_offset;
int loop_flag = 0, channels, sample_rate;
uint32_t codec;
int big_endian;
uint32_t (*read_u32)(off_t,STREAMFILE*);
/* check extension */
if (!check_extensions(streamFile,"ogg,logg"))
/* checks */
/* .vid: video + (often) audio
* .ogg: audio only [Gun (GC)], .logg: for plugins */
if (!check_extensions(sf,"vid,ogg,logg"))
goto fail;
/* chunked/blocked format containing video or audio frames */
if (read_32bitBE(0x00,streamFile) != 0x56494431) /* "VID1" */
goto fail;
/* find actual header start/size in the chunks */
{
header_offset = read_32bitBE(0x04, streamFile);
if (read_32bitBE(header_offset,streamFile) != 0x48454144) /* "HEAD" */
goto fail;
start_offset = header_offset + read_32bitBE(header_offset + 0x04, streamFile);
header_offset += 0x0c;
/* videos have VIDH before AUDH, and VIDD in blocks, but aren't parsed ATM */
if (read_32bitBE(header_offset,streamFile) != 0x41554448) /* "AUDH" */
goto fail;
header_size = read_32bitBE(header_offset + 0x04, streamFile);
header_offset += 0x0c;
if (read_32bitBE(header_offset,streamFile) != 0x56415544) /* "VAUD" (Vorbis audio?) */
goto fail;
header_offset += 0x04;
header_size -= 0x10;
if (read_u32be(0x00, sf) == 0x56494431) { /* "VID1" BE (GC) */
big_endian = 1;
}
else if (read_u32le(0x00,sf) == 0x56494431) { /* "VID1" LE (Xbox) */
big_endian = 0;
}
else {
goto fail;
}
read_u32 = big_endian ? read_u32be : read_u32le;
/* find actual header start/size in the chunks (id + size + null) */
{
off_t offset = read_u32(0x04, sf);
if (read_u32(offset + 0x00, sf) != 0x48454144) /* "HEAD" */
goto fail;
start_offset = offset + read_u32(offset + 0x04, sf);
offset += 0x0c;
/* videos have VIDH before AUDH */
if (read_u32(offset + 0x00, sf) == 0x56494448) { /* "VIDH" */
offset += read_u32(offset + 0x04, sf);
}
if (read_u32(offset, sf) != 0x41554448) /* "AUDH" */
goto fail;
offset += 0x0c;
header_offset = offset;
codec = read_u32(offset + 0x00, sf);
sample_rate = read_u32(offset + 0x04, sf);
channels = read_u8 (offset + 0x08, sf);
/* 0x09: flag? 0/1 */
/* 0x0a+: varies per codec (PCM/X-IMA: nothing, DSP: coefs, Vorbis: bitrate/frame info?) + padding */
}
channel_count = read_8bit(header_offset + 0x04,streamFile);
/* other values unknown, maybe related to vorbis (ex. bitrate/encoding modes) */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitBE(header_offset + 0x00, streamFile);
vgmstream->num_samples = read_32bitBE(header_offset + 0x1c, streamFile);
vgmstream->meta_type = meta_NGC_VID1;
vgmstream->meta_type = meta_VID1;
vgmstream->sample_rate = sample_rate;
vgmstream->codec_endian = big_endian;
switch(codec) {
case 0x50433136: /* "PC16" [Enter the Matrix (Xbox)] */
vgmstream->coding_type = coding_PCM16_int;
vgmstream->layout_type = layout_blocked_vid1;
break;
case 0x5841504D: /* "XAPM" [Enter the Matrix (Xbox)] */
vgmstream->coding_type = coding_XBOX_IMA;
vgmstream->layout_type = layout_blocked_vid1;
break;
case 0x4150434D: /* "APCM" [Enter the Matrix (GC)] */
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_blocked_vid1;
dsp_read_coefs_be(vgmstream, sf, header_offset + 0x0a, 0x20);
break;
#ifdef VGM_USE_VORBIS
{
vorbis_custom_config cfg = {0};
case 0x56415544: { /* "VAUD" [Gun (GC)] */
vorbis_custom_config cfg = {0};
vgmstream->layout_type = layout_none;
vgmstream->coding_type = coding_VORBIS_custom;
vgmstream->codec_data = init_vorbis_custom(streamFile, header_offset + 0x20, VORBIS_VID1, &cfg);
if (!vgmstream->codec_data) goto fail;
}
#else
goto fail;
vgmstream->num_samples = read_u32(header_offset + 0x20, sf);
vgmstream->codec_data = init_vorbis_custom(sf, header_offset + 0x24, VORBIS_VID1, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_VORBIS_custom;
vgmstream->layout_type = layout_none;
break;
}
#endif
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
default:
goto fail;
}
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
/* calc num_samples as playable data size varies between files/blocks */
if (vgmstream->layout_type == layout_blocked_vid1) {
int block_samples;
vgmstream->next_block_offset = start_offset;
do {
block_update(vgmstream->next_block_offset, vgmstream);
if (vgmstream->current_block_samples < 0)
break;
switch(vgmstream->coding_type) {
case coding_PCM16_int: block_samples = pcm_bytes_to_samples(vgmstream->current_block_size, 1, 16); break;
case coding_XBOX_IMA: block_samples = xbox_ima_bytes_to_samples(vgmstream->current_block_size, 1); break;
case coding_NGC_DSP: block_samples = dsp_bytes_to_samples(vgmstream->current_block_size, 1); break;
default: goto fail;
}
vgmstream->num_samples += block_samples;
}
while (vgmstream->next_block_offset < get_streamfile_size(sf));
block_update(start_offset, vgmstream);
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;

View File

@ -1107,6 +1107,7 @@ void render_vgmstream(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmst
case layout_blocked_h4m:
case layout_blocked_xa_aiff:
case layout_blocked_vs_square:
case layout_blocked_vid1:
render_vgmstream_blocked(buffer,sample_count,vgmstream);
break;
case layout_segmented:

View File

@ -274,6 +274,7 @@ typedef enum {
layout_blocked_h4m, /* H4M video */
layout_blocked_xa_aiff, /* XA in AIFF files [Crusader: No Remorse (SAT), Road Rash (3DO)] */
layout_blocked_vs_square,
layout_blocked_vid1,
/* otherwise odd */
layout_segmented, /* song divided in segments (song sections) */
@ -620,7 +621,7 @@ typedef enum {
meta_VXN, /* Gameloft mobile games */
meta_EA_SNR_SNS, /* Electronic Arts SNR+SNS (Burnout Paradise) */
meta_EA_SPS, /* Electronic Arts SPS (Burnout Crash) */
meta_NGC_VID1, /* Neversoft .ogg (Gun GC) */
meta_VID1,
meta_PC_FLX, /* Ultima IX PC */
meta_MOGG, /* Harmonix Music Systems MOGG Vorbis */
meta_OGG_VORBIS, /* Ogg Vorbis */