123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- /*
- MIT License
- Copyright (c) 2016 Błażej Szczygieł
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
- #include "OpusVorbisDecoder.hpp"
- #include <vorbis/codec.h>
- #include <opus/opus.h>
- #include <string.h>
- struct VorbisDecoder
- {
- vorbis_info info;
- vorbis_dsp_state dspState;
- vorbis_block block;
- ogg_packet op;
- bool hasDSPState, hasBlock;
- };
- /**/
- OpusVorbisDecoder::OpusVorbisDecoder(const WebMDemuxer &demuxer) :
- m_vorbis(NULL), m_opus(NULL),
- m_numSamples(0)
- {
- switch (demuxer.getAudioCodec())
- {
- case WebMDemuxer::AUDIO_VORBIS:
- m_channels = demuxer.getChannels();
- if (openVorbis(demuxer))
- return;
- break;
- case WebMDemuxer::AUDIO_OPUS:
- m_channels = demuxer.getChannels();
- if (openOpus(demuxer))
- return;
- break;
- default:
- return;
- }
- close();
- }
- OpusVorbisDecoder::~OpusVorbisDecoder()
- {
- close();
- }
- bool OpusVorbisDecoder::isOpen() const
- {
- return (m_vorbis || m_opus);
- }
- bool OpusVorbisDecoder::getPCMS16(WebMFrame &frame, short *buffer, int &numOutSamples)
- {
- if (m_vorbis)
- {
- m_vorbis->op.packet = frame.buffer;
- m_vorbis->op.bytes = frame.bufferSize;
- if (vorbis_synthesis(&m_vorbis->block, &m_vorbis->op))
- return false;
- if (vorbis_synthesis_blockin(&m_vorbis->dspState, &m_vorbis->block))
- return false;
- const int maxSamples = getBufferSamples();
- int samplesCount, count = 0;
- float **pcm;
- while ((samplesCount = vorbis_synthesis_pcmout(&m_vorbis->dspState, &pcm)))
- {
- const int toConvert = samplesCount <= maxSamples ? samplesCount : maxSamples;
- for (int c = 0; c < m_channels; ++c)
- {
- float *samples = pcm[c];
- for (int i = 0, j = c; i < toConvert; ++i, j += m_channels)
- {
- int sample = samples[i] * 32767.0f;
- if (sample > 32767)
- sample = 32767;
- else if (sample < -32768)
- sample = -32768;
- buffer[count + j] = sample;
- }
- }
- vorbis_synthesis_read(&m_vorbis->dspState, toConvert);
- count += toConvert;
- }
- numOutSamples = count;
- return true;
- }
- else if (m_opus)
- {
- const int samples = opus_decode(m_opus, frame.buffer, frame.bufferSize, buffer, m_numSamples, 0);
- if (samples >= 0)
- {
- numOutSamples = samples;
- return true;
- }
- }
- return false;
- }
- bool OpusVorbisDecoder::openVorbis(const WebMDemuxer &demuxer)
- {
- size_t extradataSize = 0;
- const unsigned char *extradata = demuxer.getAudioExtradata(extradataSize);
- if (extradataSize < 3 || !extradata || extradata[0] != 2)
- return false;
- size_t headerSize[3] = {0};
- size_t offset = 1;
- /* Calculate three headers sizes */
- for (int i = 0; i < 2; ++i)
- {
- for (;;)
- {
- if (offset >= extradataSize)
- return false;
- headerSize[i] += extradata[offset];
- if (extradata[offset++] < 0xFF)
- break;
- }
- }
- headerSize[2] = extradataSize - (headerSize[0] + headerSize[1] + offset);
- if (headerSize[0] + headerSize[1] + headerSize[2] + offset != extradataSize)
- return false;
- ogg_packet op[3];
- memset(op, 0, sizeof op);
- op[0].packet = (unsigned char *)extradata + offset;
- op[0].bytes = headerSize[0];
- op[0].b_o_s = 1;
- op[1].packet = (unsigned char *)extradata + offset + headerSize[0];
- op[1].bytes = headerSize[1];
- op[2].packet = (unsigned char *)extradata + offset + headerSize[0] + headerSize[1];
- op[2].bytes = headerSize[2];
- m_vorbis = new VorbisDecoder;
- m_vorbis->hasDSPState = m_vorbis->hasBlock = false;
- vorbis_info_init(&m_vorbis->info);
- /* Upload three Vorbis headers into libvorbis */
- vorbis_comment vc;
- vorbis_comment_init(&vc);
- for (int i = 0; i < 3; ++i)
- {
- if (vorbis_synthesis_headerin(&m_vorbis->info, &vc, &op[i]))
- {
- vorbis_comment_clear(&vc);
- return false;
- }
- }
- vorbis_comment_clear(&vc);
- if (vorbis_synthesis_init(&m_vorbis->dspState, &m_vorbis->info))
- return false;
- m_vorbis->hasDSPState = true;
- if (m_vorbis->info.channels != m_channels || m_vorbis->info.rate != demuxer.getSampleRate())
- return false;
- if (vorbis_block_init(&m_vorbis->dspState, &m_vorbis->block))
- return false;
- m_vorbis->hasBlock = true;
- memset(&m_vorbis->op, 0, sizeof m_vorbis->op);
- m_numSamples = 4096 / m_channels;
- return true;
- }
- bool OpusVorbisDecoder::openOpus(const WebMDemuxer &demuxer)
- {
- int opusErr = 0;
- m_opus = opus_decoder_create(demuxer.getSampleRate(), m_channels, &opusErr);
- if (!opusErr)
- {
- m_numSamples = demuxer.getSampleRate() * 0.06 + 0.5; //Maximum frame size (for 60 ms frame)
- return true;
- }
- return false;
- }
- void OpusVorbisDecoder::close()
- {
- if (m_vorbis)
- {
- if (m_vorbis->hasBlock)
- vorbis_block_clear(&m_vorbis->block);
- if (m_vorbis->hasDSPState)
- vorbis_dsp_clear(&m_vorbis->dspState);
- vorbis_info_clear(&m_vorbis->info);
- delete m_vorbis;
- }
- if (m_opus)
- opus_decoder_destroy(m_opus);
- }
|