mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-29 19:37:30 +01:00
Add Neversoft .OGG [Gun (GC)]
This commit is contained in:
parent
6eef1074a2
commit
b9c3bd9a01
@ -50,6 +50,7 @@ vorbis_custom_codec_data * init_vorbis_custom_codec_data(STREAMFILE *streamFile,
|
||||
case VORBIS_WWISE: ok = vorbis_custom_setup_init_wwise(streamFile, start_offset, data); break;
|
||||
case VORBIS_OGL: ok = vorbis_custom_setup_init_ogl(streamFile, start_offset, data); break;
|
||||
case VORBIS_SK: ok = vorbis_custom_setup_init_sk(streamFile, start_offset, data); break;
|
||||
case VORBIS_VID1: ok = vorbis_custom_setup_init_vid1(streamFile, start_offset, data); break;
|
||||
default: goto fail;
|
||||
}
|
||||
if(!ok) goto fail;
|
||||
@ -131,6 +132,7 @@ void decode_vorbis_custom(VGMSTREAM * vgmstream, sample * outbuf, int32_t sample
|
||||
case VORBIS_WWISE: ok = vorbis_custom_parse_packet_wwise(stream, data); break;
|
||||
case VORBIS_OGL: ok = vorbis_custom_parse_packet_ogl(stream, data); break;
|
||||
case VORBIS_SK: ok = vorbis_custom_parse_packet_sk(stream, data); break;
|
||||
case VORBIS_VID1: ok = vorbis_custom_parse_packet_vid1(stream, data); break;
|
||||
default: goto decode_fail;
|
||||
}
|
||||
if(!ok) {
|
||||
@ -142,8 +144,9 @@ void decode_vorbis_custom(VGMSTREAM * vgmstream, sample * outbuf, int32_t sample
|
||||
/* parse the fake ogg packet into a logical vorbis block */
|
||||
rc = vorbis_synthesis(&data->vb,&data->op);
|
||||
if (rc == OV_ENOTAUDIO) {
|
||||
VGM_LOG("Vorbis: not an audio packet @ %lx\n",stream->offset);
|
||||
continue; /* not tested */
|
||||
VGM_LOG("Vorbis: not an audio packet (size=0x%x) @ %lx\n",(size_t)data->op.bytes,stream->offset);
|
||||
//VGM_LOGB(data->op.packet, (size_t)data->op.bytes,0);
|
||||
continue; /* seems ok? */
|
||||
} else if (rc != 0) {
|
||||
VGM_LOG("Vorbis: cannot parse Vorbis block @ %lx\n",stream->offset);
|
||||
goto decode_fail;
|
||||
|
@ -9,11 +9,13 @@ int vorbis_custom_setup_init_fsb(STREAMFILE *streamFile, off_t start_offset, vor
|
||||
int vorbis_custom_setup_init_wwise(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data);
|
||||
int vorbis_custom_setup_init_ogl(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data);
|
||||
int vorbis_custom_setup_init_sk(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data);
|
||||
int vorbis_custom_setup_init_vid1(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data);
|
||||
|
||||
int vorbis_custom_parse_packet_fsb(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data);
|
||||
int vorbis_custom_parse_packet_wwise(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data);
|
||||
int vorbis_custom_parse_packet_ogl(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data);
|
||||
int vorbis_custom_parse_packet_sk(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data);
|
||||
int vorbis_custom_parse_packet_vid1(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data);
|
||||
#endif/* VGM_USE_VORBIS */
|
||||
|
||||
#endif/*_VORBIS_CUSTOM_DECODER_H_ */
|
||||
|
191
src/coding/vorbis_custom_utils_vid1.c
Normal file
191
src/coding/vorbis_custom_utils_vid1.c
Normal file
@ -0,0 +1,191 @@
|
||||
#include "vorbis_custom_decoder.h"
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
#include <vorbis/codec.h>
|
||||
|
||||
|
||||
/* **************************************************************************** */
|
||||
/* DEFS */
|
||||
/* **************************************************************************** */
|
||||
|
||||
/* An internal struct to pass around and simulate a bitstream. */
|
||||
typedef struct {
|
||||
uint8_t * buf; /* buffer to read/write*/
|
||||
size_t bufsize; /* max size of the buffer */
|
||||
off_t b_off; /* current offset in bits inside the buffer */
|
||||
} vgm_bitstream;
|
||||
|
||||
static int r_bits(vgm_bitstream * iw, int num_bits, uint32_t * value);
|
||||
|
||||
static int get_packet_header(STREAMFILE *streamFile, off_t *offset, size_t *size);
|
||||
static int build_header_comment(uint8_t * buf, size_t bufsize);
|
||||
|
||||
|
||||
/* **************************************************************************** */
|
||||
/* EXTERNAL API */
|
||||
/* **************************************************************************** */
|
||||
|
||||
/**
|
||||
* VID1 removes the Ogg layer and uses a block layout with custom packet headers.
|
||||
*
|
||||
* Info from hcs's vid1_2ogg: https://github.com/hcs64/vgm_ripping/tree/master/demux/vid1_2ogg
|
||||
*/
|
||||
int vorbis_custom_setup_init_vid1(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data) {
|
||||
off_t offset = start_offset;
|
||||
size_t packet_size = 0;
|
||||
|
||||
/* read header packets (id/setup), each with an VID1 header */
|
||||
|
||||
/* normal identificacion packet */
|
||||
get_packet_header(streamFile, &offset, &packet_size);
|
||||
if (packet_size > data->buffer_size) goto fail;
|
||||
data->op.bytes = read_streamfile(data->buffer,offset,packet_size, streamFile);
|
||||
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse identification header */
|
||||
offset += packet_size;
|
||||
|
||||
/* generate comment packet */
|
||||
data->op.bytes = build_header_comment(data->buffer, data->buffer_size);
|
||||
if (!data->op.bytes) goto fail;
|
||||
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) !=0 ) goto fail; /* parse comment header */
|
||||
|
||||
/* normal setup packet */
|
||||
get_packet_header(streamFile, &offset, &packet_size);
|
||||
if (packet_size > data->buffer_size) goto fail;
|
||||
data->op.bytes = read_streamfile(data->buffer,offset,packet_size, streamFile);
|
||||
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse setup header */
|
||||
offset += packet_size;
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int vorbis_custom_parse_packet_vid1(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data) {
|
||||
size_t bytes;
|
||||
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
|
||||
/* get packet info the VID1 header */
|
||||
get_packet_header(stream->streamfile, &stream->offset, (uint32_t*)&data->op.bytes);
|
||||
if (data->op.bytes == 0) {
|
||||
VGM_LOG("VID1 Vorbis: wrong packet (0x%lx) @ %lx\n", data->op.bytes, stream->offset);
|
||||
goto fail; /* EOF or end padding */
|
||||
}
|
||||
|
||||
/* read raw block */
|
||||
bytes = read_streamfile(data->buffer,stream->offset, data->op.bytes,stream->streamfile);
|
||||
stream->offset += data->op.bytes;
|
||||
if (bytes != data->op.bytes) {
|
||||
VGM_LOG("VID1 Vorbis: wrong bytes (0x%lx) @ %lx\n", data->op.bytes, stream->offset-bytes);
|
||||
goto fail; /* wrong packet? */
|
||||
}
|
||||
//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)) {
|
||||
stream->offset = data->block_offset + read_32bitBE(data->block_offset + 0x04,stream->streamfile);
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* **************************************************************************** */
|
||||
/* INTERNAL HELPERS */
|
||||
/* **************************************************************************** */
|
||||
|
||||
static int build_header_comment(uint8_t * buf, size_t bufsize) {
|
||||
int bytes = 0x19;
|
||||
|
||||
if (bytes > bufsize) return 0;
|
||||
|
||||
put_8bit (buf+0x00, 0x03); /* packet_type (comments) */
|
||||
memcpy (buf+0x01, "vorbis", 6); /* id */
|
||||
put_32bitLE(buf+0x07, 0x09); /* vendor_length */
|
||||
memcpy (buf+0x0b, "vgmstream", 9); /* vendor_string */
|
||||
put_32bitLE(buf+0x14, 0x00); /* user_comment_list_length */
|
||||
put_8bit (buf+0x18, 0x01); /* framing_flag (fixed) */
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* read header in Vorbis bitpacking format */
|
||||
static int get_packet_header(STREAMFILE *streamFile, off_t *offset, size_t *size) {
|
||||
uint8_t ibuf[0x04]; /* header buffer */
|
||||
size_t ibufsize = 0x04; /* header ~max */
|
||||
vgm_bitstream ib = {0};
|
||||
uint32_t size_bits;
|
||||
|
||||
|
||||
if (read_streamfile(ibuf,(*offset),ibufsize, streamFile) != ibufsize)
|
||||
goto fail;
|
||||
ib.buf = ibuf;
|
||||
ib.bufsize = ibufsize;
|
||||
ib.b_off = 0;
|
||||
|
||||
/* read using Vorbis weird LSF */
|
||||
r_bits(&ib, 4,&size_bits);
|
||||
r_bits(&ib, (size_bits+1),(uint32_t*)size);
|
||||
|
||||
/* special meaning, seen in silent frames */
|
||||
if (size_bits == 0 && *size == 0 && (uint8_t)read_8bit(*offset, streamFile)==0x80) {
|
||||
*size = 0x01;
|
||||
}
|
||||
|
||||
/* pad and convert to byte offset */
|
||||
if (ib.b_off % 8)
|
||||
ib.b_off += 8 - (ib.b_off % 8);
|
||||
*offset += (ib.b_off/8);
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read bits (max 32) from buf and update the bit offset. Vorbis packs values in LSB order and byte by byte.
|
||||
* (ex. from 2 bytes 00100111 00000001 we can could read 4b=0111 and 6b=010010, 6b=remainder (second value is split into the 2nd byte) */
|
||||
static int r_bits(vgm_bitstream * ib, int num_bits, uint32_t * value) {
|
||||
off_t off, pos;
|
||||
int i, bit_buf, bit_val;
|
||||
if (num_bits == 0) return 1;
|
||||
if (num_bits > 32 || num_bits < 0 || ib->b_off + num_bits > ib->bufsize*8) goto fail;
|
||||
|
||||
*value = 0; /* set all bits to 0 */
|
||||
off = ib->b_off / 8; /* byte offset */
|
||||
pos = ib->b_off % 8; /* bit sub-offset */
|
||||
for (i = 0; i < num_bits; i++) {
|
||||
bit_buf = (1U << pos) & 0xFF; /* bit check for buf */
|
||||
bit_val = (1U << i); /* bit to set in value */
|
||||
|
||||
if (ib->buf[off] & bit_buf) /* is bit in buf set? */
|
||||
*value |= bit_val; /* set bit */
|
||||
|
||||
pos++; /* new byte starts */
|
||||
if (pos%8 == 0) {
|
||||
pos = 0;
|
||||
off++;
|
||||
}
|
||||
}
|
||||
|
||||
ib->b_off += num_bits;
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@ -319,11 +319,11 @@ static const char* extension_list[] = {
|
||||
"vawx",
|
||||
"vb",
|
||||
"vbk",
|
||||
"vds",
|
||||
"vdm",
|
||||
"vgs",
|
||||
"vgv",
|
||||
"vig",
|
||||
"vds",
|
||||
"vdm",
|
||||
"vms",
|
||||
"voi",
|
||||
"vpk",
|
||||
@ -914,6 +914,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"},
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
{meta_OGG_VORBIS, "Ogg Vorbis"},
|
||||
|
@ -625,6 +625,10 @@
|
||||
<File
|
||||
RelativePath=".\meta\ngc_ulw.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ngc_vid1.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ngca.c"
|
||||
@ -1554,6 +1558,10 @@
|
||||
RelativePath=".\coding\vorbis_custom_utils_sk.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\vorbis_custom_utils_vid1.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\vorbis_custom_utils_wwise.c"
|
||||
>
|
||||
|
@ -287,6 +287,7 @@
|
||||
<ClCompile Include="meta\ngc_tydsp.c" />
|
||||
<ClCompile Include="meta\ngc_ymf.c" />
|
||||
<ClCompile Include="meta\ngc_ulw.c" />
|
||||
<ClCompile Include="meta\ngc_vid1.c" />
|
||||
<ClCompile Include="meta\nub_xma.c" />
|
||||
<ClCompile Include="meta\nwa.c" />
|
||||
<ClCompile Include="meta\ogg_vorbis_file.c" />
|
||||
@ -465,6 +466,7 @@
|
||||
<ClCompile Include="coding\vorbis_custom_utils_fsb.c" />
|
||||
<ClCompile Include="coding\vorbis_custom_utils_ogl.c" />
|
||||
<ClCompile Include="coding\vorbis_custom_utils_sk.c" />
|
||||
<ClCompile Include="coding\vorbis_custom_utils_vid1.c" />
|
||||
<ClCompile Include="coding\vorbis_custom_utils_wwise.c" />
|
||||
<ClCompile Include="coding\ws_decoder.c" />
|
||||
<ClCompile Include="coding\xa_decoder.c" />
|
||||
|
@ -376,6 +376,9 @@
|
||||
<ClCompile Include="meta\ngc_ulw.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\ngc_vid1.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\nub_xma.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -907,6 +910,9 @@
|
||||
<ClCompile Include="coding\vorbis_custom_utils_sk.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\vorbis_custom_utils_vid1.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\vorbis_custom_utils_wwise.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -698,4 +698,7 @@ VGMSTREAM * init_vgmstream_vxn(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_vid1(STREAMFILE * streamFile);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
75
src/meta/ngc_vid1.c
Normal file
75
src/meta/ngc_vid1.c
Normal file
@ -0,0 +1,75 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* VID1 - from Neversoft games (Gun, Tony Hawk's American Wasteland GC) */
|
||||
VGMSTREAM * init_vgmstream_ngc_vid1(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, header_offset, header_size;
|
||||
int loop_flag = 0, channel_count;
|
||||
|
||||
|
||||
/* check extension */
|
||||
if (!check_extensions(streamFile,"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;
|
||||
|
||||
}
|
||||
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);
|
||||
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;
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
{
|
||||
vorbis_custom_config cfg = {0};
|
||||
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->coding_type = coding_VORBIS_custom;
|
||||
vgmstream->codec_data = init_vorbis_custom_codec_data(streamFile, header_offset + 0x20, VORBIS_VID1, &cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
/* open the file for reading */
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -369,6 +369,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_vxn,
|
||||
init_vgmstream_ea_snr_sns,
|
||||
init_vgmstream_ea_sps,
|
||||
init_vgmstream_ngc_vid1,
|
||||
|
||||
init_vgmstream_txth, /* should go at the end (lower priority) */
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
|
@ -632,6 +632,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) */
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
meta_OGG_VORBIS, /* Ogg Vorbis */
|
||||
@ -804,11 +805,12 @@ typedef struct {
|
||||
|
||||
/* custom Vorbis modes */
|
||||
typedef enum {
|
||||
VORBIS_FSB, /* simplified/external setup packets, custom packet headers */
|
||||
VORBIS_WWISE, /* many variations (custom setup, headers and data) */
|
||||
VORBIS_OGL, /* custom packet headers */
|
||||
VORBIS_SK /* "OggS" replaced by "SK" */
|
||||
//VORBIS_LYN /* two interleaved Ogg (including setup, duplicated) */
|
||||
VORBIS_FSB, /* FMOD FSB: simplified/external setup packets, custom packet headers */
|
||||
VORBIS_WWISE, /* Wwise WEM: many variations (custom setup, headers and data) */
|
||||
VORBIS_OGL, /* Shin'en OGL: custom packet headers */
|
||||
VORBIS_SK, /* Silicon Knights AUD: "OggS" replaced by "SK" */
|
||||
VORBIS_VID1, /* Neversoft VID1: custom packet blocks/headers */
|
||||
//VORBIS_LYN /* Ubisoft LyN: two interleaved Ogg (including setup, duplicated) */
|
||||
} vorbis_custom_t;
|
||||
|
||||
/* config for Wwise Vorbis (3 types for flexibility though not all combinations exist) */
|
||||
@ -859,6 +861,9 @@ typedef struct {
|
||||
uint8_t prev_blockflag; /* blockflag in the last decoded packet */
|
||||
/* Ogg-style Vorbis: packet within a page */
|
||||
int current_packet;
|
||||
/* reference for page/blocks */
|
||||
off_t block_offset;
|
||||
size_t block_size;
|
||||
|
||||
} vorbis_custom_codec_data;
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user