diff --git a/src/coding/coding.h b/src/coding/coding.h index 6854ccaf..cc9995a3 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -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 diff --git a/src/coding/mpeg_decoder.c b/src/coding/mpeg_decoder.c index 2ae7c045..0a6fcfab 100644 --- a/src/coding/mpeg_decoder.c +++ b/src/coding/mpeg_decoder.c @@ -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) { diff --git a/src/coding/mpeg_decoder.h b/src/coding/mpeg_decoder.h index a8f11733..e3181dfe 100644 --- a/src/coding/mpeg_decoder.h +++ b/src/coding/mpeg_decoder.h @@ -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); diff --git a/src/meta/msf.c b/src/meta/msf.c index 9dc94fd5..332dc643 100644 --- a/src/meta/msf.c +++ b/src/meta/msf.c @@ -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 */ } diff --git a/src/meta/sqex_scd.c b/src/meta/sqex_scd.c index 286a5f9d..35bb8bc0 100644 --- a/src/meta/sqex_scd.c +++ b/src/meta/sqex_scd.c @@ -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 diff --git a/src/meta/sqex_sead.c b/src/meta/sqex_sead.c index 09b32b9a..43de6e8f 100644 --- a/src/meta/sqex_sead.c +++ b/src/meta/sqex_sead.c @@ -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; diff --git a/src/meta/ubi_lyn.c b/src/meta/ubi_lyn.c index 4e8200b8..ceafaa04 100644 --- a/src/meta/ubi_lyn.c +++ b/src/meta/ubi_lyn.c @@ -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; diff --git a/src/meta/xmv_valve.c b/src/meta/xmv_valve.c index 966287a0..cf37a03b 100644 --- a/src/meta/xmv_valve.c +++ b/src/meta/xmv_valve.c @@ -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; diff --git a/src/meta/xwc.c b/src/meta/xwc.c index 3bd30ac2..659cf4ee 100644 --- a/src/meta/xwc.c +++ b/src/meta/xwc.c @@ -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 diff --git a/src/vgmstream.h b/src/vgmstream.h index aad6d4e5..24b8b464 100644 --- a/src/vgmstream.h +++ b/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 ***/