mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-12 01:30:49 +01:00
cleanup: crlf/etc
This commit is contained in:
parent
2169f50259
commit
a6a113d813
@ -1,14 +1,14 @@
|
||||
#ifndef _MIXER_H_
|
||||
#define _MIXER_H_
|
||||
|
||||
#include "../streamtypes.h"
|
||||
|
||||
/* internal mixing pre-setup for vgmstream (doesn't imply usage).
|
||||
* If init somehow fails next calls are ignored. */
|
||||
void* mixer_init(int channels);
|
||||
void mixer_free(void* mixer);
|
||||
void mixer_update_channel(void* mixer);
|
||||
void mixer_process(void* _mixer, sample_t *outbuf, int32_t sample_count, int32_t current_pos);
|
||||
bool mixer_is_active(void* mixer);
|
||||
|
||||
#endif
|
||||
#ifndef _MIXER_H_
|
||||
#define _MIXER_H_
|
||||
|
||||
#include "../streamtypes.h"
|
||||
|
||||
/* internal mixing pre-setup for vgmstream (doesn't imply usage).
|
||||
* If init somehow fails next calls are ignored. */
|
||||
void* mixer_init(int channels);
|
||||
void mixer_free(void* mixer);
|
||||
void mixer_update_channel(void* mixer);
|
||||
void mixer_process(void* _mixer, sample_t *outbuf, int32_t sample_count, int32_t current_pos);
|
||||
bool mixer_is_active(void* mixer);
|
||||
|
||||
#endif
|
||||
|
@ -1,28 +1,28 @@
|
||||
#ifndef _SBUF_H
|
||||
#define _SBUF_H
|
||||
|
||||
#include "../streamtypes.h"
|
||||
|
||||
// TODO decide if using float 1.0 style or 32767 style (fuzzy PCM changes when doing that)
|
||||
static inline void sbuf_copy_s16_to_f32(float* buf_f32, int16_t* buf_s16, int samples, int channels) {
|
||||
for (int s = 0; s < samples * channels; s++) {
|
||||
buf_f32[s] = buf_s16[s]; // / 32767.0f
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sbuf_copy_f32_to_s16(int16_t* buf_s16, float* buf_f32, int samples, int channels) {
|
||||
/* when casting float to int, value is simply truncated:
|
||||
* - (int)1.7 = 1, (int)-1.7 = -1
|
||||
* alts for more accurate rounding could be:
|
||||
* - (int)floor(f)
|
||||
* - (int)(f < 0 ? f - 0.5f : f + 0.5f)
|
||||
* - (((int) (f1 + 32768.5)) - 32768)
|
||||
* - etc
|
||||
* but since +-1 isn't really audible we'll just cast as it's the fastest
|
||||
*/
|
||||
for (int s = 0; s < samples * channels; s++) {
|
||||
buf_s16[s] = clamp16( buf_f32[s]); // * 32767.0f
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifndef _SBUF_H
|
||||
#define _SBUF_H
|
||||
|
||||
#include "../streamtypes.h"
|
||||
|
||||
// TODO decide if using float 1.0 style or 32767 style (fuzzy PCM changes when doing that)
|
||||
static inline void sbuf_copy_s16_to_f32(float* buf_f32, int16_t* buf_s16, int samples, int channels) {
|
||||
for (int s = 0; s < samples * channels; s++) {
|
||||
buf_f32[s] = buf_s16[s]; // / 32767.0f
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sbuf_copy_f32_to_s16(int16_t* buf_s16, float* buf_f32, int samples, int channels) {
|
||||
/* when casting float to int, value is simply truncated:
|
||||
* - (int)1.7 = 1, (int)-1.7 = -1
|
||||
* alts for more accurate rounding could be:
|
||||
* - (int)floor(f)
|
||||
* - (int)(f < 0 ? f - 0.5f : f + 0.5f)
|
||||
* - (((int) (f1 + 32768.5)) - 32768)
|
||||
* - etc
|
||||
* but since +-1 isn't really audible we'll just cast as it's the fastest
|
||||
*/
|
||||
for (int s = 0; s < samples * channels; s++) {
|
||||
buf_s16[s] = clamp16( buf_f32[s]); // * 32767.0f
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
235
src/meta/9tav.c
235
src/meta/9tav.c
@ -1,118 +1,117 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "9tav_streamfile.h"
|
||||
|
||||
/* 9TAV - from Metal Gear Solid 2/3 HD (Vita) */
|
||||
VGMSTREAM * init_vgmstream_9tav(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count, sample_rate, track_count;
|
||||
int32_t num_samples, loop_start, loop_end;
|
||||
size_t track_size;
|
||||
uint32_t config_data;
|
||||
int i, is_padded;
|
||||
layered_layout_data * data = NULL;
|
||||
STREAMFILE* temp_streamFile = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .9tav: header id */
|
||||
if (!check_extensions(streamFile, "9tav"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) != 0x39544156) /* "9TAV" */
|
||||
goto fail;
|
||||
|
||||
/* 0x04: always 0x09 */
|
||||
channel_count = read_16bitLE(0x08,streamFile);
|
||||
track_count = read_16bitLE(0x0a,streamFile); /* MGS3 uses multitracks */
|
||||
sample_rate = read_32bitLE(0x0c,streamFile);
|
||||
track_size = read_32bitLE(0x10,streamFile); /* without padding */
|
||||
//data_size = read_32bitLE(0x14,streamFile); /* without padding */
|
||||
num_samples = read_32bitLE(0x18,streamFile);
|
||||
config_data = read_32bitBE(0x1c,streamFile);
|
||||
|
||||
|
||||
if (read_32bitBE(0x20,streamFile) == 0x4D544146) { /* "MTAF" */
|
||||
/* MGS3 has a MTAF header (data size and stuff don't match, probably for track info) */
|
||||
loop_start = read_32bitLE(0x78, streamFile);
|
||||
loop_end = read_32bitLE(0x7c, streamFile);
|
||||
loop_flag = read_32bitLE(0x90, streamFile) & 1;
|
||||
|
||||
is_padded = 1; /* data also has padding and other oddities */
|
||||
start_offset = 0x00;
|
||||
}
|
||||
else {
|
||||
/* MGS2 doesn't */
|
||||
loop_start = 0;
|
||||
loop_end = 0;
|
||||
loop_flag = 0;
|
||||
|
||||
is_padded = 0;
|
||||
start_offset = 0x20;
|
||||
}
|
||||
|
||||
|
||||
/* init layout */
|
||||
data = init_layout_layered(track_count);
|
||||
if (!data) goto fail;
|
||||
|
||||
/* open each layer subfile */
|
||||
for (i = 0; i < data->layer_count; i++) {
|
||||
data->layers[i] = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!data->layers[i]) goto fail;
|
||||
|
||||
data->layers[i]->meta_type = meta_9TAV;
|
||||
data->layers[i]->sample_rate = sample_rate;
|
||||
data->layers[i]->num_samples = num_samples;
|
||||
data->layers[i]->loop_start_sample = loop_start;
|
||||
data->layers[i]->loop_end_sample = loop_end;
|
||||
|
||||
#ifdef VGM_USE_ATRAC9
|
||||
{
|
||||
atrac9_config cfg = {0};
|
||||
cfg.channels = channel_count;
|
||||
cfg.config_data = config_data;
|
||||
cfg.encoder_delay = atrac9_bytes_to_samples_cfg(track_size, cfg.config_data) - num_samples; /* seems ok */
|
||||
if (cfg.encoder_delay > 4096) /* doesn't seem too normal */
|
||||
cfg.encoder_delay = 0;
|
||||
|
||||
data->layers[i]->codec_data = init_atrac9(&cfg);
|
||||
if (!data->layers[i]->codec_data) goto fail;
|
||||
data->layers[i]->coding_type = coding_ATRAC9;
|
||||
data->layers[i]->layout_type = layout_none;
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
if (is_padded) {
|
||||
temp_streamFile = setup_9tav_streamfile(streamFile, 0xFE4, track_size, i, track_count);
|
||||
if (!temp_streamFile) goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(data->layers[i],temp_streamFile == NULL ? streamFile : temp_streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
temp_streamFile = NULL;
|
||||
}
|
||||
|
||||
/* setup layered VGMSTREAMs */
|
||||
if (!setup_layout_layered(data))
|
||||
goto fail;
|
||||
|
||||
/* build the layered VGMSTREAM */
|
||||
vgmstream = allocate_layered_vgmstream(data);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
close_vgmstream(vgmstream);
|
||||
if (!vgmstream)
|
||||
free_layout_layered(data);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "9tav_streamfile.h"
|
||||
|
||||
/* 9TAV - from Metal Gear Solid 2/3 HD (Vita) */
|
||||
VGMSTREAM* init_vgmstream_9tav(STREAMFILE* sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channels, sample_rate, track_count;
|
||||
int32_t num_samples, loop_start, loop_end;
|
||||
size_t track_size;
|
||||
uint32_t config_data;
|
||||
bool is_padded;
|
||||
layered_layout_data* data = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!is_id32be(0x00,sf, "9TAV"))
|
||||
return NULL;
|
||||
/* .9tav: header id */
|
||||
if (!check_extensions(sf, "9tav"))
|
||||
return NULL;
|
||||
|
||||
/* 0x04: always 0x09 (codec?) */
|
||||
channels = read_u16le(0x08,sf);
|
||||
track_count = read_u16le(0x0a,sf); /* MGS3 uses multitracks */
|
||||
sample_rate = read_s32le(0x0c,sf);
|
||||
track_size = read_u32le(0x10,sf); /* without padding */
|
||||
//data_size = read_u32le(0x14,sf); /* without padding */
|
||||
num_samples = read_s32le(0x18,sf);
|
||||
config_data = read_u32be(0x1c,sf);
|
||||
|
||||
|
||||
if (is_id32be(0x20,sf, "MTAF")) {
|
||||
/* MGS3 has a MTAF header (data size and stuff don't match, probably for track info) */
|
||||
loop_start = read_s32le(0x78, sf);
|
||||
loop_end = read_s32le(0x7c, sf);
|
||||
loop_flag = read_u32le(0x90, sf) & 1;
|
||||
|
||||
is_padded = true; /* data also has padding and other oddities */
|
||||
start_offset = 0x00;
|
||||
}
|
||||
else {
|
||||
/* MGS2 doesn't */
|
||||
loop_start = 0;
|
||||
loop_end = 0;
|
||||
loop_flag = false;
|
||||
|
||||
is_padded = false;
|
||||
start_offset = 0x20;
|
||||
}
|
||||
|
||||
|
||||
/* init layout */
|
||||
data = init_layout_layered(track_count);
|
||||
if (!data) goto fail;
|
||||
|
||||
/* open each layer subfile */
|
||||
for (int i = 0; i < data->layer_count; i++) {
|
||||
data->layers[i] = allocate_vgmstream(channels, loop_flag);
|
||||
if (!data->layers[i]) goto fail;
|
||||
|
||||
data->layers[i]->meta_type = meta_9TAV;
|
||||
data->layers[i]->sample_rate = sample_rate;
|
||||
data->layers[i]->num_samples = num_samples;
|
||||
data->layers[i]->loop_start_sample = loop_start;
|
||||
data->layers[i]->loop_end_sample = loop_end;
|
||||
|
||||
#ifdef VGM_USE_ATRAC9
|
||||
{
|
||||
atrac9_config cfg = {0};
|
||||
cfg.channels = channels;
|
||||
cfg.config_data = config_data;
|
||||
cfg.encoder_delay = atrac9_bytes_to_samples_cfg(track_size, cfg.config_data) - num_samples; /* seems ok */
|
||||
if (cfg.encoder_delay > 4096) /* doesn't seem too normal */
|
||||
cfg.encoder_delay = 0;
|
||||
|
||||
data->layers[i]->codec_data = init_atrac9(&cfg);
|
||||
if (!data->layers[i]->codec_data) goto fail;
|
||||
data->layers[i]->coding_type = coding_ATRAC9;
|
||||
data->layers[i]->layout_type = layout_none;
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
if (is_padded) {
|
||||
temp_sf = setup_9tav_streamfile(sf, 0xFE4, track_size, i, track_count);
|
||||
if (!temp_sf) goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(data->layers[i],temp_sf == NULL ? sf : temp_sf,start_offset))
|
||||
goto fail;
|
||||
|
||||
close_streamfile(temp_sf);
|
||||
temp_sf = NULL;
|
||||
}
|
||||
|
||||
/* setup layered VGMSTREAMs */
|
||||
if (!setup_layout_layered(data))
|
||||
goto fail;
|
||||
|
||||
/* build the layered VGMSTREAM */
|
||||
vgmstream = allocate_layered_vgmstream(data);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_sf);
|
||||
close_vgmstream(vgmstream);
|
||||
if (!vgmstream)
|
||||
free_layout_layered(data);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,182 +1,182 @@
|
||||
#ifndef _9TAV_STREAMFILE_H_
|
||||
#define _9TAV_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* config */
|
||||
off_t stream_offset;
|
||||
size_t stream_size;
|
||||
size_t track_size;
|
||||
int track_number;
|
||||
int track_count;
|
||||
int skip_count;
|
||||
int read_count;
|
||||
size_t frame_size;
|
||||
size_t interleave_count;
|
||||
size_t interleave_last_count;
|
||||
|
||||
/* state */
|
||||
off_t logical_offset; /* fake offset */
|
||||
off_t physical_offset; /* actual offset */
|
||||
size_t block_size; /* current size */
|
||||
size_t skip_size; /* size from block start to reach data */
|
||||
size_t data_size; /* usable size in a block */
|
||||
|
||||
size_t logical_size;
|
||||
} ntav_io_data;
|
||||
|
||||
|
||||
static size_t ntav_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, ntav_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
|
||||
/* re-start when previous offset (can't map logical<>physical offsets) */
|
||||
if (data->logical_offset < 0 || offset < data->logical_offset) {
|
||||
data->physical_offset = data->stream_offset;
|
||||
data->logical_offset = 0x00;
|
||||
data->data_size = 0;
|
||||
data->skip_size = 0;
|
||||
data->read_count = 0;
|
||||
data->skip_count = data->interleave_count * data->track_number;
|
||||
//VGM_LOG("0 o=%lx, sc=%i\n", data->physical_offset, data->skip_count);
|
||||
}
|
||||
|
||||
/* read blocks */
|
||||
while (length > 0) {
|
||||
//VGM_LOG("1 of=%lx, so=%lx, sz=%x, of2=%lx, log=%lx\n", data->physical_offset, data->stream_offset, data->stream_size, offset, data->logical_offset);
|
||||
|
||||
/* ignore EOF */
|
||||
if (offset < 0 || data->physical_offset >= data->stream_offset + data->stream_size) {
|
||||
//VGM_LOG("9 o=%lx, so=%lx, sz=%x, of2=%lx, log=%lx\n", data->physical_offset, data->stream_offset, data->stream_size, offset, data->logical_offset);
|
||||
//VGM_LOG("eof\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* process new block */
|
||||
if (data->data_size == 0) {
|
||||
/* not very exact compared to real blocks but ok enough */
|
||||
if (read_32bitLE(data->physical_offset, streamfile) == 0x00) {
|
||||
data->block_size = 0x10;
|
||||
//VGM_LOG("1 o=%lx, lo=%lx skip\n", data->physical_offset, data->logical_offset);
|
||||
}
|
||||
else {
|
||||
data->block_size = data->frame_size;
|
||||
|
||||
//VGM_LOG("2 o=%lx, lo=%lx, skip=%i, read=%i\n", data->physical_offset, data->logical_offset, data->skip_count, data->read_count);
|
||||
|
||||
/* each track interleaves NTAV_INTERLEAVE frames, but can contain padding in between,
|
||||
* so must read one by one up to max */
|
||||
|
||||
if (data->skip_count == 0 && data->read_count == 0) {
|
||||
data->read_count = data->interleave_count;
|
||||
}
|
||||
|
||||
if (data->skip_count) {
|
||||
data->skip_count--;
|
||||
}
|
||||
|
||||
if (data->read_count) {
|
||||
data->data_size = data->block_size;
|
||||
data->read_count--;
|
||||
|
||||
if (data->read_count == 0) {
|
||||
if (data->logical_offset + data->interleave_count * data->frame_size > data->track_size)
|
||||
data->skip_count = data->interleave_last_count * (data->track_count - 1);
|
||||
else
|
||||
data->skip_count = data->interleave_count * (data->track_count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* move to next block */
|
||||
if (data->data_size == 0 || offset >= data->logical_offset + data->data_size) {
|
||||
data->physical_offset += data->block_size;
|
||||
data->logical_offset += data->data_size;
|
||||
data->data_size = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read data */
|
||||
{
|
||||
size_t bytes_consumed, bytes_done, to_read;
|
||||
|
||||
bytes_consumed = offset - data->logical_offset;
|
||||
to_read = data->data_size - bytes_consumed;
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
|
||||
|
||||
total_read += bytes_done;
|
||||
dest += bytes_done;
|
||||
offset += bytes_done;
|
||||
length -= bytes_done;
|
||||
|
||||
if (bytes_done != to_read || bytes_done == 0) {
|
||||
break; /* error/EOF */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t ntav_io_size(STREAMFILE *streamfile, ntav_io_data* data) {
|
||||
uint8_t buf[1];
|
||||
|
||||
if (data->logical_size)
|
||||
return data->logical_size;
|
||||
|
||||
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
|
||||
ntav_io_read(streamfile, buf, 0x7FFFFFFF, 1, data);
|
||||
data->logical_size = data->logical_offset;
|
||||
|
||||
return data->logical_size;
|
||||
}
|
||||
|
||||
/* Handles deinterleaving of 9TAV blocked streams. Unlike other games using .sdt,
|
||||
* KCEJ blocks have a data_size field and rest is padding. Even after that all blocks start
|
||||
* with 0 (skipped) and there are padding blocks that start with LE 0xDEADBEEF.
|
||||
* This streamfile handles 9tav extracted like regular sdt and remove padding manually. */
|
||||
static STREAMFILE* setup_9tav_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t track_size, int track_number, int track_count) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
ntav_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(ntav_io_data);
|
||||
size_t last_size;
|
||||
|
||||
io_data.stream_offset = stream_offset;
|
||||
io_data.stream_size = get_streamfile_size(streamFile) - stream_offset;
|
||||
io_data.track_size = track_size;
|
||||
io_data.track_number = track_number;
|
||||
io_data.track_count = track_count;
|
||||
io_data.frame_size = 0x40;
|
||||
io_data.interleave_count = 256;
|
||||
last_size = track_size % (io_data.interleave_count * io_data.frame_size);
|
||||
if (last_size)
|
||||
io_data.interleave_last_count = last_size / io_data.frame_size;
|
||||
io_data.logical_offset = -1; /* force state reset */
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(new_streamFile, &io_data,io_data_size, ntav_io_read,ntav_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_buffer_streamfile(new_streamFile,0);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _9TAV_STREAMFILE_H_ */
|
||||
#ifndef _9TAV_STREAMFILE_H_
|
||||
#define _9TAV_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* config */
|
||||
off_t stream_offset;
|
||||
size_t stream_size;
|
||||
size_t track_size;
|
||||
int track_number;
|
||||
int track_count;
|
||||
int skip_count;
|
||||
int read_count;
|
||||
size_t frame_size;
|
||||
size_t interleave_count;
|
||||
size_t interleave_last_count;
|
||||
|
||||
/* state */
|
||||
off_t logical_offset; /* fake offset */
|
||||
off_t physical_offset; /* actual offset */
|
||||
size_t block_size; /* current size */
|
||||
size_t skip_size; /* size from block start to reach data */
|
||||
size_t data_size; /* usable size in a block */
|
||||
|
||||
size_t logical_size;
|
||||
} ntav_io_data;
|
||||
|
||||
|
||||
static size_t ntav_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, ntav_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
|
||||
/* re-start when previous offset (can't map logical<>physical offsets) */
|
||||
if (data->logical_offset < 0 || offset < data->logical_offset) {
|
||||
data->physical_offset = data->stream_offset;
|
||||
data->logical_offset = 0x00;
|
||||
data->data_size = 0;
|
||||
data->skip_size = 0;
|
||||
data->read_count = 0;
|
||||
data->skip_count = data->interleave_count * data->track_number;
|
||||
//VGM_LOG("0 o=%lx, sc=%i\n", data->physical_offset, data->skip_count);
|
||||
}
|
||||
|
||||
/* read blocks */
|
||||
while (length > 0) {
|
||||
//VGM_LOG("1 of=%lx, so=%lx, sz=%x, of2=%lx, log=%lx\n", data->physical_offset, data->stream_offset, data->stream_size, offset, data->logical_offset);
|
||||
|
||||
/* ignore EOF */
|
||||
if (offset < 0 || data->physical_offset >= data->stream_offset + data->stream_size) {
|
||||
//VGM_LOG("9 o=%lx, so=%lx, sz=%x, of2=%lx, log=%lx\n", data->physical_offset, data->stream_offset, data->stream_size, offset, data->logical_offset);
|
||||
//VGM_LOG("eof\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* process new block */
|
||||
if (data->data_size == 0) {
|
||||
/* not very exact compared to real blocks but ok enough */
|
||||
if (read_32bitLE(data->physical_offset, streamfile) == 0x00) {
|
||||
data->block_size = 0x10;
|
||||
//VGM_LOG("1 o=%lx, lo=%lx skip\n", data->physical_offset, data->logical_offset);
|
||||
}
|
||||
else {
|
||||
data->block_size = data->frame_size;
|
||||
|
||||
//VGM_LOG("2 o=%lx, lo=%lx, skip=%i, read=%i\n", data->physical_offset, data->logical_offset, data->skip_count, data->read_count);
|
||||
|
||||
/* each track interleaves NTAV_INTERLEAVE frames, but can contain padding in between,
|
||||
* so must read one by one up to max */
|
||||
|
||||
if (data->skip_count == 0 && data->read_count == 0) {
|
||||
data->read_count = data->interleave_count;
|
||||
}
|
||||
|
||||
if (data->skip_count) {
|
||||
data->skip_count--;
|
||||
}
|
||||
|
||||
if (data->read_count) {
|
||||
data->data_size = data->block_size;
|
||||
data->read_count--;
|
||||
|
||||
if (data->read_count == 0) {
|
||||
if (data->logical_offset + data->interleave_count * data->frame_size > data->track_size)
|
||||
data->skip_count = data->interleave_last_count * (data->track_count - 1);
|
||||
else
|
||||
data->skip_count = data->interleave_count * (data->track_count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* move to next block */
|
||||
if (data->data_size == 0 || offset >= data->logical_offset + data->data_size) {
|
||||
data->physical_offset += data->block_size;
|
||||
data->logical_offset += data->data_size;
|
||||
data->data_size = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read data */
|
||||
{
|
||||
size_t bytes_consumed, bytes_done, to_read;
|
||||
|
||||
bytes_consumed = offset - data->logical_offset;
|
||||
to_read = data->data_size - bytes_consumed;
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
|
||||
|
||||
total_read += bytes_done;
|
||||
dest += bytes_done;
|
||||
offset += bytes_done;
|
||||
length -= bytes_done;
|
||||
|
||||
if (bytes_done != to_read || bytes_done == 0) {
|
||||
break; /* error/EOF */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t ntav_io_size(STREAMFILE *streamfile, ntav_io_data* data) {
|
||||
uint8_t buf[1];
|
||||
|
||||
if (data->logical_size)
|
||||
return data->logical_size;
|
||||
|
||||
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
|
||||
ntav_io_read(streamfile, buf, 0x7FFFFFFF, 1, data);
|
||||
data->logical_size = data->logical_offset;
|
||||
|
||||
return data->logical_size;
|
||||
}
|
||||
|
||||
/* Handles deinterleaving of 9TAV blocked streams. Unlike other games using .sdt,
|
||||
* KCEJ blocks have a data_size field and rest is padding. Even after that all blocks start
|
||||
* with 0 (skipped) and there are padding blocks that start with LE 0xDEADBEEF.
|
||||
* This streamfile handles 9tav extracted like regular sdt and remove padding manually. */
|
||||
static STREAMFILE* setup_9tav_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t track_size, int track_number, int track_count) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
ntav_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(ntav_io_data);
|
||||
size_t last_size;
|
||||
|
||||
io_data.stream_offset = stream_offset;
|
||||
io_data.stream_size = get_streamfile_size(streamFile) - stream_offset;
|
||||
io_data.track_size = track_size;
|
||||
io_data.track_number = track_number;
|
||||
io_data.track_count = track_count;
|
||||
io_data.frame_size = 0x40;
|
||||
io_data.interleave_count = 256;
|
||||
last_size = track_size % (io_data.interleave_count * io_data.frame_size);
|
||||
if (last_size)
|
||||
io_data.interleave_last_count = last_size / io_data.frame_size;
|
||||
io_data.logical_offset = -1; /* force state reset */
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(new_streamFile, &io_data,io_data_size, ntav_io_read,ntav_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_buffer_streamfile(new_streamFile,0);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _9TAV_STREAMFILE_H_ */
|
||||
|
@ -1,21 +1,21 @@
|
||||
#ifndef _FSB5_STREAMFILE_H_
|
||||
#define _FSB5_STREAMFILE_H_
|
||||
#include "deblock_streamfile.h"
|
||||
|
||||
static STREAMFILE* setup_fsb5_streamfile(STREAMFILE* sf, off_t stream_start, size_t stream_size, int stream_count, int stream_number, size_t interleave) {
|
||||
STREAMFILE* new_sf = NULL;
|
||||
deblock_config_t cfg = {0};
|
||||
|
||||
cfg.stream_start = stream_start;
|
||||
cfg.stream_size = stream_size;
|
||||
cfg.chunk_size = interleave;
|
||||
cfg.step_start = stream_number;
|
||||
cfg.step_count = stream_count;
|
||||
|
||||
/* setup sf */
|
||||
new_sf = open_wrap_streamfile(sf);
|
||||
new_sf = open_io_deblock_streamfile_f(new_sf, &cfg);
|
||||
return new_sf;
|
||||
}
|
||||
|
||||
#endif /* _FSB5_STREAMFILE_H_ */
|
||||
#ifndef _FSB5_STREAMFILE_H_
|
||||
#define _FSB5_STREAMFILE_H_
|
||||
#include "deblock_streamfile.h"
|
||||
|
||||
static STREAMFILE* setup_fsb5_streamfile(STREAMFILE* sf, off_t stream_start, size_t stream_size, int stream_count, int stream_number, size_t interleave) {
|
||||
STREAMFILE* new_sf = NULL;
|
||||
deblock_config_t cfg = {0};
|
||||
|
||||
cfg.stream_start = stream_start;
|
||||
cfg.stream_size = stream_size;
|
||||
cfg.chunk_size = interleave;
|
||||
cfg.step_start = stream_number;
|
||||
cfg.step_count = stream_count;
|
||||
|
||||
/* setup sf */
|
||||
new_sf = open_wrap_streamfile(sf);
|
||||
new_sf = open_io_deblock_streamfile_f(new_sf, &cfg);
|
||||
return new_sf;
|
||||
}
|
||||
|
||||
#endif /* _FSB5_STREAMFILE_H_ */
|
||||
|
@ -1,198 +1,198 @@
|
||||
#ifndef _FSB_INTERLEAVE_STREAMFILE_H_
|
||||
#define _FSB_INTERLEAVE_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
typedef enum { FSB_INT_CELT } fsb_interleave_codec_t;
|
||||
typedef struct {
|
||||
/* state */
|
||||
off_t logical_offset; /* offset that corresponds to physical_offset */
|
||||
off_t physical_offset; /* actual file offset */
|
||||
int skip_frames; /* frames to skip from other streams at points */
|
||||
|
||||
/* config */
|
||||
fsb_interleave_codec_t codec;
|
||||
int stream_count;
|
||||
int stream_number;
|
||||
size_t stream_size;
|
||||
off_t start_offset; /* pointing to the stream's beginning */
|
||||
size_t total_size; /* size of the resulting substream */
|
||||
} fsb_interleave_io_data;
|
||||
|
||||
|
||||
|
||||
/* Reads skipping other streams */
|
||||
static size_t fsb_interleave_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, fsb_interleave_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
/* ignore bad reads */
|
||||
if (offset < 0 || offset > data->total_size) {
|
||||
return total_read;
|
||||
}
|
||||
|
||||
/* previous offset: re-start as we can't map logical<>physical offsets
|
||||
* (kinda slow as it trashes buffers, but shouldn't happen often) */
|
||||
if (offset < data->logical_offset) {
|
||||
data->physical_offset = data->start_offset;
|
||||
data->logical_offset = 0x00;
|
||||
data->skip_frames = data->stream_number;
|
||||
}
|
||||
|
||||
/* read doing one frame at a time */
|
||||
while (length > 0) {
|
||||
size_t to_read, bytes_read;
|
||||
off_t intrablock_offset, intradata_offset;
|
||||
uint32_t data_size;
|
||||
|
||||
if (offset >= data->total_size)
|
||||
break;
|
||||
|
||||
/* get current data */
|
||||
switch (data->codec) {
|
||||
case FSB_INT_CELT:
|
||||
data_size = 0x04+0x04+read_32bitLE(data->physical_offset+0x04,streamfile);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* skip frames from other streams */
|
||||
if (data->skip_frames) {
|
||||
data->physical_offset += data_size;
|
||||
data->skip_frames--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* requested offset is outside current block, try next */
|
||||
if (offset >= data->logical_offset + data_size) {
|
||||
data->physical_offset += data_size;
|
||||
data->logical_offset += data_size;
|
||||
data->skip_frames = data->stream_count - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* reads could fall in the middle of the block */
|
||||
intradata_offset = offset - data->logical_offset;
|
||||
intrablock_offset = intradata_offset;
|
||||
|
||||
/* clamp reads up to this block's end */
|
||||
to_read = (data_size - intradata_offset);
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
if (to_read == 0)
|
||||
break; /* should never happen... */
|
||||
|
||||
/* finally read and move buffer/offsets */
|
||||
bytes_read = read_streamfile(dest, data->physical_offset + intrablock_offset, to_read, streamfile);
|
||||
total_read += bytes_read;
|
||||
if (bytes_read != to_read)
|
||||
break; /* couldn't read fully */
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
|
||||
/* block fully read, go next */
|
||||
if (intradata_offset + bytes_read == data_size) {
|
||||
data->physical_offset += data_size;
|
||||
data->logical_offset += data_size;
|
||||
data->skip_frames = data->stream_count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t fsb_interleave_io_size(STREAMFILE *streamfile, fsb_interleave_io_data* data) {
|
||||
off_t physical_offset, max_physical_offset;
|
||||
size_t total_size = 0;
|
||||
int skip_frames = 0;
|
||||
|
||||
if (data->total_size)
|
||||
return data->total_size;
|
||||
|
||||
physical_offset = data->start_offset;
|
||||
max_physical_offset = physical_offset + data->stream_size;
|
||||
skip_frames = data->stream_number;
|
||||
|
||||
/* get size of the underlying stream, skipping other streams
|
||||
* (all streams should have the same frame count) */
|
||||
while (physical_offset < max_physical_offset) {
|
||||
size_t data_size;
|
||||
uint32_t id;
|
||||
|
||||
switch(data->codec) {
|
||||
case FSB_INT_CELT:
|
||||
id = read_32bitBE(physical_offset+0x00,streamfile);
|
||||
if (id != 0x17C30DF3) /* incorrect FSB CELT frame sync */
|
||||
data_size = 0;
|
||||
else
|
||||
data_size = 0x04+0x04+read_32bitLE(physical_offset+0x04,streamfile);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* there may be padding at the end, so this doubles as EOF marker */
|
||||
if (data_size == 0)
|
||||
break;
|
||||
|
||||
/* skip frames from other streams */
|
||||
if (skip_frames) {
|
||||
physical_offset += data_size;
|
||||
skip_frames--;
|
||||
continue;
|
||||
}
|
||||
|
||||
physical_offset += data_size;
|
||||
total_size += data_size;
|
||||
skip_frames = data->stream_count - 1;
|
||||
}
|
||||
|
||||
data->total_size = total_size;
|
||||
return data->total_size;
|
||||
}
|
||||
|
||||
|
||||
/* Prepares custom IO for multistreams, interleaves 1 packet per stream */
|
||||
static STREAMFILE* setup_fsb_interleave_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t stream_size, int stream_count, int stream_number, fsb_interleave_codec_t codec) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
fsb_interleave_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(fsb_interleave_io_data);
|
||||
|
||||
io_data.start_offset = start_offset;
|
||||
io_data.physical_offset = start_offset;
|
||||
io_data.skip_frames = stream_number; /* adjust since start_offset points to the first */
|
||||
io_data.codec = codec;
|
||||
io_data.stream_count = stream_count;
|
||||
io_data.stream_number = stream_number;
|
||||
io_data.stream_size = stream_size;
|
||||
io_data.total_size = fsb_interleave_io_size(streamFile, &io_data); /* force init */
|
||||
|
||||
if (io_data.total_size == 0 || io_data.total_size > io_data.stream_size) {
|
||||
VGM_LOG("FSB INTERLEAVE: wrong total_size %x vs %x\n", io_data.total_size,io_data.stream_size);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, fsb_interleave_io_read,fsb_interleave_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_buffer_streamfile(new_streamFile,0);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _FSB_INTERLEAVE_STREAMFILE_H_ */
|
||||
#ifndef _FSB_INTERLEAVE_STREAMFILE_H_
|
||||
#define _FSB_INTERLEAVE_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
typedef enum { FSB_INT_CELT } fsb_interleave_codec_t;
|
||||
typedef struct {
|
||||
/* state */
|
||||
off_t logical_offset; /* offset that corresponds to physical_offset */
|
||||
off_t physical_offset; /* actual file offset */
|
||||
int skip_frames; /* frames to skip from other streams at points */
|
||||
|
||||
/* config */
|
||||
fsb_interleave_codec_t codec;
|
||||
int stream_count;
|
||||
int stream_number;
|
||||
size_t stream_size;
|
||||
off_t start_offset; /* pointing to the stream's beginning */
|
||||
size_t total_size; /* size of the resulting substream */
|
||||
} fsb_interleave_io_data;
|
||||
|
||||
|
||||
|
||||
/* Reads skipping other streams */
|
||||
static size_t fsb_interleave_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, fsb_interleave_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
/* ignore bad reads */
|
||||
if (offset < 0 || offset > data->total_size) {
|
||||
return total_read;
|
||||
}
|
||||
|
||||
/* previous offset: re-start as we can't map logical<>physical offsets
|
||||
* (kinda slow as it trashes buffers, but shouldn't happen often) */
|
||||
if (offset < data->logical_offset) {
|
||||
data->physical_offset = data->start_offset;
|
||||
data->logical_offset = 0x00;
|
||||
data->skip_frames = data->stream_number;
|
||||
}
|
||||
|
||||
/* read doing one frame at a time */
|
||||
while (length > 0) {
|
||||
size_t to_read, bytes_read;
|
||||
off_t intrablock_offset, intradata_offset;
|
||||
uint32_t data_size;
|
||||
|
||||
if (offset >= data->total_size)
|
||||
break;
|
||||
|
||||
/* get current data */
|
||||
switch (data->codec) {
|
||||
case FSB_INT_CELT:
|
||||
data_size = 0x04+0x04+read_32bitLE(data->physical_offset+0x04,streamfile);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* skip frames from other streams */
|
||||
if (data->skip_frames) {
|
||||
data->physical_offset += data_size;
|
||||
data->skip_frames--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* requested offset is outside current block, try next */
|
||||
if (offset >= data->logical_offset + data_size) {
|
||||
data->physical_offset += data_size;
|
||||
data->logical_offset += data_size;
|
||||
data->skip_frames = data->stream_count - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* reads could fall in the middle of the block */
|
||||
intradata_offset = offset - data->logical_offset;
|
||||
intrablock_offset = intradata_offset;
|
||||
|
||||
/* clamp reads up to this block's end */
|
||||
to_read = (data_size - intradata_offset);
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
if (to_read == 0)
|
||||
break; /* should never happen... */
|
||||
|
||||
/* finally read and move buffer/offsets */
|
||||
bytes_read = read_streamfile(dest, data->physical_offset + intrablock_offset, to_read, streamfile);
|
||||
total_read += bytes_read;
|
||||
if (bytes_read != to_read)
|
||||
break; /* couldn't read fully */
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
|
||||
/* block fully read, go next */
|
||||
if (intradata_offset + bytes_read == data_size) {
|
||||
data->physical_offset += data_size;
|
||||
data->logical_offset += data_size;
|
||||
data->skip_frames = data->stream_count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t fsb_interleave_io_size(STREAMFILE *streamfile, fsb_interleave_io_data* data) {
|
||||
off_t physical_offset, max_physical_offset;
|
||||
size_t total_size = 0;
|
||||
int skip_frames = 0;
|
||||
|
||||
if (data->total_size)
|
||||
return data->total_size;
|
||||
|
||||
physical_offset = data->start_offset;
|
||||
max_physical_offset = physical_offset + data->stream_size;
|
||||
skip_frames = data->stream_number;
|
||||
|
||||
/* get size of the underlying stream, skipping other streams
|
||||
* (all streams should have the same frame count) */
|
||||
while (physical_offset < max_physical_offset) {
|
||||
size_t data_size;
|
||||
uint32_t id;
|
||||
|
||||
switch(data->codec) {
|
||||
case FSB_INT_CELT:
|
||||
id = read_32bitBE(physical_offset+0x00,streamfile);
|
||||
if (id != 0x17C30DF3) /* incorrect FSB CELT frame sync */
|
||||
data_size = 0;
|
||||
else
|
||||
data_size = 0x04+0x04+read_32bitLE(physical_offset+0x04,streamfile);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* there may be padding at the end, so this doubles as EOF marker */
|
||||
if (data_size == 0)
|
||||
break;
|
||||
|
||||
/* skip frames from other streams */
|
||||
if (skip_frames) {
|
||||
physical_offset += data_size;
|
||||
skip_frames--;
|
||||
continue;
|
||||
}
|
||||
|
||||
physical_offset += data_size;
|
||||
total_size += data_size;
|
||||
skip_frames = data->stream_count - 1;
|
||||
}
|
||||
|
||||
data->total_size = total_size;
|
||||
return data->total_size;
|
||||
}
|
||||
|
||||
|
||||
/* Prepares custom IO for multistreams, interleaves 1 packet per stream */
|
||||
static STREAMFILE* setup_fsb_interleave_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t stream_size, int stream_count, int stream_number, fsb_interleave_codec_t codec) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
fsb_interleave_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(fsb_interleave_io_data);
|
||||
|
||||
io_data.start_offset = start_offset;
|
||||
io_data.physical_offset = start_offset;
|
||||
io_data.skip_frames = stream_number; /* adjust since start_offset points to the first */
|
||||
io_data.codec = codec;
|
||||
io_data.stream_count = stream_count;
|
||||
io_data.stream_number = stream_number;
|
||||
io_data.stream_size = stream_size;
|
||||
io_data.total_size = fsb_interleave_io_size(streamFile, &io_data); /* force init */
|
||||
|
||||
if (io_data.total_size == 0 || io_data.total_size > io_data.stream_size) {
|
||||
VGM_LOG("FSB INTERLEAVE: wrong total_size %x vs %x\n", io_data.total_size,io_data.stream_size);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, fsb_interleave_io_read,fsb_interleave_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_buffer_streamfile(new_streamFile,0);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _FSB_INTERLEAVE_STREAMFILE_H_ */
|
||||
|
@ -1,101 +1,101 @@
|
||||
#ifndef _PPST_STREAMFILE_H_
|
||||
#define _PPST_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
off_t start_physical_offset; /* interleaved data start, for this substream */
|
||||
size_t interleave_block_size; /* max size that can be read before encountering other substreams */
|
||||
size_t stride_size; /* step size between interleave blocks (interleave*channels) */
|
||||
size_t stream_size; /* final size of the deinterleaved substream */
|
||||
} ppst_io_data;
|
||||
|
||||
|
||||
/* Handles deinterleaving of complete files, skipping portions or other substreams. */
|
||||
static size_t ppst_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, ppst_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
|
||||
while (length > 0) {
|
||||
size_t to_read;
|
||||
size_t length_available;
|
||||
off_t block_num;
|
||||
off_t intrablock_offset;
|
||||
off_t physical_offset;
|
||||
|
||||
if (offset >= data->stream_size)
|
||||
return total_read;
|
||||
|
||||
block_num = offset / data->interleave_block_size;
|
||||
intrablock_offset = offset % data->interleave_block_size;
|
||||
physical_offset = data->start_physical_offset + block_num*data->stride_size + intrablock_offset;
|
||||
length_available = data->interleave_block_size - intrablock_offset;
|
||||
if (length_available > data->stream_size - offset)
|
||||
length_available = data->stream_size - offset;
|
||||
|
||||
if (length < length_available) {
|
||||
to_read = length;
|
||||
}
|
||||
else {
|
||||
to_read = length_available;
|
||||
}
|
||||
|
||||
if (to_read > 0) {
|
||||
size_t bytes_read;
|
||||
|
||||
bytes_read = read_streamfile(dest, physical_offset, to_read, streamfile);
|
||||
total_read += bytes_read;
|
||||
|
||||
if (bytes_read != to_read) {
|
||||
return total_read;
|
||||
}
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t ppst_io_size(STREAMFILE *streamfile, ppst_io_data* data) {
|
||||
return data->stream_size;
|
||||
}
|
||||
|
||||
|
||||
static STREAMFILE* setup_ppst_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t interleave_block_size, size_t stride_size, size_t stream_size) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
ppst_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(ppst_io_data);
|
||||
|
||||
io_data.start_physical_offset = start_offset;
|
||||
io_data.interleave_block_size = interleave_block_size;
|
||||
io_data.stride_size = stride_size;
|
||||
io_data.stream_size = stream_size;
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, ppst_io_read,ppst_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_buffer_streamfile(new_streamFile,0);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"at3");
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _SCD_STREAMFILE_H_ */
|
||||
#ifndef _PPST_STREAMFILE_H_
|
||||
#define _PPST_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
off_t start_physical_offset; /* interleaved data start, for this substream */
|
||||
size_t interleave_block_size; /* max size that can be read before encountering other substreams */
|
||||
size_t stride_size; /* step size between interleave blocks (interleave*channels) */
|
||||
size_t stream_size; /* final size of the deinterleaved substream */
|
||||
} ppst_io_data;
|
||||
|
||||
|
||||
/* Handles deinterleaving of complete files, skipping portions or other substreams. */
|
||||
static size_t ppst_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, ppst_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
|
||||
while (length > 0) {
|
||||
size_t to_read;
|
||||
size_t length_available;
|
||||
off_t block_num;
|
||||
off_t intrablock_offset;
|
||||
off_t physical_offset;
|
||||
|
||||
if (offset >= data->stream_size)
|
||||
return total_read;
|
||||
|
||||
block_num = offset / data->interleave_block_size;
|
||||
intrablock_offset = offset % data->interleave_block_size;
|
||||
physical_offset = data->start_physical_offset + block_num*data->stride_size + intrablock_offset;
|
||||
length_available = data->interleave_block_size - intrablock_offset;
|
||||
if (length_available > data->stream_size - offset)
|
||||
length_available = data->stream_size - offset;
|
||||
|
||||
if (length < length_available) {
|
||||
to_read = length;
|
||||
}
|
||||
else {
|
||||
to_read = length_available;
|
||||
}
|
||||
|
||||
if (to_read > 0) {
|
||||
size_t bytes_read;
|
||||
|
||||
bytes_read = read_streamfile(dest, physical_offset, to_read, streamfile);
|
||||
total_read += bytes_read;
|
||||
|
||||
if (bytes_read != to_read) {
|
||||
return total_read;
|
||||
}
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t ppst_io_size(STREAMFILE *streamfile, ppst_io_data* data) {
|
||||
return data->stream_size;
|
||||
}
|
||||
|
||||
|
||||
static STREAMFILE* setup_ppst_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t interleave_block_size, size_t stride_size, size_t stream_size) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
ppst_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(ppst_io_data);
|
||||
|
||||
io_data.start_physical_offset = start_offset;
|
||||
io_data.interleave_block_size = interleave_block_size;
|
||||
io_data.stride_size = stride_size;
|
||||
io_data.stream_size = stream_size;
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, ppst_io_read,ppst_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_buffer_streamfile(new_streamFile,0);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"at3");
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _SCD_STREAMFILE_H_ */
|
||||
|
@ -30,7 +30,7 @@ VGMSTREAM* init_vgmstream_rstm_rockstar(STREAMFILE* sf) {
|
||||
//loop_flag = (read_s32le(0x24,sf) > 0);
|
||||
loop_flag = loop_end != stream_size;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
|
@ -1,163 +1,163 @@
|
||||
#ifndef _XVAG_STREAMFILE_H_
|
||||
#define _XVAG_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* config */
|
||||
int stream_number;
|
||||
int stream_count;
|
||||
size_t interleave_size;
|
||||
size_t frame_size;
|
||||
off_t stream_offset;
|
||||
//size_t stream_size;
|
||||
|
||||
/* state */
|
||||
off_t logical_offset; /* offset that corresponds to physical_offset */
|
||||
off_t physical_offset; /* actual file offset */
|
||||
|
||||
size_t skip_size; /* size to skip from a block start to reach data start */
|
||||
size_t data_size; /* logical size of the block */
|
||||
|
||||
size_t logical_size;
|
||||
} xvag_io_data;
|
||||
|
||||
|
||||
static size_t xvag_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, xvag_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
/* ignore bad reads */
|
||||
if (offset < 0 || offset > data->logical_size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* previous offset: re-start as we can't map logical<>physical offsets
|
||||
* (kinda slow as it trashes buffers, but shouldn't happen often) */
|
||||
if (offset < data->logical_offset) {
|
||||
data->logical_offset = 0x00;
|
||||
data->physical_offset = data->stream_offset;
|
||||
data->data_size = 0;
|
||||
}
|
||||
|
||||
/* read blocks, one at a time */
|
||||
while (length > 0) {
|
||||
|
||||
/* ignore EOF */
|
||||
if (data->logical_offset >= data->logical_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* process new block */
|
||||
if (data->data_size == 0) {
|
||||
data->skip_size = data->interleave_size * data->stream_number;
|
||||
data->data_size = data->interleave_size;
|
||||
|
||||
/* some ATRAC9 XVAG have padding+RIFF at start [The Last of Us (PS4), Farpoint (PS4)] */
|
||||
if (data->logical_offset == 0 && read_32bitBE(data->physical_offset+data->skip_size,streamfile) == 0) {
|
||||
data->skip_size += data->frame_size;
|
||||
data->data_size -= data->frame_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* move to next block */
|
||||
if (offset >= data->logical_offset + data->data_size) {
|
||||
data->physical_offset += data->interleave_size*data->stream_count;
|
||||
data->logical_offset += data->data_size;
|
||||
data->data_size = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read data */
|
||||
{
|
||||
size_t bytes_consumed, bytes_done, to_read;
|
||||
|
||||
bytes_consumed = offset - data->logical_offset;
|
||||
|
||||
to_read = data->data_size - bytes_consumed;
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
|
||||
|
||||
offset += bytes_done;
|
||||
total_read += bytes_done;
|
||||
length -= bytes_done;
|
||||
dest += bytes_done;
|
||||
|
||||
if (bytes_done != to_read || bytes_done == 0) {
|
||||
break; /* error/EOF */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t xvag_io_size(STREAMFILE *streamfile, xvag_io_data* data) {
|
||||
off_t physical_offset = data->stream_offset;
|
||||
off_t max_physical_offset = get_streamfile_size(streamfile);
|
||||
size_t logical_size = 0;
|
||||
|
||||
if (data->logical_size)
|
||||
return data->logical_size;
|
||||
|
||||
/* get size of the logical stream */
|
||||
while (physical_offset < max_physical_offset) {
|
||||
size_t skip_size = data->interleave_size * data->stream_number;
|
||||
size_t data_size = data->interleave_size;
|
||||
|
||||
/* some ATRAC9 XVAG have padding+RIFF at start [The Last of Us (PS4), Farpoint (PS4)] */
|
||||
if (logical_size == 0 && read_32bitBE(physical_offset+skip_size,streamfile) == 0) {
|
||||
skip_size += data->frame_size;
|
||||
data_size -= data->frame_size;
|
||||
}
|
||||
|
||||
logical_size += data_size;
|
||||
physical_offset += data->interleave_size*data->stream_count;
|
||||
}
|
||||
|
||||
if (logical_size > max_physical_offset)
|
||||
return 0;
|
||||
data->logical_size = logical_size;
|
||||
return data->logical_size;
|
||||
}
|
||||
|
||||
/* Prepares custom IO for XVAG, which interleaves many superframes per subsong/layer.
|
||||
* May have start padding, even with only one subsong. All layers share config_data too. */
|
||||
static STREAMFILE* setup_xvag_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t interleave_size, size_t frame_size, int stream_number, int stream_count) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
xvag_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(xvag_io_data);
|
||||
|
||||
io_data.stream_number = stream_number;
|
||||
io_data.stream_count = stream_count;
|
||||
io_data.stream_offset = stream_offset;
|
||||
//io_data.stream_size = stream_size;
|
||||
io_data.interleave_size = interleave_size;
|
||||
io_data.frame_size = frame_size;
|
||||
io_data.physical_offset = stream_offset;
|
||||
io_data.logical_size = xvag_io_size(streamFile, &io_data); /* force init */
|
||||
|
||||
if (io_data.logical_size == 0) {
|
||||
VGM_LOG("XVAG: wrong logical size\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, xvag_io_read,xvag_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _XVAG_STREAMFILE_H_ */
|
||||
#ifndef _XVAG_STREAMFILE_H_
|
||||
#define _XVAG_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* config */
|
||||
int stream_number;
|
||||
int stream_count;
|
||||
size_t interleave_size;
|
||||
size_t frame_size;
|
||||
off_t stream_offset;
|
||||
//size_t stream_size;
|
||||
|
||||
/* state */
|
||||
off_t logical_offset; /* offset that corresponds to physical_offset */
|
||||
off_t physical_offset; /* actual file offset */
|
||||
|
||||
size_t skip_size; /* size to skip from a block start to reach data start */
|
||||
size_t data_size; /* logical size of the block */
|
||||
|
||||
size_t logical_size;
|
||||
} xvag_io_data;
|
||||
|
||||
|
||||
static size_t xvag_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, xvag_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
/* ignore bad reads */
|
||||
if (offset < 0 || offset > data->logical_size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* previous offset: re-start as we can't map logical<>physical offsets
|
||||
* (kinda slow as it trashes buffers, but shouldn't happen often) */
|
||||
if (offset < data->logical_offset) {
|
||||
data->logical_offset = 0x00;
|
||||
data->physical_offset = data->stream_offset;
|
||||
data->data_size = 0;
|
||||
}
|
||||
|
||||
/* read blocks, one at a time */
|
||||
while (length > 0) {
|
||||
|
||||
/* ignore EOF */
|
||||
if (data->logical_offset >= data->logical_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* process new block */
|
||||
if (data->data_size == 0) {
|
||||
data->skip_size = data->interleave_size * data->stream_number;
|
||||
data->data_size = data->interleave_size;
|
||||
|
||||
/* some ATRAC9 XVAG have padding+RIFF at start [The Last of Us (PS4), Farpoint (PS4)] */
|
||||
if (data->logical_offset == 0 && read_32bitBE(data->physical_offset+data->skip_size,streamfile) == 0) {
|
||||
data->skip_size += data->frame_size;
|
||||
data->data_size -= data->frame_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* move to next block */
|
||||
if (offset >= data->logical_offset + data->data_size) {
|
||||
data->physical_offset += data->interleave_size*data->stream_count;
|
||||
data->logical_offset += data->data_size;
|
||||
data->data_size = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read data */
|
||||
{
|
||||
size_t bytes_consumed, bytes_done, to_read;
|
||||
|
||||
bytes_consumed = offset - data->logical_offset;
|
||||
|
||||
to_read = data->data_size - bytes_consumed;
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
|
||||
|
||||
offset += bytes_done;
|
||||
total_read += bytes_done;
|
||||
length -= bytes_done;
|
||||
dest += bytes_done;
|
||||
|
||||
if (bytes_done != to_read || bytes_done == 0) {
|
||||
break; /* error/EOF */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t xvag_io_size(STREAMFILE *streamfile, xvag_io_data* data) {
|
||||
off_t physical_offset = data->stream_offset;
|
||||
off_t max_physical_offset = get_streamfile_size(streamfile);
|
||||
size_t logical_size = 0;
|
||||
|
||||
if (data->logical_size)
|
||||
return data->logical_size;
|
||||
|
||||
/* get size of the logical stream */
|
||||
while (physical_offset < max_physical_offset) {
|
||||
size_t skip_size = data->interleave_size * data->stream_number;
|
||||
size_t data_size = data->interleave_size;
|
||||
|
||||
/* some ATRAC9 XVAG have padding+RIFF at start [The Last of Us (PS4), Farpoint (PS4)] */
|
||||
if (logical_size == 0 && read_32bitBE(physical_offset+skip_size,streamfile) == 0) {
|
||||
skip_size += data->frame_size;
|
||||
data_size -= data->frame_size;
|
||||
}
|
||||
|
||||
logical_size += data_size;
|
||||
physical_offset += data->interleave_size*data->stream_count;
|
||||
}
|
||||
|
||||
if (logical_size > max_physical_offset)
|
||||
return 0;
|
||||
data->logical_size = logical_size;
|
||||
return data->logical_size;
|
||||
}
|
||||
|
||||
/* Prepares custom IO for XVAG, which interleaves many superframes per subsong/layer.
|
||||
* May have start padding, even with only one subsong. All layers share config_data too. */
|
||||
static STREAMFILE* setup_xvag_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t interleave_size, size_t frame_size, int stream_number, int stream_count) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
xvag_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(xvag_io_data);
|
||||
|
||||
io_data.stream_number = stream_number;
|
||||
io_data.stream_count = stream_count;
|
||||
io_data.stream_offset = stream_offset;
|
||||
//io_data.stream_size = stream_size;
|
||||
io_data.interleave_size = interleave_size;
|
||||
io_data.frame_size = frame_size;
|
||||
io_data.physical_offset = stream_offset;
|
||||
io_data.logical_size = xvag_io_size(streamFile, &io_data); /* force init */
|
||||
|
||||
if (io_data.logical_size == 0) {
|
||||
VGM_LOG("XVAG: wrong logical size\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, xvag_io_read,xvag_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _XVAG_STREAMFILE_H_ */
|
||||
|
@ -1,58 +1,58 @@
|
||||
#ifndef _ZSND_STREAMFILE_H_
|
||||
#define _ZSND_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
typedef struct {
|
||||
off_t max_offset;
|
||||
} zsnd_io_data;
|
||||
|
||||
static size_t zsnd_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, zsnd_io_data* data) {
|
||||
size_t bytes_read, bytes_to_do;
|
||||
int i;
|
||||
|
||||
/* clamp reads */
|
||||
bytes_to_do = length;
|
||||
if (offset > data->max_offset)
|
||||
offset = data->max_offset;
|
||||
if (offset + length > data->max_offset)
|
||||
bytes_to_do = data->max_offset - offset;
|
||||
|
||||
bytes_read = streamfile->read(streamfile, dest, offset, bytes_to_do);
|
||||
|
||||
/* pretend we got data after max_offset */
|
||||
if (bytes_read < length) {
|
||||
for (i = bytes_read; i < length; i++) {
|
||||
dest[i] = 0;
|
||||
}
|
||||
bytes_read = length;
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
/* ZSND removes last interleave data from the file if blank, but codecs still need to read after it.
|
||||
* This data could be from next stream or from EOF, so return blank data instead. */
|
||||
static STREAMFILE* setup_zsnd_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t stream_size) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
zsnd_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(zsnd_io_data);
|
||||
|
||||
io_data.max_offset = start_offset + stream_size;
|
||||
|
||||
/* setup custom streamfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, zsnd_io_read,NULL);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _ZSND_STREAMFILE_H_ */
|
||||
#ifndef _ZSND_STREAMFILE_H_
|
||||
#define _ZSND_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
typedef struct {
|
||||
off_t max_offset;
|
||||
} zsnd_io_data;
|
||||
|
||||
static size_t zsnd_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, zsnd_io_data* data) {
|
||||
size_t bytes_read, bytes_to_do;
|
||||
int i;
|
||||
|
||||
/* clamp reads */
|
||||
bytes_to_do = length;
|
||||
if (offset > data->max_offset)
|
||||
offset = data->max_offset;
|
||||
if (offset + length > data->max_offset)
|
||||
bytes_to_do = data->max_offset - offset;
|
||||
|
||||
bytes_read = streamfile->read(streamfile, dest, offset, bytes_to_do);
|
||||
|
||||
/* pretend we got data after max_offset */
|
||||
if (bytes_read < length) {
|
||||
for (i = bytes_read; i < length; i++) {
|
||||
dest[i] = 0;
|
||||
}
|
||||
bytes_read = length;
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
/* ZSND removes last interleave data from the file if blank, but codecs still need to read after it.
|
||||
* This data could be from next stream or from EOF, so return blank data instead. */
|
||||
static STREAMFILE* setup_zsnd_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t stream_size) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
zsnd_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(zsnd_io_data);
|
||||
|
||||
io_data.max_offset = start_offset + stream_size;
|
||||
|
||||
/* setup custom streamfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, zsnd_io_read,NULL);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _ZSND_STREAMFILE_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user