Fix EALayer3 v1b and v2

This commit is contained in:
bnnm 2017-12-01 17:32:12 +01:00
parent e2c059bc31
commit d12a5bd294
2 changed files with 207 additions and 127 deletions

View File

@ -7,11 +7,12 @@
* with regular MPEG data and optional PCM blocks. We transform EA-frames to MPEG-frames on the fly * with regular MPEG data and optional PCM blocks. We transform EA-frames to MPEG-frames on the fly
* and manually fill the sample PCM sample buffer. * and manually fill the sample PCM sample buffer.
* *
* Layer III MPEG1 uses two granules (data chunks) per frame, while MPEG2/2.5 ("LSF mode") only one. EA-frames * Layer III MPEG1 uses two granules (data chunks) per frame, while MPEG2/2.5 ("LSF mode") only one.
* contain one granule, so to reconstruct one MPEG-frame we need two EA-frames (MPEG1) or one (MPEG2). * EA-frames contain one granule, so to reconstruct one MPEG-frame we need two EA-frames (MPEG1) or
* one (MPEG2). This is only for our decoder, real EALayer3 would decode EA-frames directly.
* EALayer v1 and v2 differ in part of the header, but are mostly the same. * EALayer v1 and v2 differ in part of the header, but are mostly the same.
* *
* Reverse engineering: https://bitbucket.org/Zenchreal/ealayer3 (ealayer3.exe decoder) * Reverse engineering by Zench: https://bitbucket.org/Zenchreal/ealayer3 (ealayer3.exe decoder)
* Reference: https://www.mp3-tech.org/programmer/docs/mp3_theory.pdf * Reference: https://www.mp3-tech.org/programmer/docs/mp3_theory.pdf
* https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/mpegaudiodec_template.c#L1306 * https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/mpegaudiodec_template.c#L1306
*/ */
@ -29,7 +30,7 @@ typedef struct {
uint8_t * buf; /* buffer to read/write*/ uint8_t * buf; /* buffer to read/write*/
size_t bufsize; /* max size of the buffer */ size_t bufsize; /* max size of the buffer */
off_t b_off; /* current offset in bits inside the buffer */ off_t b_off; /* current offset in bits inside the buffer */
off_t offset; /* info only */ off_t info_offset; /* for logs */
} ealayer3_bitstream; } ealayer3_bitstream;
/* parsed info from a single EALayer3 frame */ /* parsed info from a single EALayer3 frame */
@ -38,13 +39,14 @@ typedef struct {
uint32_t v1_pcm_flag; uint32_t v1_pcm_flag;
uint32_t v1_pcm_decode_discard; uint32_t v1_pcm_decode_discard;
uint32_t v1_pcm_number; uint32_t v1_pcm_number;
uint32_t v1_pcm_unknown;
/* EALayer3 v2 header */ /* EALayer3 v2 header */
uint32_t v2_extended_flag; uint32_t v2_extended_flag;
uint32_t v2_stereo_flag; uint32_t v2_stereo_flag;
uint32_t v2_unknown; /* unused? */ uint32_t v2_unknown; /* unused? */
uint32_t v2_frame_size; /* full size including headers and pcm block */ uint32_t v2_frame_size; /* full size including headers and pcm block */
uint32_t v2_mode; /* BLOCKOFFSETMODE: IGNORE = 0x0, PRESERVE = 0x1, MUTE = 0x2, MAX = 0x3 */ uint32_t v2_mode; /* discard mode */
uint32_t v2_mode_value; /* samples to use depending on mode */ uint32_t v2_mode_value; /* samples to use depending on mode */
uint32_t v2_pcm_number; uint32_t v2_pcm_number;
uint32_t v2_common_size; /* common header+data size; can be zero */ uint32_t v2_common_size; /* common header+data size; can be zero */
@ -80,11 +82,12 @@ typedef struct {
static int ealayer3_parse_frame(mpeg_codec_data *data, ealayer3_bitstream *is, ealayer3_frame_info * eaf); static int ealayer3_parse_frame(mpeg_codec_data *data, ealayer3_bitstream *is, ealayer3_frame_info * eaf);
static int ealayer3_parse_frame_v1(ealayer3_bitstream *is, ealayer3_frame_info * eaf, int channels_per_frame); static int ealayer3_parse_frame_v1(ealayer3_bitstream *is, ealayer3_frame_info * eaf, int channels_per_frame, int is_v1b);
static int ealayer3_parse_frame_v2(ealayer3_bitstream *is, ealayer3_frame_info * eaf); static int ealayer3_parse_frame_v2(ealayer3_bitstream *is, ealayer3_frame_info * eaf);
static int ealayer3_parse_frame_common(ealayer3_bitstream *is, ealayer3_frame_info * eaf); static int ealayer3_parse_frame_common(ealayer3_bitstream *is, ealayer3_frame_info * eaf);
static int ealayer3_rebuild_mpeg_frame(ealayer3_bitstream* is_0, ealayer3_frame_info* eaf_0, ealayer3_bitstream* is_1, ealayer3_frame_info* eaf_1, ealayer3_bitstream* os); static int ealayer3_rebuild_mpeg_frame(ealayer3_bitstream* is_0, ealayer3_frame_info* eaf_0, ealayer3_bitstream* is_1, ealayer3_frame_info* eaf_1, ealayer3_bitstream* os);
static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, ealayer3_frame_info * eaf); static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, ealayer3_frame_info * eaf);
static int ealayer3_skip_data(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, int at_start, size_t last_eaframe_size);
static int r_bits(ealayer3_bitstream * iw, int num_bits, uint32_t * value); static int r_bits(ealayer3_bitstream * iw, int num_bits, uint32_t * value);
static int w_bits(ealayer3_bitstream * ow, int num_bits, uint32_t value); static int w_bits(ealayer3_bitstream * ow, int num_bits, uint32_t value);
@ -94,17 +97,13 @@ static int w_bits(ealayer3_bitstream * ow, int num_bits, uint32_t value);
/* EXTERNAL API */ /* EXTERNAL API */
/* **************************************************************************** */ /* **************************************************************************** */
/* init codec from a EALayer3 frame */ /* init codec from an EALayer3 frame */
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_ealayer3(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type) {
int ok; int ok;
ealayer3_frame_info eaf; ealayer3_frame_info eaf;
ealayer3_bitstream is; ealayer3_bitstream is = {0};
uint8_t ibuf[EALAYER3_EA_FRAME_BUFFER_SIZE]; uint8_t ibuf[EALAYER3_EA_FRAME_BUFFER_SIZE];
//;VGM_LOG("EAFRAME: EALayer3 init at %lx\n", start_offset);
if (data->type == MPEG_EAL32P || data->type == MPEG_EAL32S)
goto fail; /* untested */
/* get first frame for info */ /* get first frame for info */
{ {
@ -115,8 +114,7 @@ int mpeg_custom_setup_init_ealayer3(STREAMFILE *streamFile, off_t start_offset,
ok = ealayer3_parse_frame(data, &is, &eaf); ok = ealayer3_parse_frame(data, &is, &eaf);
if (!ok) goto fail; if (!ok) goto fail;
} }
VGM_ASSERT(!eaf.mpeg1, "MPEG EAL3: mpeg2 found at 0x%lx\n", start_offset); /* untested */
;VGM_ASSERT(!eaf.mpeg1, "MPEG EAL3: mpeg2 found at 0x%lx\n", start_offset);
*coding_type = coding_MPEG_ealayer3; *coding_type = coding_MPEG_ealayer3;
data->channels_per_frame = eaf.channels; data->channels_per_frame = eaf.channels;
@ -125,10 +123,9 @@ int mpeg_custom_setup_init_ealayer3(STREAMFILE *streamFile, off_t start_offset,
/* extra checks */ /* extra checks */
if (!data->channels_per_frame || data->config.channels != data->channels_per_frame){ if (!data->channels_per_frame || data->config.channels != data->channels_per_frame){
VGM_LOG("MPEG EAL3: unknown %i multichannel layout\n", data->config.channels); VGM_LOG("MPEG EAL3: unknown %i multichannel layout\n", data->config.channels);
goto fail; /* unknown layout */ goto fail; /* to be fixed */
} }
/* encoder delay: EALayer3 handles this while decoding (skips samples as writes PCM blocks) */ /* encoder delay: EALayer3 handles this while decoding (skips samples as writes PCM blocks) */
return 1; return 1;
@ -138,15 +135,19 @@ fail:
/* writes data to the buffer and moves offsets, transforming EALayer3 frames */ /* writes data to the buffer and moves offsets, transforming EALayer3 frames */
int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream) { int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream) {
int ok; int ok, granule_found;
off_t current_offset = stream->offset; off_t info_offset = stream->offset;
ealayer3_frame_info eaf_0, eaf_1; ealayer3_frame_info eaf_0, eaf_1;
ealayer3_bitstream is_0, is_1, os; ealayer3_bitstream is_0 = {0}, is_1 = {0}, os = {0};
uint8_t ibuf_0[EALAYER3_EA_FRAME_BUFFER_SIZE], ibuf_1[EALAYER3_EA_FRAME_BUFFER_SIZE]; uint8_t ibuf_0[EALAYER3_EA_FRAME_BUFFER_SIZE], ibuf_1[EALAYER3_EA_FRAME_BUFFER_SIZE];
/* read first frame/granule */
{ /* read first frame/granule, or PCM-only frame (found alone at the end of SCHl streams) */
{
if (!ealayer3_skip_data(stream, data, num_stream, 1, 0))
goto fail;
is_0.buf = ibuf_0; is_0.buf = ibuf_0;
is_0.bufsize = read_streamfile(ibuf_0,stream->offset,EALAYER3_EA_FRAME_BUFFER_SIZE, stream->streamfile); /* reads less at EOF */ is_0.bufsize = read_streamfile(ibuf_0,stream->offset,EALAYER3_EA_FRAME_BUFFER_SIZE, stream->streamfile); /* reads less at EOF */
is_0.b_off = 0; is_0.b_off = 0;
@ -158,35 +159,35 @@ int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *
if (!ok) goto fail; if (!ok) goto fail;
stream->offset += eaf_0.eaframe_size; stream->offset += eaf_0.eaframe_size;
}
/* get second frame/granule */ if (!ealayer3_skip_data(stream, data, num_stream, 0, eaf_0.eaframe_size))
if (eaf_0.mpeg1) { goto fail;
int granule1_found; }
do {
is_1.buf = ibuf_1;
is_1.bufsize = read_streamfile(ibuf_1,stream->offset,EALAYER3_EA_FRAME_BUFFER_SIZE, stream->streamfile); /* reads less at EOF */
is_1.b_off = 0;
ok = ealayer3_parse_frame(data, &is_1, &eaf_1); /* get second frame/granule (MPEG1 only) if first granule was found */
if (!ok) goto fail; granule_found = 0;
while (eaf_0.common_size && eaf_0.mpeg1 && !granule_found) {
if (!ealayer3_skip_data(stream, data, num_stream, 1, 0))
goto fail;
ok = ealayer3_write_pcm_block(stream, data, num_stream, &eaf_1); is_1.buf = ibuf_1;
if (!ok) goto fail; is_1.bufsize = read_streamfile(ibuf_1,stream->offset,EALAYER3_EA_FRAME_BUFFER_SIZE, stream->streamfile); /* reads less at EOF */
is_1.b_off = 0;
stream->offset += eaf_1.eaframe_size; ok = ealayer3_parse_frame(data, &is_1, &eaf_1);
if (!ok) goto fail;
ok = ealayer3_write_pcm_block(stream, data, num_stream, &eaf_1);
if (!ok) goto fail;
/* in V1 sometimes there is a PCM block between two granules, try next */ stream->offset += eaf_1.eaframe_size;
if (eaf_1.v1_pcm_flag == 0xEE)
granule1_found = 0; if (!ealayer3_skip_data(stream, data, num_stream, 0, eaf_1.eaframe_size))
else goto fail;
granule1_found = 1; /* assume it does (bad infinite loops) */
} /* in V1a there may be PCM-only frames between granules so read until next one (or parse fails) */
while(!granule1_found); if (eaf_1.common_size > 0)
} granule_found = 1;
else {
memset(&eaf_1, 0, sizeof(ealayer3_frame_info));
} }
/* rebuild EALayer frame to MPEG frame */ /* rebuild EALayer frame to MPEG frame */
@ -194,7 +195,7 @@ int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *
os.buf = data->buffer; os.buf = data->buffer;
os.bufsize = data->buffer_size; os.bufsize = data->buffer_size;
os.b_off = 0; os.b_off = 0;
os.offset = current_offset; os.info_offset = info_offset;
ok = ealayer3_rebuild_mpeg_frame(&is_0, &eaf_0, &is_1, &eaf_1, &os); ok = ealayer3_rebuild_mpeg_frame(&is_0, &eaf_0, &is_1, &eaf_1, &os);
if (!ok) goto fail; if (!ok) goto fail;
@ -202,7 +203,6 @@ int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *
data->bytes_in_buffer = os.b_off / 8; /* wrote full MPEG frame, hopefully */ data->bytes_in_buffer = os.b_off / 8; /* wrote full MPEG frame, hopefully */
} }
return 1; return 1;
fail: fail:
return 0; return 0;
@ -216,28 +216,26 @@ fail:
static int ealayer3_parse_frame(mpeg_codec_data *data, ealayer3_bitstream *is, ealayer3_frame_info * eaf) { static int ealayer3_parse_frame(mpeg_codec_data *data, ealayer3_bitstream *is, ealayer3_frame_info * eaf) {
int ok; int ok;
/* make sure as there is re-parsing in loops */
memset(eaf, 0, sizeof(ealayer3_frame_info)); memset(eaf, 0, sizeof(ealayer3_frame_info));
switch(data->type) { switch(data->type) {
case MPEG_EAL31: ok = ealayer3_parse_frame_v1(is, eaf, data->channels_per_frame); break; case MPEG_EAL31: ok = ealayer3_parse_frame_v1(is, eaf, data->channels_per_frame, 0); break;
case MPEG_EAL31b: ok = ealayer3_parse_frame_v1(is, eaf, data->channels_per_frame, 1); break;
case MPEG_EAL32P: case MPEG_EAL32P:
case MPEG_EAL32S: ok = ealayer3_parse_frame_v2(is, eaf); break; case MPEG_EAL32S: ok = ealayer3_parse_frame_v2(is, eaf); break;
default: goto fail; default: goto fail;
} }
if (!ok) goto fail; if (!ok) goto fail;
//;VGM_LOG("EAFRAME: v=%i, ch=%i, sr=%i, index=%i / pre=%x, common=%x, pcm=%x, eaframe=%x\n", eaf->version, eaf->channels, eaf->sample_rate, eaf->granule_index, eaf->pre_size, eaf->common_size, eaf->pcm_size, eaf->eaframe_size);
//if (data->type==MPEG_EAL31) VGM_LOG("EAFRAME v1: pcm=%x, unk=%x, number=%x\n", eaf->v1_pcm_flag, eaf->v1_pcm_unknown, eaf->v1_pcm_number);
//else VGM_LOG("EAFRAME v2: stereo=%x, unk=%x, fs=%x, mode=%x, val=%x, number=%x, size=%x\n", eaf->v2_stereo_flag, eaf->v2_unknown, eaf->v2_frame_size, eaf->v2_mode, eaf->v2_mode_value, eaf->v2_pcm_number, eaf->v2_common_size);
return 1; return 1;
fail: fail:
return 0; return 0;
} }
static int ealayer3_parse_frame_v1(ealayer3_bitstream *is, ealayer3_frame_info * eaf, int channels_per_frame) { /* read V1"a" (in SCHl) and V1"b" (in SNS) EALayer3 frame */
static int ealayer3_parse_frame_v1(ealayer3_bitstream *is, ealayer3_frame_info * eaf, int channels_per_frame, int is_v1b) {
int ok; int ok;
/* read EA-frame V1 header */ /* read EA-frame V1 header */
@ -249,25 +247,30 @@ static int ealayer3_parse_frame_v1(ealayer3_bitstream *is, ealayer3_frame_info *
VGM_LOG("MPEG EAL3 v1: header not 0x00 or 0xEE\n"); VGM_LOG("MPEG EAL3 v1: header not 0x00 or 0xEE\n");
goto fail; /* wrong offset? */ goto fail; /* wrong offset? */
} }
if (eaf->v1_pcm_flag == 0xEE && !channels_per_frame) {
VGM_LOG("MPEG EAL3 v1: PCM block in first frame\n");
goto fail; /* must know from a prev frame */
}
/* read EA-frame common header (v1a PCM blocks don't have EA-frames, while v1b do) */
if (is_v1b || eaf->v1_pcm_flag == 0x00) {
ok = ealayer3_parse_frame_common(is, eaf);
if (!ok) goto fail;
}
/* check PCM block */ /* check PCM block */
if (eaf->v1_pcm_flag == 0xEE) { if (eaf->v1_pcm_flag == 0xEE) {
r_bits(is, 16,&eaf->v1_pcm_decode_discard); /* samples to discard of the next decoded (not PCM block) samples */ r_bits(is, 16,&eaf->v1_pcm_decode_discard); /* samples to discard of the next decoded (not PCM block) samples */
r_bits(is, 16,&eaf->v1_pcm_number); /* number of PCM samples, can be 0 */ r_bits(is, 16,&eaf->v1_pcm_number); /* number of PCM samples, can be 0 */
if (!channels_per_frame) {
VGM_LOG("MPEG EAL3 v1: PCM block as first frame\n");
goto fail; /* must know from a prev frame */
}
eaf->pre_size += 2+2; /* 16b+16b */ eaf->pre_size += 2+2; /* 16b+16b */
eaf->pcm_size = (2*eaf->v1_pcm_number * channels_per_frame); eaf->pcm_size = (2*eaf->v1_pcm_number * channels_per_frame);
}
else { if (is_v1b) { /* extra 32b in v1b */
/* read EA-frame common header */ r_bits(is, 32,&eaf->v1_pcm_unknown);
ok = ealayer3_parse_frame_common(is, eaf); eaf->pre_size += 4; /* 32b */
if (!ok) goto fail; VGM_ASSERT(eaf->v1_pcm_unknown != 0, "EA EAL3 v1: v1_pcm_unknown not 0\n");
}
} }
eaf->eaframe_size = eaf->pre_size + eaf->common_size + eaf->pcm_size; eaf->eaframe_size = eaf->pre_size + eaf->common_size + eaf->pcm_size;
@ -277,7 +280,8 @@ fail:
return 0; return 0;
} }
/* read V2"PCM" and V2"Spike" EALayer3 frame (exactly the same but V2P seems to have bigger
* PCM blocks and maybe smaller frames) */
static int ealayer3_parse_frame_v2(ealayer3_bitstream *is, ealayer3_frame_info * eaf) { static int ealayer3_parse_frame_v2(ealayer3_bitstream *is, ealayer3_frame_info * eaf) {
int ok; int ok;
@ -299,20 +303,19 @@ static int ealayer3_parse_frame_v2(ealayer3_bitstream *is, ealayer3_frame_info *
} }
/* read EA-frame common header */ /* read EA-frame common header */
ok = ealayer3_parse_frame_common(is, eaf); if (!eaf->v2_extended_flag || (eaf->v2_extended_flag && eaf->v2_common_size)) {
if (!ok) goto fail; ok = ealayer3_parse_frame_common(is, eaf);
if (!ok) goto fail;
//todo maybe v2 frames can be PCM-only like v1
if (!eaf->channels) {
VGM_LOG("MPEG EAL3: v2 frame with no channel number");
goto fail;
} }
VGM_ASSERT(eaf->v2_extended_flag && eaf->v2_common_size == 0, "EA EAL3: v2 empty frame\n"); /* seen in V2S */
VGM_ASSERT(eaf->v2_extended_flag && eaf->v2_mode_value > 0, "EA EAL3: v2_mode=%x with 0x%x\n", eaf->v2_mode, eaf->v2_mode_value);
//VGM_ASSERT(eaf->v2_pcm_number > 0, "EA EAL3: v2_pcm_number 0x%x\n", eaf->v2_pcm_number);
eaf->pcm_size = (2*eaf->v2_pcm_number * eaf->channels); eaf->pcm_size = (2*eaf->v2_pcm_number * eaf->channels);
eaf->eaframe_size = eaf->pre_size + eaf->common_size + eaf->pcm_size; eaf->eaframe_size = eaf->pre_size + eaf->common_size + eaf->pcm_size;
if(eaf->v2_frame_size != eaf->eaframe_size) { if (eaf->v2_frame_size != eaf->eaframe_size) {
VGM_LOG("MPEG EAL3: different v2 frame size vs calculated (0x%x vs 0x%x)\n", eaf->v2_frame_size, eaf->eaframe_size); VGM_LOG("MPEG EAL3: different v2 frame size vs calculated (0x%x vs 0x%x)\n", eaf->v2_frame_size, eaf->eaframe_size);
goto fail; goto fail;
} }
@ -324,7 +327,7 @@ fail:
} }
/* Parses a EALayer3 frame (common part) */ /* parses an EALayer3 frame (common part) */
static int ealayer3_parse_frame_common(ealayer3_bitstream *is, ealayer3_frame_info * eaf) { static int ealayer3_parse_frame_common(ealayer3_bitstream *is, ealayer3_frame_info * eaf) {
/* index tables */ /* index tables */
static const int versions[4] = { /* MPEG 2.5 */ 3, /* reserved */ -1, /* MPEG 2 */ 2, /* MPEG 1 */ 1 }; static const int versions[4] = { /* MPEG 2.5 */ 3, /* reserved */ -1, /* MPEG 2 */ 2, /* MPEG 1 */ 1 };
@ -393,9 +396,11 @@ static int ealayer3_parse_frame_common(ealayer3_bitstream *is, ealayer3_frame_in
for (i = 0; i < eaf->channels; i++) { /* data size (can be 0, meaning a micro EA-frame) */ for (i = 0; i < eaf->channels; i++) { /* data size (can be 0, meaning a micro EA-frame) */
eaf->data_size_b += eaf->main_data_size[i]; eaf->data_size_b += eaf->main_data_size[i];
} }
is->b_off += eaf->data_size_b;
if ((eaf->base_size_b+eaf->data_size_b) % 8) /* aligned to closest 8b */ if ((eaf->base_size_b+eaf->data_size_b) % 8) /* aligned to closest 8b */
eaf->padding_size_b = 8 - ((eaf->base_size_b+eaf->data_size_b) % 8); eaf->padding_size_b = 8 - ((eaf->base_size_b+eaf->data_size_b) % 8);
is->b_off += eaf->padding_size_b;
eaf->common_size = (eaf->base_size_b + eaf->data_size_b + eaf->padding_size_b)/8; eaf->common_size = (eaf->base_size_b + eaf->data_size_b + eaf->padding_size_b)/8;
@ -406,36 +411,46 @@ fail:
} }
/* Converts a EALAYER3 frame to a standard MPEG frame from pre-parsed info */ /* converts an EALAYER3 frame to a standard MPEG frame from pre-parsed info */
static int ealayer3_rebuild_mpeg_frame(ealayer3_bitstream* is_0, ealayer3_frame_info* eaf_0, ealayer3_bitstream* is_1, ealayer3_frame_info* eaf_1, ealayer3_bitstream* os) { static int ealayer3_rebuild_mpeg_frame(ealayer3_bitstream* is_0, ealayer3_frame_info* eaf_0, ealayer3_bitstream* is_1, ealayer3_frame_info* eaf_1, ealayer3_bitstream* os) {
uint32_t c = 0; uint32_t c = 0;
int i,j; int i,j;
int expected_bitrate_index, expected_frame_size; int expected_bitrate_index, expected_frame_size;
if (!eaf_0->common_size && !eaf_1->common_size) /* ignore PCM-only frames */
return 1; /* empty frames, PCM block only */ if (!eaf_0->common_size)
return 1;
/* get bitrate: use max bitrate (320/160) to simplify calcs for now (but some EA-frames use bit reservoir) */
expected_bitrate_index = 0x0E;
if (eaf_0->mpeg1) { /* 44100=0x414, 48000=0x3C0, 32000=0x5A0 */
expected_frame_size = 144l * 320 * 1000l / eaf_0->sample_rate;
} else { /* 22050=0x20A, 24000=0x1E0, 16000=0x2D0, 11025=0x414, 12000=0x3C0, 8000=0x5A0 */
expected_frame_size = 72l * 160 * 1000l / eaf_0->sample_rate;
}
/* extra checks */ /* extra checks */
if (eaf_0->mpeg1) { if (eaf_0->mpeg1 && (!eaf_1
if (!eaf_1 || eaf_0->mpeg1 != eaf_1->mpeg1
|| eaf_0->mpeg1 != eaf_1->mpeg1 || eaf_0->version != eaf_1->version
|| eaf_0->version != eaf_1->version || eaf_0->granule_index == eaf_1->granule_index
|| eaf_0->granule_index == eaf_1->granule_index || !eaf_0->common_size || !eaf_1->common_size)) {
|| !eaf_0->common_size || !eaf_1->common_size) { VGM_LOG("MPEG EAL3: EA-frames for MPEG1 don't match at 0x%lx\n", os->info_offset);
VGM_LOG("MPEG EAL3: EA-frames for MPEG1 don't match at 0x%lx\n", os->offset); goto fail;
goto fail;
}
} }
#if 0 //todo broken free format detection for some MP3 in mpg123 < 1.25.8
/* get bitrate: use "free format" (bigger bitrate) to avoid the need of bit reservoir
* this feature is in the spec but some decoders may not support it */
expected_bitrate_index = 0x00;
if (eaf_0->mpeg1) {
expected_frame_size = 144l * (320*2) * 1000l / eaf_0->sample_rate;
} else {
expected_frame_size = 72l * (160*2) * 1000l / eaf_0->sample_rate;
}
#else
/* this uses max official bitrate (320/160) but some frames need more = complex bit reservoir */
expected_bitrate_index = 0x0E;
if (eaf_0->mpeg1) { /* 320: 44100=0x414, 48000=0x3C0, 32000=0x5A0 */
expected_frame_size = 144l * 320 * 1000l / eaf_0->sample_rate;
} else { /* 160: 22050=0x20A, 24000=0x1E0, 16000=0x2D0, 11025=0x414, 12000=0x3C0, 8000=0x5A0 */
expected_frame_size = 72l * 160 * 1000l / eaf_0->sample_rate;
}
#endif
/* write MPEG1/2 frame header */ /* write MPEG1/2 frame header */
w_bits(os, 11, 0x7FF); /* sync */ w_bits(os, 11, 0x7FF); /* sync */
w_bits(os, 2, eaf_0->version_index); w_bits(os, 2, eaf_0->version_index);
@ -521,12 +536,8 @@ static int ealayer3_rebuild_mpeg_frame(ealayer3_bitstream* is_0, ealayer3_frame_
if (os->b_off/8 > expected_frame_size) { if (os->b_off/8 > expected_frame_size) {
VGM_LOG("MPEG EAL3: written 0x%lx but expected less than 0x%x at 0x%lx\n", os->b_off/8, expected_frame_size, os->offset); /* bit reservoir! shouldn't happen with free bitrate, otherwise it's hard to fix as needs complex buffering/calcs */
//todo bit reservoir! (doesn't seem to affect the output too much) VGM_LOG("MPEG EAL3: written 0x%lx but expected less than 0x%x at 0x%lx\n", os->b_off/8, expected_frame_size, os->info_offset);
//;VGM_LOG("EAFRAME: F0 v=%i, ch=%i, sr=%i, index=%i / pre=%x, common=%x, pcm=%x, eaframe=%x\n", eaf_0->version, eaf_0->channels, eaf_0->sample_rate, eaf_0->granule_index, eaf_0->pre_size, eaf_0->common_size, eaf_0->pcm_size, eaf_0->eaframe_size);
//;VGM_LOG("EAFRAME: F1 v=%i, ch=%i, sr=%i, index=%i / pre=%x, common=%x, pcm=%x, eaframe=%x\n", eaf_1->version, eaf_1->channels, eaf_1->sample_rate, eaf_1->granule_index, eaf_1->pre_size, eaf_1->common_size, eaf_1->pcm_size, eaf_1->eaframe_size);
//;VGM_LOGB(os->buf, os->b_off/8, 0);
} }
else { else {
/* fill ancillary data (ignored) */ /* fill ancillary data (ignored) */
@ -541,7 +552,9 @@ fail:
return 0; return 0;
} }
/* write PCM block directly to sample buffer (EALayer3 seems to use this as a prefectch of sorts) */ /* write PCM block directly to sample buffer and setup decode discard (EALayer3 seems to use this as a prefetch of sorts).
* Meant to be written inmediatedly, as those PCM are parts that can be found after 1 decoded frame.
* (ex. EA-frame_gr0, PCM-frame_0, EA-frame_gr1, PCM-frame_1 actually writes PCM-frame_0+1, decode of EA-frame_gr0+1 + discard part */
static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, ealayer3_frame_info * eaf) { static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, ealayer3_frame_info * eaf) {
mpeg_custom_stream *ms = data->streams[num_stream]; mpeg_custom_stream *ms = data->streams[num_stream];
size_t bytes_filled; size_t bytes_filled;
@ -552,13 +565,12 @@ static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
bytes_filled = sizeof(sample)*ms->samples_filled*data->channels_per_frame; bytes_filled = sizeof(sample)*ms->samples_filled*data->channels_per_frame;
if (bytes_filled + eaf->pcm_size > ms->output_buffer_size) { if (bytes_filled + eaf->pcm_size > ms->output_buffer_size) {
VGM_LOG("MPEG EAL3: can't fill the sample buffer with 0x%x\n", eaf->pcm_size); VGM_LOG("MPEG EAL3: can't fill the sample buffer with 0x%x\n", eaf->pcm_size);
goto fail; goto fail;
} }
if (eaf->v1_pcm_number) { if (eaf->v1_pcm_number) {
//;VGM_LOG("pcm discard = %i, number = %i at 0x%lx\n", eaf->v1_pcm_decode_discard, eaf->v1_pcm_number, stream->offset);
VGM_ASSERT(eaf->v1_pcm_decode_discard > 576, "MPEG EAL3: big discard %i at 0x%lx\n", eaf->v1_pcm_decode_discard, stream->offset); VGM_ASSERT(eaf->v1_pcm_decode_discard > 576, "MPEG EAL3: big discard %i at 0x%lx\n", eaf->v1_pcm_decode_discard, stream->offset);
VGM_ASSERT(eaf->v1_pcm_number > 0x100, "MPEG EAL3: big samples %i at 0x%lx\n", eaf->v1_pcm_number, stream->offset); VGM_ASSERT(eaf->v1_pcm_number > 0x100, "MPEG EAL3: big samples %i at 0x%lx\n", eaf->v1_pcm_number, stream->offset);
@ -576,30 +588,95 @@ static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
//todo should also discard v1_pcm_number, but block layout samples may be exhausted and won't move (maybe new block if offset = new offset detected) //todo should also discard v1_pcm_number, but block layout samples may be exhausted and won't move (maybe new block if offset = new offset detected)
/* special meanings */ /* special meanings */
if (decode_to_discard == 576) if (data->type == MPEG_EAL31) {
decode_to_discard = data->samples_per_frame;//+ eaf->v1_pcm_number; if (decode_to_discard == 576)
decode_to_discard = data->samples_per_frame;//+ eaf->v1_pcm_number;
}
else {
if (decode_to_discard == 0) /* seems ok? */
decode_to_discard += data->samples_per_frame;//+ eaf->v1_pcm_number;
else if (decode_to_discard == 576) /* untested */
decode_to_discard = data->samples_per_frame;//+ eaf->v1_pcm_number;
}
ms->decode_to_discard += decode_to_discard; ms->decode_to_discard += decode_to_discard;
} }
} }
if (eaf->v2_extended_flag) {
if (eaf->v2_pcm_number) {
/* read + write PCM block samples (always BE) */
for (i = 0; i < eaf->v2_pcm_number * data->channels_per_frame; i++) {
off_t pcm_offset = stream->offset + eaf->pre_size + eaf->common_size + sizeof(sample)*i;
int16_t pcm_sample = read_16bitBE(pcm_offset,stream->streamfile);
put_16bitLE(ms->output_buffer + bytes_filled + sizeof(sample)*i, pcm_sample);
}
ms->samples_filled += eaf->v2_pcm_number;
}
#if 0
/* todo supposed skip modes:
*
* AB00CCCC CCCCCCCC if A is set: DDEEEEEE EEEEFFFF FFFFFFGG GGGGGGGG
* D = BLOCKOFFSETMODE: IGNORE = 0x0, PRESERVE = 0x1, MUTE = 0x2, MAX = 0x3
* E = samples to discard (mode == 0) or skip (mode == 1 or 2) before outputting the uncompressed samples
* (when mode == 3 this is ignored)
* F = number of uncompressed sample frames (pcm block)
* G = MPEG granule size (can be zero)
*
* if 0: 576 - E if G == 0 then F
* if 1: 576 if G == 0 then F
* if 2: 576 if G == 0 then F * 2
* if 3: 576
*/
/* modify decoded samples depending on flag */
if (eaf->v2_mode == 0x00) {
size_t decode_to_discard = eaf->v2_mode_value;
if (decode_to_discard == 576)
decode_to_discard = data->samples_per_frame;//+ eaf->v2_pcm_number;
ms->decode_to_discard += decode_to_discard;
}
#endif
}
return 1;
fail:
return 0;
}
/* todo V2 (id7 only?) supposed skip modes: /* Skip EA-frames from other streams for multichannel (interleaved 1 EA-frame per stream).
* BLOCKOFFSETMODE: IGNORE = 0x0, PRESERVE = 0x1, MUTE = 0x2, MAX = 0x3 * Due to EALayer3 being in blocks and other complexities (we can't go past a block) all
* * streams's offsets should start in the first stream's EA-frame.
* AB00CCCC CCCCCCCC if A is set: DDEEEEEE EEEEFFFF FFFFFFGG GGGGGGGG *
* D = mode: * So to properly read one MPEG-frame from a stream we need to:
* E = bytes to discard (mode == 0) or skip (mode == 1 or 2) before outputting the uncompressed samples * - skip one EA-frame per previous streams until offset is in current stream's EA-frame
* (when mode == 3 this is ignored) * (ie. 1st stream skips 0, 2nd stream skips 1, 3rd stream skips 2)
* F = number of uncompressed sample frames * - read EA-frame (granule0)
* G = MPEG granule size (can be zero) * - skip one EA-frame per following streams until offset is in first stream's EA-frame
* * (ie. 1st stream skips 2, 2nd stream skips 1, 3rd stream skips 0)
* if 0: 576 - E if G == 0 then F * - repeat again for granule1
* if 1: 576 if G == 0 then F */
* if 2: 576 if G == 0 then F * 2 static int ealayer3_skip_data(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, int at_start, size_t last_eaframe_size) {
* if 3: 576 int ok, i;
*/ ealayer3_frame_info eaf;
ealayer3_bitstream is = {0};
uint8_t ibuf[EALAYER3_EA_FRAME_BUFFER_SIZE];
int skips = at_start ? num_stream : data->streams_size - 1 - num_stream;
for (i = 0; i < skips; i++) {
is.buf = ibuf;
is.bufsize = read_streamfile(ibuf,stream->offset,EALAYER3_EA_FRAME_BUFFER_SIZE, stream->streamfile); /* reads less at EOF */
is.b_off = 0;
ok = ealayer3_parse_frame(data, &is, &eaf);
if (!ok) goto fail;
stream->offset += eaf.eaframe_size;
}
return 1; return 1;
fail: fail:

View File

@ -13,7 +13,7 @@
* - validate of channels between streams * - validate of channels between streams
*/ */
#define MPEG_DATA_BUFFER_SIZE 0x1000 /* at least one MPEG frame (max ~0x5A1) */ #define MPEG_DATA_BUFFER_SIZE 0x1000 /* at least one MPEG frame (max ~0x5A1 plus some more in case of free bitrate) */
static mpg123_handle * init_mpg123_handle(); static mpg123_handle * init_mpg123_handle();
static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels); static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
@ -137,6 +137,7 @@ mpeg_codec_data *init_mpeg_custom_codec_data(STREAMFILE *streamFile, off_t start
/* init per subtype */ /* init per subtype */
switch(data->type) { switch(data->type) {
case MPEG_EAL31: case MPEG_EAL31:
case MPEG_EAL31b:
case MPEG_EAL32P: case MPEG_EAL32P:
case MPEG_EAL32S: ok = mpeg_custom_setup_init_ealayer3(streamFile, start_offset, data, coding_type); break; 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; case MPEG_AWC: ok = mpeg_custom_setup_init_awc(streamFile, start_offset, data, coding_type); break;
@ -367,7 +368,7 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data
int rc, ok; int rc, ok;
mpeg_custom_stream *ms = data->streams[num_stream]; mpeg_custom_stream *ms = data->streams[num_stream];
//;VGM_LOG("MPEG: decode stream%i @ 0x%08lx (filled=%i, used=%i)\n", num_stream, stream->offset, ms->samples_filled, ms->samples_used); //;VGM_LOG("MPEG: decode stream%i @ 0x%08lx (filled=%i, used=%i, buffer_full=%i)\n", num_stream, stream->offset, ms->samples_filled, ms->samples_used, data->buffer_full);
/* wait until samples are depleted, so buffers don't grow too big */ /* wait until samples are depleted, so buffers don't grow too big */
if (ms->samples_filled - ms->samples_used > 0) { if (ms->samples_filled - ms->samples_used > 0) {
@ -390,6 +391,7 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data
//;VGM_LOG("MPEG: reading more raw data\n"); //;VGM_LOG("MPEG: reading more raw data\n");
switch(data->type) { switch(data->type) {
case MPEG_EAL31: case MPEG_EAL31:
case MPEG_EAL31b:
case MPEG_EAL32P: case MPEG_EAL32P:
case MPEG_EAL32S: ok = mpeg_custom_parse_frame_ealayer3(stream, data, num_stream); break; 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_AHX: ok = mpeg_custom_parse_frame_ahx(stream, data); break;
@ -413,7 +415,7 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data
bytes_filled = sizeof(sample)*ms->samples_filled*data->channels_per_frame; bytes_filled = sizeof(sample)*ms->samples_filled*data->channels_per_frame;
/* feed new raw data to the decoder if needed, copy decoded results to frame buffer output */ /* feed new raw data to the decoder if needed, copy decoded results to frame buffer output */
if (!data->buffer_used) { if (!data->buffer_used) {
//;VGM_LOG("MPEG: feed new data and get samples \n"); //;VGM_LOG("MPEG: feed new data and get samples\n");
rc = mpg123_decode(ms->m, rc = mpg123_decode(ms->m,
data->buffer, data->bytes_in_buffer, data->buffer, data->bytes_in_buffer,
(unsigned char*)ms->output_buffer + bytes_filled, ms->output_buffer_size - bytes_filled, (unsigned char*)ms->output_buffer + bytes_filled, ms->output_buffer_size - bytes_filled,
@ -448,11 +450,12 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data
/* not enough raw data, set flag to request more next time /* not enough raw data, set flag to request more next time
* (but only with empty mpg123 buffer, EA blocks wait for all samples decoded before advancing blocks) */ * (but only with empty mpg123 buffer, EA blocks wait for all samples decoded before advancing blocks) */
if (!bytes_done && rc == MPG123_NEED_MORE) { if (!bytes_done && rc == MPG123_NEED_MORE) {
//;VGM_LOG("MPEG: need more raw data to get samples (bytest_done=%x)\n", bytes_done); //;VGM_LOG("MPEG: need more raw data to get samples (bytes_done=%x)\n", bytes_done);
data->buffer_full = 0; data->buffer_full = 0;
} }
//;VGM_LOG("MPEG: stream samples now=%i, filled=%i)\n\n", ms->samples_filled, samples_filled);
return; return;
decode_fail: decode_fail: