90 lines
2.5 KiB
C++
90 lines
2.5 KiB
C++
#include "OutputProductionController.h"
|
|
|
|
#include <algorithm>
|
|
|
|
namespace
|
|
{
|
|
std::size_t ClampReadyLimit(unsigned value, std::size_t capacity)
|
|
{
|
|
const std::size_t requested = static_cast<std::size_t>(value);
|
|
if (capacity == 0)
|
|
return requested;
|
|
return (std::min)(requested, capacity);
|
|
}
|
|
}
|
|
|
|
OutputProductionController::OutputProductionController(const VideoPlayoutPolicy& policy) :
|
|
mPolicy(NormalizeVideoPlayoutPolicy(policy))
|
|
{
|
|
}
|
|
|
|
void OutputProductionController::Configure(const VideoPlayoutPolicy& policy)
|
|
{
|
|
mPolicy = NormalizeVideoPlayoutPolicy(policy);
|
|
}
|
|
|
|
OutputProductionDecision OutputProductionController::Decide(const OutputProductionPressure& pressure) const
|
|
{
|
|
OutputProductionDecision decision;
|
|
|
|
const std::size_t configuredMaxReadyFrames = static_cast<std::size_t>(mPolicy.maxReadyFrames);
|
|
const std::size_t effectiveMaxReadyFrames = pressure.readyQueueCapacity > 0
|
|
? (std::min)(configuredMaxReadyFrames, pressure.readyQueueCapacity)
|
|
: configuredMaxReadyFrames;
|
|
const std::size_t effectiveTargetReadyFrames = (std::min)(
|
|
ClampReadyLimit(mPolicy.targetReadyFrames, pressure.readyQueueCapacity),
|
|
effectiveMaxReadyFrames);
|
|
|
|
decision.targetReadyFrames = effectiveTargetReadyFrames;
|
|
decision.maxReadyFrames = effectiveMaxReadyFrames;
|
|
|
|
if (effectiveMaxReadyFrames == 0)
|
|
{
|
|
decision.action = OutputProductionAction::Throttle;
|
|
decision.reason = "no-ready-frame-capacity";
|
|
return decision;
|
|
}
|
|
|
|
if (pressure.readyQueueDepth >= effectiveMaxReadyFrames)
|
|
{
|
|
decision.action = OutputProductionAction::Throttle;
|
|
decision.reason = "ready-queue-full";
|
|
return decision;
|
|
}
|
|
|
|
if (pressure.readyQueueDepth < effectiveTargetReadyFrames)
|
|
{
|
|
decision.action = OutputProductionAction::Produce;
|
|
decision.requestedFrames = effectiveTargetReadyFrames - pressure.readyQueueDepth;
|
|
decision.reason = "ready-queue-below-target";
|
|
return decision;
|
|
}
|
|
|
|
if ((pressure.lateStreak > 0 || pressure.dropStreak > 0 || pressure.readyQueueUnderrunCount > 0) &&
|
|
pressure.readyQueueDepth < effectiveMaxReadyFrames)
|
|
{
|
|
decision.action = OutputProductionAction::Produce;
|
|
decision.requestedFrames = 1;
|
|
decision.reason = "playout-pressure";
|
|
return decision;
|
|
}
|
|
|
|
decision.action = OutputProductionAction::Wait;
|
|
decision.reason = "ready-queue-at-target";
|
|
return decision;
|
|
}
|
|
|
|
const char* OutputProductionActionName(OutputProductionAction action)
|
|
{
|
|
switch (action)
|
|
{
|
|
case OutputProductionAction::Produce:
|
|
return "Produce";
|
|
case OutputProductionAction::Throttle:
|
|
return "Throttle";
|
|
case OutputProductionAction::Wait:
|
|
default:
|
|
return "Wait";
|
|
}
|
|
}
|