22 #include "MALossyConverter.hpp" 24 #include "core/MANum.hpp" 26 #include <MCBinaryData.hpp> 28 #include <MCThreadLocalData.hpp> 30 #include <vorbis/codec.h> 31 #include <vorbis/vorbisenc.h> 32 #if defined(__unix__) || defined(__MINGW32__) || defined(__MINGW64__) 33 #define OV_EXCLUDE_STATIC_CALLBACKS 1 35 #include <vorbis/vorbisfile.h> 36 #include <ivorbisfile.h> 40 #include <boost/scoped_ptr.hpp> 47 void CheckStaticAudioCodingVariables()
49 if (unlikely(!CodingBuffer.get()))
53 if (unlikely(!DecodingBuffer.get()))
60 size_t ReadOgg(
void* dst,
size_t size1,
size_t size2,
void* fh)
71 int SeekOgg(
void* fh, ogg_int64_t to,
int type)
77 MC_WARNING(
"Can't go back in Ogg Vorbis decoding... (%d)", (
int)to);
123 long TellOgg(
void* fh)
132 const int channels,
const int quality)
137 boost::scoped_ptr<ogg_stream_state> OggStream(
new ogg_stream_state);
138 boost::scoped_ptr<ogg_packet> OggPacket(
new ogg_packet);
139 boost::scoped_ptr<ogg_page> OggPage(
new ogg_page);
140 boost::scoped_ptr<vorbis_info> VorbisInfo(
new vorbis_info);
141 boost::scoped_ptr<vorbis_comment> VorbisComment(
new vorbis_comment);
142 boost::scoped_ptr<vorbis_dsp_state> VorbisDsp(
new vorbis_dsp_state);
143 boost::scoped_ptr<vorbis_block> VorbisBlock(
new vorbis_block);
144 boost::scoped_ptr<ogg_packet> Header(
new ogg_packet);
145 boost::scoped_ptr<ogg_packet> HeaderComment(
new ogg_packet);
146 boost::scoped_ptr<ogg_packet> HeaderCode(
new ogg_packet);
147 int Quality = (int)
MANum<int>(quality, -2, 320);
149 CheckStaticAudioCodingVariables();
150 CodingBuffer->Allocate(raw_data.
GetSize()*2);
151 vorbis_info_init(&*VorbisInfo);
155 if (vorbis_encode_init_vbr(&*VorbisInfo, channels, sample_rate, (
float)Quality / 10))
157 MC_WARNING(
"Ogg Vorbis initialization failed.");
161 Quality =
MCMax(Quality, 32);
163 if (vorbis_encode_init(&*VorbisInfo, channels, sample_rate, -1, Quality*1000, -1))
165 MC_WARNING(
"Ogg Vorbis initialization failed.");
169 vorbis_comment_init(&*VorbisComment);
170 vorbis_analysis_init(&*VorbisDsp, &*VorbisInfo);
171 vorbis_block_init(&*VorbisDsp, &*VorbisBlock);
172 ogg_stream_init(&*OggStream,
MCRand(0, 1000000));
174 vorbis_analysis_headerout(&*VorbisDsp, &*VorbisComment, &*Header, &*HeaderComment, &*HeaderCode);
175 ogg_stream_packetin(&*OggStream, &*Header);
176 ogg_stream_packetin(&*OggStream, &*HeaderComment);
177 ogg_stream_packetin(&*OggStream, &*HeaderCode);
180 int Result = ogg_stream_flush(&*OggStream, &*OggPage);
185 memcpy(&CodingBuffer->GetData()[CodingBuffer->GetPosition()], (
const char*)OggPage->header, OggPage->header_len);
186 CodingBuffer->IncrementPosition(OggPage->header_len);
187 memcpy(&CodingBuffer->GetData()[CodingBuffer->GetPosition()], (
const char*)OggPage->body, OggPage->body_len);
188 CodingBuffer->IncrementPosition(OggPage->body_len);
192 const int SliceSize = 1024;
194 while (Position < raw_data.
GetSize())
196 int Size = ((raw_data.
GetSize()-Position < SliceSize) ? raw_data.
GetSize()-Position : SliceSize);
197 float** Buffer = vorbis_analysis_buffer(&*VorbisDsp, Size);
198 char* RawDataPtr = (
char*)&raw_data.
GetData()[Position];
203 for (
int i = 0; i < Size / 4 ; ++i)
205 Buffer[0][i] = ((RawDataPtr[i*4+1] << 8) | (0x00ff & (
int)RawDataPtr[i*4])) / 32768.f;
206 Buffer[1][i] = ((RawDataPtr[i*4+3] << 8) | (0x00ff & (
int)RawDataPtr[i*4+2])) / 32768.f;
208 vorbis_analysis_wrote(&*VorbisDsp, Size / 4);
210 for (
int i = 0; i < Size / 2 ; ++i)
212 Buffer[0][i] = ((RawDataPtr[i*2+1] << 8) | (0x00ff & (
int)RawDataPtr[i*2])) / 32768.f;
214 vorbis_analysis_wrote(&*VorbisDsp, Size / 2);
217 while (vorbis_analysis_blockout(&*VorbisDsp, &*VorbisBlock) == 1)
219 vorbis_analysis(&*VorbisBlock,
nullptr);
220 vorbis_bitrate_addblock(&*VorbisBlock);
222 while (vorbis_bitrate_flushpacket(&*VorbisDsp, &*OggPacket))
224 ogg_stream_packetin(&*OggStream, &*OggPacket);
228 int Result = ogg_stream_pageout(&*OggStream, &*OggPage);
233 memcpy(&CodingBuffer->GetData()[CodingBuffer->GetPosition()], (
const char*)OggPage->header, OggPage->header_len);
234 CodingBuffer->IncrementPosition(OggPage->header_len);
235 memcpy(&CodingBuffer->GetData()[CodingBuffer->GetPosition()], (
const char*)OggPage->body, OggPage->body_len);
236 CodingBuffer->IncrementPosition(OggPage->body_len);
243 vorbis_analysis_wrote(&*VorbisDsp, 0);
244 while (vorbis_analysis_blockout(&*VorbisDsp, &*VorbisBlock) == 1)
246 vorbis_analysis(&*VorbisBlock,
nullptr);
247 vorbis_bitrate_addblock(&*VorbisBlock);
249 while (vorbis_bitrate_flushpacket(&*VorbisDsp, &*OggPacket))
251 ogg_stream_packetin(&*OggStream, &*OggPacket);
255 int Result = ogg_stream_pageout(&*OggStream, &*OggPage);
260 memcpy(&CodingBuffer->GetData()[CodingBuffer->GetPosition()], (
const char*)OggPage->header, OggPage->header_len);
261 CodingBuffer->IncrementPosition(OggPage->header_len);
262 memcpy(&CodingBuffer->GetData()[CodingBuffer->GetPosition()], (
const char*)OggPage->body, OggPage->body_len);
263 CodingBuffer->IncrementPosition(OggPage->body_len);
265 if (ogg_page_eos(&*OggPage) > 0)
271 ogg_stream_clear(&*OggStream);
272 vorbis_block_clear(&*VorbisBlock);
273 vorbis_dsp_clear(&*VorbisDsp);
274 vorbis_comment_clear(&*VorbisComment);
275 vorbis_info_clear(&*VorbisInfo);
279 memcpy(Data->
GetData(), CodingBuffer->GetData(), CodingBuffer->GetPosition());
290 boost::scoped_ptr<OggVorbis_File> VorbisFile(
new OggVorbis_File);
291 ov_callbacks Callbacks;
293 memset(&*VorbisFile, 0,
sizeof(OggVorbis_File));
295 Callbacks.read_func = ReadOgg;
296 Callbacks.seek_func = SeekOgg;
297 Callbacks.close_func = CloseOgg;
298 Callbacks.tell_func = TellOgg;
300 if (ov_open_callbacks(&ogg_data, &*VorbisFile,
nullptr, -1, Callbacks) < 0)
303 ov_clear(&*VorbisFile);
308 channels = ov_info(&*VorbisFile, -1)->channels;
309 sample_rate = ov_info(&*VorbisFile, -1)->rate;
312 int DesiredSize = ov_pcm_total(&*VorbisFile, -1)*2*channels;
316 while (DesiredSize != 0)
321 Ret = ov_read(&*VorbisFile, (
char*)&DecodedData->
GetData()[Position], DesiredSize, 0, 2, 1, &Section);
322 if (Ret == 0 || DesiredSize < 10)
330 ov_clear(&*VorbisFile);
340 ov_clear(&*VorbisFile);
352 boost::scoped_ptr<vorbisidec::OggVorbis_File> VorbisFile(
new vorbisidec::OggVorbis_File);
353 vorbisidec::ov_callbacks Callbacks;
355 memset(&*VorbisFile, 0,
sizeof(vorbisidec::OggVorbis_File));
357 Callbacks.read_func = ReadOgg;
358 Callbacks.seek_func = SeekOgg;
359 Callbacks.close_func = CloseOgg;
360 Callbacks.tell_func = TellOgg;
362 if (vorbisidec::ov_open_callbacks(&ogg_data, &*VorbisFile,
nullptr, -1, Callbacks) < 0)
365 vorbisidec::ov_clear(&*VorbisFile);
370 channels = vorbisidec::ov_info(&*VorbisFile, -1)->channels;
371 sample_rate = vorbisidec::ov_info(&*VorbisFile, -1)->rate;
374 int DesiredSize = vorbisidec::ov_pcm_total(&*VorbisFile, -1)*2*channels;
378 while (DesiredSize != 0)
383 Ret = vorbisidec::ov_read(&*VorbisFile, (
char*)&DecodedData->
GetData()[Position], DesiredSize, &Section);
384 if (Ret == 0 || DesiredSize < 10)
392 vorbisidec::ov_clear(&*VorbisFile);
402 vorbisidec::ov_clear(&*VorbisFile);
409 const int channels,
const int quality)
414 lame::lame_t lame = lame::lame_init();
415 int Quality = (int)
MANum<int>(quality, 0, 320);
417 CheckStaticAudioCodingVariables();
418 CodingBuffer->Allocate(raw_data.
GetSize()*2);
420 lame::lame_set_in_samplerate(lame, sample_rate);
423 lame::lame_set_num_channels(lame, 1);
424 lame::lame_set_mode(lame, lame::MONO);
426 lame::lame_set_num_channels(lame, 2);
427 lame::lame_set_mode(lame, lame::JOINT_STEREO);
429 lame::lame_set_findReplayGain(lame, 0);
433 lame::lame_set_VBR(lame, lame::vbr_mtrh);
434 lame::lame_set_VBR_q(lame, Quality);
435 lame::lame_set_quality(lame, 0);
438 Quality =
MCMax(Quality, 48);
440 lame::lame_set_VBR(lame, lame::vbr_off);
441 lame::lame_set_brate(lame, Quality);
443 lame::lame_init_params(lame);
449 Count += lame_encode_buffer_interleaved(lame, (
short*)(
void*)raw_data.
GetData(), raw_data.
GetSize() / 4,
450 CodingBuffer->GetData(), CodingBuffer->GetSize());
452 Count += lame_encode_buffer(lame, (
short*)(
void*)raw_data.
GetData(),
nullptr, raw_data.
GetSize() / 2,
453 CodingBuffer->GetData(), CodingBuffer->GetSize());
455 Count += lame_encode_flush(lame, &CodingBuffer->GetData()[Count], CodingBuffer->GetSize()-Count);
459 memcpy(Data->GetData(), CodingBuffer->GetData(), Count);
466 int& sample_rate,
int& channels)
471 void* handler = lame::hip_decode_init();
472 lame::mp3data_struct Mp3Header;
475 memset(&Mp3Header, 0,
sizeof(Mp3Header));
476 CheckStaticAudioCodingVariables();
477 DecodingBuffer->Allocate(mp3_data.
GetSize()*50);
480 for (
int i = 0; i < mp3_data.
GetSize(); i += 128)
482 Count += lame::hip_decode1_headers(handler, &mp3_data.
GetData()[i],
484 (
short*)(
void*)&DecodingBuffer->GetData()[Count],
485 (
short*)(
void*)&RightChannel->GetData()[Count],
488 channels = Mp3Header.stereo;
489 sample_rate = Mp3Header.samplerate;
490 lame::hip_decode_exit(handler);
498 if (orig_size > 0 && Count > (
int)orig_size && Count-(
int)orig_size / channels > 0)
500 DropCount = (Count-orig_size / channels) / 2;
504 short* MonoBuffer = (
short*)(
void*)&DecodingBuffer->GetData()[DropCount*2];
505 unsigned char* TargetBuffer = Data->
GetData();
507 for (
int i = DropCount; i < Count / 2; ++i)
509 TargetBuffer[0] = (
unsigned char)(MonoBuffer[0] & 0xff);
510 TargetBuffer[1] = (
unsigned char)((MonoBuffer[0] >> 8) & 0xff);
515 short* LeftBuffer = (
short*)(
void*)&DecodingBuffer->GetData()[DropCount*2];
516 short* RightBuffer = (
short*)(
void*)&RightChannel->GetData()[DropCount*2];
517 unsigned char* TargetBuffer = Data->
GetData();
519 for (
int i = DropCount; i < Count / 2; ++i)
521 TargetBuffer[0] = (
unsigned char)(LeftBuffer[0] & 0xff);
522 TargetBuffer[1] = (
unsigned char)((LeftBuffer[0] >> 8) & 0xff);
523 TargetBuffer[2] = (
unsigned char)(RightBuffer[0] & 0xff);
524 TargetBuffer[3] = (
unsigned char)((RightBuffer[0] >> 8) & 0xff);
static MCBinaryData * EncodeToMp3(const MCBinaryData &raw_data, const int sample_rate, const int channels, const int quality)
Encode raw audio data to mp3.
#define MC_WARNING(...)
Warning macro.
static MCBinaryData * DecodeFromOggVorbis(MCBinaryData &ogg_data, int &sample_rate, int &channels)
Decode Ogg Vorbis data to raw audio.
T MCRand(const T &min, const T &max)
Get a random number generated with standard calls.
unsigned int GetRemainingCapacity(unsigned int capacity) const
Check if the binary data has enough remaining capacity.
void SetPosition(unsigned int position)
Set the cursor position.
void IncrementPosition(unsigned int position=1)
Increment the cursor position.
static MCBinaryData * DecodeFromMp3(MCBinaryData &mp3_data, unsigned int orig_size, int &sample_rate, int &channels)
Decode mp3 data to raw audio.
unsigned char * GetData() const
Get direct access to the binary data.
A wrapper class to cover boost::thread_specific_ptr/folly::ThreadLocal API on certain targets...
const T MCMax(const U &container)
Get the maximal value of a container.
static MCBinaryData * EncodeToOggVorbis(const MCBinaryData &raw_data, const int sample_rate, const int channels, const int quality)
Encode raw audio data to Ogg Vorbis.
static MCBinaryData * QuickDecodeFromOggVorbis(MCBinaryData &ogg_data, int &sample_rate, int &channels)
Decode Ogg Vorbis data with integer decoder to raw audio.
int GetPosition() const
Get the current position in the binary data.
int GetSize() const
Get binary data size.