Create version 01 of Generic Frame Descriptor - with discardability flag

The discardability flag denotes whether the frame may be dropped by
the decoder with no effect on the decodability of subsequent frames.

Bug: webrtc:10214
Change-Id: I3654951d8863b50effe9670b8d1d7eb051240039
Reviewed-on: https://webrtc-review.googlesource.com/c/122241
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Elad Alon <eladalon@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26763}
This commit is contained in:
Elad Alon 2019-02-19 13:01:31 +01:00 committed by Commit Bot
parent 0b2150c884
commit ccb9b759c5
21 changed files with 543 additions and 182 deletions

View File

@ -135,6 +135,10 @@ const char RtpExtension::kFrameMarkingUri[] =
"http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07";
const int RtpExtension::kFrameMarkingDefaultId = 10;
const char RtpExtension::kGenericFrameDescriptorUri00[] =
"http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor-00";
const char RtpExtension::kGenericFrameDescriptorUri01[] =
"http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor-01";
const char RtpExtension::kGenericFrameDescriptorUri[] =
"http://www.webrtc.org/experiments/rtp-hdrext/generic-frame-descriptor-00";
const int RtpExtension::kGenericFrameDescriptorDefaultId = 11;
@ -178,7 +182,8 @@ bool RtpExtension::IsSupportedForVideo(const std::string& uri) {
uri == webrtc::RtpExtension::kVideoTimingUri ||
uri == webrtc::RtpExtension::kMidUri ||
uri == webrtc::RtpExtension::kFrameMarkingUri ||
uri == webrtc::RtpExtension::kGenericFrameDescriptorUri ||
uri == webrtc::RtpExtension::kGenericFrameDescriptorUri00 ||
uri == webrtc::RtpExtension::kGenericFrameDescriptorUri01 ||
uri == webrtc::RtpExtension::kColorSpaceUri ||
uri == webrtc::RtpExtension::kRidUri ||
uri == webrtc::RtpExtension::kRepairedRidUri;

View File

@ -297,6 +297,9 @@ struct RtpExtension {
RTC_DEPRECATED static const int kFrameMarkingDefaultId;
// Experimental codec agnostic frame descriptor.
static const char kGenericFrameDescriptorUri00[];
static const char kGenericFrameDescriptorUri01[];
// TODO(bugs.webrtc.org/10243): Remove once dependencies have been updated.
static const char kGenericFrameDescriptorUri[];
// TODO(bugs.webrtc.org/10288): Remove once dependencies have been updated.
RTC_DEPRECATED static const int kGenericFrameDescriptorDefaultId;

View File

@ -494,7 +494,9 @@ RtpCapabilities WebRtcVideoEngine::GetCapabilities() const {
webrtc::RtpExtension(webrtc::RtpExtension::kColorSpaceUri, id++));
if (webrtc::field_trial::IsEnabled("WebRTC-GenericDescriptorAdvertised")) {
capabilities.header_extensions.push_back(webrtc::RtpExtension(
webrtc::RtpExtension::kGenericFrameDescriptorUri, id++));
webrtc::RtpExtension::kGenericFrameDescriptorUri00, id++));
capabilities.header_extensions.push_back(webrtc::RtpExtension(
webrtc::RtpExtension::kGenericFrameDescriptorUri01, id++));
}
return capabilities;

View File

@ -313,8 +313,12 @@ TEST_F(WebRtcVideoEngineTest, SupportsColorSpaceHeaderExtension) {
ExpectRtpCapabilitySupport(RtpExtension::kColorSpaceUri, true);
}
TEST_F(WebRtcVideoEngineTest, AdvertiseGenericDescriptor) {
ExpectRtpCapabilitySupport(RtpExtension::kGenericFrameDescriptorUri, false);
TEST_F(WebRtcVideoEngineTest, AdvertiseGenericDescriptor00) {
ExpectRtpCapabilitySupport(RtpExtension::kGenericFrameDescriptorUri00, false);
}
TEST_F(WebRtcVideoEngineTest, AdvertiseGenericDescriptor01) {
ExpectRtpCapabilitySupport(RtpExtension::kGenericFrameDescriptorUri01, false);
}
class WebRtcVideoEngineTestWithGenericDescriptor
@ -324,8 +328,14 @@ class WebRtcVideoEngineTestWithGenericDescriptor
: WebRtcVideoEngineTest("WebRTC-GenericDescriptorAdvertised/Enabled/") {}
};
TEST_F(WebRtcVideoEngineTestWithGenericDescriptor, AdvertiseGenericDescriptor) {
ExpectRtpCapabilitySupport(RtpExtension::kGenericFrameDescriptorUri, true);
TEST_F(WebRtcVideoEngineTestWithGenericDescriptor,
AdvertiseGenericDescriptor00) {
ExpectRtpCapabilitySupport(RtpExtension::kGenericFrameDescriptorUri00, true);
}
TEST_F(WebRtcVideoEngineTestWithGenericDescriptor,
AdvertiseGenericDescriptor01) {
ExpectRtpCapabilitySupport(RtpExtension::kGenericFrameDescriptorUri01, true);
}
TEST_F(WebRtcVideoEngineTest, CVOSetHeaderExtensionBeforeCapturer) {

View File

@ -62,7 +62,9 @@ enum RTPExtensionType : int {
kRtpExtensionRtpStreamId,
kRtpExtensionRepairedRtpStreamId,
kRtpExtensionMid,
kRtpExtensionGenericFrameDescriptor,
kRtpExtensionGenericFrameDescriptor00,
kRtpExtensionGenericFrameDescriptor = kRtpExtensionGenericFrameDescriptor00,
kRtpExtensionGenericFrameDescriptor01,
kRtpExtensionColorSpace,
kRtpExtensionNumberOfExtensions // Must be the last entity in the enum.
};

View File

@ -14,6 +14,7 @@
#include <stdint.h>
#include <vector>
#include "absl/types/optional.h"
#include "api/array_view.h"
namespace webrtc {
@ -36,8 +37,14 @@ class RtpGenericFrameDescriptor {
bool LastPacketInSubFrame() const { return end_of_subframe_; }
void SetLastPacketInSubFrame(bool last) { end_of_subframe_ = last; }
bool FirstSubFrameInFrame() const { return beginning_of_frame_; }
bool LastSubFrameInFrame() const { return end_of_frame_; }
// Denotes whether the frame is discardable. That is, whether skipping it
// would have no effect on the decodability of subsequent frames.
// An absl::optional is used because version 0 of the extension did not
// support this flag. (The optional aspect is relevant only when parsing.)
// TODO(bugs.webrtc.org/10243): Make this into a plain bool when v00 of
// the extension is deprecated.
absl::optional<bool> Discardable() const { return discardable_; }
void SetDiscardable(bool discardable) { discardable_ = discardable; }
// Properties below undefined if !FirstPacketInSubFrame()
// Valid range for temporal layer: [0, 7]
@ -66,14 +73,10 @@ class RtpGenericFrameDescriptor {
rtc::ArrayView<const uint8_t> GetByteRepresentation();
private:
friend class RtpGenericFrameDescriptorExtension;
void SetFirstSubFrameInFrame(bool first) { beginning_of_frame_ = first; }
void SetLastSubFrameInFrame(bool last) { end_of_frame_ = last; }
bool beginning_of_subframe_ = false;
bool end_of_subframe_ = false;
bool beginning_of_frame_ = true;
bool end_of_frame_ = true;
absl::optional<bool> discardable_;
uint16_t frame_id_ = 0;
uint8_t spatial_layers_ = 1;

View File

@ -17,15 +17,21 @@ namespace {
constexpr uint8_t kFlagBeginOfSubframe = 0x80;
constexpr uint8_t kFlagEndOfSubframe = 0x40;
constexpr uint8_t kFlagFirstSubframe = 0x20;
constexpr uint8_t kFlagLastSubframe = 0x10;
// In version 00, the flags F and L in the first byte correspond to
// kFlagFirstSubframeV00 and kFlagLastSubframeV00. In practice, they were
// always set to |true|. In version 01, these flags are deprecated, and we use
// one of their bits for the discardability flag.
constexpr uint8_t kFlagFirstSubframeV00 = 0x20;
constexpr uint8_t kFlagLastSubframeV00 = 0x10;
constexpr uint8_t kFlagDiscardableV01 = 0x10;
constexpr uint8_t kFlagDependencies = 0x08;
constexpr uint8_t kMaskTemporalLayer = 0x07;
constexpr uint8_t kFlagMoreDependencies = 0x01;
constexpr uint8_t kFlageXtendedOffset = 0x02;
} // namespace
// 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+
// |B|E|F|L|D| T |
@ -52,10 +58,9 @@ constexpr uint8_t kFlageXtendedOffset = 0x02;
// +---------------+
// | ... |
// +-+-+-+-+-+-+-+-+
constexpr RTPExtensionType RtpGenericFrameDescriptorExtension::kId;
constexpr char RtpGenericFrameDescriptorExtension::kUri[];
bool RtpGenericFrameDescriptorExtension::Parse(
bool RtpGenericFrameDescriptorExtensionParse(
size_t version,
rtc::ArrayView<const uint8_t> data,
RtpGenericFrameDescriptor* descriptor) {
if (data.empty()) {
@ -65,8 +70,10 @@ bool RtpGenericFrameDescriptorExtension::Parse(
bool begins_subframe = (data[0] & kFlagBeginOfSubframe) != 0;
descriptor->SetFirstPacketInSubFrame(begins_subframe);
descriptor->SetLastPacketInSubFrame((data[0] & kFlagEndOfSubframe) != 0);
descriptor->SetFirstSubFrameInFrame((data[0] & kFlagFirstSubframe) != 0);
descriptor->SetLastSubFrameInFrame((data[0] & kFlagLastSubframe) != 0);
if (version >= 1) {
descriptor->SetDiscardable((data[0] & kFlagDiscardableV01) != 0);
}
// Parse Subframe details provided in 1st packet of subframe.
if (!begins_subframe) {
@ -108,7 +115,7 @@ bool RtpGenericFrameDescriptorExtension::Parse(
return true;
}
size_t RtpGenericFrameDescriptorExtension::ValueSize(
size_t RtpGenericFrameDescriptorExtensionValueSize(
const RtpGenericFrameDescriptor& descriptor) {
if (!descriptor.FirstPacketInSubFrame())
return 1;
@ -125,15 +132,24 @@ size_t RtpGenericFrameDescriptorExtension::ValueSize(
return size;
}
bool RtpGenericFrameDescriptorExtension::Write(
bool RtpGenericFrameDescriptorExtensionWrite(
size_t version,
rtc::ArrayView<uint8_t> data,
const RtpGenericFrameDescriptor& descriptor) {
RTC_CHECK_EQ(data.size(), ValueSize(descriptor));
RTC_CHECK_EQ(data.size(),
RtpGenericFrameDescriptorExtensionValueSize(descriptor));
uint8_t base_header =
(descriptor.FirstPacketInSubFrame() ? kFlagBeginOfSubframe : 0) |
(descriptor.LastPacketInSubFrame() ? kFlagEndOfSubframe : 0) |
(descriptor.FirstSubFrameInFrame() ? kFlagFirstSubframe : 0) |
(descriptor.LastSubFrameInFrame() ? kFlagLastSubframe : 0);
(descriptor.LastPacketInSubFrame() ? kFlagEndOfSubframe : 0);
if (version == 0) {
base_header |= kFlagFirstSubframeV00;
base_header |= kFlagLastSubframeV00;
} else if (version >= 1) {
const absl::optional<bool> discardable = descriptor.Discardable();
base_header |= (discardable.value_or(false) ? kFlagDiscardableV01 : 0);
}
if (!descriptor.FirstPacketInSubFrame()) {
data[0] = base_header;
return true;
@ -168,4 +184,48 @@ bool RtpGenericFrameDescriptorExtension::Write(
return true;
}
} // namespace
constexpr RTPExtensionType RtpGenericFrameDescriptorExtension00::kId;
constexpr char RtpGenericFrameDescriptorExtension00::kUri[];
bool RtpGenericFrameDescriptorExtension00::Parse(
rtc::ArrayView<const uint8_t> data,
RtpGenericFrameDescriptor* descriptor) {
return RtpGenericFrameDescriptorExtensionParse(0, data, descriptor);
}
size_t RtpGenericFrameDescriptorExtension00::ValueSize(
const RtpGenericFrameDescriptor& descriptor) {
// No difference between existing versions.
return RtpGenericFrameDescriptorExtensionValueSize(descriptor);
}
bool RtpGenericFrameDescriptorExtension00::Write(
rtc::ArrayView<uint8_t> data,
const RtpGenericFrameDescriptor& descriptor) {
return RtpGenericFrameDescriptorExtensionWrite(0, data, descriptor);
}
constexpr RTPExtensionType RtpGenericFrameDescriptorExtension01::kId;
constexpr char RtpGenericFrameDescriptorExtension01::kUri[];
bool RtpGenericFrameDescriptorExtension01::Parse(
rtc::ArrayView<const uint8_t> data,
RtpGenericFrameDescriptor* descriptor) {
return RtpGenericFrameDescriptorExtensionParse(1, data, descriptor);
}
size_t RtpGenericFrameDescriptorExtension01::ValueSize(
const RtpGenericFrameDescriptor& descriptor) {
// No difference between existing versions.
return RtpGenericFrameDescriptorExtensionValueSize(descriptor);
}
bool RtpGenericFrameDescriptorExtension01::Write(
rtc::ArrayView<uint8_t> data,
const RtpGenericFrameDescriptor& descriptor) {
return RtpGenericFrameDescriptorExtensionWrite(1, data, descriptor);
}
} // namespace webrtc

View File

@ -19,14 +19,10 @@
namespace webrtc {
// TODO(bugs.webrtc.org/10243): Remove when downstream projects stop using
// RtpGenericFrameDescriptorExtension.
using RtpGenericFrameDescriptorExtension00 = RtpGenericFrameDescriptorExtension;
class RtpGenericFrameDescriptorExtension {
class RtpGenericFrameDescriptorExtension00 {
public:
using value_type = RtpGenericFrameDescriptor;
static constexpr RTPExtensionType kId = kRtpExtensionGenericFrameDescriptor;
static constexpr RTPExtensionType kId = kRtpExtensionGenericFrameDescriptor00;
static constexpr char kUri[] =
"http://www.webrtc.org/experiments/rtp-hdrext/"
"generic-frame-descriptor-00";
@ -34,7 +30,23 @@ class RtpGenericFrameDescriptorExtension {
static bool Parse(rtc::ArrayView<const uint8_t> data,
RtpGenericFrameDescriptor* descriptor);
static size_t ValueSize(const RtpGenericFrameDescriptor&);
static size_t ValueSize(const RtpGenericFrameDescriptor& descriptor);
static bool Write(rtc::ArrayView<uint8_t> data,
const RtpGenericFrameDescriptor& descriptor);
};
class RtpGenericFrameDescriptorExtension01 {
public:
using value_type = RtpGenericFrameDescriptor;
static constexpr RTPExtensionType kId = kRtpExtensionGenericFrameDescriptor01;
static constexpr char kUri[] =
"http://www.webrtc.org/experiments/rtp-hdrext/"
"generic-frame-descriptor-01";
static constexpr int kMaxSizeBytes = 16;
static bool Parse(rtc::ArrayView<const uint8_t> data,
RtpGenericFrameDescriptor* descriptor);
static size_t ValueSize(const RtpGenericFrameDescriptor& descriptor);
static bool Write(rtc::ArrayView<uint8_t> data,
const RtpGenericFrameDescriptor& descriptor);
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
@ -23,28 +23,87 @@ constexpr uint8_t kDeprecatedFlags = 0x30;
// TODO(danilchap): Add fuzzer to test for various invalid inputs.
TEST(RtpGenericFrameDescriptorExtensionTest,
ParseFirstPacketOfIndependenSubFrame) {
class RtpGenericFrameDescriptorExtensionTest
: public ::testing::Test,
public ::testing::WithParamInterface<int> {
public:
RtpGenericFrameDescriptorExtensionTest() : version_(GetParam()) {}
bool Parse(rtc::ArrayView<const uint8_t> data,
RtpGenericFrameDescriptor* descriptor) const {
switch (version_) {
case 0:
return RtpGenericFrameDescriptorExtension00::Parse(data, descriptor);
case 1:
return RtpGenericFrameDescriptorExtension01::Parse(data, descriptor);
}
RTC_NOTREACHED();
return false;
}
size_t ValueSize(const RtpGenericFrameDescriptor& descriptor) const {
switch (version_) {
case 0:
return RtpGenericFrameDescriptorExtension00::ValueSize(descriptor);
case 1:
return RtpGenericFrameDescriptorExtension01::ValueSize(descriptor);
}
RTC_NOTREACHED();
return 0;
}
bool Write(rtc::ArrayView<uint8_t> data,
const RtpGenericFrameDescriptor& descriptor) const {
switch (version_) {
case 0:
return RtpGenericFrameDescriptorExtension00::Write(data, descriptor);
case 1:
return RtpGenericFrameDescriptorExtension01::Write(data, descriptor);
}
RTC_NOTREACHED();
return false;
}
protected:
const int version_;
};
INSTANTIATE_TEST_SUITE_P(,
RtpGenericFrameDescriptorExtensionTest,
::testing::Values(0, 1));
TEST_P(RtpGenericFrameDescriptorExtensionTest,
ParseFirstPacketOfIndependenSubFrame) {
const int kTemporalLayer = 5;
constexpr uint8_t kRaw[] = {0x80 | kTemporalLayer, 0x49, 0x12, 0x34};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
ASSERT_TRUE(Parse(kRaw, &descriptor));
EXPECT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_FALSE(descriptor.LastPacketInSubFrame());
EXPECT_FALSE(descriptor.FirstSubFrameInFrame());
EXPECT_FALSE(descriptor.LastSubFrameInFrame());
const absl::optional<bool> discardable = descriptor.Discardable();
if (version_ == 0) {
ASSERT_FALSE(discardable.has_value());
} else {
ASSERT_TRUE(discardable.has_value());
EXPECT_FALSE(discardable.value());
}
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), IsEmpty());
EXPECT_EQ(descriptor.TemporalLayer(), kTemporalLayer);
EXPECT_EQ(descriptor.SpatialLayersBitmask(), 0x49);
EXPECT_EQ(descriptor.FrameId(), 0x3412);
}
TEST(RtpGenericFrameDescriptorExtensionTest,
WriteFirstPacketOfIndependenSubFrame) {
TEST_P(RtpGenericFrameDescriptorExtensionTest,
WriteFirstPacketOfIndependenSubFrame) {
const int kTemporalLayer = 5;
constexpr uint8_t kRaw[] = {0xb0 | kTemporalLayer, 0x49, 0x12, 0x34};
uint8_t kRaw[] = {0x80 | kTemporalLayer, 0x49, 0x12, 0x34};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
@ -52,240 +111,263 @@ TEST(RtpGenericFrameDescriptorExtensionTest,
descriptor.SetSpatialLayersBitmask(0x49);
descriptor.SetFrameId(0x3412);
ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
sizeof(kRaw));
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST(RtpGenericFrameDescriptorExtensionTest, ParseLastPacketOfSubFrame) {
TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseLastPacketOfSubFrame) {
constexpr uint8_t kRaw[] = {0x40};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
ASSERT_TRUE(Parse(kRaw, &descriptor));
EXPECT_FALSE(descriptor.FirstPacketInSubFrame());
EXPECT_FALSE(descriptor.FirstSubFrameInFrame());
EXPECT_FALSE(descriptor.LastSubFrameInFrame());
const absl::optional<bool> discardable = descriptor.Discardable();
if (version_ == 0) {
ASSERT_FALSE(discardable.has_value());
} else {
ASSERT_TRUE(discardable.has_value());
EXPECT_FALSE(discardable.value());
}
EXPECT_TRUE(descriptor.LastPacketInSubFrame());
}
TEST(RtpGenericFrameDescriptorExtensionTest, WriteLastPacketOfSubFrame) {
constexpr uint8_t kRaw[] = {0x40 | kDeprecatedFlags};
TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteLastPacketOfSubFrame) {
uint8_t kRaw[] = {0x40};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetLastPacketInSubFrame(true);
ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
sizeof(kRaw));
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST(RtpGenericFrameDescriptorExtensionTest, ParseFirstSubFrameInFrame) {
constexpr uint8_t kRaw[] = {0x20};
RtpGenericFrameDescriptor descriptor;
TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseDiscardable) {
if (version_ == 0) {
return;
}
ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
EXPECT_FALSE(descriptor.FirstPacketInSubFrame());
EXPECT_FALSE(descriptor.LastPacketInSubFrame());
EXPECT_FALSE(descriptor.LastSubFrameInFrame());
EXPECT_TRUE(descriptor.FirstSubFrameInFrame());
}
TEST(RtpGenericFrameDescriptorExtensionTest, ParseLastSubFrameInFrame) {
constexpr uint8_t kRaw[] = {0x10};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
EXPECT_FALSE(descriptor.FirstPacketInSubFrame());
EXPECT_FALSE(descriptor.LastPacketInSubFrame());
EXPECT_FALSE(descriptor.FirstSubFrameInFrame());
EXPECT_TRUE(descriptor.LastSubFrameInFrame());
ASSERT_TRUE(Parse(kRaw, &descriptor));
const absl::optional<bool> discardable = descriptor.Discardable();
ASSERT_TRUE(discardable.has_value());
EXPECT_TRUE(discardable.value());
}
TEST(RtpGenericFrameDescriptorExtensionTest, ParseMinShortFrameDependencies) {
TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteDiscardable) {
if (version_ == 0) {
return;
}
constexpr uint8_t kRaw[] = {0x10};
RtpGenericFrameDescriptor descriptor;
descriptor.SetDiscardable(true);
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseMinShortFrameDependencies) {
constexpr uint16_t kDiff = 1;
constexpr uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x04};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
TEST(RtpGenericFrameDescriptorExtensionTest, WriteMinShortFrameDependencies) {
TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteMinShortFrameDependencies) {
constexpr uint16_t kDiff = 1;
constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0x04};
uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x04};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
sizeof(kRaw));
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST(RtpGenericFrameDescriptorExtensionTest, ParseMaxShortFrameDependencies) {
TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseMaxShortFrameDependencies) {
constexpr uint16_t kDiff = 0x3f;
constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0xfc};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
TEST(RtpGenericFrameDescriptorExtensionTest, WriteMaxShortFrameDependencies) {
TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteMaxShortFrameDependencies) {
constexpr uint16_t kDiff = 0x3f;
constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0xfc};
uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0xfc};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
sizeof(kRaw));
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST(RtpGenericFrameDescriptorExtensionTest, ParseMinLongFrameDependencies) {
TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseMinLongFrameDependencies) {
constexpr uint16_t kDiff = 0x40;
constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0x02, 0x01};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
TEST(RtpGenericFrameDescriptorExtensionTest, WriteMinLongFrameDependencies) {
TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteMinLongFrameDependencies) {
constexpr uint16_t kDiff = 0x40;
constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0x02, 0x01};
uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x02, 0x01};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
sizeof(kRaw));
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST(RtpGenericFrameDescriptorExtensionTest,
ParseLongFrameDependenciesAsBigEndian) {
TEST_P(RtpGenericFrameDescriptorExtensionTest,
ParseLongFrameDependenciesAsBigEndian) {
constexpr uint16_t kDiff = 0x7654 >> 2;
constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0x54 | 0x02, 0x76};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
TEST(RtpGenericFrameDescriptorExtensionTest,
WriteLongFrameDependenciesAsBigEndian) {
TEST_P(RtpGenericFrameDescriptorExtensionTest,
WriteLongFrameDependenciesAsBigEndian) {
constexpr uint16_t kDiff = 0x7654 >> 2;
constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0x54 | 0x02, 0x76};
uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0x54 | 0x02, 0x76};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
sizeof(kRaw));
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST(RtpGenericFrameDescriptorExtensionTest, ParseMaxLongFrameDependencies) {
TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseMaxLongFrameDependencies) {
constexpr uint16_t kDiff = 0x3fff;
constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0xfe, 0xff};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff));
}
TEST(RtpGenericFrameDescriptorExtensionTest, WriteMaxLongFrameDependencies) {
TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteMaxLongFrameDependencies) {
constexpr uint16_t kDiff = 0x3fff;
constexpr uint8_t kRaw[] = {0xb8, 0x01, 0x00, 0x00, 0xfe, 0xff};
uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, 0xfe, 0xff};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff);
ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
sizeof(kRaw));
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST(RtpGenericFrameDescriptorExtensionTest, ParseTwoFrameDependencies) {
TEST_P(RtpGenericFrameDescriptorExtensionTest, ParseTwoFrameDependencies) {
constexpr uint16_t kDiff1 = 9;
constexpr uint16_t kDiff2 = 15;
constexpr uint8_t kRaw[] = {
0xb8, 0x01, 0x00, 0x00, (kDiff1 << 2) | 0x01, kDiff2 << 2};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
ASSERT_TRUE(Parse(kRaw, &descriptor));
ASSERT_TRUE(descriptor.FirstPacketInSubFrame());
EXPECT_THAT(descriptor.FrameDependenciesDiffs(), ElementsAre(kDiff1, kDiff2));
}
TEST(RtpGenericFrameDescriptorExtensionTest, WriteTwoFrameDependencies) {
TEST_P(RtpGenericFrameDescriptorExtensionTest, WriteTwoFrameDependencies) {
constexpr uint16_t kDiff1 = 9;
constexpr uint16_t kDiff2 = 15;
constexpr uint8_t kRaw[] = {
0xb8, 0x01, 0x00, 0x00, (kDiff1 << 2) | 0x01, kDiff2 << 2};
uint8_t kRaw[] = {0x88, 0x01, 0x00, 0x00, (kDiff1 << 2) | 0x01, kDiff2 << 2};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.AddFrameDependencyDiff(kDiff1);
descriptor.AddFrameDependencyDiff(kDiff2);
ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
sizeof(kRaw));
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
TEST(RtpGenericFrameDescriptorExtensionTest,
ParseResolutionOnIndependentFrame) {
TEST_P(RtpGenericFrameDescriptorExtensionTest,
ParseResolutionOnIndependentFrame) {
constexpr int kWidth = 0x2468;
constexpr int kHeight = 0x6543;
constexpr uint8_t kRaw[] = {0xb0, 0x01, 0x00, 0x00, 0x24, 0x68, 0x65, 0x43};
RtpGenericFrameDescriptor descriptor;
ASSERT_TRUE(RtpGenericFrameDescriptorExtension::Parse(kRaw, &descriptor));
ASSERT_TRUE(Parse(kRaw, &descriptor));
EXPECT_EQ(descriptor.Width(), kWidth);
EXPECT_EQ(descriptor.Height(), kHeight);
}
TEST(RtpGenericFrameDescriptorExtensionTest,
WriteResolutionOnIndependentFrame) {
TEST_P(RtpGenericFrameDescriptorExtensionTest,
WriteResolutionOnIndependentFrame) {
constexpr int kWidth = 0x2468;
constexpr int kHeight = 0x6543;
constexpr uint8_t kRaw[] = {0xb0, 0x01, 0x00, 0x00, 0x24, 0x68, 0x65, 0x43};
uint8_t kRaw[] = {0x80, 0x01, 0x00, 0x00, 0x24, 0x68, 0x65, 0x43};
if (version_ == 0) {
kRaw[0] |= kDeprecatedFlags;
}
RtpGenericFrameDescriptor descriptor;
descriptor.SetFirstPacketInSubFrame(true);
descriptor.SetResolution(kWidth, kHeight);
ASSERT_EQ(RtpGenericFrameDescriptorExtension::ValueSize(descriptor),
sizeof(kRaw));
ASSERT_EQ(ValueSize(descriptor), sizeof(kRaw));
uint8_t buffer[sizeof(kRaw)];
EXPECT_TRUE(RtpGenericFrameDescriptorExtension::Write(buffer, descriptor));
EXPECT_TRUE(Write(buffer, descriptor));
EXPECT_THAT(buffer, ElementsAreArray(kRaw));
}
} // namespace

View File

@ -42,7 +42,8 @@ constexpr ExtensionInfo kExtensions[] = {
CreateExtensionInfo<RtpStreamId>(),
CreateExtensionInfo<RepairedRtpStreamId>(),
CreateExtensionInfo<RtpMid>(),
CreateExtensionInfo<RtpGenericFrameDescriptorExtension>(),
CreateExtensionInfo<RtpGenericFrameDescriptorExtension00>(),
CreateExtensionInfo<RtpGenericFrameDescriptorExtension01>(),
CreateExtensionInfo<ColorSpaceExtension>(),
};

View File

@ -79,8 +79,10 @@ constexpr RtpExtensionSize kVideoExtensionSizes[] = {
CreateMaxExtensionSize<RtpStreamId>(),
CreateMaxExtensionSize<RepairedRtpStreamId>(),
CreateMaxExtensionSize<RtpMid>(),
{RtpGenericFrameDescriptorExtension::kId,
RtpGenericFrameDescriptorExtension::kMaxSizeBytes},
{RtpGenericFrameDescriptorExtension00::kId,
RtpGenericFrameDescriptorExtension00::kMaxSizeBytes},
{RtpGenericFrameDescriptorExtension01::kId,
RtpGenericFrameDescriptorExtension01::kMaxSizeBytes},
};
} // namespace

View File

@ -43,7 +43,8 @@ namespace {
enum : int { // The first valid value is 1.
kAbsoluteSendTimeExtensionId = 1,
kAudioLevelExtensionId,
kGenericDescriptorId,
kGenericDescriptorId00,
kGenericDescriptorId01,
kMidExtensionId,
kRepairedRidExtensionId,
kRidExtensionId,
@ -92,8 +93,10 @@ class LoopbackTransportTest : public webrtc::Transport {
receivers_extensions_.Register(kRtpExtensionVideoTiming,
kVideoTimingExtensionId);
receivers_extensions_.Register(kRtpExtensionMid, kMidExtensionId);
receivers_extensions_.Register(kRtpExtensionGenericFrameDescriptor,
kGenericDescriptorId);
receivers_extensions_.Register(kRtpExtensionGenericFrameDescriptor00,
kGenericDescriptorId00);
receivers_extensions_.Register(kRtpExtensionGenericFrameDescriptor01,
kGenericDescriptorId01);
receivers_extensions_.Register(kRtpExtensionRtpStreamId, kRidExtensionId);
receivers_extensions_.Register(kRtpExtensionRepairedRtpStreamId,
kRepairedRidExtensionId);

View File

@ -97,6 +97,7 @@ void AddRtpHeaderExtensions(const RTPVideoHeader& video_header,
RtpGenericFrameDescriptor generic_descriptor;
generic_descriptor.SetFirstPacketInSubFrame(first_packet);
generic_descriptor.SetLastPacketInSubFrame(last_packet);
generic_descriptor.SetDiscardable(video_header.generic->discardable);
if (first_packet) {
generic_descriptor.SetFrameId(
@ -121,8 +122,13 @@ void AddRtpHeaderExtensions(const RTPVideoHeader& video_header,
video_header.height);
}
}
packet->SetExtension<RtpGenericFrameDescriptorExtension>(
generic_descriptor);
if (!packet->SetExtension<RtpGenericFrameDescriptorExtension01>(
generic_descriptor) &&
!packet->SetExtension<RtpGenericFrameDescriptorExtension00>(
generic_descriptor)) {
RTC_LOG(LS_ERROR)
<< "Could not set RTP extension - Generic Frame Descriptor";
}
}
}
@ -539,8 +545,21 @@ bool RTPSenderVideo::SendVideo(FrameType frame_type,
RTPVideoHeader minimized_video_header;
const RTPVideoHeader* packetize_video_header = video_header;
rtc::ArrayView<const uint8_t> generic_descriptor_raw_00 =
first_packet->GetRawExtension<RtpGenericFrameDescriptorExtension00>();
rtc::ArrayView<const uint8_t> generic_descriptor_raw_01 =
first_packet->GetRawExtension<RtpGenericFrameDescriptorExtension01>();
if (!generic_descriptor_raw_00.empty() &&
!generic_descriptor_raw_01.empty()) {
RTC_LOG(LS_WARNING) << "Two versions of GFD extension used.";
return false;
}
rtc::ArrayView<const uint8_t> generic_descriptor_raw =
first_packet->GetRawExtension<RtpGenericFrameDescriptorExtension>();
!generic_descriptor_raw_01.empty() ? generic_descriptor_raw_01
: generic_descriptor_raw_00;
if (!generic_descriptor_raw.empty()) {
if (MinimizeDescriptor(*video_header, &minimized_video_header)) {
packetize_video_header = &minimized_video_header;

View File

@ -37,7 +37,8 @@ using ::testing::ElementsAre;
enum : int { // The first valid value is 1.
kAbsoluteSendTimeExtensionId = 1,
kFrameMarkingExtensionId,
kGenericDescriptorId,
kGenericDescriptorId00,
kGenericDescriptorId01,
kTransmissionTimeOffsetExtensionId,
kTransportSequenceNumberExtensionId,
kVideoRotationExtensionId,
@ -65,8 +66,10 @@ class LoopbackTransportTest : public webrtc::Transport {
kVideoRotationExtensionId);
receivers_extensions_.Register(kRtpExtensionVideoTiming,
kVideoTimingExtensionId);
receivers_extensions_.Register(kRtpExtensionGenericFrameDescriptor,
kGenericDescriptorId);
receivers_extensions_.Register(kRtpExtensionGenericFrameDescriptor00,
kGenericDescriptorId00);
receivers_extensions_.Register(kRtpExtensionGenericFrameDescriptor01,
kGenericDescriptorId01);
receivers_extensions_.Register(kRtpExtensionFrameMarking,
kFrameMarkingExtensionId);
}
@ -139,6 +142,11 @@ class RtpSenderVideoTest : public ::testing::TestWithParam<bool> {
rtp_sender_video_.RegisterPayloadType(kPayload, "generic");
}
void PopulateGenericFrameDescriptor(int version);
void UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed(
int version);
protected:
test::ScopedFieldTrials field_trials_;
SimulatedClock fake_clock_;
@ -512,11 +520,16 @@ TEST_P(RtpSenderVideoTest, ConditionalRetransmitLimit) {
rtp_sender_video_.GetStorageType(header, kSettings, kRttMs));
}
TEST_P(RtpSenderVideoTest, PopulateGenericFrameDescriptor) {
void RtpSenderVideoTest::PopulateGenericFrameDescriptor(int version) {
const RTPExtensionType ext_type =
(version == 0) ? RTPExtensionType::kRtpExtensionGenericFrameDescriptor00
: RTPExtensionType::kRtpExtensionGenericFrameDescriptor01;
const int ext_id =
(version == 0) ? kGenericDescriptorId00 : kGenericDescriptorId01;
const int64_t kFrameId = 100000;
uint8_t kFrame[100];
EXPECT_EQ(0, rtp_sender_.RegisterRtpHeaderExtension(
kRtpExtensionGenericFrameDescriptor, kGenericDescriptorId));
EXPECT_EQ(0, rtp_sender_.RegisterRtpHeaderExtension(ext_type, ext_id));
RTPVideoHeader hdr;
RTPVideoHeader::GenericDescriptorInfo& generic = hdr.generic.emplace();
@ -532,9 +545,15 @@ TEST_P(RtpSenderVideoTest, PopulateGenericFrameDescriptor) {
RtpGenericFrameDescriptor descriptor_wire;
EXPECT_EQ(1, transport_.packets_sent());
EXPECT_TRUE(
transport_.last_sent_packet()
.GetExtension<RtpGenericFrameDescriptorExtension>(&descriptor_wire));
if (version == 0) {
ASSERT_TRUE(transport_.last_sent_packet()
.GetExtension<RtpGenericFrameDescriptorExtension00>(
&descriptor_wire));
} else {
ASSERT_TRUE(transport_.last_sent_packet()
.GetExtension<RtpGenericFrameDescriptorExtension01>(
&descriptor_wire));
}
EXPECT_EQ(static_cast<uint16_t>(generic.frame_id), descriptor_wire.FrameId());
EXPECT_EQ(generic.temporal_index, descriptor_wire.TemporalLayer());
EXPECT_THAT(descriptor_wire.FrameDependenciesDiffs(), ElementsAre(1, 500));
@ -542,13 +561,28 @@ TEST_P(RtpSenderVideoTest, PopulateGenericFrameDescriptor) {
EXPECT_EQ(spatial_bitmask, descriptor_wire.SpatialLayersBitmask());
}
TEST_P(RtpSenderVideoTest,
UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed) {
TEST_P(RtpSenderVideoTest, PopulateGenericFrameDescriptor00) {
PopulateGenericFrameDescriptor(0);
}
TEST_P(RtpSenderVideoTest, PopulateGenericFrameDescriptor01) {
PopulateGenericFrameDescriptor(1);
}
void RtpSenderVideoTest::
UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed(
int version) {
const int64_t kFrameId = 100000;
const size_t kFrameSize = 100;
uint8_t kFrame[kFrameSize];
ASSERT_TRUE(rtp_sender_.RegisterRtpHeaderExtension(
RtpGenericFrameDescriptorExtension::kUri, kGenericDescriptorId));
if (version == 0) {
ASSERT_TRUE(rtp_sender_.RegisterRtpHeaderExtension(
RtpGenericFrameDescriptorExtension00::kUri, kGenericDescriptorId00));
} else {
ASSERT_TRUE(rtp_sender_.RegisterRtpHeaderExtension(
RtpGenericFrameDescriptorExtension01::kUri, kGenericDescriptorId01));
}
RTPVideoHeader hdr;
hdr.codec = kVideoCodecVP8;
@ -569,6 +603,16 @@ TEST_P(RtpSenderVideoTest,
EXPECT_EQ(transport_.last_sent_packet().payload_size(), 1 + kFrameSize);
}
TEST_P(RtpSenderVideoTest,
UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed00) {
UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed(0);
}
TEST_P(RtpSenderVideoTest,
UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed01) {
UsesMinimalVp8DescriptorWhenGenericFrameDescriptorExtensionIsUsed(1);
}
INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead,
RtpSenderVideoTest,
::testing::Bool());

View File

@ -502,7 +502,8 @@ void RtpHeaderParser::ParseOneByteExtensionHeader(
header->extension.mid.Set(rtc::MakeArrayView(ptr, len + 1));
break;
}
case kRtpExtensionGenericFrameDescriptor:
case kRtpExtensionGenericFrameDescriptor00:
case kRtpExtensionGenericFrameDescriptor01:
RTC_LOG(WARNING)
<< "RtpGenericFrameDescriptor unsupported by rtp header parser.";
break;

View File

@ -43,6 +43,7 @@ struct RTPVideoHeader {
int temporal_index = 0;
absl::InlinedVector<int64_t, 5> dependencies;
absl::InlinedVector<int, 5> higher_spatial_layers;
bool discardable = false;
};
RTPVideoHeader();

View File

@ -262,7 +262,9 @@ void CallTest::CreateVideoSendConfig(VideoSendStream::Config* video_config,
&video_config->rtp.extensions);
AddRtpExtensionByUri(RtpExtension::kVideoContentTypeUri,
&video_config->rtp.extensions);
AddRtpExtensionByUri(RtpExtension::kGenericFrameDescriptorUri,
AddRtpExtensionByUri(RtpExtension::kGenericFrameDescriptorUri00,
&video_config->rtp.extensions);
AddRtpExtensionByUri(RtpExtension::kGenericFrameDescriptorUri01,
&video_config->rtp.extensions);
if (video_encoder_configs_.empty()) {
video_encoder_configs_.emplace_back();

View File

@ -116,9 +116,14 @@ void FuzzOneInput(const uint8_t* data, size_t size) {
packet.GetExtension<RtpMid>(&mid);
break;
}
case kRtpExtensionGenericFrameDescriptor: {
case kRtpExtensionGenericFrameDescriptor00: {
RtpGenericFrameDescriptor descriptor;
packet.GetExtension<RtpGenericFrameDescriptorExtension>(&descriptor);
packet.GetExtension<RtpGenericFrameDescriptorExtension00>(&descriptor);
break;
}
case kRtpExtensionGenericFrameDescriptor01: {
RtpGenericFrameDescriptor descriptor;
packet.GetExtension<RtpGenericFrameDescriptorExtension01>(&descriptor);
break;
}
case kRtpExtensionColorSpace: {

View File

@ -531,17 +531,31 @@ void RtpVideoStreamReceiver::ReceivePacket(const RtpPacketReceived& packet) {
absl::optional<RtpGenericFrameDescriptor> generic_descriptor_wire;
generic_descriptor_wire.emplace();
if (packet.GetExtension<RtpGenericFrameDescriptorExtension>(
&generic_descriptor_wire.value())) {
generic_descriptor_wire->SetByteRepresentation(
packet.GetRawExtension<RtpGenericFrameDescriptorExtension>());
const bool generic_descriptor_v00 =
packet.GetExtension<RtpGenericFrameDescriptorExtension00>(
&generic_descriptor_wire.value());
const bool generic_descriptor_v01 =
packet.GetExtension<RtpGenericFrameDescriptorExtension01>(
&generic_descriptor_wire.value());
if (generic_descriptor_v00 && generic_descriptor_v01) {
RTC_LOG(LS_WARNING) << "RTP packet had two different GFD versions.";
return;
}
if (generic_descriptor_v00 || generic_descriptor_v01) {
if (generic_descriptor_v00) {
generic_descriptor_wire->SetByteRepresentation(
packet.GetRawExtension<RtpGenericFrameDescriptorExtension00>());
} else {
generic_descriptor_wire->SetByteRepresentation(
packet.GetRawExtension<RtpGenericFrameDescriptorExtension01>());
}
webrtc_rtp_header.video_header().is_first_packet_in_frame =
generic_descriptor_wire->FirstSubFrameInFrame() &&
generic_descriptor_wire->FirstPacketInSubFrame();
webrtc_rtp_header.video_header().is_last_packet_in_frame =
webrtc_rtp_header.header.markerBit ||
(generic_descriptor_wire->LastSubFrameInFrame() &&
generic_descriptor_wire->LastPacketInSubFrame());
generic_descriptor_wire->LastPacketInSubFrame();
if (generic_descriptor_wire->FirstPacketInSubFrame()) {
webrtc_rtp_header.frameType =

View File

@ -32,6 +32,7 @@
using ::testing::_;
using ::testing::Invoke;
using ::testing::Values;
namespace webrtc {
@ -284,10 +285,9 @@ class RtpVideoStreamReceiverTestH264
RtpVideoStreamReceiverTestH264() : RtpVideoStreamReceiverTest(GetParam()) {}
};
INSTANTIATE_TEST_SUITE_P(
SpsPpsIdrIsKeyframe,
RtpVideoStreamReceiverTestH264,
::testing::Values("", "WebRTC-SpsPpsIdrIsH264Keyframe/Enabled/"));
INSTANTIATE_TEST_SUITE_P(SpsPpsIdrIsKeyframe,
RtpVideoStreamReceiverTestH264,
Values("", "WebRTC-SpsPpsIdrIsH264Keyframe/Enabled/"));
TEST_P(RtpVideoStreamReceiverTestH264, InBandSpsPps) {
std::vector<uint8_t> sps_data;
@ -500,7 +500,51 @@ TEST_F(RtpVideoStreamReceiverTest,
rtp_video_stream_receiver_->RemoveSecondarySink(&secondary_sink);
}
TEST_F(RtpVideoStreamReceiverTest, ParseGenericDescriptorOnePacket) {
class RtpVideoStreamReceiverGenericDescriptorTest
: public RtpVideoStreamReceiverTest,
public ::testing::WithParamInterface<int> {
public:
void RegisterRtpGenericFrameDescriptorExtension(
RtpHeaderExtensionMap* extension_map,
int version) {
constexpr int kId00 = 5;
constexpr int kId01 = 6;
switch (version) {
case 0:
extension_map->Register<RtpGenericFrameDescriptorExtension00>(kId00);
return;
case 1:
extension_map->Register<RtpGenericFrameDescriptorExtension01>(kId01);
return;
}
RTC_NOTREACHED();
}
bool SetExtensionRtpGenericFrameDescriptorExtension(
const RtpGenericFrameDescriptor& generic_descriptor,
RtpPacketReceived* rtp_packet,
int version) {
switch (version) {
case 0:
return rtp_packet->SetExtension<RtpGenericFrameDescriptorExtension00>(
generic_descriptor);
case 1:
return rtp_packet->SetExtension<RtpGenericFrameDescriptorExtension01>(
generic_descriptor);
}
RTC_NOTREACHED();
return false;
}
};
INSTANTIATE_TEST_SUITE_P(,
RtpVideoStreamReceiverGenericDescriptorTest,
Values(0, 1));
TEST_P(RtpVideoStreamReceiverGenericDescriptorTest,
ParseGenericDescriptorOnePacket) {
const int version = GetParam();
const std::vector<uint8_t> data = {0, 1, 2, 3, 4};
const int kPayloadType = 123;
const int kSpatialIndex = 1;
@ -511,7 +555,7 @@ TEST_F(RtpVideoStreamReceiverTest, ParseGenericDescriptorOnePacket) {
rtp_video_stream_receiver_->StartReceive();
RtpHeaderExtensionMap extension_map;
extension_map.Register<RtpGenericFrameDescriptorExtension>(5);
RegisterRtpGenericFrameDescriptorExtension(&extension_map, version);
RtpPacketReceived rtp_packet(&extension_map);
RtpGenericFrameDescriptor generic_descriptor;
@ -521,8 +565,8 @@ TEST_F(RtpVideoStreamReceiverTest, ParseGenericDescriptorOnePacket) {
generic_descriptor.SetSpatialLayersBitmask(1 << kSpatialIndex);
generic_descriptor.AddFrameDependencyDiff(90);
generic_descriptor.AddFrameDependencyDiff(80);
EXPECT_TRUE(rtp_packet.SetExtension<RtpGenericFrameDescriptorExtension>(
generic_descriptor));
ASSERT_TRUE(SetExtensionRtpGenericFrameDescriptorExtension(
generic_descriptor, &rtp_packet, version));
uint8_t* payload = rtp_packet.SetPayloadSize(data.size());
memcpy(payload, data.data(), data.size());
@ -545,7 +589,10 @@ TEST_F(RtpVideoStreamReceiverTest, ParseGenericDescriptorOnePacket) {
rtp_video_stream_receiver_->OnRtpPacket(rtp_packet);
}
TEST_F(RtpVideoStreamReceiverTest, ParseGenericDescriptorTwoPackets) {
TEST_P(RtpVideoStreamReceiverGenericDescriptorTest,
ParseGenericDescriptorTwoPackets) {
const int version = GetParam();
const std::vector<uint8_t> data = {0, 1, 2, 3, 4};
const int kPayloadType = 123;
const int kSpatialIndex = 1;
@ -556,7 +603,7 @@ TEST_F(RtpVideoStreamReceiverTest, ParseGenericDescriptorTwoPackets) {
rtp_video_stream_receiver_->StartReceive();
RtpHeaderExtensionMap extension_map;
extension_map.Register<RtpGenericFrameDescriptorExtension>(5);
RegisterRtpGenericFrameDescriptorExtension(&extension_map, version);
RtpPacketReceived first_packet(&extension_map);
RtpGenericFrameDescriptor first_packet_descriptor;
@ -565,8 +612,8 @@ TEST_F(RtpVideoStreamReceiverTest, ParseGenericDescriptorTwoPackets) {
first_packet_descriptor.SetFrameId(100);
first_packet_descriptor.SetSpatialLayersBitmask(1 << kSpatialIndex);
first_packet_descriptor.SetResolution(480, 360);
EXPECT_TRUE(first_packet.SetExtension<RtpGenericFrameDescriptorExtension>(
first_packet_descriptor));
ASSERT_TRUE(SetExtensionRtpGenericFrameDescriptorExtension(
first_packet_descriptor, &first_packet, version));
uint8_t* first_packet_payload = first_packet.SetPayloadSize(data.size());
memcpy(first_packet_payload, data.data(), data.size());
@ -582,8 +629,8 @@ TEST_F(RtpVideoStreamReceiverTest, ParseGenericDescriptorTwoPackets) {
RtpGenericFrameDescriptor second_packet_descriptor;
second_packet_descriptor.SetFirstPacketInSubFrame(false);
second_packet_descriptor.SetLastPacketInSubFrame(true);
EXPECT_TRUE(second_packet.SetExtension<RtpGenericFrameDescriptorExtension>(
second_packet_descriptor));
ASSERT_TRUE(SetExtensionRtpGenericFrameDescriptorExtension(
second_packet_descriptor, &second_packet, version));
second_packet.SetMarker(true);
second_packet.SetPayloadType(kPayloadType);
@ -606,6 +653,45 @@ TEST_F(RtpVideoStreamReceiverTest, ParseGenericDescriptorTwoPackets) {
rtp_video_stream_receiver_->OnRtpPacket(second_packet);
}
TEST_F(RtpVideoStreamReceiverGenericDescriptorTest,
DropPacketsWithMultipleVersionsOfExtension) {
const std::vector<uint8_t> data = {0, 1, 2, 3, 4};
const int kPayloadType = 123;
VideoCodec codec;
codec.plType = kPayloadType;
rtp_video_stream_receiver_->AddReceiveCodec(codec, {});
rtp_video_stream_receiver_->StartReceive();
RtpHeaderExtensionMap extension_map;
RegisterRtpGenericFrameDescriptorExtension(&extension_map, 0);
RegisterRtpGenericFrameDescriptorExtension(&extension_map, 1);
RtpPacketReceived rtp_packet(&extension_map);
RtpGenericFrameDescriptor generic_descriptors[2];
for (size_t i = 0; i < 2; ++i) {
generic_descriptors[i].SetFirstPacketInSubFrame(true);
generic_descriptors[i].SetLastPacketInSubFrame(true);
generic_descriptors[i].SetFrameId(100);
ASSERT_TRUE(SetExtensionRtpGenericFrameDescriptorExtension(
generic_descriptors[i], &rtp_packet, i));
}
uint8_t* payload = rtp_packet.SetPayloadSize(data.size());
memcpy(payload, data.data(), data.size());
// The first byte is the header, so we ignore the first byte of |data|.
mock_on_complete_frame_callback_.AppendExpectedBitstream(data.data() + 1,
data.size() - 1);
rtp_packet.SetMarker(true);
rtp_packet.SetPayloadType(kPayloadType);
rtp_packet.SetSequenceNumber(1);
EXPECT_CALL(mock_on_complete_frame_callback_, DoOnCompleteFrame).Times(0);
rtp_video_stream_receiver_->OnRtpPacket(rtp_packet);
}
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST_F(RtpVideoStreamReceiverTest, RepeatedSecondarySinkDisallowed) {
MockRtpPacketSink secondary_sink;

View File

@ -49,7 +49,8 @@ namespace webrtc {
namespace {
enum : int { // The first valid value is 1.
kAbsSendTimeExtensionId = 1,
kGenericFrameDescriptorExtensionId,
kGenericFrameDescriptorExtensionId00,
kGenericFrameDescriptorExtensionId01,
kTransportSequenceNumberExtensionId,
kVideoContentTypeExtensionId,
kVideoTimingExtensionId,
@ -732,8 +733,11 @@ void VideoQualityTest::SetupVideo(Transport* send_transport,
RTC_CHECK(field_trial::IsEnabled("WebRTC-GenericDescriptor"));
video_send_configs_[video_idx].rtp.extensions.emplace_back(
RtpExtension::kGenericFrameDescriptorUri,
kGenericFrameDescriptorExtensionId);
RtpExtension::kGenericFrameDescriptorUri00,
kGenericFrameDescriptorExtensionId00);
video_send_configs_[video_idx].rtp.extensions.emplace_back(
RtpExtension::kGenericFrameDescriptorUri01,
kGenericFrameDescriptorExtensionId01);
}
video_send_configs_[video_idx].rtp.extensions.emplace_back(