Forráskód Böngészése

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.
Bart van Strien 6 éve
szülő
commit
c4b21b6efe
2 módosított fájl, 63 hozzáadás és 23 törlés
  1. 2 0
      changes.txt
  2. 61 23
      src/modules/sound/lullaby/Sound.cpp

+ 2 - 0
changes.txt

@@ -8,6 +8,8 @@ Released: N/A
 * Added love.window.get/setVSync, to allow setting vsync without recreating the window.
 * 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 love.math.hash returning an incorrect hash for certain input sizes.
 * Fixed t.audio.mixwithsystem.

+ 61 - 23
src/modules/sound/lullaby/Sound.cpp

@@ -21,6 +21,7 @@
 #include "common/config.h"
 
 #include <algorithm>
+#include <sstream>
 
 #include "Sound.h"
 
@@ -38,6 +39,27 @@
 #	include "CoreAudioDecoder.h"
 #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 sound
@@ -66,37 +88,53 @@ sound::Decoder *Sound::newDecoder(love::filesystem::FileData *data, int bufferSi
 	std::string ext = data->getExtension();
 	std::transform(ext.begin(), ext.end(), ext.begin(), tolower);
 
-	sound::Decoder *decoder = nullptr;
-
-	// Find a suitable decoder here, and return it.
-	if (false)
-		/* nothing */;
+	std::vector<DecoderImpl> possibleDecoders = {
 #ifndef LOVE_NO_MODPLUG
-	else if (ModPlugDecoder::accepts(ext))
-		decoder = new ModPlugDecoder(data, bufferSize);
+		DecoderImplFor<ModPlugDecoder>(),
 #endif // LOVE_NO_MODPLUG
 #ifndef LOVE_NOMPG123
-	else if (Mpg123Decoder::accepts(ext))
-		decoder = new Mpg123Decoder(data, bufferSize);
+		DecoderImplFor<Mpg123Decoder>(),
 #endif // LOVE_NOMPG123
-	else if (VorbisDecoder::accepts(ext))
-		decoder = new VorbisDecoder(data, bufferSize);
+		DecoderImplFor<VorbisDecoder>(),
 #ifdef LOVE_SUPPORT_GME
-	else if (GmeDecoder::accepts(ext))
-		decoder = new GmeDecoder(data, bufferSize);
+		DecoderImplFor<GmeDecoder>(),
 #endif // LOVE_SUPPORT_GME
 #ifdef LOVE_SUPPORT_COREAUDIO
-	else if (CoreAudioDecoder::accepts(ext))
-		decoder = new CoreAudioDecoder(data, bufferSize);
+		DecoderImplFor<CoreAudioDecoder>(),
 #endif
-	else if (WaveDecoder::accepts(ext))
-		decoder = new WaveDecoder(data, bufferSize);
-	/*else if (FLACDecoder::accepts(ext))
-		decoder = new FLACDecoder(data, bufferSize);*/
-
-	// else if (OtherDecoder::accept(ext))
-
-	return decoder;
+		DecoderImplFor<WaveDecoder>(),
+		// DecoderImplFor<FLACDecoder>(),
+		// DecoderImplFor<OtherDecoder>(),
+	};
+
+	// First find a matching decoder based on extension
+	for (DecoderImpl &possibleDecoder : possibleDecoders)
+	{
+		if (possibleDecoder.accepts(ext))
+			return possibleDecoder.create(data, bufferSize);
+	}
+
+	// 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