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

239 lines
6.2 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
*******************************************************************************
* INCLUDE
*******************************************************************************
*/
#include "AudioDecoder.h"
#include "Logger.h"
#include "Demuxer.h"
#include "System.h"
#include <Poco/Exception.h>
#include <Logger.h>
namespace Video
{
namespace Core
{
/*
*******************************************************************************
* 追帧(catch-up)阈值配置
* 说明:所有阈值均以"队列中待解码包个数"为单位。
* 音频帧典型时长约 20ms(AAC),队列上限 300,约 6s 缓冲。
*******************************************************************************
*/
namespace
{
constexpr int CATCH_UP_ENTER = 10;
constexpr int CATCH_UP_EXIT = 2;
constexpr int DROP_LEVEL_1 = 6;
constexpr int DROP_LEVEL_2 = 15;
constexpr int DROP_LEVEL_3 = 30;
}
/*
*******************************************************************************
* * CLASS DEFINE
*******************************************************************************
*/
AudioDecodeHandler::AudioDecodeHandler(const std::string& name, CodecID codecID, AudioComponent::Ptr pPrevious)
: _pPrevious(pPrevious)
{
}
AudioDecodeHandler::~AudioDecodeHandler()
{
}
void AudioDecodeHandler::conceal(Packet::Ptr pPacket)
{
(void)pPacket;
}
/*
*******************************************************************************
* CLASS DEFINE
*******************************************************************************
*/
AudioDecoder::AudioDecoder(const std::string& name)
: AbstractAudioInput(name), _synchronizer(name + "/sync"),
_catchUpEnabled(name.find("NET") != std::string::npos ? true : false), _isCatchingUp(false), _dropPhase(0)
{
}
AudioDecoder::~AudioDecoder()
{
}
void AudioDecoder::start()
{
run();
}
void AudioDecoder::stop()
{
cancel();
setTimeline(0);
_isCatchingUp = false;
_dropPhase = 0;
}
Frame::Ptr AudioDecoder::readFrame()
{
if (previousComponents().size() == 0 || packetQueues().empty())
throw Poco::NotFoundException("No previous components");
updateCatchUpState();
Frame::Ptr pFrame = nullptr;
if (!_pHandler.isNull())
{
pFrame = _pHandler->read();
if (!pFrame.isNull())
{
syncFrame(pFrame, _isCatchingUp);
return pFrame;
}
}
while (pFrame.isNull())
{
Packet::Ptr pPacket;
try
{
long timeOut = _isCatchingUp ? 1 : 1000;
pPacket = packetQueues().first()->dequeue(timeOut);
}
catch (std::exception& e)
{
if (packetQueues().first()->size() == 0)
{
if (_isCatchingUp)
{
_isCatchingUp = false;
_dropPhase = 0;
_synchronizer.reset();
logger().information("%s: catch-up exit (queue drained)", name());
}
}
setTimeline(0);
throw;
}
if (serialCodeWatcher().isChanged(pPacket->serialCode(), true))
{
auto pPrevious = previousComponents().first();
auto pDemuxer = pPrevious.cast<Demuxer>();
if (pDemuxer)
{
auto pEncoder = pDemuxer->audioEncoder();
pEncoder->config().copyTo(config());
serialCodeManager().increment();
_pHandler = AudioDecodeHandler::create(pEncoder->getCodecID(), pEncoder);
if (_catchUpEnabled)
{
while (packetQueues().first()->size() > 2)
{
try
{
packetQueues().first()->dequeue(0);
}
catch (...)
{
break;
}
}
}
}
else
throw Poco::NotImplementedException(
Poco::format("Unsupported previous component: %s", pPrevious->name()));
}
if (_isCatchingUp && shouldDropPacket())
{
_pHandler->conceal(pPacket);
continue;
}
_pHandler->write(pPacket);
pFrame = _pHandler->read();
}
syncFrame(pFrame, _isCatchingUp);
return pFrame;
}
void AudioDecoder::onLink(Core::Component::Ptr pPrevious)
{
if (!packetQueues().empty() && packetQueues().firstComponent() != pPrevious)
throw Poco::LogicException(name() + ": Support only one previous component, conflict with: " +
pPrevious->name() + ", Current: " + packetQueues().firstComponent()->name());
packetQueues().add(pPrevious, name(), MediaType::AUDIO);
}
void AudioDecoder::onUnlink(Core::Component::Ptr pPrevious)
{
packetQueues().remove(pPrevious);
}
void AudioDecoder::syncFrame(Frame::Ptr pFrame, bool isCatchingUp)
{
if (!isCatchingUp)
_synchronizer.syncFrame(pFrame->timestamp);
setTimeline(pFrame->timestamp);
pFrame->timestamp = System::timestamp();
}
void AudioDecoder::updateCatchUpState()
{
if (!_catchUpEnabled)
return;
const int queueSize = packetQueues().first()->size();
if (!_isCatchingUp && queueSize > CATCH_UP_ENTER)
{
_isCatchingUp = true;
_dropPhase = 0;
logger().information("%s: catch-up enter (queue=%d)", name(), queueSize);
}
else if (_isCatchingUp && queueSize <= CATCH_UP_EXIT)
{
_isCatchingUp = false;
_dropPhase = 0;
_synchronizer.reset();
logger().information("%s: catch-up exit (queue=%d)", name(), queueSize);
}
}
bool AudioDecoder::shouldDropPacket()
{
const int queueSize = packetQueues().first()->size();
bool drop = false;
if (queueSize >= DROP_LEVEL_3)
{
drop = (_dropPhase % 3) != 2;
}
else if (queueSize >= DROP_LEVEL_2)
{
drop = (_dropPhase % 2) == 0;
}
else
{
drop = (_dropPhase % 3) == 0;
}
_dropPhase++;
return drop;
}
}
}