Try probing the audio type if extension matching fails (resolves #1487)

At the moment it still only tries a single decoder if it does find a matching extension. It might be a good idea to simply always probe, but try the matching decoder first, that way you could name your mp3 .ogg.
This commit is contained in:
Bart van Strien
2019-05-04 11:35:41 +02:00
parent 4662580059
commit c4b21b6efe
2 changed files with 61 additions and 21 deletions
+2
View File
@@ -8,6 +8,8 @@ Released: N/A
* Added love.window.get/setVSync, to allow setting vsync without recreating the window. * Added love.window.get/setVSync, to allow setting vsync without recreating the window.
* Added love.window.getSafeArea, currently only fully implemented on iOS. * Added love.window.getSafeArea, currently only fully implemented on iOS.
* Changed audio file type detection, so it probes all supported backends for unrecognized extensions.
* Fixed the deprecation system not fully restarting when love.event.quit("restart") is used. * Fixed the deprecation system not fully restarting when love.event.quit("restart") is used.
* Fixed love.math.hash returning an incorrect hash for certain input sizes. * Fixed love.math.hash returning an incorrect hash for certain input sizes.
* Fixed t.audio.mixwithsystem. * Fixed t.audio.mixwithsystem.
+59 -21
View File
@@ -21,6 +21,7 @@
#include "common/config.h" #include "common/config.h"
#include <algorithm> #include <algorithm>
#include <sstream>
#include "Sound.h" #include "Sound.h"
@@ -38,6 +39,27 @@
# include "CoreAudioDecoder.h" # include "CoreAudioDecoder.h"
#endif #endif
struct DecoderImpl
{
love::sound::Decoder *(*create)(love::filesystem::FileData *data, int bufferSize);
bool (*accepts)(const std::string& ext);
};
template<typename DecoderType>
DecoderImpl DecoderImplFor()
{
DecoderImpl decoderImpl;
decoderImpl.create = [](love::filesystem::FileData *data, int bufferSize) -> love::sound::Decoder*
{
return new DecoderType(data, bufferSize);
};
decoderImpl.accepts = [](const std::string& ext) -> bool
{
return DecoderType::accepts(ext);
};
return decoderImpl;
}
namespace love namespace love
{ {
namespace sound namespace sound
@@ -66,37 +88,53 @@ sound::Decoder *Sound::newDecoder(love::filesystem::FileData *data, int bufferSi
std::string ext = data->getExtension(); std::string ext = data->getExtension();
std::transform(ext.begin(), ext.end(), ext.begin(), tolower); std::transform(ext.begin(), ext.end(), ext.begin(), tolower);
sound::Decoder *decoder = nullptr; std::vector<DecoderImpl> possibleDecoders = {
// Find a suitable decoder here, and return it.
if (false)
/* nothing */;
#ifndef LOVE_NO_MODPLUG #ifndef LOVE_NO_MODPLUG
else if (ModPlugDecoder::accepts(ext)) DecoderImplFor<ModPlugDecoder>(),
decoder = new ModPlugDecoder(data, bufferSize);
#endif // LOVE_NO_MODPLUG #endif // LOVE_NO_MODPLUG
#ifndef LOVE_NOMPG123 #ifndef LOVE_NOMPG123
else if (Mpg123Decoder::accepts(ext)) DecoderImplFor<Mpg123Decoder>(),
decoder = new Mpg123Decoder(data, bufferSize);
#endif // LOVE_NOMPG123 #endif // LOVE_NOMPG123
else if (VorbisDecoder::accepts(ext)) DecoderImplFor<VorbisDecoder>(),
decoder = new VorbisDecoder(data, bufferSize);
#ifdef LOVE_SUPPORT_GME #ifdef LOVE_SUPPORT_GME
else if (GmeDecoder::accepts(ext)) DecoderImplFor<GmeDecoder>(),
decoder = new GmeDecoder(data, bufferSize);
#endif // LOVE_SUPPORT_GME #endif // LOVE_SUPPORT_GME
#ifdef LOVE_SUPPORT_COREAUDIO #ifdef LOVE_SUPPORT_COREAUDIO
else if (CoreAudioDecoder::accepts(ext)) DecoderImplFor<CoreAudioDecoder>(),
decoder = new CoreAudioDecoder(data, bufferSize);
#endif #endif
else if (WaveDecoder::accepts(ext)) DecoderImplFor<WaveDecoder>(),
decoder = new WaveDecoder(data, bufferSize); // DecoderImplFor<FLACDecoder>(),
/*else if (FLACDecoder::accepts(ext)) // DecoderImplFor<OtherDecoder>(),
decoder = new FLACDecoder(data, bufferSize);*/ };
// else if (OtherDecoder::accept(ext)) // First find a matching decoder based on extension
for (DecoderImpl &possibleDecoder : possibleDecoders)
{
if (possibleDecoder.accepts(ext))
return possibleDecoder.create(data, bufferSize);
}
return decoder; // If that fails, start probing instead
std::stringstream decodingErrors;
decodingErrors << "Failed to determine file type:\n";
for (DecoderImpl &possibleDecoder : possibleDecoders)
{
try
{
sound::Decoder *decoder = possibleDecoder.create(data, bufferSize);
return decoder;
}
catch (love::Exception &e)
{
decodingErrors << e.what() << '\n';
}
}
// Probing failed too, bail with the accumulated errors
throw love::Exception(decodingErrors.str().c_str());
// Unreachable, but here to prevent (possible) warnings
return nullptr;
} }
} // lullaby } // lullaby