Skip to content

Commit

Permalink
implemented opus encoder
Browse files Browse the repository at this point in the history
  • Loading branch information
i-saint committed May 30, 2017
1 parent eec6cb2 commit 7045d20
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ public enum fcWebMVideoEncoder
public enum fcWebMAudioEncoder
{
Vorbis,
//Opus, // not implemented yet
Opus,
};

[Serializable]
Expand Down
70 changes: 50 additions & 20 deletions Plugin/fccore/Encoder/WebM/fcOpusEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,49 @@ class fcOpusEncoder : public fcIWebMAudioEncoder

private:
fcOpusEncoderConfig m_conf;
Buffer m_codec_private;
RawVector<float> m_samples;
Buffer m_buf_encoded;
Buffer m_codec_private;
RawVector<float> m_samples;
Buffer m_buf_encoded;

OpusEncoder *m_op_encoder = nullptr;
OpusEncoder *m_opus = nullptr;
int m_preskip = 0;
uint64_t m_total_samples = 0;
};


fcOpusEncoder::fcOpusEncoder(const fcOpusEncoderConfig& conf)
: m_conf(conf)
{
int err;
m_op_encoder = opus_encoder_create(conf.sample_rate, conf.num_channels, OPUS_APPLICATION_RESTRICTED_LOWDELAY, &err);
opus_encoder_ctl(m_op_encoder, OPUS_SET_BITRATE(conf.target_bitrate));
m_opus = opus_encoder_create(conf.sample_rate, conf.num_channels, OPUS_APPLICATION_RESTRICTED_LOWDELAY, &err);
opus_encoder_ctl(m_opus, OPUS_SET_BITRATE(conf.target_bitrate));

{
m_codec_private.resize(19);
auto *cp = (uint8_t*)m_codec_private.data();

memcpy(cp, "OpusHead", 8);
cp[8] = 1; // version
cp[9] = (uint8_t)conf.num_channels;

// pre-skip
opus_encoder_ctl(m_opus, OPUS_GET_LOOKAHEAD(&m_preskip));
(uint16_t&)cp[10] = m_preskip;

// sample rate
(uint32_t&)cp[12] = conf.sample_rate;

// output gain (set to 0)
cp[16] = cp[17] = 0;

// channel mapping
cp[18] = 0;
}
}

fcOpusEncoder::~fcOpusEncoder()
{
opus_encoder_destroy(m_op_encoder);
opus_encoder_destroy(m_opus);
}

const char* fcOpusEncoder::getMatroskaCodecID() const
Expand All @@ -62,32 +86,38 @@ const Buffer& fcOpusEncoder::getCodecPrivate() const

bool fcOpusEncoder::encode(fcWebMFrameData& dst, const float *samples, size_t num_samples)
{
if (!m_op_encoder || !samples) { return false; }

return false;
// todo: implement
if (!m_opus || !samples) { return false; }

m_samples.append(samples, num_samples);

int block_size = m_conf.sample_rate * m_conf.num_channels / 10;
bool result = true;
int frame_size = m_conf.sample_rate / 100;
int processed_size = 0;
m_buf_encoded.resize(block_size);
while (processed_size + block_size <= num_samples) {
auto n = opus_encode_float(m_op_encoder,
m_samples.data() + processed_size, block_size / m_conf.num_channels,
m_buf_encoded.resize(m_conf.sample_rate);

while (processed_size + frame_size * m_conf.num_channels <= m_samples.size()) {
opus_int32 n = opus_encode_float(m_opus,
m_samples.data() + processed_size, frame_size,
(uint8_t*)m_buf_encoded.data(), (int)m_buf_encoded.size());
if (n > 0) {
m_buf_encoded.resize(n);
dst.data.append(m_buf_encoded.data(), m_buf_encoded.size());
dst.data.append(m_buf_encoded.data(), n);
processed_size += frame_size * m_conf.num_channels;
m_total_samples += frame_size;

double timestamp = (double)m_total_samples / (double)m_conf.sample_rate;
dst.packets.push_back({ (uint32_t)n, timestamp, 1 });
}
else if (n == 0) {
break;
}
else {
return false;
result = false;
break;
}
}
return true;

m_samples.erase(m_samples.begin(), m_samples.begin() + processed_size);
return result;
}

bool fcOpusEncoder::flush(fcWebMFrameData& dst)
Expand Down
2 changes: 1 addition & 1 deletion Plugin/fccore/Encoder/WebM/fcWebMContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ fcWebMContext::~fcWebMContext()
m_video_tasks.wait();
m_audio_tasks.wait();

if (m_conf.video) {
if (m_conf.video && m_conf.audio) {
writeOut(m_video_last_timestamp);
}
m_mkv_frames.clear();
Expand Down

0 comments on commit 7045d20

Please sign in to comment.