Add AWC MP3 [Red Dead Redemption (PS3), GTA5 (PS3)]

This commit is contained in:
bnnm 2017-08-28 15:14:24 +02:00
parent c4a6e6e194
commit 953022b983
15 changed files with 445 additions and 12 deletions

View File

@ -49,6 +49,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("AST", ast);
VGMSTREAM_DECLARE_FILE_TYPE("ATRAC3plus", at3);
VGMSTREAM_DECLARE_FILE_TYPE("AUD", aud);
VGMSTREAM_DECLARE_FILE_TYPE("AUS", aus);
VGMSTREAM_DECLARE_FILE_TYPE("AWC", awc);
VGMSTREAM_DECLARE_FILE_TYPE("B1S", b1s);
VGMSTREAM_DECLARE_FILE_TYPE("BAF", baf);

View File

@ -63,7 +63,7 @@ supports Winamp plugins you may also use in_vgmstream.dll instead.
Because the XMPlay MP3 decoder incorrectly tries to play some vgmstream exts,
you need to manually fix it by going to options > plugins > input > vgmstream
and in the "priority filetypes" put: ckd,fsb,genh,msf,p3d,rak,scd,xvag
and in the "priority filetypes" put: awc,ckd,fsb,genh,msf,p3d,rak,scd,xvag
--- foo_input_vgmstream ---
Every should be installed automatically by the .fb2k-component bundle.

View File

@ -54,7 +54,6 @@ int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, m
break;
case MPEG_LYN:
case MPEG_AWC:
goto fail; /* not fully implemented */
case MPEG_STANDARD:

View File

@ -0,0 +1,138 @@
#include "mpeg_decoder.h"
#ifdef VGM_USE_MPEG
/**
* AWC music uses blocks (sfx doesn't), the fun part being each channel has different num_samples/frames
* per block, so it's unsuitable for the normal "blocked" layout and parsed here instead.
* Channel data is separate within the block (first all frames of ch0, then ch1, etc), padded, and sometimes
* the last few frames of a channel are repeated in the new block (marked with the "discard samples" field).
*/
static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, mpeg_codec_data *data) {
size_t header_size = 0;
int i;
int entries = data->config.channels;
int32_t (*read_32bit)(off_t,STREAMFILE*) = data->config.big_endian ? read_32bitBE : read_32bitLE;
for (i = 0; i < entries; i++) {
header_size += 0x18;
header_size += read_32bit(offset + 0x18*i + 0x04, streamFile) * 0x04; /* entries in the table */
}
if (header_size % 0x800) /* padded */
header_size += 0x800 - (header_size % 0x800);
return header_size;
}
/* init config and validate */
int mpeg_custom_setup_init_awc(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type) {
mpeg_frame_info info;
int is_music;
/* start_offset can point to a block header that always starts with 0 (music) or normal data (sfx) */
is_music = read_32bitBE(start_offset, streamFile) == 0x00000000;
if (is_music)
start_offset += get_block_header_size(streamFile, start_offset, data);
/* get frame info at offset */
if ( !mpeg_get_frame_info(streamFile, start_offset, &info))
goto fail;
switch(info.layer) {
case 1: *coding_type = coding_MPEG_layer1; break;
case 2: *coding_type = coding_MPEG_layer2; break;
case 3: *coding_type = coding_MPEG_layer3; break;
default: goto fail;
}
data->channels_per_frame = info.channels;
data->samples_per_frame = info.frame_samples;
/* extra checks */
if (is_music) {
if (data->config.chunk_size <= 0)
goto fail; /* needs block size */
}
/* no big encoder delay added (for sfx they can start in less than ~300 samples) */
return 1;
fail:
return 0;
}
/* writes data to the buffer and moves offsets, parsing AWC blocks */
int mpeg_custom_parse_frame_awc(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream) {
mpeg_custom_stream *ms = data->streams[num_stream];
mpeg_frame_info info;
size_t current_data_size = 0, data_offset;
size_t file_size = get_streamfile_size(stream->streamfile);
int i;
/* blocked layout used for music */
if (data->config.chunk_size) {
/* block ended for this channel, move to next block start */
if (ms->current_size_count > 0 && ms->current_size_count == ms->current_size_target) {
//mpg123_open_feed(ms->m); //todo reset maybe needed?
data_offset = stream->offset - stream->channel_start_offset; /* ignoring header */
data_offset -= data_offset % data->config.chunk_size; /* start of current block */
stream->offset = stream->channel_start_offset + data_offset + data->config.chunk_size;
ms->current_size_count = 0;
ms->current_size_target = 0;
}
/* just in case, shouldn't happen */
if (stream->offset >= file_size) {
goto fail;
}
/* block starts for this channel, point to mpeg data */
if (ms->current_size_count == 0) {
int32_t (*read_32bit)(off_t,STREAMFILE*) = data->config.big_endian ? read_32bitBE : read_32bitLE;
off_t channel_offset = 0;
/* block has a header with base info per channel and table per channel (see blocked_awc.c) */
ms->decode_to_discard = read_32bit(stream->offset + 0x18*num_stream + 0x08, stream->streamfile);
ms->current_size_target = read_32bit(stream->offset + 0x18*num_stream + 0x14, stream->streamfile);
for (i = 0; i < num_stream; i++) { /* num_stream serves as channel */
size_t channel_size = read_32bit(stream->offset + 0x18*i + 0x14, stream->streamfile);
if (channel_size % 0x10) /* 32b aligned */
channel_size += 0x10 - channel_size % 0x10;
channel_offset += channel_size;
}
//VGM_ASSERT(ms->decode_to_discard > 0, "AWC: s%i discard of %x found at chunk %lx\n", num_stream, ms->decode_to_discard, stream->offset);
//;VGM_LOG("AWC: s%i off=%lx to %lx\n", num_stream, stream->offset, stream->offset + channel_offset + get_block_header_size(stream->streamfile, stream->offset, data));
stream->offset += channel_offset + get_block_header_size(stream->streamfile, stream->offset, data);
}
}
/* update frame */
if ( !mpeg_get_frame_info(stream->streamfile, stream->offset, &info) )
goto fail;
current_data_size = info.frame_size;
data->bytes_in_buffer = read_streamfile(data->buffer,stream->offset, current_data_size, stream->streamfile);
stream->offset += current_data_size;
ms->current_size_count += current_data_size;
return 1;
fail:
return 0;
}
#endif

View File

@ -579,7 +579,7 @@ static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
if (decode_to_discard == 576)
decode_to_discard = data->samples_per_frame;//+ eaf->v1_pcm_number;
data->decode_to_discard += decode_to_discard;
ms->decode_to_discard += decode_to_discard;
}
}

View File

@ -140,6 +140,7 @@ mpeg_codec_data *init_mpeg_custom_codec_data(STREAMFILE *streamFile, off_t start
case MPEG_EAL31:
case MPEG_EAL32P:
case MPEG_EAL32S: ok = mpeg_custom_setup_init_ealayer3(streamFile, start_offset, data, coding_type); break;
case MPEG_AWC: ok = mpeg_custom_setup_init_awc(streamFile, start_offset, data, coding_type); break;
default: ok = mpeg_custom_setup_init_default(streamFile, start_offset, data, coding_type); break;
}
if (!ok)
@ -393,6 +394,7 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data
case MPEG_EAL32P:
case MPEG_EAL32S: ok = mpeg_custom_parse_frame_ealayer3(stream, data, num_stream); break;
case MPEG_AHX: ok = mpeg_custom_parse_frame_ahx(stream, data); break;
case MPEG_AWC: ok = mpeg_custom_parse_frame_awc(stream, data, num_stream); break;
default: ok = mpeg_custom_parse_frame_default(stream, data); break;
}
if (!ok) {
@ -440,16 +442,16 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data
}
samples_filled = (bytes_done / sizeof(sample) / data->channels_per_frame);
/* for EALayer3, that discards decoded samples and writes PCM blocks instead */
if (data->decode_to_discard) {
/* discard for weird features (EALayer3 and PCM blocks, AWC and repeated frames) */
if (ms->decode_to_discard) {
size_t bytes_to_discard = 0;
size_t decode_to_discard = data->decode_to_discard;
size_t decode_to_discard = ms->decode_to_discard;
if (decode_to_discard > samples_filled)
decode_to_discard = samples_filled;
bytes_to_discard = sizeof(sample)*decode_to_discard*data->channels_per_frame;
bytes_done -= bytes_to_discard;
data->decode_to_discard -= decode_to_discard;
ms->decode_to_discard -= decode_to_discard;
ms->samples_used += decode_to_discard;
}
@ -522,10 +524,10 @@ void reset_mpeg(VGMSTREAM *vgmstream) {
mpg123_feedseek(data->streams[i]->m,0,SEEK_SET,&input_offset);
data->streams[i]->samples_filled = 0;
data->streams[i]->samples_used = 0;
data->streams[i]->decode_to_discard = 0;
}
data->samples_to_discard = data->skip_samples; /* initial delay */
data->decode_to_discard = 0;
}
}
@ -546,6 +548,7 @@ void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
mpg123_feedseek(data->streams[i]->m,0,SEEK_SET,&input_offset);
data->streams[i]->samples_filled = 0;
data->streams[i]->samples_used = 0;
data->streams[i]->decode_to_discard = 0;
if (vgmstream->loop_ch)
vgmstream->loop_ch[i].offset = vgmstream->loop_ch[i].channel_start_offset;
@ -558,7 +561,6 @@ void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
data->buffer_full = 0;
data->buffer_used = 0;
data->decode_to_discard = 0;
}
/* resets mpg123 decoder and its internals (with mpg123_open_feed as mpg123_feedseek won't work) */
@ -577,10 +579,10 @@ void flush_mpeg(mpeg_codec_data * data) {
mpg123_open_feed(data->streams[i]->m);
data->streams[i]->samples_filled = 0;
data->streams[i]->samples_used = 0;
data->streams[i]->decode_to_discard = 0;
}
data->samples_to_discard = data->skip_samples; /* initial delay */
data->decode_to_discard = 0;
}
data->bytes_in_buffer = 0;

View File

@ -19,10 +19,12 @@ int mpeg_get_frame_info(STREAMFILE *streamfile, off_t offset, mpeg_frame_info *
int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type);
int mpeg_custom_setup_init_ealayer3(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type);
int mpeg_custom_setup_init_awc(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type);
int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data);
int mpeg_custom_parse_frame_ahx(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data);
int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream);
int mpeg_custom_parse_frame_awc(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream);
#endif/* VGM_USE_MPEG */

View File

@ -42,6 +42,7 @@ static const char* extension_list[] = {
"at3",
"aud",
"aus",
"awc",
"b1s",
"baf",
@ -880,6 +881,7 @@ static const meta_info meta_info_list[] = {
{meta_STM, "Angel Studios/Rockstar San Diego STMA header"},
{meta_BINK, "RAD Game Tools Bink header"},
{meta_EA_SNU, "Electronic Arts SNU header"},
{meta_AWC, "Rockstar AWC header"},
#ifdef VGM_USE_VORBIS
{meta_OGG_VORBIS, "Ogg Vorbis"},

View File

@ -1398,6 +1398,10 @@
RelativePath=".\coding\mpeg_custom_utils_ahx.c"
>
</File>
<File
RelativePath=".\coding\mpeg_custom_utils_awc.c"
>
</File>
<File
RelativePath=".\coding\mpeg_custom_utils_ealayer3.c"
>

View File

@ -427,6 +427,7 @@
<ClCompile Include="coding\mc3_decoder.c" />
<ClCompile Include="coding\mpeg_custom_utils.c" />
<ClCompile Include="coding\mpeg_custom_utils_ahx.c" />
<ClCompile Include="coding\mpeg_custom_utils_awc.c" />
<ClCompile Include="coding\mpeg_custom_utils_ealayer3.c" />
<ClCompile Include="coding\mpeg_decoder.c" />
<ClCompile Include="coding\msadpcm_decoder.c" />

View File

@ -817,6 +817,9 @@
<ClCompile Include="coding\mpeg_custom_utils_ahx.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\mpeg_custom_utils_awc.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\mpeg_custom_utils_ealayer3.c">
<Filter>coding\Source Files</Filter>
</ClCompile>

272
src/meta/awc.c Normal file
View File

@ -0,0 +1,272 @@
#include "meta.h"
#include "../coding/coding.h"
typedef struct {
int big_endian;
int is_encrypted;
int is_music;
int total_streams;
int channel_count;
int sample_rate;
int codec;
int num_samples;
int block_chunk;
off_t stream_offset;
off_t stream_size;
} awc_header;
static int parse_awc_header(STREAMFILE* streamFile, awc_header* awc);
/* AWC - from RAGE (Rockstar Advanced Game Engine) audio (Red Dead Redemption, Max Payne 3, GTA5) */
VGMSTREAM * init_vgmstream_awc(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
awc_header awc;
/* check extension */
if (!check_extensions(streamFile,"awc"))
goto fail;
/* check header */
if (!parse_awc_header(streamFile, &awc))
goto fail;
if (awc.is_encrypted)
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(awc.channel_count, 0);
if (!vgmstream) goto fail;
vgmstream->sample_rate = awc.sample_rate;
vgmstream->num_samples = awc.num_samples;
vgmstream->num_streams = awc.total_streams;
vgmstream->meta_type = meta_AWC;
switch(awc.codec) {
//case 0x01: /* PCM (PC/PS3) */
// vgmstream->coding_type = coding_PCM!6;
// vgmstream->layout_type = awc.is_music ? layout_blocked_awc : layout_none;
// break;
//case 0x04: /* IMA (PC) */
// vgmstream->coding_type = coding_AWC_IMA;
// vgmstream->layout_type = awc.is_music ? layout_blocked_awc : layout_none;
// break;
#ifdef VGM_USE_MPEG
case 0x07: { /* MPEG (PS3) */
mpeg_custom_config cfg;
memset(&cfg, 0, sizeof(mpeg_custom_config));
cfg.chunk_size = awc.block_chunk;
cfg.big_endian = awc.big_endian;
vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, awc.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_AWC, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
break;
}
#endif
case 0x05: /* XMA2 (X360) */
default:
VGM_LOG("AWC: unknown codec 0x%02x\n", awc.codec);
goto fail;
}
/* open files; channel offsets are updated below */
if (!vgmstream_open_stream(vgmstream,streamFile,awc.stream_offset))
goto fail;
//if (vgmstream->layout_type == layout_blocked_awc)
// update_
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* Parse Rockstar's AWC header (much info from LibertyV: https://github.com/koolkdev/libertyv).
* Made of entries for N streams, each with a number of tags pointing to chunks (header, data, events, etc). */
static int parse_awc_header(STREAMFILE* streamFile, awc_header* awc) {
int64_t (*read_64bit)(off_t,STREAMFILE*) = NULL;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
int i, ch, entries;
uint32_t flags, info_header, tag_count = 0, tags_skip = 0;
off_t off;
int target_stream = streamFile->stream_index;
memset(awc,0,sizeof(awc_header));
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x41444154 && /* "ADAT" (LE) */
read_32bitBE(0x00,streamFile) != 0x54414441) /* "TADA" (BE) */
goto fail;
awc->big_endian = read_32bitBE(0x00,streamFile) == 0x54414441;
if (awc->big_endian) {
read_64bit = read_64bitBE;
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
} else {
read_64bit = read_64bitLE;
read_32bit = read_32bitLE;
read_16bit = read_16bitLE;
}
flags = read_32bit(0x04,streamFile);
entries = read_32bit(0x08,streamFile);
//header_size = read_32bit(0x0c,streamFile); /* after to stream id/tags, not including chunks */
off = 0x10;
if ((flags & 0xFF00FFFF) != 0xFF000001 || (flags & 0x00F00000)) {
VGM_LOG("AWC: unknown flags 0x%08x\n", flags);
goto fail;
}
if (flags & 0x00010000) /* some kind of mini offset table */
off += 0x2 * entries;
//if (flags % 0x00020000) /* seems to indicate chunks are not ordered (ie. header may go after data) */
// ...
//if (flags % 0x00040000) /* music/multichannel flag? (GTA5, not seen in RDR) */
// awc->is_music = 1;
if (flags & 0x00080000) /* encrypted data chunk (most of GTA5 PC) */
awc->is_encrypted = 1;
/* Music when the first id is 0 (base/fake entry with info for all channels), sfx pack otherwise.
* sfx = N single streams, music = N-1 interleaved mono channels (even for MP3/XMA).
* Music seems layered (N-1/2 stereo pairs), maybe set with events? */
awc->is_music = (read_32bit(off + 0x00,streamFile) & 0x1FFFFFFF) == 0x00000000;
if (awc->is_music) { /* all streams except id 0 is a channel */
awc->total_streams = 1;
target_stream = 1; /* we only need id 0, though channels may have its own tags/chunks */
}
else { /* each stream is a single sound */
awc->total_streams = entries;
if (target_stream == 0) target_stream = 1;
if (target_stream < 0 || target_stream > awc->total_streams || awc->total_streams < 1) goto fail;
}
/* get stream base info */
for (i = 0; i < entries; i++) {
info_header = read_32bit(off + 0x04*i, streamFile);
tag_count = (info_header >> 29) & 0x7; /* 3b */
//id = (info_header >> 0) & 0x1FFFFFFF; /* 29b */
if (target_stream-1 == i)
break;
tags_skip += tag_count; /* tags to skip to reach target's tags, in the next header */
}
off += 0x04*entries;
off += 0x08*tags_skip;
/* get stream tags */
for (i = 0; i < tag_count; i++) {
uint64_t tag_header, tag, size, offset;
tag_header = (uint64_t)read_64bit(off + 0x08*i,streamFile);
tag = (tag_header >> 56) & 0xFF; /* 8b */
size = (tag_header >> 28) & 0x0FFFFFFF; /* 28b */
offset = (tag_header >> 0) & 0x0FFFFFFF; /* 28b */
/* Tags are apparently part of a hash derived from a word ("data", "format", etc).
* If music + 1ch, the header and data chunks can repeat for no reason (sometimes not even pointed). */
switch(tag) {
case 0x55: /* data */
awc->stream_offset = offset;
awc->stream_size = size;
break;
case 0x48: /* music header */
if (!awc->is_music) {
VGM_LOG("AWC: music header found in sfx\n");
goto fail;
}
/* 0x00(32): unknown (some count?) */
awc->block_chunk = read_32bit(offset + 0x04,streamFile);
awc->channel_count = read_32bit(offset + 0x08,streamFile);
if (awc->channel_count != entries - 1) { /* not counting id-0 */
VGM_LOG("AWC: number of music channels doesn't match entries\n");
goto fail;
}
for (ch = 0; ch < awc->channel_count; ch++) {
int num_samples, sample_rate, codec;
/* 0x00(32): stream id (not always in the header entries order) */
/* 0x08(16): headroom?, 0x0d(8): round size?, 0x0e(16): unknown (zero?) */
num_samples = read_32bit(offset + 0x0c + 0x10*ch + 0x04,streamFile);
sample_rate = (uint16_t)read_16bit(offset + 0x0c + 0x10*ch + 0x0a,streamFile);
codec = read_8bit(offset + 0x0c + 0x10*ch + 0x0c, streamFile);
/* validate as all channels should repeat this */
if ((awc->num_samples && awc->num_samples != num_samples) ||
(awc->sample_rate && awc->sample_rate != sample_rate) ||
(awc->codec && awc->codec != codec)) {
VGM_LOG("AWC: found header diffs between channels\n"); /* can rarely happen in stereo pairs */
goto fail;
}
awc->num_samples = num_samples;
awc->sample_rate = sample_rate;
awc->codec = codec;
}
break;
case 0xFA: /* sfx header */
if (awc->is_music) {
VGM_LOG("AWC: sfx header found in music\n");
goto fail;
}
/* 0x04(32): -1?, 0x0a(16x4): unknown x4, 0x12: null? */
awc->num_samples = read_32bit(offset + 0x00,streamFile);
awc->sample_rate = (uint16_t)read_16bit(offset + 0x08,streamFile);
awc->codec = read_8bit(offset + 0x13, streamFile);
awc->channel_count = 1;
break;
case 0xA3: /* block-to-sample table (32b x number of blocks w/ num_samples at the start of each block) */
case 0xBD: /* events (32bx4): type_hash, params_hash, timestamp_ms, flags */
default: /* 0x5C=animation/RSC?, 0x68=midi?, 0x36/0x2B/0x5A/0xD9=? */
//VGM_LOG("AWC: ignoring unknown tag 0x%02x\n", tag);
break;
}
}
if (!awc->stream_offset) {
VGM_LOG("AWC: stream offset not found\n");
goto fail;
}
/* If music, data is divided into blocks of block_chunk size with padding.
* Each block has a header/seek table and interleaved data for all channels */
if (awc->is_music && read_32bit(awc->stream_offset, streamFile) != 0) {
VGM_LOG("AWC: music found, but block doesn't start with seek table\n");
goto fail;
}
return 1;
fail:
return 0;
}

View File

@ -684,4 +684,6 @@ VGMSTREAM * init_vgmstream_stm(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_awc(STREAMFILE * streamFile);
#endif /*_META_H*/

View File

@ -367,6 +367,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_sk_aud,
init_vgmstream_stm,
init_vgmstream_ea_snu,
init_vgmstream_awc,
init_vgmstream_txth, /* should go at the end (lower priority) */
#ifdef VGM_USE_FFMPEG

View File

@ -621,6 +621,7 @@ typedef enum {
meta_STM, /* Angel Studios/Rockstar San Diego Games */
meta_BINK, /* RAD Game Tools BINK audio/video */
meta_EA_SNU, /* Electronic Arts SNU (Dead Space) */
meta_AWC, /* Rockstar AWC (GTA5, RDR) */
#ifdef VGM_USE_VORBIS
meta_OGG_VORBIS, /* Ogg Vorbis */
@ -874,7 +875,7 @@ typedef enum {
MPEG_EAL32P, /* EALayer3 v2 "P" (PCM?), custom frames with v2 header */
MPEG_EAL32S, /* EALayer3 v2 "S" (Spike?), custom frames with v2 header */
MPEG_LYN, /* N streams of fixed interleave */
MPEG_AWC /* N streams in absolute offsets (consecutive) */
MPEG_AWC /* N streams in block layout (music) or absolute offsets (sfx) */
} mpeg_custom_t;
/* config for the above modes */
@ -884,6 +885,7 @@ typedef struct {
int chunk_size; /* size of a data portion */
int interleave; /* size of stream interleave */
int encryption; /* encryption mode */
int big_endian;
/* for AHX */
int cri_type;
uint16_t cri_key1;
@ -899,6 +901,11 @@ typedef struct {
size_t output_buffer_size;
size_t samples_filled; /* data in the buffer (in samples) */
size_t samples_used; /* data extracted from the buffer */
size_t current_size_count; /* data read (if the parser needs to know) */
size_t current_size_target; /* max data, until something happens */
size_t decode_to_discard; /* discard from this stream only (for EALayer3 or AWC) */
} mpeg_custom_stream;
typedef struct {
@ -924,7 +931,6 @@ typedef struct {
size_t skip_samples; /* base encoder delay */
size_t samples_to_discard; /* for custom mpeg looping */
size_t decode_to_discard; /* for EALayer3, that discards decoded samples and writes PCM blocks in their place */
} mpeg_codec_data;
#endif