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

Refactored OpenAudio readers so they properly handle non-zero stream offset
Fixed a couple of streaming issues in OpenAudio AudioClip
Updated roadmap

BearishSun 9 éve
szülő
commit
d2e336ffa1

+ 1 - 0
Documentation/GitHub/roadmap.md

@@ -35,6 +35,7 @@ There are many more features planned, but these are without a specific timeline
  - Script debugging
  - Level of detail
  - XBONE/PS4 ports
+ - BSP brushes for level prototyping
  - And more to be decided later...
  
 Implementation times for each of those roughly ranges from 1-4 months.

+ 3 - 2
Source/BansheeOpenAudio/Include/BsOAFLACReader.h

@@ -16,6 +16,7 @@ namespace BansheeEngine
 	struct FLACDecoderData
 	{
 		SPtr<DataStream> stream;
+		UINT32 streamOffset = 0;
 		AudioFileInfo info;
 		UINT8* output = nullptr;
 		Vector<UINT8> overflow;
@@ -31,7 +32,7 @@ namespace BansheeEngine
 		~OAFLACReader();
 
 		/** @copydoc OAFileReader::open */
-		bool open(const SPtr<DataStream>& stream, AudioFileInfo& info) override;
+		bool open(const SPtr<DataStream>& stream, AudioFileInfo& info, UINT32 offset = 0) override;
 
 		/** @copydoc OAFileReader::seek */
 		void seek(UINT32 offset) override;
@@ -40,7 +41,7 @@ namespace BansheeEngine
 		UINT32 read(UINT8* samples, UINT32 numSamples) override;
 
 		/** @copydoc OAFileReader::isValid */
-		bool isValid(const SPtr<DataStream>& stream) override;
+		bool isValid(const SPtr<DataStream>& stream, UINT32 offset = 0) override;
 	private:
 		/** Cleans up the FLAC decoder. */
 		void close();

+ 7 - 2
Source/BansheeOpenAudio/Include/BsOAFileReader.h

@@ -21,9 +21,10 @@ namespace BansheeEngine
 		 *
 		 * @param[in]	stream	Data stream audio data is stored in.
 		 * @param[out]	info	Output information describing meta-data of the audio in the stream.
+		 * @param[in]	offset	Offset at which audio data in the stream begins, in bytes.
 		 * @return				True if the data is valid, false otherwise.
 		 */
-		virtual bool open(const SPtr<DataStream>& stream, AudioFileInfo& info) = 0;
+		virtual bool open(const SPtr<DataStream>& stream, AudioFileInfo& info, UINT32 offset = 0) = 0;
 
 		/** 
 		 * Moves the read pointer to the specified offset. Any further read() calls will read from this location. User must
@@ -48,8 +49,12 @@ namespace BansheeEngine
 		/** 
 		 * Checks if the data in the provided stream valid audio data for the current format. You should check this before
 		 * calling open().
+		 *
+		 * @param[in]	stream	Stream to check.
+		 * @param[in]	offset	Offset at which audio data in the stream begins, in bytes.
+		 * @return				True if the data is valid, false otherwise.
 		 */
-		virtual bool isValid(const SPtr<DataStream>& stream) = 0;
+		virtual bool isValid(const SPtr<DataStream>& stream, UINT32 offset = 0) = 0;
 	};
 
 	/** @} */

+ 14 - 3
Source/BansheeOpenAudio/Include/BsOAOggVorbisReader.h

@@ -12,6 +12,17 @@ namespace BansheeEngine
 	 *  @{
 	 */
 
+	/** Information used by the active decoder. */
+	struct OggDecoderData
+	{
+		OggDecoderData()
+			: offset(0)
+		{ }
+
+		SPtr<DataStream> stream;
+		UINT32 offset;
+	};
+
 	/** Used for reading Ogg Vorbis audio data. */
 	class OAOggVorbisReader : public OAFileReader
 	{
@@ -20,7 +31,7 @@ namespace BansheeEngine
 		~OAOggVorbisReader();
 
 		/** @copydoc OAFileReader::open */
-		bool open(const SPtr<DataStream>& stream, AudioFileInfo& info) override;
+		bool open(const SPtr<DataStream>& stream, AudioFileInfo& info, UINT32 offset = 0) override;
 
 		/** @copydoc OAFileReader::read */
 		UINT32 read(UINT8* samples, UINT32 numSamples) override;
@@ -29,9 +40,9 @@ namespace BansheeEngine
 		void seek(UINT32 offset) override;
 
 		/** @copydoc OAFileReader::isValid */
-		bool isValid(const SPtr<DataStream>& stream) override;
+		bool isValid(const SPtr<DataStream>& stream, UINT32 offset = 0) override;
 	private:
-		SPtr<DataStream> mStream;
+		OggDecoderData mDecoderData;
 		OggVorbis_File mOggVorbisFile;
 		UINT32 mChannelCount;
 	};

+ 2 - 2
Source/BansheeOpenAudio/Include/BsOAWaveReader.h

@@ -18,7 +18,7 @@ namespace BansheeEngine
 		OAWaveReader();
 
 		/** @copydoc OAFileReader::open */
-		bool open(const SPtr<DataStream>& stream, AudioFileInfo& info) override;
+		bool open(const SPtr<DataStream>& stream, AudioFileInfo& info, UINT32 offset = 0) override;
 
 		/** @copydoc OAFileReader::read */
 		UINT32 read(UINT8* samples, UINT32 numSamples) override;
@@ -27,7 +27,7 @@ namespace BansheeEngine
 		void seek(UINT32 offset) override;
 
 		/** @copydoc OAFileReader::isValid */
-		bool isValid(const SPtr<DataStream>& stream) override;
+		bool isValid(const SPtr<DataStream>& stream, UINT32 offset = 0) override;
 	private:
 		/** Parses the WAVE header and output audio file meta-data. Returns false if the header is not valid. */
 		bool parseHeader(AudioFileInfo& info);

+ 4 - 7
Source/BansheeOpenAudio/Source/BsOAAudioClip.cpp

@@ -61,7 +61,6 @@ namespace BansheeEngine
 					offset = mStreamOffset;
 				}
 
-				stream->seek(offset);
 				UINT32 bufferSize = info.numSamples * (info.bitDepth / 8);
 				UINT8* sampleBuffer = (UINT8*)bs_stack_alloc(bufferSize);
 
@@ -69,7 +68,7 @@ namespace BansheeEngine
 				if (mDesc.format == AudioFormat::VORBIS)
 				{
 					OAOggVorbisReader reader;
-					if (reader.open(stream, info))
+					if (reader.open(stream, info, offset))
 						reader.read(sampleBuffer, info.numSamples);
 					else
 						LOGERR("Failed decompressing AudioClip stream.");
@@ -77,6 +76,7 @@ namespace BansheeEngine
 				// Load directly
 				else
 				{
+					stream->seek(offset);
 					stream->read(sampleBuffer, bufferSize);
 				}
 
@@ -122,13 +122,10 @@ namespace BansheeEngine
 
 				if (mStreamData != nullptr)
 				{
-					if (!mVorbisReader.open(mStreamData, info))
+					if (!mVorbisReader.open(mStreamData, info, mStreamOffset))
 						LOGERR("Failed decompressing AudioClip stream.");
 				}
 			}
-
-			if (mStreamData != nullptr)
-				mStreamData->seek(mStreamOffset);
 		}
 
 		AudioClip::initialize();
@@ -139,7 +136,7 @@ namespace BansheeEngine
 		Lock lock(mMutex);
 
 		// Try to read from normal stream, and if that fails read from in-memory stream if it exists
-		if (mStreamData == nullptr)
+		if (mStreamData != nullptr)
 		{
 			if (mNeedsDecompression)
 			{

+ 10 - 8
Source/BansheeOpenAudio/Source/BsOAFLACReader.cpp

@@ -26,8 +26,8 @@ namespace BansheeEngine
 	{
 		FLACDecoderData* data = (FLACDecoderData*)(clientData);
 
-		data->stream->seek(absoluteByteOffset);
-		INT64 position = (INT64)data->stream->tell();
+		data->stream->seek(data->streamOffset + absoluteByteOffset);
+		INT64 position = (INT64)(data->stream->tell() - data->streamOffset);
 		if (position >= 0)
 			return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
 		else
@@ -38,7 +38,7 @@ namespace BansheeEngine
 	{
 		FLACDecoderData* data = (FLACDecoderData*)(clientData);
 
-		INT64 position = (INT64)data->stream->tell();
+		INT64 position = (INT64)(data->stream->tell() - data->streamOffset);
 		if (position >= 0)
 		{
 			*absoluteByteOffset = position;
@@ -54,7 +54,7 @@ namespace BansheeEngine
 	{
 		FLACDecoderData* data = (FLACDecoderData*)(clientData);
 
-		*streamLength = data->stream->size();
+		*streamLength = data->stream->size() - data->streamOffset;
 		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
 	}
 
@@ -143,9 +143,9 @@ namespace BansheeEngine
 		close();
 	}
 
-	bool OAFLACReader::isValid(const SPtr<DataStream>& stream)
+	bool OAFLACReader::isValid(const SPtr<DataStream>& stream, UINT32 offset)
 	{
-		stream->seek(0);
+		stream->seek(offset);
 
 		FLAC__StreamDecoder* decoder = FLAC__stream_decoder_new();
 		if (!decoder)
@@ -153,6 +153,7 @@ namespace BansheeEngine
 
 		FLACDecoderData data;
 		data.stream = stream;
+		mData.streamOffset = offset;
 		FLAC__stream_decoder_init_stream(decoder, &streamRead, &streamSeek, &streamTell, &streamLength, &streamEof, 
 			&streamWrite, nullptr, &streamError, &data);
 
@@ -164,12 +165,12 @@ namespace BansheeEngine
 		return valid && !data.error;
 	}
 
-	bool OAFLACReader::open(const SPtr<DataStream>& stream, AudioFileInfo& info)
+	bool OAFLACReader::open(const SPtr<DataStream>& stream, AudioFileInfo& info, UINT32 offset)
 	{
 		if (stream == nullptr)
 			return false;
 
-		stream->seek(0);
+		stream->seek(offset);
 
 		mDecoder = FLAC__stream_decoder_new();
 		if (mDecoder == nullptr)
@@ -179,6 +180,7 @@ namespace BansheeEngine
 		}
 
 		mData.stream = stream;
+		mData.streamOffset = offset;
 		FLAC__stream_decoder_init_stream(mDecoder, &streamRead, &streamSeek, &streamTell, &streamLength, &streamEof,
 			&streamWrite, &streamMetadata, &streamError, &mData);
 

+ 21 - 16
Source/BansheeOpenAudio/Source/BsOAOggVorbisReader.cpp

@@ -8,32 +8,34 @@ namespace BansheeEngine
 {
 	size_t oggRead(void* ptr, size_t size, size_t nmemb, void* data)
 	{
-		DataStream* stream = static_cast<DataStream*>(data);
-		return static_cast<std::size_t>(stream->read(ptr, size * nmemb));
+		OggDecoderData* decoderData = static_cast<OggDecoderData*>(data);
+		return static_cast<std::size_t>(decoderData->stream->read(ptr, size * nmemb));
 	}
 
 	int oggSeek(void* data, ogg_int64_t offset, int whence)
 	{
-		DataStream* stream = static_cast<DataStream*>(data);
+		OggDecoderData* decoderData = static_cast<OggDecoderData*>(data);
 		switch (whence)
 		{
 		case SEEK_SET:
+			offset += decoderData->offset;
 			break;
 		case SEEK_CUR:
-			offset += stream->tell();
+			offset += decoderData->stream->tell();
 			break;
 		case SEEK_END:
-			offset = stream->size() - offset;
+			offset = std::max(0, (INT32)decoderData->stream->size() - 1);
+			break;
 		}
 
-		stream->seek(offset);
-		return (int)stream->tell();
+		decoderData->stream->seek(offset);
+		return (int)(decoderData->stream->tell() - decoderData->offset);
 	}
 
 	long oggTell(void* data)
 	{
-		DataStream* stream = static_cast<DataStream*>(data);
-		return static_cast<long>(stream->tell());
+		OggDecoderData* decoderData = static_cast<OggDecoderData*>(data);
+		return (long)(decoderData->stream->tell() - decoderData->offset);
 	}
 
 	static ov_callbacks callbacks = { &oggRead, &oggSeek, nullptr, &oggTell };
@@ -50,12 +52,14 @@ namespace BansheeEngine
 			ov_clear(&mOggVorbisFile);
 	}
 
-	bool OAOggVorbisReader::isValid(const SPtr<DataStream>& stream)
+	bool OAOggVorbisReader::isValid(const SPtr<DataStream>& stream, UINT32 offset)
 	{
-		stream->seek(0);
+		stream->seek(offset);
+		mDecoderData.stream = stream;
+		mDecoderData.offset = offset;
 
 		OggVorbis_File file;
-		if (ov_test_callbacks(stream.get(), &file, nullptr, 0, callbacks) == 0)
+		if (ov_test_callbacks(&mDecoderData, &file, nullptr, 0, callbacks) == 0)
 		{
 			ov_clear(&file);
 			return true;
@@ -64,15 +68,16 @@ namespace BansheeEngine
 		return false;
 	}
 
-	bool OAOggVorbisReader::open(const SPtr<DataStream>& stream, AudioFileInfo& info)
+	bool OAOggVorbisReader::open(const SPtr<DataStream>& stream, AudioFileInfo& info, UINT32 offset)
 	{
 		if (stream == nullptr)
 			return false;
 
-		stream->seek(0);
-		mStream = stream;
+		stream->seek(offset);
+		mDecoderData.stream = stream;
+		mDecoderData.offset = offset;
 
-		int status = ov_open_callbacks(stream.get(), &mOggVorbisFile, nullptr, 0, callbacks);
+		int status = ov_open_callbacks(&mDecoderData, &mOggVorbisFile, nullptr, 0, callbacks);
 		if (status < 0)
 		{
 			LOGERR("Failed to open Ogg Vorbis file.");

+ 5 - 5
Source/BansheeOpenAudio/Source/BsOAWaveReader.cpp

@@ -12,9 +12,9 @@ namespace BansheeEngine
 		:mDataOffset(0), mBytesPerSample(0)
 	{ }
 
-	bool OAWaveReader::isValid(const SPtr<DataStream>& stream)
+	bool OAWaveReader::isValid(const SPtr<DataStream>& stream, UINT32 offset)
 	{
-		stream->seek(0);
+		stream->seek(offset);
 
 		INT8 header[MAIN_CHUNK_SIZE];
 		if (stream->read(header, sizeof(header)) < (sizeof(header)))
@@ -24,14 +24,14 @@ namespace BansheeEngine
 			&& (header[8] == 'W') && (header[9] == 'A') && (header[10] == 'V') && (header[11] == 'E');
 	}
 
-	bool OAWaveReader::open(const SPtr<DataStream>& stream, AudioFileInfo& info)
+	bool OAWaveReader::open(const SPtr<DataStream>& stream, AudioFileInfo& info, UINT32 offset)
 	{
 		if (stream == nullptr)
 			return false;
 
 		mStream = stream;
-		mStream->seek(MAIN_CHUNK_SIZE);
-
+		mStream->seek(offset + MAIN_CHUNK_SIZE);
+		
 		if (!parseHeader(info))
 		{
 			LOGERR("Provided file is not a valid WAVE file.");