270 lines · 7.3 KB · C++
RawDownload
 #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);}