/* ******************************************************************************* * INCLUDE ******************************************************************************* */ #include "AudioDecodeHandler.h" #include "Util.h" namespace Video { namespace FFmpeg { /* ******************************************************************************* * CLASS DEFINE ******************************************************************************* */ AudioDecodeHandler::AudioDecodeHandler(Core::CodecID codecID, Core::AudioComponent::Ptr pPrevious) : Core::AudioDecodeHandler(Poco::format("FFmpeg::AudioDecodeHandler(%s)", Core::codecIDToString(codecID)), codecID, pPrevious) { const AVCodec* pCodec = Util::getDecoder(codecID); if (!pCodec) throw Poco::NotImplementedException( Poco::format("%s: Unsupported codec: %s", name(), Core::codecIDToString(codecID)), -EINVAL); _pCodecCtx = avcodec_alloc_context3(pCodec); if (!_pCodecCtx) throw Poco::InvalidAccessException(Poco::format("%s: Could not alloc an encoding context", name()), -EACCES); _pCodecCtx->ch_layout = Util::getChannelLayout(pPrevious->getChannelLayout()); _pCodecCtx->sample_rate = pPrevious->getSampleRate(); _pCodecCtx->sample_fmt = Util::getSampleFormat(pPrevious->getSampleFormat()); int rc = avcodec_open2(_pCodecCtx, pCodec, nullptr); if (rc < 0) throw Poco::InvalidAccessException( Poco::format("%s: Open %s FAIL: %d(%s)", name(), std::string(pCodec->name), rc, Util::getErrorString(rc)), rc); _pFrame = av_frame_alloc(); if (Core::sampleFormatIsPlanar(pPrevious->getSampleFormat())) { const int c = Core::channelLayoutChannels(pPrevious->getChannelLayout()); switch (c) { case 1: _frameConvertor = [](AVFrame* from, Core::Frame::Ptr to) -> void { memcpy(to->data[0], from->data[0], to->length); }; break; case 2: _frameConvertor = [](AVFrame* from, Core::Frame::Ptr to) -> void { memcpy(to->data[0], from->data[0], to->length); memcpy(to->data[1], from->data[1], to->length); }; break; default: throw Poco::BugcheckException(Poco::format("%s: Unsupported channle-count: %d", name(), c), -EINVAL); } } else { _frameConvertor = [](AVFrame* from, Core::Frame::Ptr to) -> void { memcpy(to->data[0], from->data[0], to->length); }; } } AudioDecodeHandler::~AudioDecodeHandler() { av_frame_free(&_pFrame); avcodec_free_context(&_pCodecCtx); } void AudioDecodeHandler::write(Core::Packet::Ptr pPacket) { AVPacket* pAVPacket; pPacket->moveTo(&pAVPacket); int rc = avcodec_send_packet(_pCodecCtx, pAVPacket); av_packet_free(&pAVPacket); if (rc < 0) throw Poco::RuntimeException(Poco::format("%s: Error submitting the packet to the decoder: %d(%s)", name(), rc, Util::getErrorString(rc)), rc); } Core::Frame::Ptr AudioDecodeHandler::read() { int rc = avcodec_receive_frame(_pCodecCtx, _pFrame); if (rc == AVERROR(EAGAIN) || rc == AVERROR_EOF) return nullptr; if (rc < 0) throw Poco::RuntimeException( Poco::format("%s: Error during decoding: %d(%s)", name(), rc, Util::getErrorString(rc)), rc); return convert(_pFrame); } Core::Frame::Ptr AudioDecodeHandler::convert(AVFrame* pAVFrame) { int length = av_get_bytes_per_sample(_pCodecCtx->sample_fmt) * _pFrame->nb_samples; Core::Frame::Ptr pFrame = new Core::Frame(); pFrame->length = length; pFrame->timestamp = pAVFrame->pts; for (int i = 0; i < pAVFrame->ch_layout.nb_channels; i++) pFrame->data[i] = new uint8_t[length]; _frameConvertor(pAVFrame, pFrame); return pFrame; } } }