diff --git a/src/coding/mpeg_custom_utils_ealayer3.c b/src/coding/mpeg_custom_utils_ealayer3.c index b233b3bf..cf41d624 100644 --- a/src/coding/mpeg_custom_utils_ealayer3.c +++ b/src/coding/mpeg_custom_utils_ealayer3.c @@ -7,11 +7,12 @@ * 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. * - * Layer III MPEG1 uses two granules (data chunks) per frame, while MPEG2/2.5 ("LSF mode") only one. EA-frames - * contain one granule, so to reconstruct one MPEG-frame we need two EA-frames (MPEG1) or one (MPEG2). + * Layer III MPEG1 uses two granules (data chunks) per frame, while MPEG2/2.5 ("LSF mode") only one. + * 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. * - * 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 * 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*/ size_t bufsize; /* max size of 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; /* parsed info from a single EALayer3 frame */ @@ -38,13 +39,14 @@ typedef struct { uint32_t v1_pcm_flag; uint32_t v1_pcm_decode_discard; uint32_t v1_pcm_number; + uint32_t v1_pcm_unknown; /* EALayer3 v2 header */ uint32_t v2_extended_flag; uint32_t v2_stereo_flag; uint32_t v2_unknown; /* unused? */ 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_pcm_number; 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_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_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_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 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 */ /* **************************************************************************** */ -/* 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 ok; ealayer3_frame_info eaf; - ealayer3_bitstream is; + ealayer3_bitstream is = {0}; 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 */ { @@ -115,8 +114,7 @@ int mpeg_custom_setup_init_ealayer3(STREAMFILE *streamFile, off_t start_offset, ok = ealayer3_parse_frame(data, &is, &eaf); if (!ok) goto fail; } - - ;VGM_ASSERT(!eaf.mpeg1, "MPEG EAL3: mpeg2 found at 0x%lx\n", start_offset); + VGM_ASSERT(!eaf.mpeg1, "MPEG EAL3: mpeg2 found at 0x%lx\n", start_offset); /* untested */ *coding_type = coding_MPEG_ealayer3; data->channels_per_frame = eaf.channels; @@ -125,10 +123,9 @@ int mpeg_custom_setup_init_ealayer3(STREAMFILE *streamFile, off_t start_offset, /* extra checks */ if (!data->channels_per_frame || data->config.channels != data->channels_per_frame){ 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) */ return 1; @@ -138,15 +135,19 @@ fail: /* 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 ok; - off_t current_offset = stream->offset; + int ok, granule_found; + off_t info_offset = stream->offset; 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]; - /* 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.bufsize = read_streamfile(ibuf_0,stream->offset,EALAYER3_EA_FRAME_BUFFER_SIZE, stream->streamfile); /* reads less at EOF */ is_0.b_off = 0; @@ -158,35 +159,35 @@ int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data * if (!ok) goto fail; stream->offset += eaf_0.eaframe_size; - } - /* get second frame/granule */ - if (eaf_0.mpeg1) { - 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; + if (!ealayer3_skip_data(stream, data, num_stream, 0, eaf_0.eaframe_size)) + goto fail; + } - ok = ealayer3_parse_frame(data, &is_1, &eaf_1); - if (!ok) goto fail; + /* get second frame/granule (MPEG1 only) if first granule was found */ + 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); - if (!ok) goto fail; + 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; - 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 */ - if (eaf_1.v1_pcm_flag == 0xEE) - granule1_found = 0; - else - granule1_found = 1; /* assume it does (bad infinite loops) */ - } - while(!granule1_found); - } - else { - memset(&eaf_1, 0, sizeof(ealayer3_frame_info)); + stream->offset += eaf_1.eaframe_size; + + if (!ealayer3_skip_data(stream, data, num_stream, 0, eaf_1.eaframe_size)) + goto fail; + + /* in V1a there may be PCM-only frames between granules so read until next one (or parse fails) */ + if (eaf_1.common_size > 0) + granule_found = 1; } /* 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.bufsize = data->buffer_size; 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); 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 */ } - return 1; fail: return 0; @@ -216,28 +216,26 @@ fail: static int ealayer3_parse_frame(mpeg_codec_data *data, ealayer3_bitstream *is, ealayer3_frame_info * eaf) { int ok; + /* make sure as there is re-parsing in loops */ memset(eaf, 0, sizeof(ealayer3_frame_info)); 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_EAL32S: ok = ealayer3_parse_frame_v2(is, eaf); break; default: 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; fail: 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; /* 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"); 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 */ 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_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->pcm_size = (2*eaf->v1_pcm_number * channels_per_frame); - } - else { - /* read EA-frame common header */ - ok = ealayer3_parse_frame_common(is, eaf); - if (!ok) goto fail; + + if (is_v1b) { /* extra 32b in v1b */ + r_bits(is, 32,&eaf->v1_pcm_unknown); + eaf->pre_size += 4; /* 32b */ + 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; @@ -277,7 +280,8 @@ fail: 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) { int ok; @@ -286,7 +290,7 @@ static int ealayer3_parse_frame_v2(ealayer3_bitstream *is, ealayer3_frame_info * r_bits(is, 1,&eaf->v2_stereo_flag); r_bits(is, 2,&eaf->v2_unknown); r_bits(is, 12,&eaf->v2_frame_size); - + eaf->pre_size = 2; /* 16b */ if (eaf->v2_extended_flag) { @@ -294,25 +298,24 @@ static int ealayer3_parse_frame_v2(ealayer3_bitstream *is, ealayer3_frame_info * r_bits(is, 10,&eaf->v2_mode_value); r_bits(is, 10,&eaf->v2_pcm_number); r_bits(is, 10,&eaf->v2_common_size); - + eaf->pre_size += 4; /* 32b */ } /* read EA-frame common header */ - 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; + if (!eaf->v2_extended_flag || (eaf->v2_extended_flag && eaf->v2_common_size)) { + ok = ealayer3_parse_frame_common(is, eaf); + if (!ok) 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->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); 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) { /* index tables */ 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) */ 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 */ 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; @@ -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) { uint32_t c = 0; int i,j; int expected_bitrate_index, expected_frame_size; - if (!eaf_0->common_size && !eaf_1->common_size) - return 1; /* empty frames, PCM block only */ - - /* 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; - } + /* ignore PCM-only frames */ + if (!eaf_0->common_size) + return 1; /* extra checks */ - if (eaf_0->mpeg1) { - if (!eaf_1 - || eaf_0->mpeg1 != eaf_1->mpeg1 - || eaf_0->version != eaf_1->version - || eaf_0->granule_index == eaf_1->granule_index - || !eaf_0->common_size || !eaf_1->common_size) { - VGM_LOG("MPEG EAL3: EA-frames for MPEG1 don't match at 0x%lx\n", os->offset); - goto fail; - } + if (eaf_0->mpeg1 && (!eaf_1 + || eaf_0->mpeg1 != eaf_1->mpeg1 + || eaf_0->version != eaf_1->version + || eaf_0->granule_index == eaf_1->granule_index + || !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); + 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 */ w_bits(os, 11, 0x7FF); /* sync */ 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) { - 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); - //todo bit reservoir! (doesn't seem to affect the output too much) - - //;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); + /* bit reservoir! shouldn't happen with free bitrate, otherwise it's hard to fix as needs complex buffering/calcs */ + 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); } else { /* fill ancillary data (ignored) */ @@ -541,7 +552,9 @@ fail: 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) { mpeg_custom_stream *ms = data->streams[num_stream]; 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; 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); - goto fail; + VGM_LOG("MPEG EAL3: can't fill the sample buffer with 0x%x\n", eaf->pcm_size); + goto fail; } 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_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) /* special meanings */ - if (decode_to_discard == 576) - decode_to_discard = data->samples_per_frame;//+ eaf->v1_pcm_number; - + if (data->type == MPEG_EAL31) { + 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; } } + 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: - * BLOCKOFFSETMODE: IGNORE = 0x0, PRESERVE = 0x1, MUTE = 0x2, MAX = 0x3 - * - * AB00CCCC CCCCCCCC if A is set: DDEEEEEE EEEEFFFF FFFFFFGG GGGGGGGG - * D = mode: - * E = bytes 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 - * 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 - */ +/* Skip EA-frames from other streams for multichannel (interleaved 1 EA-frame per stream). + * 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. + * + * So to properly read one MPEG-frame from a stream we need to: + * - skip one EA-frame per previous streams until offset is in current stream's EA-frame + * (ie. 1st stream skips 0, 2nd stream skips 1, 3rd stream skips 2) + * - read EA-frame (granule0) + * - 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) + * - repeat again for granule1 + */ +static int ealayer3_skip_data(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, int at_start, size_t last_eaframe_size) { + 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; fail: diff --git a/src/coding/mpeg_decoder.c b/src/coding/mpeg_decoder.c index b0bf45a8..4442e03d 100644 --- a/src/coding/mpeg_decoder.c +++ b/src/coding/mpeg_decoder.c @@ -13,7 +13,7 @@ * - 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 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 */ switch(data->type) { case MPEG_EAL31: + case MPEG_EAL31b: 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; @@ -367,7 +368,7 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data int rc, ok; 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 */ 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"); switch(data->type) { case MPEG_EAL31: + case MPEG_EAL31b: 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; @@ -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; /* feed new raw data to the decoder if needed, copy decoded results to frame buffer output */ 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, data->buffer, data->bytes_in_buffer, (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 * (but only with empty mpg123 buffer, EA blocks wait for all samples decoded before advancing blocks) */ 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; } + //;VGM_LOG("MPEG: stream samples now=%i, filled=%i)\n\n", ms->samples_filled, samples_filled); return; decode_fail: