p26001-store-acs-soc-fw-app/video/ffmpeg/AudioDecodeHandler.cpp
2026-09-28 21:33:04 +08:00

119 lines
4 KiB
C++

/*
*******************************************************************************
* 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;
}
}
}