#include "common.hpp"
#include "RTC/RTP/Codecs/VP9.hpp"
#include "RTC/RTP/Packet.hpp"
#include "test/include/RTC/RTP/rtpCommon.hpp"
#include <catch2/catch_test_macros.hpp>
#include <cstring>
namespace
{
RTC::RTP::Codecs::VP9::PayloadDescriptor* createVP9PayloadDescriptor(
uint8_t* buffer, size_t bufferLen, uint16_t pictureId, uint8_t tlIndex)
{
buffer[0] = 0xAD; uint16_t netPictureId = htons(pictureId);
std::memcpy(buffer + 1, &netPictureId, 2);
buffer[1] |= 0x80;
buffer[3] = (tlIndex << 5) | (1 << 4);
auto* payloadDescriptor = RTC::RTP::Codecs::VP9::Parse(buffer, bufferLen);
REQUIRE(payloadDescriptor);
return payloadDescriptor;
}
std::unique_ptr<RTC::RTP::Codecs::VP9::PayloadDescriptor> processVP9Packet(
RTC::RTP::Codecs::VP9::EncodingContext& context, uint16_t pictureId, uint8_t tlIndex)
{
uint8_t payload[] =
{
0xAD, 0x80, 0x00, 0x00, 0x00, 0x00
};
bool marker;
auto* payloadDescriptor =
createVP9PayloadDescriptor(payload, sizeof(payload), pictureId, tlIndex);
std::unique_ptr<RTC::RTP::Codecs::VP9::PayloadDescriptorHandler> payloadDescriptorHandler(
new RTC::RTP::Codecs::VP9::PayloadDescriptorHandler(payloadDescriptor));
std::unique_ptr<RTC::RTP::Packet> packet{ RTC::RTP::Packet::Factory(
rtpCommon::FactoryBuffer, sizeof(rtpCommon::FactoryBuffer)) };
packet->SetPayload(payload, sizeof(payload));
if (payloadDescriptorHandler->Process(&context, packet.get(), marker))
{
return std::unique_ptr<RTC::RTP::Codecs::VP9::PayloadDescriptor>(
RTC::RTP::Codecs::VP9::Parse(payload, sizeof(payload)));
}
return nullptr;
}
}
SCENARIO("process VP9 payload descriptor", "[rtp][codecs][vp9]")
{
constexpr uint16_t MaxPictureId = (1 << 15) - 1;
SECTION("drop packets that belong to other temporal layers after rolling over pictureID")
{
RTC::RTP::Codecs::EncodingContext::Params params;
params.spatialLayers = 1;
params.temporalLayers = 3;
RTC::RTP::Codecs::VP9::EncodingContext context(params);
context.SyncRequired();
context.SetCurrentTemporalLayer(0);
context.SetTargetTemporalLayer(0);
context.SetCurrentSpatialLayer(0);
context.SetTargetSpatialLayer(0);
auto forwarded = processVP9Packet(context, MaxPictureId, 0);
REQUIRE(forwarded);
REQUIRE(forwarded->pictureId == MaxPictureId);
forwarded = processVP9Packet(context, 0, 0);
REQUIRE(forwarded);
REQUIRE(forwarded->pictureId == 0);
forwarded = processVP9Packet(context, 1, 1);
REQUIRE(!forwarded);
}
SECTION("PayloadDescriptorHandler")
{
RTC::RTP::Codecs::EncodingContext::Params params;
params.spatialLayers = 1;
params.temporalLayers = 3;
RTC::RTP::Codecs::VP9::EncodingContext context(params);
const uint16_t start = MaxPictureId - 2000;
context.SetCurrentTemporalLayer(0, start + 0);
context.SetCurrentTemporalLayer(1, start + 1);
context.SetCurrentTemporalLayer(2, start + 5);
context.SetCurrentTemporalLayer(0, start + 6);
REQUIRE(context.GetTemporalLayerForPictureId(start + 0) == 0);
REQUIRE(context.GetTemporalLayerForPictureId(start + 1) == 1);
REQUIRE(context.GetTemporalLayerForPictureId(start + 2) == 1);
REQUIRE(context.GetTemporalLayerForPictureId(start + 5) == 2);
REQUIRE(context.GetTemporalLayerForPictureId(start + 6) == 0);
context.SetCurrentTemporalLayer(1, start + 1000);
context.SetCurrentTemporalLayer(2, start + 1001);
REQUIRE(context.GetTemporalLayerForPictureId(start + 1000) == 1);
REQUIRE(context.GetTemporalLayerForPictureId(start + 0) == 1);
context.SetCurrentTemporalLayer(0, 0);
REQUIRE(context.GetTemporalLayerForPictureId(0) == 0);
REQUIRE(
context.GetTemporalLayerForPictureId(start + 0) == 1); }
SECTION("drop packets that belong to other temporal layers with unordered pictureID")
{
RTC::RTP::Codecs::EncodingContext::Params params;
params.spatialLayers = 1;
params.temporalLayers = 3;
RTC::RTP::Codecs::VP9::EncodingContext context(params);
context.SyncRequired();
context.SetCurrentSpatialLayer(0, 0);
context.SetTargetSpatialLayer(0);
const uint16_t start = MaxPictureId - 20;
const std::vector<std::tuple<uint16_t, uint16_t, int16_t, bool>> packets = {
{ start, 0, 0, true },
{ start, 1, -1, false },
{ start + 1, 0, -1, true },
{ start + 1, 1, -1, false },
{ start + 2, 0, -1, true },
{ start + 2, 1, -1, false },
{ start + 10, 0, 1, true },
{ start + 10, 1, -1, true },
{ start + 11, 0, -1, true },
{ start + 11, 1, -1, true },
{ start + 3, 0, -1, true }, { start + 3, 1, -1, false },
{ start + 12, 0, -1, true },
{ start + 12, 1, -1, true },
{ start + 14, 0, 0, true },
{ start + 14, 1, -1, false },
{ start + 13, 0, -1, true }, { start + 13, 1, -1, true },
{ start + 15, 0, 1, true },
{ start + 15, 1, -1, true },
{ 0, 0, 0, true },
{ 0, 1, -1, false },
{ 1, 0, -1, true },
{ 1, 1, -1, false },
{ start + 16, 0, -1, true }, { start + 16, 1, -1, true },
};
for (const auto& packet : packets)
{
auto pictureId = std::get<0>(packet);
auto tlIndex = std::get<1>(packet);
auto targetTemporalLayer = std::get<2>(packet);
auto shouldForward = std::get<3>(packet);
if (targetTemporalLayer >= 0)
{
context.SetTargetTemporalLayer(targetTemporalLayer);
}
auto forwarded = processVP9Packet(context, pictureId, tlIndex);
if (shouldForward)
{
REQUIRE(forwarded);
REQUIRE(forwarded->pictureId == pictureId);
}
else
{
REQUIRE(!forwarded);
}
}
}
}