Make MPEG custom decoder use their own data buffer instead sharing one

In rare cases (ex. EALayer3) mpg123 may need several passes to feed one
stream's data buffer, and meanwhile other streams would overwrite it
This commit is contained in:
bnnm 2017-12-01 20:02:30 +01:00
parent 02d0231ff2
commit 7d9e5a93e4
6 changed files with 60 additions and 42 deletions

View File

@ -60,7 +60,7 @@ int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, m
case MPEG_STANDARD:
case MPEG_AHX:
case MPEG_EA:
if (data->channels_per_frame != data->config.channels)
if (info.channels != data->config.channels)
goto fail; /* no multichannel expected */
break;
@ -89,7 +89,8 @@ fail:
/* writes data to the buffer and moves offsets */
int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data) {
int mpeg_custom_parse_frame_default(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;
size_t current_padding = 0;
@ -137,14 +138,14 @@ int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
current_data_size = info.frame_size;
break;
}
if (!current_data_size || current_data_size > data->buffer_size) {
if (!current_data_size || current_data_size > ms->buffer_size) {
VGM_LOG("MPEG: incorrect data_size 0x%x\n", current_data_size);
goto fail;
}
/* read single frame */
data->bytes_in_buffer = read_streamfile(data->buffer,stream->offset, current_data_size, stream->streamfile);
ms->bytes_in_buffer = read_streamfile(ms->buffer,stream->offset, current_data_size, stream->streamfile);
/* update offsets */

View File

@ -3,11 +3,12 @@
#ifdef VGM_USE_MPEG
#define MPEG_AHX_EXPECTED_FRAME_SIZE 0x414
static int ahx_decrypt_type08(mpeg_codec_data *data);
static int ahx_decrypt_type08(uint8_t * buffer, mpeg_custom_config *config);
/* writes data to the buffer and moves offsets, transforming AHX frames as needed */
int mpeg_custom_parse_frame_ahx(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data) {
int mpeg_custom_parse_frame_ahx(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream) {
/* 0xFFF5E0C0 header: frame size 0x414 (160kbps, 22050Hz) but they actually are much shorter */
mpeg_custom_stream *ms = data->streams[num_stream];
size_t current_data_size = 0;
size_t file_size = get_streamfile_size(stream->streamfile);
@ -33,22 +34,22 @@ int mpeg_custom_parse_frame_ahx(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data)
next_offset++;
}
}
if (!current_data_size || current_data_size > data->buffer_size || current_data_size > MPEG_AHX_EXPECTED_FRAME_SIZE) {
if (!current_data_size || current_data_size > ms->buffer_size || current_data_size > MPEG_AHX_EXPECTED_FRAME_SIZE) {
VGM_LOG("MPEG AHX: incorrect data_size 0x%x\n", current_data_size);
goto fail;
}
/* 0-fill up to expected size to keep mpg123 happy */
data->bytes_in_buffer = read_streamfile(data->buffer,stream->offset,current_data_size,stream->streamfile);
memset(data->buffer + data->bytes_in_buffer,0, MPEG_AHX_EXPECTED_FRAME_SIZE - data->bytes_in_buffer);
data->bytes_in_buffer = MPEG_AHX_EXPECTED_FRAME_SIZE;
ms->bytes_in_buffer = read_streamfile(ms->buffer,stream->offset,current_data_size,stream->streamfile);
memset(ms->buffer + ms->bytes_in_buffer,0, MPEG_AHX_EXPECTED_FRAME_SIZE - ms->bytes_in_buffer);
ms->bytes_in_buffer = MPEG_AHX_EXPECTED_FRAME_SIZE;
/* decrypt if needed */
switch(data->config.encryption) {
case 0x00: break;
case 0x08: ahx_decrypt_type08(data); break;
case 0x08: ahx_decrypt_type08(ms->buffer, &data->config); break;
default:
VGM_LOG("MPEG AHX: unknown encryption 0x%x\n", data->config.encryption);
break; /* garbled frame */
@ -66,7 +67,7 @@ fail:
}
/* Decrypts an AHX type 0x08 (keystring) encrypted frame. Algorithm by Thealexbarney */
static int ahx_decrypt_type08(mpeg_codec_data *data) {
static int ahx_decrypt_type08(uint8_t * buffer, mpeg_custom_config *config) {
int i, index, encrypted_bits;
uint32_t value;
uint16_t current_key;
@ -78,18 +79,18 @@ static int ahx_decrypt_type08(mpeg_codec_data *data) {
/* read 2b from a bitstream offset to decrypt, and use it as an index to get the key.
* AHX encrypted bitstream starts at 107b (0x0d*8+3), every frame, and seem to always use index 2 */
value = (uint32_t)get_32bitBE(data->buffer + 0x0d);
value = (uint32_t)get_32bitBE(buffer + 0x0d);
index = (value >> (32-3-2)) & 0x03;
switch(index) {
case 0: current_key = 0; break;
case 1: current_key = data->config.cri_key1; break;
case 2: current_key = data->config.cri_key2; break;
case 3: current_key = data->config.cri_key3; break;
case 1: current_key = config->cri_key1; break;
case 2: current_key = config->cri_key2; break;
case 3: current_key = config->cri_key3; break;
default: goto fail;
}
/* AHX for DC: 16b, normal: 6b (no idea, probably some Layer II field) */
encrypted_bits = data->config.cri_type == 0x10 ? 16 : 6;
encrypted_bits = config->cri_type == 0x10 ? 16 : 6;
/* decrypt next bitstream 2b pairs, up to 16b (max key size):
* - read 2b from bitstream (from higher to lower)
@ -101,7 +102,7 @@ static int ahx_decrypt_type08(mpeg_codec_data *data) {
}
/* write output */
put_32bitBE(data->buffer + 0x0d, value);
put_32bitBE(buffer + 0x0d, value);
return 1;
fail:

View File

@ -170,7 +170,7 @@ int mpeg_custom_parse_frame_awc(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data,
goto fail;
current_data_size = info.frame_size;
data->bytes_in_buffer = read_streamfile(data->buffer,stream->offset, current_data_size, stream->streamfile);
ms->bytes_in_buffer = read_streamfile(ms->buffer,stream->offset, current_data_size, stream->streamfile);
stream->offset += current_data_size;

View File

@ -123,11 +123,6 @@ mpeg_codec_data *init_mpeg_custom_codec_data(STREAMFILE *streamFile, off_t start
data = calloc(1,sizeof(mpeg_codec_data));
if (!data) goto fail;
data->buffer_size = MPEG_DATA_BUFFER_SIZE;
data->buffer = calloc(sizeof(uint8_t), data->buffer_size);
if (!data->buffer) goto fail;
/* keep around to decode */
data->custom = 1;
data->type = type;
@ -162,6 +157,11 @@ mpeg_codec_data *init_mpeg_custom_codec_data(STREAMFILE *streamFile, off_t start
data->streams[i]->output_buffer_size = sizeof(sample) * data->channels_per_frame * data->samples_per_frame;
data->streams[i]->output_buffer = calloc(data->streams[i]->output_buffer_size, sizeof(uint8_t));
if (!data->streams[i]->output_buffer) goto fail;
/* one per stream as sometimes mpg123 can't read the whole buffer in one pass */
data->streams[i]->buffer_size = MPEG_DATA_BUFFER_SIZE;
data->streams[i]->buffer = calloc(sizeof(uint8_t), data->streams[i]->buffer_size);
if (!data->streams[i]->buffer) goto fail;
}
@ -368,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, buffer_full=%i)\n", num_stream, stream->offset, ms->samples_filled, ms->samples_used, data->buffer_full);
//;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, ms->buffer_full);
/* wait until samples are depleted, so buffers don't grow too big */
if (ms->samples_filled - ms->samples_used > 0) {
@ -380,47 +380,47 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data
ms->samples_used = 0;
/* extra EOF check for edge cases when the caller tries to read more samples than possible */
if (!data->buffer_full && stream->offset >= stream_size) {
if (!ms->buffer_full && stream->offset >= stream_size) {
VGM_LOG("MPEG: EOF found but more data is requested\n");
goto decode_fail;
}
/* read more raw data (could fill the sample buffer too in some cases, namely EALayer3) */
if (!data->buffer_full) {
if (!ms->buffer_full) {
//;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;
case MPEG_AHX: ok = mpeg_custom_parse_frame_ahx(stream, data, num_stream); 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;
default: ok = mpeg_custom_parse_frame_default(stream, data, num_stream); break;
}
if (!ok) {
VGM_LOG("MPEG: cannot parse frame @ around %lx\n",stream->offset);
goto decode_fail; /* mpg123 could resync but custom MPEGs wouldn't need that */
}
//;VGM_LOG("MPEG: read results: bytes_in_buffer=0x%x, new offset=%lx\n", data->bytes_in_buffer, stream->offset);
//;VGM_LOG("MPEG: read results: bytes_in_buffer=0x%x, new offset=%lx\n", ms->bytes_in_buffer, stream->offset);
/* parse frame may not touch the buffer (only move offset, or fill the sample buffer) */
if (data->bytes_in_buffer) {
data->buffer_full = 1;
data->buffer_used = 0;
if (ms->bytes_in_buffer) {
ms->buffer_full = 1;
ms->buffer_used = 0;
}
}
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) {
if (!ms->buffer_used) {
//;VGM_LOG("MPEG: feed new data and get samples\n");
rc = mpg123_decode(ms->m,
data->buffer, data->bytes_in_buffer,
ms->buffer, ms->bytes_in_buffer,
(unsigned char*)ms->output_buffer + bytes_filled, ms->output_buffer_size - bytes_filled,
&bytes_done);
data->buffer_used = 1;
ms->buffer_used = 1;
}
else {
//;VGM_LOG("MPEG: get samples from old data\n");
@ -451,7 +451,7 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data
* (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 (bytes_done=%x)\n", bytes_done);
data->buffer_full = 0;
ms->buffer_full = 0;
}
@ -481,6 +481,7 @@ void free_mpeg(mpeg_codec_data *data) {
int i;
for (i=0; i < data->streams_size; i++) {
mpg123_delete(data->streams[i]->m);
free(data->streams[i]->buffer);
free(data->streams[i]->output_buffer);
free(data->streams[i]);
}
@ -528,6 +529,8 @@ void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
/* seek multistream */
if (!data->custom) {
mpg123_feedseek(data->m, num_sample,SEEK_SET,&input_offset);
/* force first offset as discard-looping needs to start from the beginning */
if (vgmstream->loop_ch)
vgmstream->loop_ch[0].offset = vgmstream->loop_ch[0].channel_start_offset + input_offset;
}
@ -539,7 +542,10 @@ void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
data->streams[i]->samples_filled = 0;
data->streams[i]->samples_used = 0;
data->streams[i]->decode_to_discard = 0;
data->streams[i]->buffer_full = 0;
data->streams[i]->buffer_used = 0;
/* force first offset as discard-looping needs to start from the beginning */
if (vgmstream->loop_ch)
vgmstream->loop_ch[i].offset = vgmstream->loop_ch[i].channel_start_offset;
}
@ -570,6 +576,9 @@ void flush_mpeg(mpeg_codec_data * data) {
data->streams[i]->samples_filled = 0;
data->streams[i]->samples_used = 0;
data->streams[i]->decode_to_discard = 0;
data->streams[i]->bytes_in_buffer = 0;
data->streams[i]->buffer_full = 0;
data->streams[i]->buffer_used = 0;
}
data->samples_to_discard = data->skip_samples; /* initial delay */

View File

@ -21,8 +21,8 @@ int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, m
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_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream);
int mpeg_custom_parse_frame_ahx(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 mpeg_custom_parse_frame_awc(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream);

View File

@ -898,6 +898,12 @@ typedef struct {
/* represents a single MPEG stream */
typedef struct {
/* per stream as sometimes mpg123 must be fed in passes if data is big enough (ex. EALayer3 multichannel) */
uint8_t *buffer; /* raw data buffer */
size_t buffer_size;
size_t bytes_in_buffer;
int buffer_full; /* raw buffer has been filled */
int buffer_used; /* raw buffer has been fed to the decoder */
mpg123_handle *m; /* MPEG decoder */
uint8_t *output_buffer; /* decoded samples from this stream (in bytes for mpg123) */
@ -909,16 +915,17 @@ typedef struct {
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 {
uint8_t *buffer; /* internal raw data buffer */
/* regular/single MPEG internals */
uint8_t *buffer; /* raw data buffer */
size_t buffer_size;
size_t bytes_in_buffer;
int buffer_full; /* raw buffer has been filled */
int buffer_used; /* raw buffer has been fed to the decoder */
mpg123_handle *m; /* regular/single MPEG decoder */
mpg123_handle *m; /* MPEG decoder */
/* for internal use, assumed to be constant for all frames */
int channels_per_frame;