Write corruption detection header extension to last packet

Bug: webrtc:358039777
Change-Id: Iaa69310e361b51cb109a43cc46aed124af69bd97
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/363302
Reviewed-by: Erik Språng <sprang@webrtc.org>
Auto-Submit: Fanny Linderborg <linderborg@webrtc.org>
Commit-Queue: Fanny Linderborg <linderborg@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#43084}
This commit is contained in:
Fanny Linderborg 2024-09-26 08:51:49 +02:00 committed by WebRTC LUCI CQ
parent f8b3dab7c6
commit 28d1a9a4de
3 changed files with 111 additions and 0 deletions

View File

@ -316,6 +316,9 @@ rtc_library("rtp_rtcp") {
"../../api/video_codecs:video_codecs_api",
"../../call:rtp_interfaces",
"../../common_video",
"../../common_video:corruption_detection_converters",
"../../common_video:corruption_detection_message",
"../../common_video:frame_instrumentation_data",
"../../logging:rtc_event_rtp_rtcp",
"../../rtc_base:bit_buffer",
"../../rtc_base:bitrate_tracker",
@ -704,6 +707,8 @@ if (rtc_include_tests) {
"../../call:rtp_receiver",
"../../call:video_stream_api",
"../../common_video",
"../../common_video:corruption_detection_message",
"../../common_video:frame_instrumentation_data",
"../../common_video/generic_frame_descriptor",
"../../common_video/test:utilities",
"../../logging:mocks",

View File

@ -40,8 +40,12 @@
#include "api/video/video_layers_allocation.h"
#include "api/video/video_rotation.h"
#include "api/video/video_timing.h"
#include "common_video/corruption_detection_converters.h"
#include "common_video/corruption_detection_message.h"
#include "common_video/frame_instrumentation_data.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/absolute_capture_time_sender.h"
#include "modules/rtp_rtcp/source/corruption_detection_extension.h"
#include "modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h"
#include "modules/rtp_rtcp/source/rtp_descriptor_authentication.h"
#include "modules/rtp_rtcp/source/rtp_format.h"
@ -476,6 +480,28 @@ void RTPSenderVideo::AddRtpHeaderExtensions(const RTPVideoHeader& video_header,
packet->SetExtension<VideoFrameTrackingIdExtension>(
*video_header.video_frame_tracking_id);
}
if (last_packet && video_header.frame_instrumentation_data) {
std::optional<CorruptionDetectionMessage> message;
if (absl::holds_alternative<FrameInstrumentationData>(
*video_header.frame_instrumentation_data)) {
message = ConvertFrameInstrumentationDataToCorruptionDetectionMessage(
absl::get<FrameInstrumentationData>(
*video_header.frame_instrumentation_data));
} else if (absl::holds_alternative<FrameInstrumentationSyncData>(
*video_header.frame_instrumentation_data)) {
message = ConvertFrameInstrumentationSyncDataToCorruptionDetectionMessage(
absl::get<FrameInstrumentationSyncData>(
*video_header.frame_instrumentation_data));
}
if (message.has_value()) {
packet->SetExtension<CorruptionDetectionExtension>(*message);
} else {
RTC_LOG(LS_WARNING) << "Failed to convert frame instrumentation data to "
"corruption detection message.";
}
}
}
bool RTPSenderVideo::SendVideo(int payload_type,

View File

@ -10,6 +10,7 @@
#include "modules/rtp_rtcp/source/rtp_sender_video.h"
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
@ -27,9 +28,13 @@
#include "api/transport/rtp/dependency_descriptor.h"
#include "api/units/timestamp.h"
#include "api/video/video_codec_constants.h"
#include "api/video/video_frame_type.h"
#include "api/video/video_timing.h"
#include "common_video/corruption_detection_message.h"
#include "common_video/frame_instrumentation_data.h"
#include "modules/rtp_rtcp/include/rtp_cvo.h"
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
#include "modules/rtp_rtcp/source/corruption_detection_extension.h"
#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
@ -78,6 +83,7 @@ enum : int { // The first valid value is 1.
kAbsoluteCaptureTimeExtensionId,
kPlayoutDelayExtensionId,
kVideoLayersAllocationExtensionId,
kCorruptionDetectionExtensionId,
};
constexpr int kPayload = 100;
@ -112,6 +118,8 @@ class LoopbackTransportTest : public webrtc::Transport {
kPlayoutDelayExtensionId);
receivers_extensions_.Register<RtpVideoLayersAllocationExtension>(
kVideoLayersAllocationExtensionId);
receivers_extensions_.Register<CorruptionDetectionExtension>(
kCorruptionDetectionExtensionId);
}
bool SendRtp(rtc::ArrayView<const uint8_t> data,
@ -235,6 +243,78 @@ TEST_F(RtpSenderVideoTest, TimingFrameHasPacketizationTimstampSet) {
EXPECT_EQ(kEncodeFinishDeltaMs, timing.encode_finish_delta_ms);
}
TEST_F(RtpSenderVideoTest,
WriteCorruptionExtensionIfHeaderContainsFrameInstrumentationData) {
uint8_t kFrame[kMaxPacketLength];
rtp_module_.RegisterRtpHeaderExtension(CorruptionDetectionExtension::Uri(),
kCorruptionDetectionExtensionId);
RTPVideoHeader hdr;
hdr.frame_type = VideoFrameType::kVideoFrameKey;
hdr.frame_instrumentation_data = FrameInstrumentationData{
.sequence_index = 130, // 128 + 2
.communicate_upper_bits = false,
.std_dev = 2.0,
.luma_error_threshold = 3,
.chroma_error_threshold = 2,
.sample_values = {12.0, 12.0, 12.0, 12.0, 12.0, 12.0, 12.0, 12.0}};
CorruptionDetectionMessage message;
rtp_sender_video_->SendVideo(
kPayload, kType, kTimestamp, fake_clock_.CurrentTime(), kFrame,
sizeof(kFrame), hdr, kDefaultExpectedRetransmissionTime, {});
// Only written on last packet.
for (const RtpPacketReceived& packet : transport_.sent_packets()) {
if (&packet == &transport_.last_sent_packet()) {
EXPECT_TRUE(transport_.last_sent_packet()
.GetExtension<CorruptionDetectionExtension>(&message));
} else {
EXPECT_FALSE(packet.HasExtension<CorruptionDetectionExtension>());
}
}
EXPECT_EQ(message.sequence_index(), 2);
EXPECT_FALSE(message.interpret_sequence_index_as_most_significant_bits());
EXPECT_NEAR(message.std_dev(), 2.0392156862745097, 0.041); // ~2%
EXPECT_EQ(message.luma_error_threshold(), 3);
EXPECT_EQ(message.chroma_error_threshold(), 2);
EXPECT_THAT(message.sample_values(),
ElementsAre(12.0, 12.0, 12.0, 12.0, 12.0, 12.0, 12.0, 12.0));
}
TEST_F(RtpSenderVideoTest,
WriteCorruptionExtensionIfHeaderContainsFrameInstrumentationSyncData) {
uint8_t kFrame[kMaxPacketLength];
rtp_module_.RegisterRtpHeaderExtension(CorruptionDetectionExtension::Uri(),
kCorruptionDetectionExtensionId);
RTPVideoHeader hdr;
hdr.frame_type = VideoFrameType::kVideoFrameKey;
hdr.frame_instrumentation_data = FrameInstrumentationSyncData{
.sequence_index = 130, // 128 + 2
.communicate_upper_bits = true,
};
CorruptionDetectionMessage message;
rtp_sender_video_->SendVideo(
kPayload, kType, kTimestamp, fake_clock_.CurrentTime(), kFrame,
sizeof(kFrame), hdr, kDefaultExpectedRetransmissionTime, {});
// Only written on last packet.
for (const RtpPacketReceived& packet : transport_.sent_packets()) {
if (&packet == &transport_.last_sent_packet()) {
EXPECT_TRUE(transport_.last_sent_packet()
.GetExtension<CorruptionDetectionExtension>(&message));
} else {
EXPECT_FALSE(packet.HasExtension<CorruptionDetectionExtension>());
}
}
EXPECT_EQ(message.sequence_index(), 1);
EXPECT_TRUE(message.interpret_sequence_index_as_most_significant_bits());
EXPECT_DOUBLE_EQ(message.std_dev(), 0.0);
EXPECT_EQ(message.luma_error_threshold(), 0);
EXPECT_EQ(message.chroma_error_threshold(), 0);
EXPECT_THAT(message.sample_values(), IsEmpty());
}
TEST_F(RtpSenderVideoTest, DeltaFrameHasCVOWhenChanged) {
uint8_t kFrame[kMaxPacketLength];
rtp_module_.RegisterRtpHeaderExtension(VideoOrientation::Uri(),