mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-18 15:54:05 +01:00
mpeg decoder cleanup
This commit is contained in:
parent
73db56f327
commit
729e13ebb0
@ -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
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
108
src/vgmstream.h
108
src/vgmstream.h
@ -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 ***/
|
||||
|
Loading…
x
Reference in New Issue
Block a user