mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-17 23:36:41 +01:00
Add .vid VID1 and XBOX-IMA/DSP/PCM [Enter the Matrix (GC/Xbox)]
This commit is contained in:
parent
e3727da3b7
commit
7fc20cb49f
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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"},
|
||||
|
@ -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
61
src/layout/blocked_vid1.c
Normal 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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -2278,6 +2278,10 @@
|
||||
RelativePath=".\layout\blocked_vgs.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_vid1.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_vs_square.c"
|
||||
>
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
158
src/meta/vid1.c
158
src/meta/vid1.c
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user