123 lines
3.5 KiB
C++
123 lines
3.5 KiB
C++
#include "AudioStreamingPartPersistentDecoder.h"
|
|
|
|
#include "rtc_base/logging.h"
|
|
#include "rtc_base/third_party/base64/base64.h"
|
|
|
|
namespace tgcalls {
|
|
|
|
WrappedCodecParameters::WrappedCodecParameters(AVCodecParameters const *codecParameters) {
|
|
_value = avcodec_parameters_alloc();
|
|
avcodec_parameters_copy(_value, codecParameters);
|
|
}
|
|
|
|
WrappedCodecParameters::~WrappedCodecParameters() {
|
|
avcodec_parameters_free(&_value);
|
|
}
|
|
|
|
bool WrappedCodecParameters::isEqual(AVCodecParameters const *other) {
|
|
if (_value->codec_id != other->codec_id) {
|
|
return false;
|
|
}
|
|
if (_value->format != other->format) {
|
|
return false;
|
|
}
|
|
if (_value->channels != other->channels) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
class AudioStreamingPartPersistentDecoderState {
|
|
public:
|
|
AudioStreamingPartPersistentDecoderState(AVCodecParameters const *codecParameters, AVRational timeBase) :
|
|
_codecParameters(codecParameters),
|
|
_timeBase(timeBase) {
|
|
const AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id);
|
|
if (codec) {
|
|
_codecContext = avcodec_alloc_context3(codec);
|
|
int ret = avcodec_parameters_to_context(_codecContext, codecParameters);
|
|
if (ret < 0) {
|
|
avcodec_free_context(&_codecContext);
|
|
_codecContext = nullptr;
|
|
} else {
|
|
_codecContext->pkt_timebase = timeBase;
|
|
|
|
_channelCount = _codecContext->channels;
|
|
|
|
ret = avcodec_open2(_codecContext, codec, nullptr);
|
|
if (ret < 0) {
|
|
avcodec_free_context(&_codecContext);
|
|
_codecContext = nullptr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
~AudioStreamingPartPersistentDecoderState() {
|
|
if (_codecContext) {
|
|
avcodec_free_context(&_codecContext);
|
|
}
|
|
}
|
|
|
|
int decode(AVPacket &packet, AVFrame *frame) {
|
|
int ret = avcodec_send_packet(_codecContext, &packet);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
int bytesPerSample = av_get_bytes_per_sample(_codecContext->sample_fmt);
|
|
if (bytesPerSample != 2 && bytesPerSample != 4) {
|
|
return -1;
|
|
}
|
|
|
|
ret = avcodec_receive_frame(_codecContext, frame);
|
|
return ret;
|
|
}
|
|
|
|
public:
|
|
WrappedCodecParameters _codecParameters;
|
|
AVRational _timeBase;
|
|
AVCodecContext *_codecContext = nullptr;
|
|
int _channelCount = 0;
|
|
};
|
|
|
|
AudioStreamingPartPersistentDecoder::AudioStreamingPartPersistentDecoder() {
|
|
}
|
|
|
|
AudioStreamingPartPersistentDecoder::~AudioStreamingPartPersistentDecoder() {
|
|
}
|
|
|
|
void AudioStreamingPartPersistentDecoder::maybeReset(AVCodecParameters const *codecParameters, AVRational timeBase) {
|
|
if (_state) {
|
|
bool isUpdated = false;
|
|
if (!_state->_codecParameters.isEqual(codecParameters)) {
|
|
isUpdated = true;
|
|
}
|
|
if (_state->_timeBase.num != timeBase.num || _state->_timeBase.den != timeBase.den) {
|
|
isUpdated = true;
|
|
}
|
|
if (!isUpdated) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (_state) {
|
|
delete _state;
|
|
_state = nullptr;
|
|
}
|
|
|
|
_state = new AudioStreamingPartPersistentDecoderState(codecParameters, timeBase);
|
|
}
|
|
|
|
int AudioStreamingPartPersistentDecoder::decode(AVCodecParameters const *codecParameters, AVRational timeBase, AVPacket &packet, AVFrame *frame) {
|
|
maybeReset(codecParameters, timeBase);
|
|
|
|
if (!_state) {
|
|
return -1;
|
|
}
|
|
|
|
return _state->decode(packet, frame);
|
|
}
|
|
|
|
}
|