cog/Frameworks/vgmstream/vgmstream/src/meta/xavs.c

88 lines
2.9 KiB
C

#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
#include "xavs_streamfile.h"
/* XAVS - Reflections audio and video+audio container [Stuntman (PS2)] */
VGMSTREAM * init_vgmstream_xavs(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count;
int total_subsongs, target_subsong = streamFile->stream_index;
STREAMFILE *temp_streamFile = NULL;
/* checks */
if (!check_extensions(streamFile, "xav"))
goto fail;
if (read_32bitBE(0x00, streamFile) != 0x58415653) /* "XAVS" */
goto fail;
loop_flag = 0;
channel_count = 2;
start_offset = 0x00;
/* 0x04: 16b width + height (0 if file has no video) */
/* 0x08: related to video (0 if file has no video) */
total_subsongs = read_16bitLE(0x0c, streamFile);
/* 0x0c: volume? (0x50, 0x4e) */
/* 0x10: biggest video chunk? (0 if file has no video) */
/* 0x14: biggest audio chunk? */
if (target_subsong == 0) target_subsong = 1;
if (target_subsong > total_subsongs || total_subsongs <= 0) goto fail;
/* could use a blocked layout, but this needs interleaved PCM within blocks which can't be done ATM */
temp_streamFile = setup_xavs_streamfile(streamFile, 0x18, target_subsong - 1);
if (!temp_streamFile) goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_XAVS;
vgmstream->num_streams = total_subsongs;
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
/* no apparent flags, most videos use 0x41 but not all */
{
off_t offset = 0x18;
while (offset < get_streamfile_size(streamFile)) {
uint32_t chunk_id = read_32bitLE(offset+0x00, streamFile) & 0xFF;
uint32_t chunk_size = read_32bitLE(offset+0x00, streamFile) >> 8;
if ((chunk_id & 0xF0) == 0x40) {
vgmstream->sample_rate = 48000;
vgmstream->interleave_block_size = 0x200;
break;
} else if ((chunk_id & 0xF0) == 0x60) {
vgmstream->sample_rate = 24000;
vgmstream->interleave_block_size = 0x100;
break;
} else if (chunk_id == 0x56) {
offset += 0x04 + chunk_size;
} else if (chunk_id == 0x21) {
offset += 0x04;
} else {
goto fail;
}
}
}
vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(temp_streamFile), channel_count, 16);
if (!vgmstream_open_stream(vgmstream,temp_streamFile,start_offset))
goto fail;
close_streamfile(temp_streamFile);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}