BsOggVorbisEncoder.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. #include "BsOggVorbisEncoder.h"
  2. #include "FileSystem/BsDataStream.h"
  3. #include "Audio/BsAudioUtility.h"
  4. namespace bs
  5. {
  6. // Writes to the internal cached buffer and flushes it if needed
  7. #define WRITE_TO_BUFFER(data, length) \
  8. if ((mBufferOffset + length) > BUFFER_SIZE) \
  9. flush(); \
  10. \
  11. if(length > BUFFER_SIZE) \
  12. mWriteCallback(data, length); \
  13. else \
  14. { \
  15. memcpy(mBuffer + mBufferOffset, data, length); \
  16. mBufferOffset += length; \
  17. }
  18. OggVorbisEncoder::OggVorbisEncoder()
  19. :mBufferOffset(0), mNumChannels(0), mBitDepth(0), mClosed(true)
  20. { }
  21. OggVorbisEncoder::~OggVorbisEncoder()
  22. {
  23. close();
  24. }
  25. bool OggVorbisEncoder::open(std::function<void(UINT8*, UINT32)> writeCallback, UINT32 sampleRate, UINT32 bitDepth,
  26. UINT32 numChannels)
  27. {
  28. mNumChannels = numChannels;
  29. mBitDepth = bitDepth;
  30. mWriteCallback = writeCallback;
  31. mClosed = false;
  32. ogg_stream_init(&mOggState, std::rand());
  33. vorbis_info_init(&mVorbisInfo);
  34. // Automatic bitrate management with quality 0.4 (~128 kbps for 44 KHz stereo sound)
  35. INT32 status = vorbis_encode_init_vbr(&mVorbisInfo, numChannels, sampleRate, 0.4f);
  36. if (status != 0)
  37. {
  38. LOGERR("Failed to write Ogg Vorbis file.");
  39. close();
  40. return false;
  41. }
  42. vorbis_analysis_init(&mVorbisState, &mVorbisInfo);
  43. vorbis_block_init(&mVorbisState, &mVorbisBlock);
  44. // Generate header
  45. vorbis_comment comment;
  46. vorbis_comment_init(&comment);
  47. ogg_packet headerPacket, commentPacket, codePacket;
  48. status = vorbis_analysis_headerout(&mVorbisState, &comment, &headerPacket, &commentPacket, &codePacket);
  49. vorbis_comment_clear(&comment);
  50. if (status != 0)
  51. {
  52. LOGERR("Failed to write Ogg Vorbis file.");
  53. close();
  54. return false;
  55. }
  56. // Write header
  57. ogg_stream_packetin(&mOggState, &headerPacket);
  58. ogg_stream_packetin(&mOggState, &commentPacket);
  59. ogg_stream_packetin(&mOggState, &codePacket);
  60. ogg_page page;
  61. while (ogg_stream_flush(&mOggState, &page) > 0)
  62. {
  63. WRITE_TO_BUFFER(page.header, page.header_len);
  64. WRITE_TO_BUFFER(page.body, page.body_len);
  65. }
  66. return true;
  67. }
  68. void OggVorbisEncoder::write(UINT8* samples, UINT32 numSamples)
  69. {
  70. static const UINT32 WRITE_LENGTH = 1024;
  71. UINT32 numFrames = numSamples / mNumChannels;
  72. while (numFrames > 0)
  73. {
  74. UINT32 numFramesToWrite = std::min(numFrames, WRITE_LENGTH);
  75. float** buffer = vorbis_analysis_buffer(&mVorbisState, numFramesToWrite);
  76. if (mBitDepth == 8)
  77. {
  78. for (UINT32 i = 0; i < numFramesToWrite; i++)
  79. {
  80. for (UINT32 j = 0; j < mNumChannels; j++)
  81. {
  82. INT8 sample = *(INT8*)samples;
  83. float encodedSample = sample / 127.0f;
  84. buffer[j][i] = encodedSample;
  85. samples++;
  86. }
  87. }
  88. }
  89. else if (mBitDepth == 16)
  90. {
  91. for (UINT32 i = 0; i < numFramesToWrite; i++)
  92. {
  93. for (UINT32 j = 0; j < mNumChannels; j++)
  94. {
  95. INT16 sample = *(INT16*)samples;
  96. float encodedSample = sample / 32767.0f;
  97. buffer[j][i] = encodedSample;
  98. samples += 2;
  99. }
  100. }
  101. }
  102. else if (mBitDepth == 24)
  103. {
  104. for (UINT32 i = 0; i < numFramesToWrite; i++)
  105. {
  106. for (UINT32 j = 0; j < mNumChannels; j++)
  107. {
  108. INT32 sample = AudioUtility::convert24To32Bits(samples);
  109. float encodedSample = sample / 2147483647.0f;
  110. buffer[j][i] = encodedSample;
  111. samples += 3;
  112. }
  113. }
  114. }
  115. else if (mBitDepth == 32)
  116. {
  117. for (UINT32 i = 0; i < numFramesToWrite; i++)
  118. {
  119. for (UINT32 j = 0; j < mNumChannels; j++)
  120. {
  121. INT32 sample = *(INT32*)samples;
  122. float encodedSample = sample / 2147483647.0f;
  123. buffer[j][i] = encodedSample;
  124. samples += 4;
  125. }
  126. }
  127. }
  128. else
  129. assert(false);
  130. // Signal how many frames were written
  131. vorbis_analysis_wrote(&mVorbisState, numFramesToWrite);
  132. writeBlocks();
  133. numFrames -= numFramesToWrite;
  134. }
  135. }
  136. void OggVorbisEncoder::writeBlocks()
  137. {
  138. while (vorbis_analysis_blockout(&mVorbisState, &mVorbisBlock) == 1)
  139. {
  140. // Analyze and determine optimal bitrate
  141. vorbis_analysis(&mVorbisBlock, nullptr);
  142. vorbis_bitrate_addblock(&mVorbisBlock);
  143. // Write block into ogg packets
  144. ogg_packet packet;
  145. while (vorbis_bitrate_flushpacket(&mVorbisState, &packet))
  146. {
  147. ogg_stream_packetin(&mOggState, &packet);
  148. // If new page, write it to the internal buffer
  149. ogg_page page;
  150. while (ogg_stream_flush(&mOggState, &page) > 0)
  151. {
  152. WRITE_TO_BUFFER(page.header, page.header_len);
  153. WRITE_TO_BUFFER(page.body, page.body_len);
  154. }
  155. }
  156. }
  157. }
  158. void OggVorbisEncoder::flush()
  159. {
  160. if (mBufferOffset > 0 && mWriteCallback != nullptr)
  161. mWriteCallback(mBuffer, mBufferOffset);
  162. mBufferOffset = 0;
  163. }
  164. void OggVorbisEncoder::close()
  165. {
  166. if (mClosed)
  167. return;
  168. // Mark end of data and flush any remaining data in the buffers
  169. vorbis_analysis_wrote(&mVorbisState, 0);
  170. writeBlocks();
  171. flush();
  172. ogg_stream_clear(&mOggState);
  173. vorbis_block_clear(&mVorbisBlock);
  174. vorbis_dsp_clear(&mVorbisState);
  175. vorbis_info_clear(&mVorbisInfo);
  176. mClosed = true;
  177. }
  178. UINT8* OggVorbisEncoder::PCMToOggVorbis(UINT8* samples, const AudioDataInfo& info, UINT32& size)
  179. {
  180. struct EncodedBlock
  181. {
  182. UINT8* data;
  183. UINT32 size;
  184. };
  185. Vector<EncodedBlock> blocks;
  186. UINT32 totalEncodedSize = 0;
  187. auto writeCallback = [&](UINT8* buffer, UINT32 size)
  188. {
  189. EncodedBlock newBlock;
  190. newBlock.data = bs_frame_alloc(size);
  191. newBlock.size = size;
  192. memcpy(newBlock.data, buffer, size);
  193. blocks.push_back(newBlock);
  194. totalEncodedSize += size;
  195. };
  196. bs_frame_mark();
  197. OggVorbisEncoder writer;
  198. writer.open(writeCallback, info.sampleRate, info.bitDepth, info.numChannels);
  199. writer.write(samples, info.numSamples);
  200. writer.close();
  201. UINT8* outSampleBuffer = (UINT8*)bs_alloc(totalEncodedSize);
  202. UINT32 offset = 0;
  203. for (auto& block : blocks)
  204. {
  205. memcpy(outSampleBuffer + offset, block.data, block.size);
  206. offset += block.size;
  207. bs_frame_free(block.data);
  208. }
  209. bs_frame_clear();
  210. size = totalEncodedSize;
  211. return outSampleBuffer;
  212. }
  213. #undef WRITE_TO_BUFFER
  214. }