mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-15 02:57:38 +01:00
Add .xopus decoding [Angry Birds Transformers (Android)]
This commit is contained in:
parent
cca676bb0f
commit
e49a688559
@ -281,12 +281,14 @@ void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples);
|
||||
ffmpeg_codec_data * init_ffmpeg_switch_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
|
||||
ffmpeg_codec_data * init_ffmpeg_ue4_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
|
||||
ffmpeg_codec_data * init_ffmpeg_ea_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
|
||||
ffmpeg_codec_data * init_ffmpeg_x_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
|
||||
|
||||
size_t switch_opus_get_samples(off_t offset, size_t data_size, STREAMFILE *streamFile);
|
||||
|
||||
size_t switch_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile);
|
||||
size_t ue4_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile);
|
||||
size_t ea_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile);
|
||||
size_t x_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -16,8 +16,9 @@
|
||||
static size_t make_oggs_first(uint8_t * buf, int buf_size, int channels, int skip, int sample_rate);
|
||||
static size_t make_oggs_page(uint8_t * buf, int buf_size, size_t data_size, int page_sequence, int granule);
|
||||
static size_t opus_get_packet_samples(const uint8_t * buf, int len);
|
||||
static size_t get_xopus_packet_size(int packet, STREAMFILE * streamfile);
|
||||
|
||||
typedef enum { OPUS_SWITCH, OPUS_UE4, OPUS_EA } opus_type_t;
|
||||
typedef enum { OPUS_SWITCH, OPUS_UE4, OPUS_EA, OPUS_X } opus_type_t;
|
||||
typedef struct {
|
||||
/* config */
|
||||
opus_type_t type;
|
||||
@ -104,6 +105,10 @@ static size_t opus_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
|
||||
data_size = (uint16_t)read_16bitBE(data->physical_offset, streamfile);
|
||||
skip_size = 0x02;
|
||||
break;
|
||||
case OPUS_X:
|
||||
data_size = get_xopus_packet_size(data->sequence - 2, streamfile);
|
||||
skip_size = 0;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -162,6 +167,7 @@ static size_t opus_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
|
||||
static size_t opus_io_size(STREAMFILE *streamfile, opus_io_data* data) {
|
||||
off_t physical_offset, max_physical_offset;
|
||||
size_t logical_size = 0;
|
||||
int packet = 0;
|
||||
|
||||
if (data->logical_size)
|
||||
return data->logical_size;
|
||||
@ -192,6 +198,10 @@ static size_t opus_io_size(STREAMFILE *streamfile, opus_io_data* data) {
|
||||
data_size = (uint16_t)read_16bitBE(physical_offset, streamfile);
|
||||
skip_size = 0x02;
|
||||
break;
|
||||
case OPUS_X:
|
||||
data_size = get_xopus_packet_size(packet, streamfile);
|
||||
skip_size = 0x00;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -199,6 +209,7 @@ static size_t opus_io_size(STREAMFILE *streamfile, opus_io_data* data) {
|
||||
|
||||
physical_offset += data_size + skip_size;
|
||||
logical_size += oggs_size + data_size;
|
||||
packet++;
|
||||
}
|
||||
|
||||
/* logical size can be bigger though */
|
||||
@ -390,6 +401,24 @@ fail:
|
||||
|
||||
static size_t make_opus_header(uint8_t * buf, int buf_size, int channels, int skip, int sample_rate) {
|
||||
size_t header_size = 0x13;
|
||||
int mapping_family = 0; /* channel config: 0=standard (single stream mono/stereo), 1=vorbis, 255: not defined */
|
||||
#if 0
|
||||
int stream_count = 1; /* number of internal mono/stereo streams (N mono/stereo streams form M channels) */
|
||||
int coupled_count = channels - 1; /* number of stereo streams (packet has which one is mono or stereo) */
|
||||
|
||||
/* special multichannel config */
|
||||
if (channels > 2) {
|
||||
header_size += 0x01+0x01+channels;
|
||||
switch(type) {
|
||||
|
||||
case ...:
|
||||
...
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (header_size > buf_size) {
|
||||
VGM_LOG("OPUS: buffer can't hold header\n");
|
||||
@ -403,7 +432,19 @@ static size_t make_opus_header(uint8_t * buf, int buf_size, int channels, int sk
|
||||
put_16bitLE(buf+0x0A, skip);
|
||||
put_32bitLE(buf+0x0c, sample_rate);
|
||||
put_16bitLE(buf+0x10, 0); /* output gain */
|
||||
put_8bit (buf+0x12, 0); /* channel mapping family */
|
||||
put_8bit (buf+0x12, mapping_family);
|
||||
|
||||
#if 0
|
||||
if (mapping_family > 0) {
|
||||
int 0;
|
||||
|
||||
put_8bit(buf+0x13, stream_count);
|
||||
put_8bit(buf+0x14, coupled_count);
|
||||
for (i = 0; i < channels; i++) {
|
||||
put_8bit(buf+0x15+i, i); /* channel mapping (may need to change per family) */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return header_size;
|
||||
fail:
|
||||
@ -471,6 +512,7 @@ static size_t opus_get_packet_samples(const uint8_t * buf, int len) {
|
||||
static size_t custom_opus_get_samples(off_t offset, size_t data_size, STREAMFILE *streamFile, opus_type_t type) {
|
||||
size_t num_samples = 0;
|
||||
off_t end_offset = offset + data_size;
|
||||
int packet = 0;
|
||||
|
||||
if (end_offset > get_streamfile_size(streamFile)) {
|
||||
VGM_LOG("OPUS: wrong end offset found\n");
|
||||
@ -495,6 +537,10 @@ static size_t custom_opus_get_samples(off_t offset, size_t data_size, STREAMFILE
|
||||
data_size = (uint16_t)read_16bitBE(offset, streamFile);
|
||||
skip_size = 0x02;
|
||||
break;
|
||||
case OPUS_X:
|
||||
data_size = get_xopus_packet_size(packet, streamFile);
|
||||
skip_size = 0x00;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -503,6 +549,7 @@ static size_t custom_opus_get_samples(off_t offset, size_t data_size, STREAMFILE
|
||||
num_samples += opus_get_packet_samples(buf, 0x04);
|
||||
|
||||
offset += skip_size + data_size;
|
||||
packet++;
|
||||
}
|
||||
|
||||
return num_samples;
|
||||
@ -527,6 +574,9 @@ static size_t custom_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile
|
||||
case OPUS_EA:
|
||||
skip_size = 0x02;
|
||||
break;
|
||||
case OPUS_X:
|
||||
skip_size = 0x00;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -544,8 +594,21 @@ size_t ue4_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile) {
|
||||
size_t ea_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile) {
|
||||
return custom_opus_get_encoder_delay(offset, streamFile, OPUS_EA);
|
||||
}
|
||||
size_t x_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile) {
|
||||
return custom_opus_get_encoder_delay(offset, streamFile, OPUS_X);
|
||||
}
|
||||
|
||||
|
||||
static size_t get_xopus_packet_size(int packet, STREAMFILE * streamfile) {
|
||||
/* XOPUS has a packet size table at the beginning, get size from there.
|
||||
* Maybe should copy the table during setup to avoid IO, but all XOPUS are
|
||||
* quite small so it isn't very noticeable. */
|
||||
return (uint16_t)read_16bitLE(0x20 + packet*0x02, streamfile);
|
||||
}
|
||||
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
static ffmpeg_codec_data * init_ffmpeg_custom_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate, opus_type_t type) {
|
||||
ffmpeg_codec_data * ffmpeg_data = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
@ -577,5 +640,8 @@ ffmpeg_codec_data * init_ffmpeg_ue4_opus(STREAMFILE *streamFile, off_t start_off
|
||||
ffmpeg_codec_data * init_ffmpeg_ea_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate) {
|
||||
return init_ffmpeg_custom_opus(streamFile, start_offset, data_size, channels, skip, sample_rate, OPUS_EA);
|
||||
}
|
||||
ffmpeg_codec_data * init_ffmpeg_x_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate) {
|
||||
return init_ffmpeg_custom_opus(streamFile, start_offset, data_size, channels, skip, sample_rate, OPUS_X);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -459,6 +459,7 @@ static const char* extension_list[] = {
|
||||
"xwav",//fake, to be removed
|
||||
"xwb",
|
||||
"xmd",
|
||||
"xopus",
|
||||
"xwc",
|
||||
"xwm",
|
||||
"xwma",
|
||||
@ -1094,6 +1095,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_UE4OPUS, "Epic Games UE4OPUS header"},
|
||||
{meta_XWMA, "Microsoft XWMA RIFF header"},
|
||||
{meta_VA3, "Konami / Sony ATRAC3 Header" },
|
||||
{meta_XOPUS, "Rovio XOPUS header"},
|
||||
|
||||
};
|
||||
|
||||
|
@ -1593,6 +1593,10 @@
|
||||
<File
|
||||
RelativePath=".\meta\xnb.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\xopus.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\xss.c"
|
||||
|
@ -472,6 +472,7 @@
|
||||
<ClCompile Include="meta\x360_pasx.c" />
|
||||
<ClCompile Include="meta\xma.c" />
|
||||
<ClCompile Include="meta\xnb.c" />
|
||||
<ClCompile Include="meta\xopus.c" />
|
||||
<ClCompile Include="meta\xss.c" />
|
||||
<ClCompile Include="meta\xvag.c" />
|
||||
<ClCompile Include="meta\xmd.c" />
|
||||
|
@ -1435,6 +1435,9 @@
|
||||
<ClCompile Include="meta\xnb.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\xopus.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\x360_cxs.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -797,4 +797,6 @@ VGMSTREAM * init_vgmstream_ue4opus(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_xwma(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_xopus(STREAMFILE * streamFile);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
66
src/meta/xopus.c
Normal file
66
src/meta/xopus.c
Normal file
@ -0,0 +1,66 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* XOPUS - from Rovio games [Angry Birds: Transformers (Android), Angry Birds: Go (Android)] */
|
||||
VGMSTREAM * init_vgmstream_xopus(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag = 0, channel_count, sample_rate, num_samples, skip;
|
||||
size_t data_size;
|
||||
int entries;
|
||||
|
||||
|
||||
/* checks*/
|
||||
if (!check_extensions(streamFile, "xopus"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00, streamFile) != 0x584F7075) /* "XOpu" */
|
||||
goto fail;
|
||||
|
||||
/* 0x04: always 1? 0x30? */
|
||||
channel_count = read_8bit(0x05, streamFile);
|
||||
/* 0x06: always 0x30? */
|
||||
/* 0x08: always 0xc8? encoder delay? */
|
||||
num_samples = read_32bitLE(0x0c, streamFile);
|
||||
/* 0x10: always 0x138? max packet size? */
|
||||
entries = read_32bitLE(0x14, streamFile); /* packet sizes */
|
||||
/* 0x18: data size */
|
||||
/* 0x1c: unused */
|
||||
/* 0x20+: packet sizes table */
|
||||
|
||||
|
||||
sample_rate = 48000;
|
||||
loop_flag = 0;
|
||||
|
||||
start_offset = 0x20 + 0x02*entries;
|
||||
data_size = get_streamfile_size(streamFile) - start_offset;
|
||||
skip = x_opus_get_encoder_delay(start_offset, streamFile);
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_XOPUS;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = num_samples /*- skip*/;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
{
|
||||
vgmstream->codec_data = init_ffmpeg_x_opus(streamFile, start_offset,data_size, vgmstream->channels, skip, vgmstream->sample_rate);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -443,6 +443,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_adpcm_capcom,
|
||||
init_vgmstream_ue4opus,
|
||||
init_vgmstream_xwma,
|
||||
init_vgmstream_xopus,
|
||||
|
||||
|
||||
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
|
||||
|
@ -700,6 +700,7 @@ typedef enum {
|
||||
meta_UE4OPUS,
|
||||
meta_XWMA,
|
||||
meta_VA3, /* DDR Supernova 2 AC */
|
||||
meta_XOPUS,
|
||||
|
||||
} meta_t;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user