#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; }