mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 03:58:07 +02:00
Initial attempt at Opus compression.
This commit is contained in:
parent
a39ad97a1f
commit
cf56bf415f
7 changed files with 486 additions and 33 deletions
|
@ -22,6 +22,9 @@
|
||||||
#include <opus/opus_multistream.h>
|
#include <opus/opus_multistream.h>
|
||||||
#include <opus/opus_projection.h>
|
#include <opus/opus_projection.h>
|
||||||
|
|
||||||
|
#include "OpusEncoder.h"
|
||||||
|
#include "OpusDecoder.h"
|
||||||
|
|
||||||
#define FRAME_SIZE 960
|
#define FRAME_SIZE 960
|
||||||
#define SAMPLE_RATE 48000
|
#define SAMPLE_RATE 48000
|
||||||
#define CHANNELS 2
|
#define CHANNELS 2
|
||||||
|
@ -31,56 +34,41 @@
|
||||||
#define MAX_FRAME_SIZE 6*FRAME_SIZE
|
#define MAX_FRAME_SIZE 6*FRAME_SIZE
|
||||||
#define MAX_PACKET_SIZE 3*1276
|
#define MAX_PACKET_SIZE 3*1276
|
||||||
|
|
||||||
const char* OpusCodec::NAME { "opus" };
|
const char* AthenaOpusCodec::NAME { "opus" };
|
||||||
|
|
||||||
void OpusCodec::init() {
|
void AthenaOpusCodec::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpusCodec::deinit() {
|
void AthenaOpusCodec::deinit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpusCodec::activate() {
|
bool AthenaOpusCodec::activate() {
|
||||||
CodecPlugin::activate();
|
CodecPlugin::activate();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpusCodec::deactivate() {
|
void AthenaOpusCodec::deactivate() {
|
||||||
CodecPlugin::deactivate();
|
CodecPlugin::deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool OpusCodec::isSupported() const {
|
bool AthenaOpusCodec::isSupported() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class OpusEncoder : public Encoder {
|
Encoder* AthenaOpusCodec::createEncoder(int sampleRate, int numChannels) {
|
||||||
public:
|
return new AthenaOpusEncoder(sampleRate, numChannels);
|
||||||
OpusEncoder(int sampleRate, int numChannels) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) override {
|
|
||||||
encodedBuffer.resize(_encodedSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int _encodedSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Encoder* OpusCodec::createEncoder(int sampleRate, int numChannels) {
|
|
||||||
return new OpusEncoder(sampleRate, numChannels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Decoder* OpusCodec::createDecoder(int sampleRate, int numChannels) {
|
Decoder* AthenaOpusCodec::createDecoder(int sampleRate, int numChannels) {
|
||||||
return this;
|
return new AthenaOpusDecoder(sampleRate, numChannels);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpusCodec::releaseEncoder(Encoder* encoder) {
|
void AthenaOpusCodec::releaseEncoder(Encoder* encoder) {
|
||||||
delete encoder;
|
delete encoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpusCodec::releaseDecoder(Decoder* decoder) {
|
void AthenaOpusCodec::releaseDecoder(Decoder* decoder) {
|
||||||
delete decoder;
|
delete decoder;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#include <plugins/CodecPlugin.h>
|
#include <plugins/CodecPlugin.h>
|
||||||
|
|
||||||
class OpusCodec : public CodecPlugin, public Encoder, public Decoder {
|
class AthenaOpusCodec : public CodecPlugin {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -35,6 +35,7 @@ public:
|
||||||
virtual void releaseEncoder(Encoder* encoder) override;
|
virtual void releaseEncoder(Encoder* encoder) override;
|
||||||
virtual void releaseDecoder(Decoder* decoder) override;
|
virtual void releaseDecoder(Decoder* decoder) override;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const char* NAME;
|
static const char* NAME;
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,20 +17,20 @@
|
||||||
|
|
||||||
#include "OpusCodecManager.h"
|
#include "OpusCodecManager.h"
|
||||||
|
|
||||||
class OpusCodecProvider : public QObject, public CodecProvider {
|
class AthenaOpusCodecProvider : public QObject, public CodecProvider {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PLUGIN_METADATA(IID CodecProvider_iid FILE "plugin.json")
|
Q_PLUGIN_METADATA(IID CodecProvider_iid FILE "plugin.json")
|
||||||
Q_INTERFACES(CodecProvider)
|
Q_INTERFACES(CodecProvider)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OpusCodecProvider(QObject* parent = nullptr) : QObject(parent) {}
|
AthenaOpusCodecProvider(QObject* parent = nullptr) : QObject(parent) {}
|
||||||
virtual ~OpusCodecProvider() {}
|
virtual ~AthenaOpusCodecProvider() {}
|
||||||
|
|
||||||
virtual CodecPluginList getCodecPlugins() override {
|
virtual CodecPluginList getCodecPlugins() override {
|
||||||
static std::once_flag once;
|
static std::once_flag once;
|
||||||
std::call_once(once, [&] {
|
std::call_once(once, [&] {
|
||||||
|
|
||||||
CodecPluginPointer opusCodec(new OpusCodec());
|
CodecPluginPointer opusCodec(new AthenaOpusCodec());
|
||||||
if (opusCodec->isSupported()) {
|
if (opusCodec->isSupported()) {
|
||||||
_codecPlugins.push_back(opusCodec);
|
_codecPlugins.push_back(opusCodec);
|
||||||
}
|
}
|
||||||
|
|
97
plugins/opusCodec/src/OpusDecoder.cpp
Normal file
97
plugins/opusCodec/src/OpusDecoder.cpp
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
#include <PerfStat.h>
|
||||||
|
#include <QtCore/QLoggingCategory>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "OpusDecoder.h"
|
||||||
|
|
||||||
|
static QLoggingCategory decoder("AthenaOpusDecoder");
|
||||||
|
|
||||||
|
static QString error_to_string(int error) {
|
||||||
|
switch (error) {
|
||||||
|
case OPUS_OK:
|
||||||
|
return "OK";
|
||||||
|
case OPUS_BAD_ARG:
|
||||||
|
return "One or more invalid/out of range arguments.";
|
||||||
|
case OPUS_BUFFER_TOO_SMALL:
|
||||||
|
return "The mode struct passed is invalid.";
|
||||||
|
case OPUS_INTERNAL_ERROR:
|
||||||
|
return "An internal error was detected.";
|
||||||
|
case OPUS_INVALID_PACKET:
|
||||||
|
return "The compressed data passed is corrupted.";
|
||||||
|
case OPUS_UNIMPLEMENTED:
|
||||||
|
return "Invalid/unsupported request number.";
|
||||||
|
case OPUS_INVALID_STATE:
|
||||||
|
return "An encoder or decoder structure is invalid or already freed.";
|
||||||
|
default:
|
||||||
|
return QString("Unknown error code: %i").arg(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AthenaOpusDecoder::AthenaOpusDecoder(int sampleRate, int numChannels)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
_opus_sample_rate = sampleRate;
|
||||||
|
_opus_num_channels = numChannels;
|
||||||
|
|
||||||
|
_decoder = opus_decoder_create(sampleRate, numChannels, &error);
|
||||||
|
|
||||||
|
if ( error != OPUS_OK ) {
|
||||||
|
qCCritical(decoder) << "Failed to initialize Opus encoder: " << error_to_string(error);
|
||||||
|
_decoder = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
qCDebug(decoder) << "Opus decoder initialized";
|
||||||
|
}
|
||||||
|
|
||||||
|
AthenaOpusDecoder::~AthenaOpusDecoder()
|
||||||
|
{
|
||||||
|
if ( _decoder )
|
||||||
|
opus_decoder_destroy(_decoder);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AthenaOpusDecoder::decode(const QByteArray &encodedBuffer, QByteArray &decodedBuffer)
|
||||||
|
{
|
||||||
|
assert(_decoder);
|
||||||
|
|
||||||
|
PerformanceTimer perfTimer("AthenaOpusDecoder::decode");
|
||||||
|
|
||||||
|
decodedBuffer.resize( 65536 ); // Brute force, yeah!
|
||||||
|
int frame_size = decodedBuffer.size() / _opus_num_channels / static_cast<int>(sizeof( opus_int16 ));
|
||||||
|
|
||||||
|
int frames = opus_decode( _decoder, reinterpret_cast<const unsigned char*>(encodedBuffer.data()), encodedBuffer.length(), reinterpret_cast<opus_int16*>(decodedBuffer.data()), frame_size, 1 );
|
||||||
|
|
||||||
|
if ( frames >= 0 ) {
|
||||||
|
qCDebug(decoder) << "Decoded " << frames << " Opus frames";
|
||||||
|
decodedBuffer.resize( frames * static_cast<int>(sizeof( opus_int16 )) * _opus_num_channels );
|
||||||
|
} else {
|
||||||
|
qCCritical(decoder) << "Failed to decode audio: " << error_to_string(frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AthenaOpusDecoder::lostFrame(QByteArray &decodedBuffer)
|
||||||
|
{
|
||||||
|
assert(_decoder);
|
||||||
|
|
||||||
|
PerformanceTimer perfTimer("AthenaOpusDecoder::lostFrame");
|
||||||
|
|
||||||
|
decodedBuffer.resize( 65536 ); // Brute force, yeah!
|
||||||
|
int frame_size = decodedBuffer.size() / _opus_num_channels / static_cast<int>(sizeof( opus_int16 ));
|
||||||
|
|
||||||
|
int frames = opus_decode( _decoder, nullptr, 0, reinterpret_cast<opus_int16*>(decodedBuffer.data()), frame_size, 1 );
|
||||||
|
|
||||||
|
if ( frames >= 0 ) {
|
||||||
|
qCDebug(decoder) << "Produced " << frames << " opus frames from a lost frame";
|
||||||
|
decodedBuffer.resize( frames * static_cast<int>(sizeof( opus_int16 )) * _opus_num_channels );
|
||||||
|
} else {
|
||||||
|
qCCritical(decoder) << "Failed to decode lost frame: " << error_to_string(frames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
28
plugins/opusCodec/src/OpusDecoder.h
Normal file
28
plugins/opusCodec/src/OpusDecoder.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef OPUSDECODER_H
|
||||||
|
#define OPUSDECODER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <plugins/CodecPlugin.h>
|
||||||
|
#include "opus/opus.h"
|
||||||
|
|
||||||
|
|
||||||
|
class AthenaOpusDecoder : public Decoder {
|
||||||
|
public:
|
||||||
|
AthenaOpusDecoder(int sampleRate, int numChannels);
|
||||||
|
~AthenaOpusDecoder() override;
|
||||||
|
|
||||||
|
|
||||||
|
virtual void decode(const QByteArray& encodedBuffer, QByteArray& decodedBuffer) override;
|
||||||
|
virtual void lostFrame( QByteArray &decodedBuffer) override;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _encodedSize;
|
||||||
|
|
||||||
|
OpusDecoder *_decoder = nullptr;
|
||||||
|
int _opus_sample_rate = 0;
|
||||||
|
int _opus_num_channels = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // OPUSDECODER_H
|
270
plugins/opusCodec/src/OpusEncoder.cpp
Normal file
270
plugins/opusCodec/src/OpusEncoder.cpp
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
|
||||||
|
#include <PerfStat.h>
|
||||||
|
#include <QtCore/QLoggingCategory>
|
||||||
|
|
||||||
|
#include "OpusEncoder.h"
|
||||||
|
#include "OpusWrapper.h"
|
||||||
|
#include "opus/opus.h"
|
||||||
|
|
||||||
|
static QLoggingCategory encoder("AthenaOpusEncoder");
|
||||||
|
|
||||||
|
static QString error_to_string(int error) {
|
||||||
|
switch (error) {
|
||||||
|
case OPUS_OK:
|
||||||
|
return "OK";
|
||||||
|
case OPUS_BAD_ARG:
|
||||||
|
return "One or more invalid/out of range arguments.";
|
||||||
|
case OPUS_BUFFER_TOO_SMALL:
|
||||||
|
return "The mode struct passed is invalid.";
|
||||||
|
case OPUS_INTERNAL_ERROR:
|
||||||
|
return "An internal error was detected.";
|
||||||
|
case OPUS_INVALID_PACKET:
|
||||||
|
return "The compressed data passed is corrupted.";
|
||||||
|
case OPUS_UNIMPLEMENTED:
|
||||||
|
return "Invalid/unsupported request number.";
|
||||||
|
case OPUS_INVALID_STATE:
|
||||||
|
return "An encoder or decoder structure is invalid or already freed.";
|
||||||
|
default:
|
||||||
|
return QString("Unknown error code: %i").arg(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AthenaOpusEncoder::AthenaOpusEncoder(int sampleRate, int numChannels)
|
||||||
|
{
|
||||||
|
_opus_sample_rate = sampleRate;
|
||||||
|
_opus_channels = numChannels;
|
||||||
|
|
||||||
|
int error;
|
||||||
|
|
||||||
|
_encoder = opus_encoder_create(sampleRate, numChannels, DEFAULT_APPLICATION, &error);
|
||||||
|
|
||||||
|
if ( error != OPUS_OK ) {
|
||||||
|
qCCritical(encoder) << "Failed to initialize Opus encoder: " << error_to_string(error);
|
||||||
|
_encoder = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setBitrate(DEFAULT_BITRATE);
|
||||||
|
setComplexity(DEFAULT_COMPLEXITY);
|
||||||
|
setApplication(DEFAULT_APPLICATION);
|
||||||
|
setSignal(DEFAULT_SIGNAL);
|
||||||
|
|
||||||
|
qCDebug(encoder) << "Opus encoder initialized";
|
||||||
|
}
|
||||||
|
|
||||||
|
AthenaOpusEncoder::~AthenaOpusEncoder()
|
||||||
|
{
|
||||||
|
opus_encoder_destroy(_encoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AthenaOpusEncoder::encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) {
|
||||||
|
|
||||||
|
PerformanceTimer perfTimer("AthenaOpusEncoder::encode");
|
||||||
|
assert(_encoder);
|
||||||
|
|
||||||
|
encodedBuffer.resize( decodedBuffer.size() );
|
||||||
|
int frame_size = decodedBuffer.length()/ _opus_channels / static_cast<int>(sizeof(opus_int16));
|
||||||
|
|
||||||
|
int bytes = opus_encode(_encoder, reinterpret_cast<const opus_int16*>(decodedBuffer.data()), frame_size, reinterpret_cast<unsigned char*>(encodedBuffer.data()), encodedBuffer.size() );
|
||||||
|
|
||||||
|
if ( bytes >= 0 ) {
|
||||||
|
qCDebug(encoder) << "Encoded " << decodedBuffer.length() << " bytes into " << bytes << " opus bytes";
|
||||||
|
encodedBuffer.resize(bytes);
|
||||||
|
} else {
|
||||||
|
encodedBuffer.resize(0);
|
||||||
|
|
||||||
|
qCWarning(encoder) << "Error when encoding " << decodedBuffer.length() << " bytes of audio: " << error_to_string(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int AthenaOpusEncoder::getComplexity() const
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret;
|
||||||
|
opus_encoder_ctl(_encoder, OPUS_GET_COMPLEXITY(&ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AthenaOpusEncoder::setComplexity(int complexity)
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret = opus_encoder_ctl(_encoder, OPUS_SET_COMPLEXITY(complexity));
|
||||||
|
|
||||||
|
if ( ret != OPUS_OK )
|
||||||
|
qCWarning(encoder) << "Error when setting complexity to " << complexity << ": " << error_to_string(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AthenaOpusEncoder::getBitrate() const
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret;
|
||||||
|
opus_encoder_ctl(_encoder, OPUS_GET_BITRATE(&ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AthenaOpusEncoder::setBitrate(int bitrate)
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret = opus_encoder_ctl(_encoder, OPUS_SET_BITRATE(bitrate));
|
||||||
|
if ( ret != OPUS_OK )
|
||||||
|
qCWarning(encoder) << "Error when setting bitrate to " << bitrate << ": " << error_to_string(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AthenaOpusEncoder::getVBR() const
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret;
|
||||||
|
opus_encoder_ctl(_encoder, OPUS_GET_VBR(&ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AthenaOpusEncoder::setVBR(int vbr)
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret = opus_encoder_ctl(_encoder, OPUS_SET_VBR(vbr));
|
||||||
|
if ( ret != OPUS_OK )
|
||||||
|
qCWarning(encoder) << "Error when setting VBR to " << vbr << ": " << error_to_string(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AthenaOpusEncoder::getVBRConstraint() const
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret;
|
||||||
|
opus_encoder_ctl(_encoder, OPUS_GET_VBR_CONSTRAINT(&ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AthenaOpusEncoder::setVBRConstraint(int vbr_const)
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret = opus_encoder_ctl(_encoder, OPUS_SET_VBR_CONSTRAINT(vbr_const));
|
||||||
|
if ( ret != OPUS_OK )
|
||||||
|
qCWarning(encoder) << "Error when setting VBR constraint to " << vbr_const << ": " << error_to_string(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AthenaOpusEncoder::getMaxBandwidth() const
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret;
|
||||||
|
opus_encoder_ctl(_encoder, OPUS_GET_MAX_BANDWIDTH(&ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AthenaOpusEncoder::setMaxBandwidth(int maxbw)
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret = opus_encoder_ctl(_encoder, OPUS_SET_MAX_BANDWIDTH(maxbw));
|
||||||
|
if ( ret != OPUS_OK )
|
||||||
|
qCWarning(encoder) << "Error when setting max bandwidth to " << maxbw << ": " << error_to_string(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AthenaOpusEncoder::getBandwidth() const
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret;
|
||||||
|
opus_encoder_ctl(_encoder, OPUS_GET_BANDWIDTH(&ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AthenaOpusEncoder::setBandwidth(int bw)
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret = opus_encoder_ctl(_encoder, OPUS_SET_BANDWIDTH(bw));
|
||||||
|
if ( ret != OPUS_OK )
|
||||||
|
qCWarning(encoder) << "Error when setting bandwidth to " << bw << ": " << error_to_string(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AthenaOpusEncoder::getSignal() const
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret;
|
||||||
|
opus_encoder_ctl(_encoder, OPUS_GET_SIGNAL(&ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AthenaOpusEncoder::setSignal(int signal)
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret = opus_encoder_ctl(_encoder, OPUS_SET_SIGNAL(signal));
|
||||||
|
if ( ret != OPUS_OK )
|
||||||
|
qCWarning(encoder) << "Error when setting signal to " << signal << ": " << error_to_string(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AthenaOpusEncoder::getApplication() const
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret;
|
||||||
|
opus_encoder_ctl(_encoder, OPUS_GET_APPLICATION(&ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AthenaOpusEncoder::setApplication(int app)
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret = opus_encoder_ctl(_encoder, OPUS_SET_APPLICATION(app));
|
||||||
|
if ( ret != OPUS_OK )
|
||||||
|
qCWarning(encoder) << "Error when setting application to " << app << ": " << error_to_string(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AthenaOpusEncoder::getLookahead() const
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret;
|
||||||
|
opus_encoder_ctl(_encoder, OPUS_GET_LOOKAHEAD(&ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AthenaOpusEncoder::getInbandFEC() const
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret;
|
||||||
|
opus_encoder_ctl(_encoder, OPUS_GET_INBAND_FEC(&ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AthenaOpusEncoder::setInbandFEC(int fec)
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret = opus_encoder_ctl(_encoder, OPUS_SET_INBAND_FEC(fec));
|
||||||
|
if ( ret != OPUS_OK )
|
||||||
|
qCWarning(encoder) << "Error when setting inband FEC to " << fec << ": " << error_to_string(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AthenaOpusEncoder::getExpectedPacketLossPercent() const
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret;
|
||||||
|
opus_encoder_ctl(_encoder, OPUS_GET_PACKET_LOSS_PERC(&ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AthenaOpusEncoder::setExpectedPacketLossPercent(int perc)
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret = opus_encoder_ctl(_encoder, OPUS_SET_PACKET_LOSS_PERC(perc));
|
||||||
|
if ( ret != OPUS_OK )
|
||||||
|
qCWarning(encoder) << "Error when setting loss percent to " << perc << ": " << error_to_string(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AthenaOpusEncoder::getDTX() const
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret;
|
||||||
|
opus_encoder_ctl(_encoder, OPUS_GET_DTX(&ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AthenaOpusEncoder::setDTX(int dtx)
|
||||||
|
{
|
||||||
|
assert(_encoder);
|
||||||
|
int ret = opus_encoder_ctl(_encoder, OPUS_SET_DTX(dtx));
|
||||||
|
if ( ret != OPUS_OK )
|
||||||
|
qCWarning(encoder) << "Error when setting DTX to " << dtx << ": " << error_to_string(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
69
plugins/opusCodec/src/OpusEncoder.h
Normal file
69
plugins/opusCodec/src/OpusEncoder.h
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#ifndef OPUSENCODER_H
|
||||||
|
#define OPUSENCODER_H
|
||||||
|
#include <plugins/CodecPlugin.h>
|
||||||
|
#include "OpusWrapper.h"
|
||||||
|
#include "opus/opus.h"
|
||||||
|
|
||||||
|
|
||||||
|
class AthenaOpusEncoder : public Encoder {
|
||||||
|
public:
|
||||||
|
const int DEFAULT_BITRATE = 44100;
|
||||||
|
const int DEFAULT_COMPLEXITY = 10;
|
||||||
|
const int DEFAULT_APPLICATION = OPUS_APPLICATION_VOIP;
|
||||||
|
const int DEFAULT_SIGNAL = OPUS_AUTO;
|
||||||
|
|
||||||
|
|
||||||
|
AthenaOpusEncoder(int sampleRate, int numChannels);
|
||||||
|
~AthenaOpusEncoder() override;
|
||||||
|
|
||||||
|
virtual void encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) override;
|
||||||
|
|
||||||
|
|
||||||
|
int getComplexity() const;
|
||||||
|
void setComplexity(int complexity);
|
||||||
|
|
||||||
|
int getBitrate() const;
|
||||||
|
void setBitrate(int bitrate);
|
||||||
|
|
||||||
|
int getVBR() const;
|
||||||
|
void setVBR(int vbr);
|
||||||
|
|
||||||
|
int getVBRConstraint() const;
|
||||||
|
void setVBRConstraint(int vbr_const);
|
||||||
|
|
||||||
|
int getMaxBandwidth() const;
|
||||||
|
void setMaxBandwidth(int maxbw);
|
||||||
|
|
||||||
|
int getBandwidth() const;
|
||||||
|
void setBandwidth(int bw);
|
||||||
|
|
||||||
|
int getSignal() const;
|
||||||
|
void setSignal(int signal);
|
||||||
|
|
||||||
|
int getApplication() const;
|
||||||
|
void setApplication(int app);
|
||||||
|
|
||||||
|
int getLookahead() const;
|
||||||
|
|
||||||
|
int getInbandFEC() const;
|
||||||
|
void setInbandFEC(int fec);
|
||||||
|
|
||||||
|
int getExpectedPacketLossPercent() const;
|
||||||
|
void setExpectedPacketLossPercent(int perc);
|
||||||
|
|
||||||
|
int getDTX() const;
|
||||||
|
void setDTX(int dtx);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
int _opus_sample_rate = 0;
|
||||||
|
int _opus_channels = 0;
|
||||||
|
int _opus_expected_loss = 0;
|
||||||
|
|
||||||
|
|
||||||
|
OpusEncoder *_encoder = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // OPUSENCODER_H
|
Loading…
Reference in a new issue