From b347209bafce18de70338c0e62b0be4acd5f4251 Mon Sep 17 00:00:00 2001 From: Ozkan Sezer Date: Sat, 14 Dec 2019 18:10:10 +0300 Subject: [PATCH] backport commits db2d266 to 092f7e1 from default / 2.0: - move tag skip and SDL_RW with bookkeeping code into separate mp3utils.c - remove unnecessary file rewind calls in tag detection code. - music_mpg: use tag handling from mp3utils to avoid frame error reports - initial support for skipping the old MusicMatch tags --- Makefile.in | 2 +- VisualC/SDL_mixer.vcproj | 16 +- Xcode-iOS/SDL_mixer.xcodeproj/project.pbxproj | 16 + Xcode/SDL_mixer.xcodeproj/project.pbxproj | 12 + configure | 5 +- configure.in | 5 +- dynamic_mp3.c | 2 +- mp3utils.c | 374 ++++++++++++++++++ mp3utils.h | 34 ++ music_mad.c | 254 +----------- music_mad.h | 4 +- music_mpg.c | 19 +- music_mpg.h | 5 +- 13 files changed, 488 insertions(+), 260 deletions(-) create mode 100644 mp3utils.c create mode 100644 mp3utils.h diff --git a/Makefile.in b/Makefile.in index 66fd819c..dc1ed7e1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -39,7 +39,7 @@ VERSION_OBJECTS = @VERSION_OBJECTS@ PLAYWAVE_OBJECTS = @PLAYWAVE_OBJECTS@ PLAYMUS_OBJECTS = @PLAYMUS_OBJECTS@ -DIST = Android.mk CHANGES COPYING CWProjects.sea.bin MPWmake.sea.bin Makefile.in SDL_mixer.pc.in README SDL_mixer.h SDL_mixer.qpg.in SDL_mixer.spec SDL_mixer.spec.in VisualC Watcom-OS2.zip Xcode Xcode-iOS acinclude autogen.sh build-scripts configure configure.in dynamic_flac.c dynamic_flac.h dynamic_fluidsynth.c dynamic_fluidsynth.h dynamic_mod.c dynamic_mod.h dynamic_mp3.c dynamic_mp3.h dynamic_ogg.c dynamic_ogg.h effect_position.c effect_stereoreverse.c effects_internal.c effects_internal.h fluidsynth.c fluidsynth.h gcc-fat.sh libmikmod-3.1.12.zip load_aiff.c load_aiff.h load_flac.c load_flac.h load_ogg.c load_ogg.h load_voc.c load_voc.h mixer.c music.c music_cmd.c music_cmd.h music_flac.c music_flac.h music_mad.c music_mad.h music_mod.c music_mod.h music_modplug.c music_modplug.h music_ogg.c music_ogg.h native_midi playmus.c playwave.c timidity wavestream.c wavestream.h version.rc +DIST = Android.mk CHANGES COPYING CWProjects.sea.bin MPWmake.sea.bin Makefile.in SDL_mixer.pc.in README SDL_mixer.h SDL_mixer.qpg.in SDL_mixer.spec SDL_mixer.spec.in VisualC Watcom-OS2.zip Xcode Xcode-iOS acinclude autogen.sh build-scripts configure configure.in dynamic_flac.c dynamic_flac.h dynamic_fluidsynth.c dynamic_fluidsynth.h dynamic_mod.c dynamic_mod.h dynamic_mp3.c dynamic_mp3.h dynamic_ogg.c dynamic_ogg.h effect_position.c effect_stereoreverse.c effects_internal.c effects_internal.h fluidsynth.c fluidsynth.h gcc-fat.sh libmikmod-3.1.12.zip load_aiff.c load_aiff.h load_flac.c load_flac.h load_ogg.c load_ogg.h load_voc.c load_voc.h mixer.c mp3utils.c mp3utils.h music.c music_cmd.c music_cmd.h music_flac.c music_flac.h music_mad.c music_mad.h music_mod.c music_mod.h music_modplug.c music_modplug.h music_ogg.c music_ogg.h native_midi playmus.c playwave.c timidity wavestream.c wavestream.h version.rc LT_AGE = @LT_AGE@ LT_CURRENT = @LT_CURRENT@ diff --git a/VisualC/SDL_mixer.vcproj b/VisualC/SDL_mixer.vcproj index cb57aacd..0ee9d10a 100644 --- a/VisualC/SDL_mixer.vcproj +++ b/VisualC/SDL_mixer.vcproj @@ -884,19 +884,19 @@ > + + + + diff --git a/Xcode-iOS/SDL_mixer.xcodeproj/project.pbxproj b/Xcode-iOS/SDL_mixer.xcodeproj/project.pbxproj index a79ff1d4..9f36664e 100644 --- a/Xcode-iOS/SDL_mixer.xcodeproj/project.pbxproj +++ b/Xcode-iOS/SDL_mixer.xcodeproj/project.pbxproj @@ -14,6 +14,10 @@ 00938E57108A397A0009CF19 /* dynamic_ogg.h in Headers */ = {isa = PBXBuildFile; fileRef = 00938E4D108A397A0009CF19 /* dynamic_ogg.h */; }; 04A8FCA60A19CAEC0046373F /* dynamic_mp3.c in Sources */ = {isa = PBXBuildFile; fileRef = 04A8FCA40A19CAEC0046373F /* dynamic_mp3.c */; }; 04A8FCAB0A19CB070046373F /* dynamic_ogg.c in Sources */ = {isa = PBXBuildFile; fileRef = 04A8FCA90A19CB070046373F /* dynamic_ogg.c */; }; + 639090F823A5305400D5554E /* music_mpg.c in Sources */ = {isa = PBXBuildFile; fileRef = 639090F623A5305400D5554E /* music_mpg.c */; }; + 639090F923A5305400D5554E /* music_mpg.h in Headers */ = {isa = PBXBuildFile; fileRef = 639090F723A5305400D5554E /* music_mpg.h */; }; + 639090FC23A5306500D5554E /* mp3utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 639090FA23A5306500D5554E /* mp3utils.c */; }; + 639090FD23A5306500D5554E /* mp3utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 639090FB23A5306500D5554E /* mp3utils.h */; }; AA5F0F0914B6A6490036992F /* dynamic_fluidsynth.c in Sources */ = {isa = PBXBuildFile; fileRef = AA5F0F0214B6A6490036992F /* dynamic_fluidsynth.c */; }; AA5F0F0A14B6A6490036992F /* dynamic_fluidsynth.h in Headers */ = {isa = PBXBuildFile; fileRef = AA5F0F0314B6A6490036992F /* dynamic_fluidsynth.h */; }; AA5F0F0B14B6A6490036992F /* dynamic_mod.h in Headers */ = {isa = PBXBuildFile; fileRef = AA5F0F0414B6A6490036992F /* dynamic_mod.h */; }; @@ -116,6 +120,10 @@ 5CC1B898012FB8CD7F000001 /* timidity.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = timidity.h; sourceTree = ""; }; 5CC1B89B012FB8CD7F000001 /* wavestream.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = wavestream.c; path = ../wavestream.c; sourceTree = ""; }; 5CC1B89C012FB8CD7F000001 /* wavestream.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = wavestream.h; path = ../wavestream.h; sourceTree = ""; }; + 639090F623A5305400D5554E /* music_mpg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = music_mpg.c; path = ../music_mpg.c; sourceTree = SOURCE_ROOT; }; + 639090F723A5305400D5554E /* music_mpg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = music_mpg.h; path = ../music_mpg.h; sourceTree = SOURCE_ROOT; }; + 639090FA23A5306500D5554E /* mp3utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mp3utils.c; path = ../mp3utils.c; sourceTree = SOURCE_ROOT; }; + 639090FB23A5306500D5554E /* mp3utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mp3utils.h; path = ../mp3utils.h; sourceTree = SOURCE_ROOT; }; AA5F0F0214B6A6490036992F /* dynamic_fluidsynth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dynamic_fluidsynth.c; path = ../dynamic_fluidsynth.c; sourceTree = ""; }; AA5F0F0314B6A6490036992F /* dynamic_fluidsynth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dynamic_fluidsynth.h; path = ../dynamic_fluidsynth.h; sourceTree = ""; }; AA5F0F0414B6A6490036992F /* dynamic_mod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dynamic_mod.h; path = ../dynamic_mod.h; sourceTree = ""; }; @@ -184,6 +192,10 @@ 08FB77ACFE841707C02AAC07 /* Library Source */ = { isa = PBXGroup; children = ( + 639090FA23A5306500D5554E /* mp3utils.c */, + 639090FB23A5306500D5554E /* mp3utils.h */, + 639090F623A5305400D5554E /* music_mpg.c */, + 639090F723A5305400D5554E /* music_mpg.h */, 00938E49108A397A0009CF19 /* dynamic_flac.c */, 00938E4A108A397A0009CF19 /* dynamic_flac.h */, AA5F0F0214B6A6490036992F /* dynamic_fluidsynth.c */, @@ -295,6 +307,8 @@ AA5F0F0B14B6A6490036992F /* dynamic_mod.h in Headers */, AA5F0F0D14B6A6490036992F /* fluidsynth.h in Headers */, AA5F0F0F14B6A6490036992F /* music_modplug.h in Headers */, + 639090F923A5305400D5554E /* music_mpg.h in Headers */, + 639090FD23A5306500D5554E /* mp3utils.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -394,6 +408,8 @@ AA5F0F0914B6A6490036992F /* dynamic_fluidsynth.c in Sources */, AA5F0F0C14B6A6490036992F /* fluidsynth.c in Sources */, AA5F0F0E14B6A6490036992F /* music_modplug.c in Sources */, + 639090F823A5305400D5554E /* music_mpg.c in Sources */, + 639090FC23A5306500D5554E /* mp3utils.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Xcode/SDL_mixer.xcodeproj/project.pbxproj b/Xcode/SDL_mixer.xcodeproj/project.pbxproj index 354d702d..28eff5e5 100644 --- a/Xcode/SDL_mixer.xcodeproj/project.pbxproj +++ b/Xcode/SDL_mixer.xcodeproj/project.pbxproj @@ -37,6 +37,10 @@ 639076AC216EC43000ED9E54 /* music_mpg.c in Sources */ = {isa = PBXBuildFile; fileRef = 639076AA216EC43000ED9E54 /* music_mpg.c */; }; 639076AE216EC49000ED9E54 /* music_mpg.h in Headers */ = {isa = PBXBuildFile; fileRef = 639076AD216EC49000ED9E54 /* music_mpg.h */; }; 639076AF216EC49000ED9E54 /* music_mpg.h in Headers */ = {isa = PBXBuildFile; fileRef = 639076AD216EC49000ED9E54 /* music_mpg.h */; }; + 639090DF23A52FF400D5554E /* mp3utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 639090DD23A52FF400D5554E /* mp3utils.c */; }; + 639090E023A52FF400D5554E /* mp3utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 639090DE23A52FF400D5554E /* mp3utils.h */; }; + 639090E123A52FF400D5554E /* mp3utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 639090DD23A52FF400D5554E /* mp3utils.c */; }; + 639090E223A52FF400D5554E /* mp3utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 639090DE23A52FF400D5554E /* mp3utils.h */; }; 63CB2527216EC68100928244 /* mpg123.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 639076A3216EC3E200ED9E54 /* mpg123.framework */; }; AA9F7DB514B15ADC00278D1E /* Ogg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA9F7DB314B15ADC00278D1E /* Ogg.framework */; }; AA9F7DB614B15ADC00278D1E /* Vorbis.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA9F7DB414B15ADC00278D1E /* Vorbis.framework */; }; @@ -218,6 +222,8 @@ 639076A3216EC3E200ED9E54 /* mpg123.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = mpg123.framework; path = Frameworks/mpg123.framework; sourceTree = ""; }; 639076AA216EC43000ED9E54 /* music_mpg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = music_mpg.c; path = ../music_mpg.c; sourceTree = SOURCE_ROOT; }; 639076AD216EC49000ED9E54 /* music_mpg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = music_mpg.h; path = ../music_mpg.h; sourceTree = SOURCE_ROOT; }; + 639090DD23A52FF400D5554E /* mp3utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mp3utils.c; path = ../mp3utils.c; sourceTree = SOURCE_ROOT; }; + 639090DE23A52FF400D5554E /* mp3utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mp3utils.h; path = ../mp3utils.h; sourceTree = SOURCE_ROOT; }; AA9F7DB314B15ADC00278D1E /* Ogg.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Ogg.framework; path = Frameworks/Ogg.framework; sourceTree = ""; }; AA9F7DB414B15ADC00278D1E /* Vorbis.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Vorbis.framework; path = Frameworks/Vorbis.framework; sourceTree = ""; }; AA9F7DB714B15AE700278D1E /* FLAC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FLAC.framework; path = Frameworks/FLAC.framework; sourceTree = ""; }; @@ -308,6 +314,8 @@ 08FB77ACFE841707C02AAC07 /* Library Source */ = { isa = PBXGroup; children = ( + 639090DD23A52FF400D5554E /* mp3utils.c */, + 639090DE23A52FF400D5554E /* mp3utils.h */, 639076AD216EC49000ED9E54 /* music_mpg.h */, 639076AA216EC43000ED9E54 /* music_mpg.c */, 00938E49108A397A0009CF19 /* dynamic_flac.c */, @@ -466,6 +474,7 @@ 00938E51108A397A0009CF19 /* dynamic_mp3.h in Headers */, 00938E52108A397A0009CF19 /* dynamic_ogg.h in Headers */, 639076AE216EC49000ED9E54 /* music_mpg.h in Headers */, + 639090E023A52FF400D5554E /* mp3utils.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -496,6 +505,7 @@ 00938E56108A397A0009CF19 /* dynamic_mp3.h in Headers */, 00938E57108A397A0009CF19 /* dynamic_ogg.h in Headers */, 639076AF216EC49000ED9E54 /* music_mpg.h in Headers */, + 639090E223A52FF400D5554E /* mp3utils.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -695,6 +705,7 @@ 00938E50108A397A0009CF19 /* dynamic_mod.c in Sources */, 0448E8AE108B937A00C9D3EA /* native_midi_macosx.c in Sources */, 639076AB216EC43000ED9E54 /* music_mpg.c in Sources */, + 639090DF23A52FF400D5554E /* mp3utils.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -732,6 +743,7 @@ 00938E55108A397A0009CF19 /* dynamic_mod.c in Sources */, 0448E8AF108B937A00C9D3EA /* native_midi_macosx.c in Sources */, 639076AC216EC43000ED9E54 /* music_mpg.c in Sources */, + 639090E123A52FF400D5554E /* mp3utils.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/configure b/configure index d7341c90..59097d04 100755 --- a/configure +++ b/configure @@ -14883,6 +14883,7 @@ else enable_music_mp3_shared=yes fi +have_mpg123=no if test x$enable_music_mp3 = xyes; then if test "${ac_cv_header_mpg123_h+set}" = set; then { $as_echo "$as_me:$LINENO: checking for mpg123.h" >&5 @@ -15119,10 +15120,10 @@ else enable_music_mp3_mad_gpl=no fi +have_libmad=no if test x$enable_music_mp3_mad_gpl = xyes; then { $as_echo "$as_me:$LINENO: checking for libmad headers" >&5 $as_echo_n "checking for libmad headers... " >&6; } - have_libmad=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF @@ -15185,6 +15186,8 @@ fi if test x$have_mpg123 != xyes -a x$have_libmad != xyes; then { $as_echo "$as_me:$LINENO: WARNING: MP3 support disabled" >&5 $as_echo "$as_me: WARNING: MP3 support disabled" >&2;} +else + SOURCES="$SOURCES $srcdir/mp3utils.c" fi EXTRA_LDFLAGS="$EXTRA_LDFLAGS $LIBM" diff --git a/configure.in b/configure.in index 33a06569..237d11ce 100644 --- a/configure.in +++ b/configure.in @@ -558,6 +558,7 @@ AC_HELP_STRING([--enable-music-mp3], [enable MP3 music via libmpg123 [[default=y AC_ARG_ENABLE([music-mp3-shared], AC_HELP_STRING([--enable-music-mp3-shared], [dynamically load MP3 support [[default=yes]]]), [], [enable_music_mp3_shared=yes]) +have_mpg123=no if test x$enable_music_mp3 = xyes; then AC_CHECK_HEADER([mpg123.h], [have_mpg123_hdr=yes]) AC_CHECK_LIB([mpg123], [mpg123_replace_reader_handle], [have_mpg123_lib=yes]) @@ -590,9 +591,9 @@ fi AC_ARG_ENABLE(music-mp3-mad-gpl, AC_HELP_STRING([--enable-music-mp3-mad-gpl], [enable MP3 music via libmad GPL code [[default=no]]]), [], [enable_music_mp3_mad_gpl=no]) +have_libmad=no if test x$enable_music_mp3_mad_gpl = xyes; then AC_MSG_CHECKING(for libmad headers) - have_libmad=no AC_TRY_COMPILE([ #include "mad.h" ],[ @@ -611,6 +612,8 @@ fi if test x$have_mpg123 != xyes -a x$have_libmad != xyes; then AC_MSG_WARN([MP3 support disabled]) +else + SOURCES="$SOURCES $srcdir/mp3utils.c" fi EXTRA_LDFLAGS="$EXTRA_LDFLAGS $LIBM" diff --git a/dynamic_mp3.c b/dynamic_mp3.c index 5b0f6ed4..00f6918c 100644 --- a/dynamic_mp3.c +++ b/dynamic_mp3.c @@ -57,7 +57,7 @@ int Mix_InitMP3(void) FUNCTION_LOADER(mpg123_new, mpg123_handle *(*)(const char* decoder, int *error)) FUNCTION_LOADER(mpg123_open_handle, int (*)(mpg123_handle *mh, void *iohandle)) FUNCTION_LOADER(mpg123_plain_strerror, const char* (*)(int errcode)) - FUNCTION_LOADER(mpg123_rates, void (*)(const long **list, size_t *number)); + FUNCTION_LOADER(mpg123_rates, void (*)(const long **list, size_t *number)) FUNCTION_LOADER(mpg123_read, int (*)(mpg123_handle *mh, unsigned char *outmemory, size_t outmemsize, size_t *done )) FUNCTION_LOADER(mpg123_replace_reader_handle, int (*)( mpg123_handle *mh, ssize_t (*r_read) (void *, void *, size_t), off_t (*r_lseek)(void *, off_t, int), void (*cleanup)(void*) )) FUNCTION_LOADER(mpg123_seek, off_t (*)( mpg123_handle *mh, off_t sampleoff, int whence )) diff --git a/mp3utils.c b/mp3utils.c new file mode 100644 index 00000000..dd65f17a --- /dev/null +++ b/mp3utils.c @@ -0,0 +1,374 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "SDL_stdinc.h" +#include "SDL_rwops.h" + +#include "mp3utils.h" + +#if defined(MP3_MAD_MUSIC) || defined(MP3_MUSIC) + +/*********************** SDL_RW WITH BOOKKEEPING ************************/ + +int MP3_RWread(struct mp3file_t *fil, void *ptr, int size, int maxnum) { + int remaining = fil->length - fil->pos; + int ret; + maxnum *= size; + if (maxnum > remaining) maxnum = remaining; + ret = SDL_RWread(fil->rw, ptr, 1, maxnum); + if (ret > 0) fil->pos += ret; + return ret; +} + +int MP3_RWseek(struct mp3file_t *fil, int offset, int whence) { + int ret; + switch (whence) { /* assumes a legal whence value */ + case RW_SEEK_CUR: + offset += fil->pos; + break; + case RW_SEEK_END: + offset = fil->length + offset; + break; + } + if (offset < 0) return -1; + if (offset > fil->length) + offset = fil->length; + ret = SDL_RWseek(fil->rw, fil->start + offset, RW_SEEK_SET); + if (ret < 0) return ret; + fil->pos = offset; + return (fil->pos - fil->start); +} + + +/*************************** TAG HANDLING: ******************************/ + +static __inline__ SDL_bool is_id3v1(const unsigned char *data, int length) +{ + /* http://id3.org/ID3v1 : 3 bytes "TAG" identifier and 125 bytes tag data */ + if (length < 3 || SDL_memcmp(data,"TAG",3) != 0) { + return SDL_FALSE; + } + return SDL_TRUE; +} +static __inline__ SDL_bool is_id3v2(const unsigned char *data, int length) +{ + /* ID3v2 header is 10 bytes: http://id3.org/id3v2.4.0-structure */ + /* bytes 0-2: "ID3" identifier */ + if (length < 10 || SDL_memcmp(data,"ID3",3) != 0) { + return SDL_FALSE; + } + /* bytes 3-4: version num (major,revision), each byte always less than 0xff. */ + if (data[3] == 0xff || data[4] == 0xff) { + return SDL_FALSE; + } + /* bytes 6-9 are the ID3v2 tag size: a 32 bit 'synchsafe' integer, i.e. the + * highest bit 7 in each byte zeroed. i.e.: 7 bit information in each byte -> + * effectively a 28 bit value. */ + if (data[6] >= 0x80 || data[7] >= 0x80 || data[8] >= 0x80 || data[9] >= 0x80) { + return SDL_FALSE; + } + return SDL_TRUE; +} +static __inline__ int get_id3v2_len(const unsigned char *data, int length) +{ + /* size is a 'synchsafe' integer (see above) */ + int size = (int)((data[6]<<21) + (data[7]<<14) + (data[8]<<7) + data[9]); + size += 10; /* header size */ + /* ID3v2 header[5] is flags (bits 4-7 only, 0-3 are zero). + * bit 4 set: footer is present (a copy of the header but + * with "3DI" as ident.) */ + if (data[5] & 0x10) { + size += 10; /* footer size */ + } + /* optional padding (always zeroes) */ + while (size < length && data[size] == 0) { + ++size; + } + return size; +} +static __inline__ SDL_bool is_apetag(const unsigned char *data, int length) +{ + /* http://wiki.hydrogenaud.io/index.php?title=APEv2_specification + * Header/footer is 32 bytes: bytes 0-7 ident, bytes 8-11 version, + * bytes 12-17 size. bytes 24-31 are reserved: must be all zeroes. */ + Uint32 v; + + if (length < 32 || SDL_memcmp(data,"APETAGEX",8) != 0) { + return SDL_FALSE; + } + v = (Uint32)((data[11]<<24) | (data[10]<<16) | (data[9]<<8) | data[8]); /* version */ + if (v != 2000U && v != 1000U) { + return SDL_FALSE; + } + v = 0; /* reserved bits : */ + if (SDL_memcmp(&data[24],&v,4) != 0 || SDL_memcmp(&data[28],&v,4) != 0) { + return SDL_FALSE; + } + return SDL_TRUE; +} +static __inline__ int get_ape_len(const unsigned char *data) +{ + Uint32 flags, version; + int size = (int)((data[15]<<24) | (data[14]<<16) | (data[13]<<8) | data[12]); + version = (Uint32)((data[11]<<24) | (data[10]<<16) | (data[9]<<8) | data[8]); + flags = (Uint32)((data[23]<<24) | (data[22]<<16) | (data[21]<<8) | data[20]); + if (version == 2000U && (flags & (1U<<31))) size += 32; /* header present. */ + return size; +} +static __inline__ int is_lyrics3tag(const unsigned char *data, int length) { + /* http://id3.org/Lyrics3 + * http://id3.org/Lyrics3v2 */ + if (length < 15) return 0; + if (SDL_memcmp(data+6,"LYRICS200",9) == 0) return 2; /* v2 */ + if (SDL_memcmp(data+6,"LYRICSEND",9) == 0) return 1; /* v1 */ + return 0; +} +static __inline__ int get_lyrics3v1_len(struct mp3file_t *m) { + const char *p; int i, len; + char buf[5104]; + /* needs manual search: http://id3.org/Lyrics3 */ + if (m->length < 20) return -1; + len = (m->length > 5109)? 5109 : m->length; + MP3_RWseek(m, -len, RW_SEEK_END); + MP3_RWread(m, buf, 1, (len -= 9)); /* exclude footer */ + /* strstr() won't work here. */ + for (i = len - 11, p = buf; i >= 0; --i, ++p) { + if (SDL_memcmp(p, "LYRICSBEGIN", 11) == 0) + break; + } + if (i < 0) return -1; + return len - (int)(p - buf) + 9 /* footer */; +} +static __inline__ int get_lyrics3v2_len(const unsigned char *data, int length) { + /* 6 bytes before the end marker is size in decimal format - + * does not include the 9 bytes end marker and size field. */ + if (length != 6) return 0; + return SDL_strtol((const char *)data, NULL, 10) + 15; +} +static __inline__ SDL_bool verify_lyrics3v2(const unsigned char *data, int length) { + if (length < 11) return SDL_FALSE; + if (SDL_memcmp(data,"LYRICSBEGIN",11) == 0) return SDL_TRUE; + return SDL_FALSE; +} +#define MMTAG_PARANOID +static __inline__ SDL_bool is_musicmatch(const unsigned char *data, int length) { + /* From docs/musicmatch.txt in id3lib: https://sourceforge.net/projects/id3lib/ + Overall tag structure: + + +-----------------------------+ + | Header | + | (256 bytes, OPTIONAL) | + +-----------------------------+ + | Image extension (4 bytes) | + +-----------------------------+ + | Image binary | + | (var. length >= 4 bytes) | + +-----------------------------+ + | Unused (4 bytes) | + +-----------------------------+ + | Version info (256 bytes) | + +-----------------------------+ + | Audio meta-data | + | (var. length >= 7868 bytes) | + +-----------------------------+ + | Data offsets (20 bytes) | + +-----------------------------+ + | Footer (48 bytes) | + +-----------------------------+ + */ + if (length < 48) return SDL_FALSE; + /* sig: 19 bytes company name + 13 bytes space */ + if (SDL_memcmp(data,"Brava Software Inc. ",32) != 0) { + return SDL_FALSE; + } + /* 4 bytes version: x.xx */ + if (!SDL_isdigit(data[32]) || data[33] != '.' || + !SDL_isdigit(data[34]) ||!SDL_isdigit(data[35])) { + return SDL_FALSE; + } + #ifdef MMTAG_PARANOID + /* [36..47]: 12 bytes trailing space */ + for (length = 36; length < 48; ++length) { + if (data[length] != ' ') return SDL_FALSE; + } + #endif + return SDL_TRUE; +} +static __inline__ int get_musicmatch_len(struct mp3file_t *m) { + const Sint32 metasizes[4] = { 7868, 7936, 8004, 8132 }; + const unsigned char syncstr[10] = {'1','8','2','7','3','6','4','5',0,0}; + unsigned char buf[256]; + Sint32 i, j, imgext_ofs, version_ofs; + int len; + + MP3_RWseek(m, -68, RW_SEEK_END); + MP3_RWread(m, buf, 1, 20); + imgext_ofs = (Sint32)((buf[3] <<24) | (buf[2] <<16) | (buf[1] <<8) | buf[0] ); + version_ofs = (Sint32)((buf[15]<<24) | (buf[14]<<16) | (buf[13]<<8) | buf[12]); + if (version_ofs <= imgext_ofs) return -1; + if (version_ofs <= 0 || imgext_ofs <= 0) return -1; + /* Try finding the version info section: + * Because metadata section comes after it, and because metadata section + * has different sizes across versions (format ver. <= 3.00: always 7868 + * bytes), we can _not_ directly calculate using deltas from the offsets + * section. */ + for (i = 0; i < 4; ++i) { + /* 48: footer, 20: offsets, 256: version info */ + len = metasizes[i] + 48 + 20 + 256; + if (m->length < len) return -1; + MP3_RWseek(m, -len, RW_SEEK_END); + MP3_RWread(m, buf, 1, 256); + /* [0..9]: sync string, [30..255]: 0x20 */ + #ifdef MMTAG_PARANOID + for (j = 30; j < 256; ++j) { + if (buf[j] != ' ') break; + } + if (j < 256) continue; + #endif + if (SDL_memcmp(buf, syncstr, 10) == 0) { + break; + } + } + if (i == 4) return -1; /* no luck. */ + #ifdef MMTAG_PARANOID + /* unused section: (4 bytes of 0x00) */ + MP3_RWseek(m, -(len + 4), RW_SEEK_END); + MP3_RWread(m, buf, 1, 4); j = 0; + if (SDL_memcmp(buf, &j, 4) != 0) return -1; + #endif + len += (version_ofs - imgext_ofs); + if (m->length < len) return -1; + MP3_RWseek(m, -len, RW_SEEK_END); + MP3_RWread(m, buf, 1, 8); + j = (Sint32)((buf[7] <<24) | (buf[6] <<16) | (buf[5] <<8) | buf[4]); + if (j < 0) return -1; + /* verify image size: */ + /* without this, we may land at a wrong place. */ + if (j + 12 != version_ofs - imgext_ofs) return -1; + /* try finding the optional header */ + if (m->length < len + 256) return len; + MP3_RWseek(m, -(len + 256), RW_SEEK_END); + MP3_RWread(m, buf, 1, 256); + /* [0..9]: sync string, [30..255]: 0x20 */ + if (SDL_memcmp(buf, syncstr, 10) != 0) { + return len; + } + #ifdef MMTAG_PARANOID + for (j = 30; j < 256; ++j) { + if (buf[j] != ' ') return len; + } + #endif + return len + 256; /* header is present. */ +} + +int mp3_skiptags(struct mp3file_t *fil) +{ + unsigned char buf[128]; + int len, readsize; + int rc = -1; + + readsize = MP3_RWread(fil, buf, 1, 128); + if (readsize <= 0) goto fail; + + /* ID3v2 tag is at the start */ + if (is_id3v2(buf, readsize)) { + len = get_id3v2_len(buf, readsize); + if (len >= fil->length) goto fail; + fil->start += len; + fil->length -= len; + } + /* APE tag _might_ be at the start (discouraged + * but not forbidden, either.) read the header. */ + else if (is_apetag(buf, readsize)) { + len = get_ape_len(buf); + if (len >= fil->length) goto fail; + fil->start += len; + fil->length -= len; + } + + /* ID3v1 tag is at the end */ + if (fil->length >= 128) { + MP3_RWseek(fil, -128, RW_SEEK_END); + readsize = MP3_RWread(fil, buf, 1, 128); + if (readsize != 128) goto fail; + if (is_id3v1(buf, 128)) { + fil->length -= 128; + /* FIXME: handle possible double-ID3v1 tags?? */ + } + } + + /* do we know whether ape or lyrics3 is the first? + * well, we don't: we need to handle that later... */ + + /* check for the _old_ MusicMatch tag at end. */ + if (fil->length >= 68) { + MP3_RWseek(fil, -48, RW_SEEK_END); + readsize = MP3_RWread(fil, buf, 1, 48); + if (readsize != 48) goto fail; + if (is_musicmatch(buf, 48)) { + len = get_musicmatch_len(fil); + if (len < 0) goto fail; + if (len >= fil->length) goto fail; + fil->length -= len; + } + } + + /* APE tag may be at the end: read the footer */ + if (fil->length >= 32) { + MP3_RWseek(fil, -32, RW_SEEK_END); + readsize = MP3_RWread(fil, buf, 1, 32); + if (readsize != 32) goto fail; + if (is_apetag(buf, 32)) { + len = get_ape_len(buf); + if (len >= fil->length) goto fail; + fil->length -= len; + } + } + + if (fil->length >= 15) { + MP3_RWseek(fil, -15, RW_SEEK_END); + readsize = MP3_RWread(fil, buf, 1, 15); + if (readsize != 15) goto fail; + len = is_lyrics3tag(buf, 15); + if (len == 2) { + len = get_lyrics3v2_len(buf, 6); + if (len >= fil->length) goto fail; + if (len < 15) goto fail; + MP3_RWseek(fil, -len, RW_SEEK_END); + readsize = MP3_RWread(fil, buf, 1, 11); + if (readsize != 11) goto fail; + if (!verify_lyrics3v2(buf, 11)) goto fail; + fil->length -= len; + } + else if (len == 1) { + len = get_lyrics3v1_len(fil); + if (len < 0) goto fail; + fil->length -= len; + } + } + + rc = (fil->length > 0)? 0 : -1; + fail: + MP3_RWseek(fil, 0, RW_SEEK_SET); + return rc; +} + +#endif /* MP3_???_MUSIC */ diff --git a/mp3utils.h b/mp3utils.h new file mode 100644 index 00000000..e2cd7dc2 --- /dev/null +++ b/mp3utils.h @@ -0,0 +1,34 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef MP3UTILS_H_ +#define MP3UTILS_H_ + +struct mp3file_t { + SDL_RWops *rw; + int start, length, pos; +}; + +extern int mp3_skiptags(struct mp3file_t *fil); +extern int MP3_RWread(struct mp3file_t *fil, void *ptr, int size, int maxnum); +extern int MP3_RWseek(struct mp3file_t *fil, int offset, int whence); + +#endif /* MP3UTILS_H_ */ diff --git a/music_mad.c b/music_mad.c index 68767813..21846b84 100644 --- a/music_mad.c +++ b/music_mad.c @@ -25,48 +25,6 @@ #include "music_mad.h" -static int -MAD_RWread(mad_data *music, void *ptr, int size, int maxnum) { - int remaining = music->length - music->pos; - int ret; - maxnum *= size; - if (maxnum > remaining) maxnum = remaining; - ret = SDL_RWread(music->rw, ptr, 1, maxnum); - if (ret > 0) music->pos += ret; - return ret; -} - -static int -MAD_RWseek(mad_data *music, int offset, int whence) { - int ret; - switch (whence) { /* assumes a legal whence value */ - case RW_SEEK_CUR: - offset += music->pos; - break; - case RW_SEEK_END: - offset = music->length + offset; - break; - } - if (offset < 0) return -1; - if (offset > music->length) - offset = music->length; - ret = SDL_RWseek(music->rw, music->start + offset, RW_SEEK_SET); - if (ret < 0) return ret; - music->pos = offset; - return (music->pos - music->start); -} - -/* SDL-1.2 doesn't have a SDL_RWsize() */ -static int SDL12_RWsize(SDL_RWops *rw) { - int pos, size; - if ((pos=SDL_RWtell(rw))<0) return -1; - size = SDL_RWseek(rw, 0, RW_SEEK_END); - SDL_RWseek(rw, pos, RW_SEEK_SET); - return size; -} - -static int skip_tags (mad_data *); - mad_data * mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer, int freerw) { @@ -74,13 +32,15 @@ mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer, int freerw) mp3_mad = (mad_data *)SDL_malloc(sizeof(mad_data)); if (mp3_mad) { - mp3_mad->rw = rw; - mp3_mad->start = 0; - mp3_mad->pos = 0; - mp3_mad->length = SDL12_RWsize(rw); - if (skip_tags(mp3_mad) < 0) { + int pos = SDL_RWtell(rw); + mp3_mad->mp3file.rw = rw; + mp3_mad->mp3file.start = 0; + mp3_mad->mp3file.pos = 0; + mp3_mad->mp3file.length = SDL_RWseek(rw, 0, RW_SEEK_END); + SDL_RWseek(rw, pos, RW_SEEK_SET); + if (mp3_skiptags(&mp3_mad->mp3file) < 0) { SDL_free(mp3_mad); - Mix_SetError("music_mad: corrupt mp3 file."); + Mix_SetError("music_mad: corrupt mp3 file (bad tags.)"); return NULL; } mp3_mad->freerw = freerw; @@ -106,7 +66,7 @@ mad_closeFile(mad_data *mp3_mad) mad_synth_finish(&mp3_mad->synth); if (mp3_mad->freerw) { - SDL_RWclose(mp3_mad->rw); + SDL_RWclose(mp3_mad->mp3file.rw); } SDL_free(mp3_mad); } @@ -130,198 +90,6 @@ mad_isPlaying(mad_data *mp3_mad) { } -/*************************** TAG HANDLING: ******************************/ - -static __inline__ SDL_bool is_id3v1(const unsigned char *data, int length) -{ - /* http://id3.org/ID3v1 : 3 bytes "TAG" identifier and 125 bytes tag data */ - if (length < 3 || SDL_memcmp(data,"TAG",3) != 0) { - return SDL_FALSE; - } - return SDL_TRUE; -} -static __inline__ SDL_bool is_id3v2(const unsigned char *data, int length) -{ - /* ID3v2 header is 10 bytes: http://id3.org/id3v2.4.0-structure */ - /* bytes 0-2: "ID3" identifier */ - if (length < 10 || SDL_memcmp(data,"ID3",3) != 0) { - return SDL_FALSE; - } - /* bytes 3-4: version num (major,revision), each byte always less than 0xff. */ - if (data[3] == 0xff || data[4] == 0xff) { - return SDL_FALSE; - } - /* bytes 6-9 are the ID3v2 tag size: a 32 bit 'synchsafe' integer, i.e. the - * highest bit 7 in each byte zeroed. i.e.: 7 bit information in each byte -> - * effectively a 28 bit value. */ - if (data[6] >= 0x80 || data[7] >= 0x80 || data[8] >= 0x80 || data[9] >= 0x80) { - return SDL_FALSE; - } - return SDL_TRUE; -} -static __inline__ int get_id3v2_len(const unsigned char *data, int length) -{ - /* size is a 'synchsafe' integer (see above) */ - int size = (int)((data[6]<<21) + (data[7]<<14) + (data[8]<<7) + data[9]); - size += 10; /* header size */ - /* ID3v2 header[5] is flags (bits 4-7 only, 0-3 are zero). - * bit 4 set: footer is present (a copy of the header but - * with "3DI" as ident.) */ - if (data[5] & 0x10) { - size += 10; /* footer size */ - } - /* optional padding (always zeroes) */ - while (size < length && data[size] == 0) { - ++size; - } - return size; -} -static __inline__ SDL_bool is_apetag(const unsigned char *data, int length) -{ - /* http://wiki.hydrogenaud.io/index.php?title=APEv2_specification - * Header/footer is 32 bytes: bytes 0-7 ident, bytes 8-11 version, - * bytes 12-17 size. bytes 24-31 are reserved: must be all zeroes. */ - Uint32 v; - - if (length < 32 || SDL_memcmp(data,"APETAGEX",8) != 0) { - return SDL_FALSE; - } - v = (data[11]<<24) | (data[10]<<16) | (data[9]<<8) | data[8]; /* version */ - if (v != 2000U && v != 1000U) { - return SDL_FALSE; - } - v = 0; /* reserved bits : */ - if (SDL_memcmp(&data[24],&v,4) != 0 || SDL_memcmp(&data[28],&v,4) != 0) { - return SDL_FALSE; - } - return SDL_TRUE; -} -static __inline__ int get_ape_len(const unsigned char *data) -{ - Uint32 flags, version; - int size = (int)((data[15]<<24) | (data[14]<<16) | (data[13]<<8) | data[12]); - version = (data[11]<<24) | (data[10]<<16) | (data[9]<<8) | data[8]; - flags = (data[23]<<24) | (data[22]<<16) | (data[21]<<8) | data[20]; - if (version == 2000U && (flags & (1U<<31))) size += 32; /* header present. */ - return size; -} -static __inline__ int is_lyrics3tag(const unsigned char *data, int length) { - /* http://id3.org/Lyrics3 - * http://id3.org/Lyrics3v2 */ - if (length < 15) return 0; - if (SDL_memcmp(data+6,"LYRICS200",9) == 0) return 2; /* v2 */ - if (SDL_memcmp(data+6,"LYRICSEND",9) == 0) return 1; /* v1 */ - return 0; -} -static __inline__ int get_lyrics3v1_len(mad_data *m) { - const char *p; int i, len; - /* needs manual search: http://id3.org/Lyrics3 */ - /* this relies on the input_buffer size >= 5100 */ - if (m->length < 20) return -1; - len = (m->length > 5109)? 5109 : m->length; - MAD_RWseek(m, -len, RW_SEEK_END); - MAD_RWread(m, m->input_buffer, 1, (len -= 9)); /* exclude footer */ - MAD_RWseek(m, 0, RW_SEEK_SET); - /* strstr() won't work here. */ - for (i = len - 11, p = (const char*)m->input_buffer; i >= 0; --i, ++p) { - if (SDL_memcmp(p, "LYRICSBEGIN", 11) == 0) - break; - } - if (i < 0) return -1; - return len - (int)(p - (const char*)m->input_buffer) + 9 /* footer */; -} -static __inline__ int get_lyrics3v2_len(const unsigned char *data, int length) { - /* 6 bytes before the end marker is size in decimal format - - * does not include the 9 bytes end marker and size field. */ - if (length != 6) return 0; - return SDL_strtol((const char *)data, NULL, 10) + 15; -} -static __inline__ SDL_bool verify_lyrics3v2(const unsigned char *data, int length) { - if (length < 11) return SDL_FALSE; - if (SDL_memcmp(data,"LYRICSBEGIN",11) == 0) return SDL_TRUE; - return SDL_FALSE; -} - -static int skip_tags(mad_data *music) -{ - int len, readsize; - - readsize = MAD_RWread(music, music->input_buffer, 1, MAD_INPUT_BUFFER_SIZE); - if (readsize <= 0) return -1; - - /* ID3v2 tag is at the start */ - if (is_id3v2(music->input_buffer, readsize)) { - len = get_id3v2_len(music->input_buffer, readsize); - if (len >= music->length) return -1; - music->start += len; - music->length -= len; - MAD_RWseek(music, 0, RW_SEEK_SET); - } - /* APE tag _might_ be at the start (discouraged - * but not forbidden, either.) read the header. */ - else if (is_apetag(music->input_buffer, readsize)) { - len = get_ape_len(music->input_buffer); - if (len >= music->length) return -1; - music->start += len; - music->length -= len; - MAD_RWseek(music, 0, RW_SEEK_SET); - } - - /* ID3v1 tag is at the end */ - if (music->length < 128) goto ape; - MAD_RWseek(music, -128, RW_SEEK_END); - readsize = MAD_RWread(music, music->input_buffer, 1, 128); - MAD_RWseek(music, 0, RW_SEEK_SET); - if (readsize != 128) return -1; - if (is_id3v1(music->input_buffer, 128)) { - music->length -= 128; - - /* FIXME: handle possible double-ID3v1 tags?? */ - } - - /* do we know whether ape or lyrics3 is the first? - * well, we don't: we need to handle that later... */ - - ape: /* APE tag may be at the end: read the footer */ - if (music->length >= 32) { - MAD_RWseek(music, -32, RW_SEEK_END); - readsize = MAD_RWread(music, music->input_buffer, 1, 32); - MAD_RWseek(music, 0, RW_SEEK_SET); - if (readsize != 32) return -1; - if (is_apetag(music->input_buffer, 32)) { - len = get_ape_len(music->input_buffer); - if (len >= music->length) return -1; - music->length -= len; - } - } - - if (music->length >= 15) { - MAD_RWseek(music, -15, RW_SEEK_END); - readsize = MAD_RWread(music, music->input_buffer, 1, 15); - MAD_RWseek(music, 0, RW_SEEK_SET); - if (readsize != 15) return -1; - len = is_lyrics3tag(music->input_buffer, 15); - if (len == 2) { - len = get_lyrics3v2_len(music->input_buffer, 6); - if (len >= music->length) return -1; - if (len < 15) return -1; - MAD_RWseek(music, -len, RW_SEEK_END); - readsize = MAD_RWread(music, music->input_buffer, 1, 11); - MAD_RWseek(music, 0, RW_SEEK_SET); - if (readsize != 11) return -1; - if (!verify_lyrics3v2(music->input_buffer, 11)) return -1; - music->length -= len; - } - else if (len == 1) { - len = get_lyrics3v1_len(music); - if (len < 0) return -1; - music->length -= len; - } - } - - return (music->length > 0)? 0: -1; -} - /* Reads the next frame from the file. Returns true on success or false on failure. */ static int @@ -348,7 +116,7 @@ read_next_frame(mad_data *mp3_mad) { } /* Now read additional bytes from the input file. */ - read_size = MAD_RWread(mp3_mad, read_start, 1, read_size); + read_size = MP3_RWread(&mp3_mad->mp3file, read_start, 1, read_size); if (read_size <= 0) { if ((mp3_mad->status & (MS_input_eof | MS_input_error)) == 0) { @@ -539,7 +307,7 @@ mad_seek(mad_data *mp3_mad, double position) { mp3_mad->output_begin = 0; mp3_mad->output_end = 0; - MAD_RWseek(mp3_mad, 0, RW_SEEK_SET); + MP3_RWseek(&mp3_mad->mp3file, 0, RW_SEEK_SET); } /* Now we have to skip frames until we come to the right one. diff --git a/music_mad.h b/music_mad.h index b43b1105..81019fb4 100644 --- a/music_mad.h +++ b/music_mad.h @@ -25,6 +25,7 @@ #include "SDL_rwops.h" #include "SDL_audio.h" #include "SDL_mixer.h" +#include "mp3utils.h" #define MAD_INPUT_BUFFER_SIZE (5*8192) #define MAD_OUTPUT_BUFFER_SIZE 8192 @@ -41,8 +42,7 @@ enum { }; typedef struct { - SDL_RWops *rw; - int start, length, pos; + struct mp3file_t mp3file; int freerw; struct mad_stream stream; struct mad_frame frame; diff --git a/music_mpg.c b/music_mpg.c index 8da20dfb..9070c03f 100644 --- a/music_mpg.c +++ b/music_mpg.c @@ -83,12 +83,12 @@ mpg_err(mpg123_handle* mpg, int code) /* we're gonna override mpg123's I/O with these wrappers for RWops */ static ssize_t rwops_read(void* p, void* dst, size_t n) { - return (ssize_t)SDL_RWread((SDL_RWops*)p, dst, 1, n); + return (ssize_t)MP3_RWread((struct mp3file_t *)p, dst, 1, n); } static off_t rwops_seek(void* p, off_t offset, int whence) { - return (off_t)SDL_RWseek((SDL_RWops*)p, (Sint64)offset, whence); + return (off_t)MP3_RWseek((struct mp3file_t *)p, (int)offset, whence); } static @@ -103,6 +103,7 @@ mpg_data* mpg_new_rw(SDL_RWops *src, SDL_AudioSpec* mixer, int freesrc) { int fmt, result; + int pos; mpg_data* m = NULL; if (!Mix_Init(MIX_INIT_MP3)) { @@ -117,9 +118,17 @@ mpg_new_rw(SDL_RWops *src, SDL_AudioSpec* mixer, int freesrc) SDL_memset(m, 0, sizeof(mpg_data)); - m->src = src; + m->mp3file.rw = src; m->freesrc = freesrc; + pos = SDL_RWtell(src); + m->mp3file.length = SDL_RWseek(src, 0, RW_SEEK_END); + SDL_RWseek(src, pos, RW_SEEK_SET); + if (mp3_skiptags(&m->mp3file) < 0) { + Mix_SetError("music_mpg: corrupt mp3 file (bad tags.)"); + goto fail; + } + m->handle = mpg123.mpg123_new(0, &result); if (result != MPG123_OK) { goto fail; @@ -148,7 +157,7 @@ mpg_new_rw(SDL_RWops *src, SDL_AudioSpec* mixer, int freesrc) goto fail; } - result = mpg123.mpg123_open_handle(m->handle, m->src); + result = mpg123.mpg123_open_handle(m->handle, &m->mp3file); if (result != MPG123_OK) { goto fail; } @@ -188,7 +197,7 @@ mpg_delete(mpg_data* m) } if (m->freesrc) { - SDL_RWclose(m->src); + SDL_RWclose(m->mp3file.rw); } if (m->cvt.buf) { diff --git a/music_mpg.h b/music_mpg.h index 0b1eda07..d118be80 100644 --- a/music_mpg.h +++ b/music_mpg.h @@ -22,10 +22,12 @@ #ifdef MP3_MUSIC #include +#include "SDL_rwops.h" +#include "mp3utils.h" typedef struct { - SDL_RWops* src; + struct mp3file_t mp3file; int freesrc; SDL_AudioSpec mixer; @@ -55,4 +57,3 @@ void mpg_seek(mpg_data* m, double seconds); void mpg_volume(mpg_data* m, int volume); #endif -