mpeg decoder cleanup

This commit is contained in:
bnnm 2020-07-17 19:42:05 +02:00
parent 73db56f327
commit 729e13ebb0
10 changed files with 122 additions and 128 deletions

View File

@ -379,6 +379,43 @@ void free_vorbis_custom(vorbis_custom_codec_data* data);
#ifdef VGM_USE_MPEG
/* mpeg_decoder */
typedef struct mpeg_codec_data mpeg_codec_data;
/* Custom MPEG modes, mostly differing in the data layout */
typedef enum {
MPEG_STANDARD, /* 1 stream */
MPEG_AHX, /* 1 stream with false frame headers */
MPEG_XVAG, /* N streams of fixed interleave (frame-aligned, several data-frames of fixed size) */
MPEG_FSB, /* N streams of 1 data-frame+padding (=interleave) */
MPEG_P3D, /* N streams of fixed interleave (not frame-aligned) */
MPEG_SCD, /* N streams of fixed interleave (not frame-aligned) */
MPEG_EA, /* 1 stream (maybe N streams in absolute offsets?) */
MPEG_EAL31, /* EALayer3 v1 (SCHl), custom frames with v1 header */
MPEG_EAL31b, /* EALayer3 v1 (SNS), custom frames with v1 header + minor changes */
MPEG_EAL32P, /* EALayer3 v2 "PCM", custom frames with v2 header + bigger PCM blocks? */
MPEG_EAL32S, /* EALayer3 v2 "Spike", custom frames with v2 header + smaller PCM blocks? */
MPEG_LYN, /* N streams of fixed interleave */
MPEG_AWC, /* N streams in block layout (music) or absolute offsets (sfx) */
MPEG_EAMP3 /* custom frame header + MPEG frame + PCM blocks */
} mpeg_custom_t;
/* config for the above modes */
typedef struct {
int channels; /* max channels */
int fsb_padding; /* fsb padding mode */
int chunk_size; /* size of a data portion */
int data_size; /* playable size */
int interleave; /* size of stream interleave */
int encryption; /* encryption mode */
int big_endian;
int skip_samples;
/* for AHX */
int cri_type;
uint16_t cri_key1;
uint16_t cri_key2;
uint16_t cri_key3;
} mpeg_custom_config;
mpeg_codec_data* init_mpeg(STREAMFILE* sf, off_t start_offset, coding_t *coding_type, int channels);
mpeg_codec_data* init_mpeg_custom(STREAMFILE* sf, off_t start_offset, coding_t* coding_type, int channels, mpeg_custom_t custom_type, mpeg_custom_config* config);
void decode_mpeg(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do, int channels);
@ -387,6 +424,7 @@ void seek_mpeg(VGMSTREAM* vgmstream, int32_t num_sample);
void free_mpeg(mpeg_codec_data* data);
void flush_mpeg(mpeg_codec_data* data);
int mpeg_get_sample_rate(mpeg_codec_data* data);
long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data* data);
#endif

View File

@ -593,6 +593,10 @@ void flush_mpeg(mpeg_codec_data * data) {
data->buffer_used = 0;
}
int mpeg_get_sample_rate(mpeg_codec_data* data) {
return data->sample_rate_per_frame;
}
long mpeg_bytes_to_samples(long bytes, const mpeg_codec_data *data) {
/* if not found just return 0 and expect to fail (if used for num_samples) */
if (!data->custom) {

View File

@ -16,6 +16,59 @@ typedef struct {
int channels;
} mpeg_frame_info;
/* 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) */
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) */
int channels_per_frame; /* for rare cases that streams don't share this */
} mpeg_custom_stream;
struct mpeg_codec_data {
/* 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; /* MPEG decoder */
struct mpg123_frameinfo mi; /* start info, so it's available even when resetting */
/* for internal use */
int channels_per_frame;
int samples_per_frame;
/* for some calcs */
int bitrate_per_frame;
int sample_rate_per_frame;
/* custom MPEG internals */
int custom; /* flag */
mpeg_custom_t type; /* mpeg subtype */
mpeg_custom_config config; /* config depending on the mode */
size_t default_buffer_size;
mpeg_custom_stream **streams; /* array of MPEG streams (ex. 2ch+2ch) */
size_t streams_size;
size_t skip_samples; /* base encoder delay */
size_t samples_to_discard; /* for custom mpeg looping */
};
int mpeg_get_frame_info(STREAMFILE *streamfile, off_t offset, mpeg_frame_info * info);
int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type);

View File

@ -128,17 +128,15 @@ VGMSTREAM * init_vgmstream_msf(STREAMFILE *streamFile) {
#endif
#if defined(VGM_USE_MPEG)
case 0x07: { /* MPEG (CBR LAME MP3) [Dengeki Bunko Fighting Climax (PS3)] */
mpeg_codec_data *mpeg_data = NULL;
mpeg_data = init_mpeg(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels);
if (!mpeg_data) goto fail;
vgmstream->codec_data = mpeg_data;
vgmstream->codec_data = init_mpeg(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = mpeg_bytes_to_samples(data_size, mpeg_data);
vgmstream->num_samples = mpeg_bytes_to_samples(data_size, vgmstream->codec_data);
if (loop_flag) {
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data);
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data);
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, vgmstream->codec_data);
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, vgmstream->codec_data);
/* loops are always aligned to CBR frame beginnings */
}

View File

@ -241,22 +241,20 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
#ifdef VGM_USE_MPEG
case 0x07: { /* MPEG [Final Fantasy XIII (PS3)] */
mpeg_codec_data *mpeg_data = NULL;
mpeg_custom_config cfg = {0};
cfg.interleave = 0x800; /* for multistream [Final Fantasy XIII-2 (PS3)], otherwise ignored */
cfg.data_size = stream_size;
mpeg_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_SCD, &cfg);
if (!mpeg_data) goto fail;
vgmstream->codec_data = mpeg_data;
vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_SCD, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
/* some Drakengard 3, Kingdom Hearts HD have adjusted sample rate (47999, 44099), for looping? */
vgmstream->num_samples = mpeg_bytes_to_samples(stream_size, mpeg_data);
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data);
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data);
vgmstream->num_samples = mpeg_bytes_to_samples(stream_size, vgmstream->codec_data);
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, vgmstream->codec_data);
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, vgmstream->codec_data);
/* somehow loops offsets aren't always frame-aligned, and the code below supposedly helped,
* but there isn't much difference since MPEG loops are rough (1152-aligned). Seems it

View File

@ -230,7 +230,6 @@ VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) {
#ifdef VGM_USE_MPEG
case 0x06: { /* MSMP3 (MSF subfile) [Dragon Quest Builders (PS3)] */
mpeg_codec_data *mpeg_data = NULL;
mpeg_custom_config cfg = {0};
start_offset = sead.extradata_offset + sead.extradata_size;
@ -238,12 +237,11 @@ VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) {
/* extradata: */
/* proper MSF header, but sample rate/loops are ignored in favor of SAB's */
mpeg_data = init_mpeg_custom(sf, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_STANDARD, &cfg);
if (!mpeg_data) goto fail;
vgmstream->codec_data = mpeg_data;
vgmstream->codec_data = init_mpeg_custom(sf, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_STANDARD, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = mpeg_bytes_to_samples(sead.stream_size, mpeg_data);
vgmstream->num_samples = mpeg_bytes_to_samples(sead.stream_size, vgmstream->codec_data);
vgmstream->loop_start_sample = sead.loop_start;
vgmstream->loop_end_sample = sead.loop_end;
break;

View File

@ -154,7 +154,6 @@ VGMSTREAM * init_vgmstream_ubi_lyn(STREAMFILE *streamFile) {
#ifdef VGM_USE_MPEG
case 0x5051: { /* MPEG (PS3/PC), interleaved 1ch */
mpeg_codec_data *mpeg_data = NULL;
mpeg_custom_config cfg = {0};
int i;
@ -175,9 +174,8 @@ VGMSTREAM * init_vgmstream_ubi_lyn(STREAMFILE *streamFile) {
cfg.data_size = data_size;
//todo data parsing looks correct but some files decode a bit wrong at the end (ex. Tintin: Music~Boss~Allan~Victory~02)
mpeg_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_LYN, &cfg);
if (!mpeg_data) goto fail;
vgmstream->codec_data = mpeg_data;
vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_LYN, &cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
break;

View File

@ -163,16 +163,13 @@ VGMSTREAM *init_vgmstream_xmv_valve(STREAMFILE *streamFile) {
#endif
#ifdef VGM_USE_MPEG
case 0x03: { /* MP3 */
mpeg_codec_data *mpeg_data;
coding_t mpeg_coding;
if (loop_flag) /* should never happen, Source cannot loop MP3 */
goto fail;
mpeg_data = init_mpeg(streamFile, start_offset, &mpeg_coding, channels);
if (!mpeg_data) goto fail;
vgmstream->codec_data = mpeg_data;
vgmstream->codec_data = init_mpeg(streamFile, start_offset, &mpeg_coding, channels);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = mpeg_coding;
vgmstream->layout_type = layout_none;

View File

@ -67,7 +67,7 @@ VGMSTREAM * init_vgmstream_xwc(STREAMFILE *streamFile) {
if (!vgmstream->codec_data) goto fail;
vgmstream->layout_type = layout_none;
vgmstream->sample_rate = ((mpeg_codec_data*)vgmstream->codec_data)->sample_rate_per_frame;
vgmstream->sample_rate = mpeg_get_sample_rate(vgmstream->codec_data);
break;
}
#endif

View File

@ -927,105 +927,6 @@ typedef struct {
} VGMSTREAM;
#ifdef VGM_USE_MPEG
/* Custom MPEG modes, mostly differing in the data layout */
typedef enum {
MPEG_STANDARD, /* 1 stream */
MPEG_AHX, /* 1 stream with false frame headers */
MPEG_XVAG, /* N streams of fixed interleave (frame-aligned, several data-frames of fixed size) */
MPEG_FSB, /* N streams of 1 data-frame+padding (=interleave) */
MPEG_P3D, /* N streams of fixed interleave (not frame-aligned) */
MPEG_SCD, /* N streams of fixed interleave (not frame-aligned) */
MPEG_EA, /* 1 stream (maybe N streams in absolute offsets?) */
MPEG_EAL31, /* EALayer3 v1 (SCHl), custom frames with v1 header */
MPEG_EAL31b, /* EALayer3 v1 (SNS), custom frames with v1 header + minor changes */
MPEG_EAL32P, /* EALayer3 v2 "PCM", custom frames with v2 header + bigger PCM blocks? */
MPEG_EAL32S, /* EALayer3 v2 "Spike", custom frames with v2 header + smaller PCM blocks? */
MPEG_LYN, /* N streams of fixed interleave */
MPEG_AWC, /* N streams in block layout (music) or absolute offsets (sfx) */
MPEG_EAMP3 /* custom frame header + MPEG frame + PCM blocks */
} mpeg_custom_t;
/* config for the above modes */
typedef struct {
int channels; /* max channels */
int fsb_padding; /* fsb padding mode */
int chunk_size; /* size of a data portion */
int data_size; /* playable size */
int interleave; /* size of stream interleave */
int encryption; /* encryption mode */
int big_endian;
int skip_samples;
/* for AHX */
int cri_type;
uint16_t cri_key1;
uint16_t cri_key2;
uint16_t cri_key3;
} mpeg_custom_config;
/* 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) */
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) */
int channels_per_frame; /* for rare cases that streams don't share this */
} mpeg_custom_stream;
typedef struct {
/* 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; /* MPEG decoder */
struct mpg123_frameinfo mi; /* start info, so it's available even when resetting */
/* for internal use */
int channels_per_frame;
int samples_per_frame;
/* for some calcs */
int bitrate_per_frame;
int sample_rate_per_frame;
/* custom MPEG internals */
int custom; /* flag */
mpeg_custom_t type; /* mpeg subtype */
mpeg_custom_config config; /* config depending on the mode */
size_t default_buffer_size;
mpeg_custom_stream **streams; /* array of MPEG streams (ex. 2ch+2ch) */
size_t streams_size;
size_t skip_samples; /* base encoder delay */
size_t samples_to_discard; /* for custom mpeg looping */
} mpeg_codec_data;
#endif
/* libacm interface */
typedef struct {
STREAMFILE* streamfile;
void* handle;
void* io_config;
} acm_codec_data;
/* for files made of "continuous" segments, one per section of a song (using a complete sub-VGMSTREAM) */
typedef struct {
int segment_count;
@ -1046,6 +947,15 @@ typedef struct {
} layered_layout_data;
/* libacm interface */
typedef struct {
STREAMFILE* streamfile;
void* handle;
void* io_config;
} acm_codec_data;
#ifdef VGM_USE_FFMPEG
typedef struct {
/*** IO internals ***/