- work to allow Opus codec work with both audio and stereo data (fixing old problem)
This commit is contained in:
parent
f0c37b1bb1
commit
8cb34fad83
|
|
@ -407,7 +407,7 @@ PCodec OpusCodec::OpusFactory::create()
|
||||||
}
|
}
|
||||||
|
|
||||||
OpusCodec::OpusCodec(int samplerate, int channels, int ptime)
|
OpusCodec::OpusCodec(int samplerate, int channels, int ptime)
|
||||||
:mEncoderCtx(NULL), mDecoderCtx(NULL), mChannels(channels), mPTime(ptime), mSamplerate(samplerate)
|
:mEncoderCtx(nullptr), mDecoderCtx(nullptr), mChannels(channels), mPTime(ptime), mSamplerate(samplerate), mDecoderChannels(0)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
mEncoderCtx = opus_encoder_create(48000, mChannels, OPUS_APPLICATION_VOIP, &status);
|
mEncoderCtx = opus_encoder_create(48000, mChannels, OPUS_APPLICATION_VOIP, &status);
|
||||||
|
|
@ -415,7 +415,7 @@ OpusCodec::OpusCodec(int samplerate, int channels, int ptime)
|
||||||
ICELogError(<< "Failed to set Opus encoder complexity");
|
ICELogError(<< "Failed to set Opus encoder complexity");
|
||||||
//if (OPUS_OK != opus_encoder_ctl(mEncoderCtx, OPUS_SET_FORCE_CHANNELS(AUDIO_CHANNELS)))
|
//if (OPUS_OK != opus_encoder_ctl(mEncoderCtx, OPUS_SET_FORCE_CHANNELS(AUDIO_CHANNELS)))
|
||||||
// ICELogCritical(<<"Failed to set channel number in Opus encoder");
|
// ICELogCritical(<<"Failed to set channel number in Opus encoder");
|
||||||
mDecoderCtx = opus_decoder_create(48000, mChannels, &status);
|
// Decoder creation is postponed until first packet arriving (because it may use different channel number
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpusCodec::applyParams(const Params ¶ms)
|
void OpusCodec::applyParams(const Params ¶ms)
|
||||||
|
|
@ -441,13 +441,13 @@ OpusCodec::~OpusCodec()
|
||||||
if (mDecoderCtx)
|
if (mDecoderCtx)
|
||||||
{
|
{
|
||||||
opus_decoder_destroy(mDecoderCtx);
|
opus_decoder_destroy(mDecoderCtx);
|
||||||
mDecoderCtx = NULL;
|
mDecoderCtx = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mEncoderCtx)
|
if (mEncoderCtx)
|
||||||
{
|
{
|
||||||
opus_encoder_destroy(mEncoderCtx);
|
opus_encoder_destroy(mEncoderCtx);
|
||||||
mEncoderCtx = NULL;
|
mEncoderCtx = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -493,46 +493,96 @@ int OpusCodec::encode(const void* input, int inputBytes, void* output, int outpu
|
||||||
|
|
||||||
int OpusCodec::decode(const void* input, int inputBytes, void* output, int outputCapacity)
|
int OpusCodec::decode(const void* input, int inputBytes, void* output, int outputCapacity)
|
||||||
{
|
{
|
||||||
int nr_of_channels = opus_packet_get_nb_channels((const unsigned char*)input);
|
// Examine the number of channels available in incoming packet
|
||||||
if (nr_of_channels != channels())
|
int nr_of_channels = opus_packet_get_nb_channels((const unsigned char *) input);
|
||||||
{
|
int nr_of_frames = opus_decoder_get_nb_samples(mDecoderCtx, (const unsigned char *) input,
|
||||||
// Most probably bad configuration
|
inputBytes);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nr_of_frames = opus_decoder_get_nb_samples(mDecoderCtx, (const unsigned char*)input, inputBytes);
|
// Recreate decoder if needed
|
||||||
if (nr_of_frames > 0)
|
if (mDecoderChannels != nr_of_channels)
|
||||||
{
|
{
|
||||||
// Send number of bytes for input and number of samples for output
|
if (mDecoderCtx)
|
||||||
int capacity = nr_of_frames * sizeof(opus_int16) * channels();
|
|
||||||
|
|
||||||
// Dangerous !
|
|
||||||
opus_int16* buffer = (opus_int16*)alloca(capacity);
|
|
||||||
int decoded = opus_decode(mDecoderCtx, (const unsigned char*)input, inputBytes, (opus_int16*)buffer, capacity / (sizeof(short) * channels()), 0 /* FEC decoding is for lost packets */);
|
|
||||||
if (decoded < 0)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Resample 48000 to requested samplerate
|
opus_decoder_destroy(mDecoderCtx);
|
||||||
size_t processed = 0;
|
mDecoderCtx = nullptr;
|
||||||
return mDecodeResampler.processBuffer(buffer, decoded * sizeof(short) * channels(), processed, output, outputCapacity);
|
|
||||||
}
|
}
|
||||||
|
mDecoderChannels = nr_of_channels;
|
||||||
}
|
}
|
||||||
else
|
int status = 0;
|
||||||
|
mDecoderCtx = opus_decoder_create(48000, mDecoderChannels, &status);
|
||||||
|
if (status)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// We support stereo and mono here.
|
||||||
|
int buffer_capacity = nr_of_frames * sizeof(opus_int16) * nr_of_channels;
|
||||||
|
opus_int16 *buffer_decode = (opus_int16 *) alloca(buffer_capacity);
|
||||||
|
int decoded = opus_decode(mDecoderCtx,
|
||||||
|
reinterpret_cast<const unsigned char *>(input), inputBytes,
|
||||||
|
buffer_decode, nr_of_frames, 0);
|
||||||
|
|
||||||
|
size_t resampler_processed = 0;
|
||||||
|
opus_int16 *buffer_stereo = nullptr;
|
||||||
|
switch (nr_of_channels) {
|
||||||
|
case 1:
|
||||||
|
// Convert to stereo before
|
||||||
|
buffer_stereo = (opus_int16 *) alloca(buffer_capacity * 2);
|
||||||
|
for (int i = 0; i < nr_of_frames; i++) {
|
||||||
|
buffer_stereo[i * 2 + 1] = buffer_decode[i];
|
||||||
|
buffer_stereo[i * 2] = buffer_decode[i];
|
||||||
|
}
|
||||||
|
return (int) mDecodeResampler.processBuffer(buffer_stereo,
|
||||||
|
decoded * sizeof(opus_int16) * 2,
|
||||||
|
resampler_processed, output,
|
||||||
|
outputCapacity);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return (int) mDecodeResampler.processBuffer(buffer_decode,
|
||||||
|
decoded * sizeof(opus_int16) *
|
||||||
|
nr_of_channels, resampler_processed, output,
|
||||||
|
outputCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int OpusCodec::plc(int lostFrames, void* output, int outputCapacity)
|
int OpusCodec::plc(int lostPackets, void* output, int outputCapacity)
|
||||||
{
|
{
|
||||||
int nrOfSamplesInFrame = pcmLength() / (sizeof(short) * channels());
|
// Find how much frames do we need to produce and prefill it with silence
|
||||||
|
int frames_per_packet = (int)pcmLength() / (sizeof(opus_int16) * channels());
|
||||||
memset(output, 0, outputCapacity);
|
memset(output, 0, outputCapacity);
|
||||||
|
|
||||||
int nr_of_decoded_samples = 0;
|
// Use this pointer as output
|
||||||
for (int i=0; i<lostFrames; i++)
|
opus_int16* data_output = reinterpret_cast<opus_int16*>(output);
|
||||||
|
|
||||||
|
int nr_of_decoded_frames = 0;
|
||||||
|
|
||||||
|
// Buffer for single lost frame
|
||||||
|
opus_int16* buffer_plc = (opus_int16*)alloca(frames_per_packet * mDecoderChannels * sizeof(opus_int16));
|
||||||
|
for (int i=0; i<lostPackets; i++)
|
||||||
{
|
{
|
||||||
nr_of_decoded_samples += opus_decode(mDecoderCtx, nullptr, 0, (opus_int16*)output + nrOfSamplesInFrame * i, nrOfSamplesInFrame, 0);
|
nr_of_decoded_frames = opus_decode(mDecoderCtx, nullptr, 0, buffer_plc, frames_per_packet, 0);
|
||||||
|
assert(nr_of_decoded_frames == frames_per_packet);
|
||||||
|
switch (mDecoderChannels)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
// Convert mono to stereo
|
||||||
|
for (int i=0; i < nr_of_decoded_frames; i++)
|
||||||
|
{
|
||||||
|
data_output[i * 2] = buffer_plc[i];
|
||||||
|
data_output[i * 2 + 1] = buffer_plc[i+1];
|
||||||
|
}
|
||||||
|
data_output += frames_per_packet * mChannels;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// Just copy data
|
||||||
|
memcpy(data_output, buffer_plc, frames_per_packet * sizeof(opus_int16) * mDecoderChannels);
|
||||||
|
data_output += frames_per_packet * mChannels;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nr_of_decoded_samples ? lostFrames * pcmLength() : 0;
|
return ((char*)data_output - (char*)output) * sizeof(opus_int16);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ protected:
|
||||||
OpusDecoder *mDecoderCtx;
|
OpusDecoder *mDecoderCtx;
|
||||||
int mPTime, mSamplerate, mChannels;
|
int mPTime, mSamplerate, mChannels;
|
||||||
Audio::SpeexResampler mDecodeResampler;
|
Audio::SpeexResampler mDecodeResampler;
|
||||||
|
int mDecoderChannels;
|
||||||
public:
|
public:
|
||||||
struct Params
|
struct Params
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue