#define MS_CLASS "RTC::Codecs::DependencyDescriptor"
#include "RTC/RTP/Codecs/DependencyDescriptor.hpp"
#include "Logger.hpp"
#include <bitset>
#include <string>
#include <vector>
namespace RTC
{
namespace RTP
{
namespace Codecs
{
ankerl::unordered_dense::map<DependencyDescriptor::DecodeTargetIndication, std::string> DependencyDescriptor::dtiToString =
{
{ DependencyDescriptor::DecodeTargetIndication::NOT_PRESENT, "-" },
{ DependencyDescriptor::DecodeTargetIndication::DISCARDABLE, "D" },
{ DependencyDescriptor::DecodeTargetIndication::SWITCH, "S" },
{ DependencyDescriptor::DecodeTargetIndication::REQUIRED, "R" },
};
DependencyDescriptor* DependencyDescriptor::Parse(
const uint8_t* data,
size_t len,
DependencyDescriptor::Listener* listener,
std::unique_ptr<TemplateDependencyStructure>& templateDependencyStructure)
{
MS_TRACE();
if (len < 3)
{
MS_WARN_DEV("ignoring payload with length < 3");
return nullptr;
}
if (len > Consts::TwoBytesRtpExtensionMaxLength)
{
MS_WARN_DEV("ignoring payload with length > %" PRIu8, Consts::TwoBytesRtpExtensionMaxLength);
return nullptr;
}
if (templateDependencyStructure == nullptr)
{
templateDependencyStructure = std::make_unique<TemplateDependencyStructure>();
}
std::unique_ptr<DependencyDescriptor> dependencyDescriptor(
new DependencyDescriptor(data, len, listener, templateDependencyStructure.get()));
if (!dependencyDescriptor->ReadMandatoryDescriptorFields())
{
MS_WARN_DEV("failed to read mandatory fields");
return nullptr;
}
if (len > 3)
{
if (!dependencyDescriptor->ReadExtendedDescriptorFields())
{
MS_WARN_DEV("failed to read extended fields");
return nullptr;
}
}
if (!dependencyDescriptor->ReadFrameDependencyDefinition())
{
MS_WARN_DEV("failed to read frame dependency definition");
return nullptr;
}
return dependencyDescriptor.release();
}
DependencyDescriptor::DependencyDescriptor(
const uint8_t* data,
size_t len,
DependencyDescriptor::Listener* listener,
TemplateDependencyStructure* templateDependencyStructure)
: templateDependencyStructure(templateDependencyStructure),
listener(listener),
bitStream(const_cast<uint8_t*>(data), len)
{
MS_TRACE();
}
uint8_t DependencyDescriptor::GetSpatialLayer() const
{
return this->templateDependencyStructure->templateLayers[this->templateId].spatialLayer;
}
uint8_t DependencyDescriptor::GetTemporalLayer() const
{
return this->templateDependencyStructure->templateLayers[this->templateId].temporalLayer;
}
void DependencyDescriptor::Dump(int indentation) const
{
MS_TRACE();
MS_DUMP_CLEAN(indentation, "<DependencyDescriptor>");
MS_DUMP_CLEAN(indentation, " startOfFrame: %s", this->startOfFrame ? "true" : "false");
MS_DUMP_CLEAN(indentation, " endOfFrame: %s", this->endOfFrame ? "true" : "false");
MS_DUMP_CLEAN(indentation, " frameDependencyTemplateId: %u", this->frameDependencyTemplateId);
MS_DUMP_CLEAN(indentation, " frameNumber: %u", this->frameNumber);
MS_DUMP_CLEAN(indentation, " templateId: %u", this->templateId);
MS_DUMP_CLEAN(indentation, " spatialLayer: %u", this->spatialLayer);
MS_DUMP_CLEAN(indentation, " temporalLayer: %u", this->temporalLayer);
if (this->isKeyFrame)
{
MS_DUMP_CLEAN(indentation + 1, "<TemplateDependencyStructure>");
MS_DUMP_CLEAN(
indentation + 1, " spatialLayers: %u", this->templateDependencyStructure->spatialLayers);
MS_DUMP_CLEAN(
indentation + 1, " temporalLayers: %u", this->templateDependencyStructure->temporalLayers);
MS_DUMP_CLEAN(
indentation + 1,
" templateIdOffset: %u",
this->templateDependencyStructure->templateIdOffset);
MS_DUMP_CLEAN(
indentation + 1,
" decodeTargetCount: %u",
this->templateDependencyStructure->decodeTargetCount);
MS_DUMP_CLEAN(indentation + 2, "<TemplateLayers>");
for (const auto& layer : this->templateDependencyStructure->templateLayers)
{
MS_DUMP_CLEAN(indentation + 3, "<FrameDependencyTemplate>");
MS_DUMP_CLEAN(indentation + 3, " spatialLayerId: %u", layer.spatialLayer);
MS_DUMP_CLEAN(indentation + 3, " temporalLayerId: %u", layer.temporalLayer);
std::string dtis;
for (const auto& dti : layer.decodeTargetIndications)
{
dtis += dtiToString[dti];
}
MS_DUMP_CLEAN(indentation + 3, " decodeTargetIndications: %s", dtis.c_str());
std::string fdiffs;
for (const auto& fdiff : layer.frameDiffs)
{
if (!fdiffs.empty())
{
fdiffs += ",";
}
fdiffs += std::to_string(fdiff);
}
MS_DUMP_CLEAN(indentation + 3, " frameDiffs: %s", fdiffs.c_str());
std::string fdiffChains;
for (const auto& fdiffChain : layer.frameDiffChains)
{
if (!fdiffChains.empty())
{
fdiffChains += ",";
}
fdiffChains += std::to_string(fdiffChain);
}
MS_DUMP_CLEAN(indentation + 3, " frameDiffChains: %s", fdiffChains.c_str());
MS_DUMP_CLEAN(indentation + 3, "</FrameDependencyTemplate>");
}
MS_DUMP_CLEAN(indentation + 2, "</TemplateLayers>");
MS_DUMP_CLEAN(indentation + 1, "</TemplateDependencyStructure>");
}
if (this->activeDecodeTargetsBitmask.has_value())
{
MS_DUMP_CLEAN(
indentation + 1,
"activeDecodeTargetsBitmask: %s",
std::bitset<32>(this->activeDecodeTargetsBitmask.value()).to_string().c_str());
}
MS_DUMP_CLEAN(indentation, "</DependencyDescriptor>");
}
void DependencyDescriptor::UpdateListener(DependencyDescriptor::Listener* listener)
{
this->listener = listener;
}
bool DependencyDescriptor::ReadMandatoryDescriptorFields()
{
MS_TRACE();
if (this->bitStream.GetLeftBits() < 24)
{
return false;
}
this->startOfFrame = this->bitStream.GetBit();
this->endOfFrame = this->bitStream.GetBit();
this->frameDependencyTemplateId = this->bitStream.GetBits(6);
this->frameNumber = this->bitStream.GetBits(16);
return true;
}
bool DependencyDescriptor::ReadExtendedDescriptorFields()
{
MS_TRACE();
if (this->bitStream.GetLeftBits() < 5)
{
return false;
}
auto templateDependencyStructurePresentFlag = this->bitStream.GetBit();
auto activeDecodeTargetLayersPresentFlag = this->bitStream.GetBit();
bitStream.SkipBits(3);
if (templateDependencyStructurePresentFlag)
{
if (!ReadTemplateDependencyStructure())
{
return false;
}
this->activeDecodeTargetsBitmask =
(1 << this->templateDependencyStructure->decodeTargetCount) - 1;
}
if (activeDecodeTargetLayersPresentFlag)
{
if (this->bitStream.GetLeftBits() < this->templateDependencyStructure->decodeTargetCount)
{
return false;
}
this->activeDecodeTargetsBitmask =
this->bitStream.GetBits(this->templateDependencyStructure->decodeTargetCount);
}
return true;
}
bool DependencyDescriptor::ReadTemplateDependencyStructure()
{
MS_TRACE();
if (this->bitStream.GetLeftBits() < 11)
{
return false;
}
this->templateDependencyStructure->templateIdOffset = this->bitStream.GetBits(6);
this->templateDependencyStructure->decodeTargetCount = this->bitStream.GetBits(5) + 1;
if (!ReadTemplateLayers())
{
return false;
}
if (!ReadTemplateDecodeTargetIndications())
{
return false;
}
if (!ReadTemplateFrameDiffs())
{
return false;
}
if (!ReadTemplateFrameDiffChains())
{
return false;
}
return true;
}
bool DependencyDescriptor::ReadTemplateLayers()
{
MS_TRACE();
uint8_t temporalId = 0;
uint8_t spatialId = 0;
uint32_t nextLayerIdc = 0;
this->templateDependencyStructure->templateLayers.clear();
this->isKeyFrame = true;
do
{
this->templateDependencyStructure->templateLayers.emplace_back(spatialId, temporalId);
if (this->bitStream.GetLeftBits() < 2)
{
return false;
}
nextLayerIdc = this->bitStream.GetBits(2);
if (nextLayerIdc == 1)
{
temporalId++;
}
else if (nextLayerIdc == 2)
{
temporalId = 0;
spatialId++;
}
} while (nextLayerIdc != 3);
this->templateDependencyStructure->spatialLayers = spatialId;
this->templateDependencyStructure->temporalLayers = temporalId;
return true;
}
bool DependencyDescriptor::ReadTemplateDecodeTargetIndications()
{
MS_TRACE();
auto templateCount = this->templateDependencyStructure->templateLayers.size();
for (size_t templateIndex = 0; templateIndex < templateCount; ++templateIndex)
{
for (uint8_t dtIndex = 0; dtIndex < this->templateDependencyStructure->decodeTargetCount;
++dtIndex)
{
if (this->bitStream.GetLeftBits() < 2)
{
return false;
}
this->templateDependencyStructure->templateLayers[templateIndex]
.decodeTargetIndications.push_back(
static_cast<DecodeTargetIndication>(this->bitStream.GetBits(2)));
}
}
return true;
}
bool DependencyDescriptor::ReadTemplateFrameDiffs()
{
MS_TRACE();
auto templateCount = this->templateDependencyStructure->templateLayers.size();
for (size_t templateIndex = 0; templateIndex < templateCount; ++templateIndex)
{
if (this->bitStream.GetLeftBits() < 1)
{
return false;
}
bool followsFlag = this->bitStream.GetBit();
while (followsFlag)
{
if (this->bitStream.GetLeftBits() < 5)
{
return false;
}
const uint8_t fdiff = this->bitStream.GetBits(4) + 1;
this->templateDependencyStructure->templateLayers[templateIndex].frameDiffs.push_back(
fdiff);
followsFlag = this->bitStream.GetBit();
}
}
return true;
}
bool DependencyDescriptor::ReadTemplateFrameDiffChains()
{
MS_TRACE();
auto chainCount =
this->bitStream.ReadNs(this->templateDependencyStructure->decodeTargetCount + 1);
if (!chainCount.has_value())
{
return false;
}
if (chainCount == 0)
{
return true;
}
for (uint8_t dtIndex = 0; dtIndex < this->templateDependencyStructure->decodeTargetCount;
++dtIndex)
{
auto chain = this->bitStream.ReadNs(chainCount.value());
if (!chain.has_value())
{
return false;
}
this->decodeTargetProtectedBy.push_back(chain.value());
}
auto templateCount = this->templateDependencyStructure->templateLayers.size();
for (size_t templateIndex = 0; templateIndex < templateCount; ++templateIndex)
{
for (uint32_t chainIndex = 0; chainIndex < chainCount; ++chainIndex)
{
if (this->bitStream.GetLeftBits() < 4)
{
return false;
}
this->templateDependencyStructure->templateLayers[templateIndex].frameDiffChains.push_back(
this->bitStream.GetBits(4));
}
}
return true;
}
bool DependencyDescriptor::ReadFrameDependencyDefinition()
{
MS_TRACE();
const uint8_t templateIndex = (this->frameDependencyTemplateId + 64 -
this->templateDependencyStructure->templateIdOffset) %
64;
if (this->templateDependencyStructure->templateLayers.size() <= templateIndex)
{
MS_WARN_DEV("invalid template index %u", templateIndex);
return false;
}
this->templateId = templateIndex;
this->spatialLayer =
this->templateDependencyStructure->templateLayers[this->templateId].spatialLayer;
this->temporalLayer =
this->templateDependencyStructure->templateLayers[this->templateId].temporalLayer;
return true;
}
const uint8_t* DependencyDescriptor::Serialize(uint8_t& len)
{
MS_TRACE();
MS_ASSERT(!this->isKeyFrame, "serialization of key frames is not supported");
this->bitStream.Reset();
WriteMandatoryDescriptorFields();
WriteExtendedDescriptorFields();
len = std::ceil((this->bitStream.GetOffset() + 7) >> 3);
return this->bitStream.GetData();
}
bool DependencyDescriptor::WriteMandatoryDescriptorFields()
{
MS_TRACE();
this->bitStream.PutBit(this->startOfFrame ? 1 : 0);
this->bitStream.PutBit(this->endOfFrame ? 1 : 0);
this->bitStream.PutBits(6, this->frameDependencyTemplateId);
this->bitStream.PutBits(16, this->frameNumber);
return true;
}
bool DependencyDescriptor::WriteExtendedDescriptorFields()
{
MS_TRACE();
this->bitStream.PutBit(0);
this->bitStream.PutBit(this->activeDecodeTargetsBitmask.has_value() ? 1 : 0);
this->bitStream.PutBit(0);
this->bitStream.PutBit(0);
this->bitStream.PutBit(0);
if (this->activeDecodeTargetsBitmask.has_value())
{
this->bitStream.PutBits(
this->templateDependencyStructure->decodeTargetCount,
this->activeDecodeTargetsBitmask.value());
}
return true;
}
bool DependencyDescriptor::UpdateActiveDecodeTargets(
uint32_t maxSpatialLayer, uint32_t maxTemporalLayer)
{
MS_TRACE();
if (this->isKeyFrame)
{
this->listener->OnDependencyDescriptorUpdated(
this->bitStream.GetData(), this->bitStream.GetLength());
return true;
}
auto availableSpatialLayers = this->templateDependencyStructure->spatialLayers;
auto availableTemporalLayers = this->templateDependencyStructure->temporalLayers;
MS_ASSERT(
maxSpatialLayer <= availableSpatialLayers,
"maxSpatialLayer must be less than or equal to availableSpatialLayers");
MS_ASSERT(
maxTemporalLayer <= availableTemporalLayers,
"maxTemporalLayer must be less than or equal to availableTemporalLayers");
uint32_t activeDecodeTargetsBitmask = 0;
size_t bitIndex = 0;
for (uint32_t spatialLayer = 0; spatialLayer <= maxSpatialLayer; ++spatialLayer)
{
for (uint32_t temporalLayer = 0; temporalLayer <= availableTemporalLayers; ++temporalLayer)
{
if (temporalLayer <= maxTemporalLayer)
{
activeDecodeTargetsBitmask |= (1 << bitIndex);
}
else
{
activeDecodeTargetsBitmask &= ~(1 << bitIndex);
}
bitIndex += 1;
}
}
this->activeDecodeTargetsBitmask = activeDecodeTargetsBitmask;
uint8_t len;
const auto* data = this->Serialize(len);
this->listener->OnDependencyDescriptorUpdated(data, len);
return true;
}
} } }