Quellcode durchsuchen

Fixing Vorbis compression

BearishSun vor 9 Jahren
Ursprung
Commit
8a18861996

+ 2 - 0
Source/BansheeOpenAudio/Include/BsOAOggVorbisWriter.h

@@ -72,10 +72,12 @@ namespace BansheeEngine
 		UINT32 mBufferOffset;
 		UINT32 mNumChannels;
 		UINT32 mBitDepth;
+		bool mClosed;
 
 		ogg_stream_state mOggState;
 		vorbis_info mVorbisInfo;
 		vorbis_dsp_state mVorbisState;
+		vorbis_block mVorbisBlock;
 	};
 
 	/** @} */

+ 67 - 59
Source/BansheeOpenAudio/Source/BsOAOggVorbisWriter.cpp

@@ -18,7 +18,7 @@ namespace BansheeEngine
 	}
 
 	OAOggVorbisWriter::OAOggVorbisWriter()
-		:mBufferOffset(0), mNumChannels(0), mBitDepth(0)
+		:mBufferOffset(0), mNumChannels(0), mBitDepth(0), mClosed(true)
 	{ }
 
 	OAOggVorbisWriter::~OAOggVorbisWriter()
@@ -38,7 +38,7 @@ namespace BansheeEngine
 
 		// Automatic bitrate management with quality 0.4 (~128 kbps for 44 KHz stereo sound)
 		INT32 status = vorbis_encode_init_vbr(&mVorbisInfo, numChannels, sampleRate, 0.4f);
-		if (status < 0)
+		if (status != 0)
 		{
 			LOGERR("Failed to write Ogg Vorbis file.");
 			close();
@@ -46,6 +46,7 @@ namespace BansheeEngine
 		}
 
 		vorbis_analysis_init(&mVorbisState, &mVorbisInfo);
+		vorbis_block_init(&mVorbisState, &mVorbisBlock);
 
 		// Generate header
 		vorbis_comment comment;
@@ -55,7 +56,7 @@ namespace BansheeEngine
 		status = vorbis_analysis_headerout(&mVorbisState, &comment, &headerPacket, &commentPacket, &codePacket);
 		vorbis_comment_clear(&comment);
 
-		if (status < 0)
+		if (status != 0)
 		{
 			LOGERR("Failed to write Ogg Vorbis file.");
 			close();
@@ -79,84 +80,88 @@ namespace BansheeEngine
 
 	void OAOggVorbisWriter::write(UINT8* samples, UINT32 numSamples)
 	{
-		// Allocate new buffer and write PCM data to it
-		UINT32 numFrames = numSamples / mNumChannels;
-		float** buffer = vorbis_analysis_buffer(&mVorbisState, numFrames);
+		static const UINT32 WRITE_LENGTH = 1024;
 
-		if (mBitDepth == 8)
+		UINT32 numFrames = numSamples / mNumChannels;
+		while (numFrames > 0)
 		{
-			for (UINT32 i = 0; i < numFrames; i++)
+			UINT32 numFramesToWrite = std::min(numFrames, WRITE_LENGTH);
+			float** buffer = vorbis_analysis_buffer(&mVorbisState, numFramesToWrite);
+
+			if (mBitDepth == 8)
 			{
-				for (UINT32 j = 0; j < mNumChannels; j++)
+				for (UINT32 i = 0; i < numFramesToWrite; i++)
 				{
-					UINT8 sample = *(UINT8*)samples;
-					float encodedSample = sample / 255.0f;
-					buffer[j][i] = encodedSample;
-
-					samples++;
+					for (UINT32 j = 0; j < mNumChannels; j++)
+					{
+						UINT8 sample = *(UINT8*)samples;
+						float encodedSample = sample / 255.0f;
+						buffer[j][i] = encodedSample;
+
+						samples++;
+					}
 				}
 			}
-		}
-		else if (mBitDepth == 16)
-		{
-			for (UINT32 i = 0; i < numFrames; i++)
+			else if (mBitDepth == 16)
 			{
-				for (UINT32 j = 0; j < mNumChannels; j++)
+				for (UINT32 i = 0; i < numFramesToWrite; i++)
 				{
-					INT16 sample = *(INT16*)samples;
-					float encodedSample = sample / 32767.0f;
-					buffer[j][i] = encodedSample;
-
-					samples += 2;
+					for (UINT32 j = 0; j < mNumChannels; j++)
+					{
+						INT16 sample = *(INT16*)samples;
+						float encodedSample = sample / 32767.0f;
+						buffer[j][i] = encodedSample;
+
+						samples += 2;
+					}
 				}
 			}
-		}
-		else if (mBitDepth == 24)
-		{
-			for (UINT32 i = 0; i < numFrames; i++)
+			else if (mBitDepth == 24)
 			{
-				for (UINT32 j = 0; j < mNumChannels; j++)
+				for (UINT32 i = 0; i < numFramesToWrite; i++)
 				{
-					INT32 sample = AudioUtility::convert24To32Bits(samples);
-					float encodedSample = sample / 2147483647.0f;
-					buffer[j][i] = encodedSample;
-
-					samples += 3;
+					for (UINT32 j = 0; j < mNumChannels; j++)
+					{
+						INT32 sample = AudioUtility::convert24To32Bits(samples);
+						float encodedSample = sample / 2147483647.0f;
+						buffer[j][i] = encodedSample;
+
+						samples += 3;
+					}
 				}
 			}
-		}
-		else if (mBitDepth == 32)
-		{
-			for (UINT32 i = 0; i < numFrames; i++)
+			else if (mBitDepth == 32)
 			{
-				for (UINT32 j = 0; j < mNumChannels; j++)
+				for (UINT32 i = 0; i < numFramesToWrite; i++)
 				{
-					INT32 sample = *(INT32*)samples;
-					float encodedSample = sample / 2147483647.0f;
-					buffer[j][i] = encodedSample;
-
-					samples += 4;
+					for (UINT32 j = 0; j < mNumChannels; j++)
+					{
+						INT32 sample = *(INT32*)samples;
+						float encodedSample = sample / 2147483647.0f;
+						buffer[j][i] = encodedSample;
+
+						samples += 4;
+					}
 				}
 			}
-		}
-		else
-			assert(false);
+			else
+				assert(false);
 
-		// Signal how many frames were written
-		vorbis_analysis_wrote(&mVorbisState, numFrames);
-		writeBlocks();
+			// Signal how many frames were written
+			vorbis_analysis_wrote(&mVorbisState, numFramesToWrite);
+			writeBlocks();
+
+			numFrames -= numFramesToWrite;
+		}
 	}
 
 	void OAOggVorbisWriter::writeBlocks()
 	{
-		// Create a new block
-		vorbis_block block;
-		vorbis_block_init(&mVorbisState, &block);
-		while (vorbis_analysis_blockout(&mVorbisState, &block) == 1)
+		while (vorbis_analysis_blockout(&mVorbisState, &mVorbisBlock) == 1)
 		{
 			// Analyze and determine optimal bitrate
-			vorbis_analysis(&block, nullptr);
-			vorbis_bitrate_addblock(&block);
+			vorbis_analysis(&mVorbisBlock, nullptr);
+			vorbis_bitrate_addblock(&mVorbisBlock);
 
 			// Write block into ogg packets
 			ogg_packet packet;
@@ -173,9 +178,6 @@ namespace BansheeEngine
 				}
 			}
 		}
-
-		// Clear the allocated block
-		vorbis_block_clear(&block);
 	}
 
 	void OAOggVorbisWriter::flush()
@@ -188,14 +190,20 @@ namespace BansheeEngine
 
 	void OAOggVorbisWriter::close()
 	{
+		if (mClosed)
+			return;
+
 		// Mark end of data and flush any remaining data in the buffers
 		vorbis_analysis_wrote(&mVorbisState, 0);
 		writeBlocks();
 		flush();
 
 		ogg_stream_clear(&mOggState);
+		vorbis_block_clear(&mVorbisBlock);
 		vorbis_dsp_clear(&mVorbisState);
 		vorbis_info_clear(&mVorbisInfo);
+
+		mClosed = true;
 	}
 
 	UINT8* OAOggVorbisWriter::PCMToOggVorbis(UINT8* samples, const AudioFileInfo& info, UINT32& size)