/* ******************************************************************************* * INCLUDE ******************************************************************************* */ #include "AudioDecoder.h" #include "Logger.h" #include "Demuxer.h" #include "System.h" #include #include 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(); 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; } } }