mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 22:00:47 +01:00

This CL was generated by running git ls-files | grep -P "(\.h|\.cc)$" | grep -v 'sdk/' | grep -v 'rtc_base/ssl_' | \ grep -v 'fake_rtc_certificate_generator.h' | grep -v 'modules/audio_device/win/' | \ grep -v 'system_wrappers/source/clock.cc' | grep -v 'rtc_base/trace_event.h' | \ grep -v 'modules/audio_coding/codecs/ilbc/' | grep -v 'screen_capturer_mac.h' | \ grep -v 'spl_inl_mips.h' | grep -v 'data_size_unittest.cc' | grep -v 'timestamp_unittest.cc' \ | xargs clang-format -i ; git cl format Most of these changes are clang-format grouping and reordering includes differently. Bug: webrtc:9340 Change-Id: Ic83ddbc169bfacd21883e381b5181c3dd4fe8a63 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/144051 Commit-Queue: Jonas Olsson <jonasolsson@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Cr-Commit-Position: refs/heads/master@{#28505}
816 lines
30 KiB
C++
816 lines
30 KiB
C++
/*
|
|
* Copyright (c) 2015 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
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "modules/rtp_rtcp/source/rtp_format_vp9.h"
|
|
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
|
|
#include "test/gmock.h"
|
|
#include "test/gtest.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
void VerifyHeader(const RTPVideoHeaderVP9& expected,
|
|
const RTPVideoHeaderVP9& actual) {
|
|
EXPECT_EQ(expected.inter_layer_predicted, actual.inter_layer_predicted);
|
|
EXPECT_EQ(expected.inter_pic_predicted, actual.inter_pic_predicted);
|
|
EXPECT_EQ(expected.flexible_mode, actual.flexible_mode);
|
|
EXPECT_EQ(expected.beginning_of_frame, actual.beginning_of_frame);
|
|
EXPECT_EQ(expected.end_of_frame, actual.end_of_frame);
|
|
EXPECT_EQ(expected.ss_data_available, actual.ss_data_available);
|
|
EXPECT_EQ(expected.non_ref_for_inter_layer_pred,
|
|
actual.non_ref_for_inter_layer_pred);
|
|
EXPECT_EQ(expected.picture_id, actual.picture_id);
|
|
EXPECT_EQ(expected.max_picture_id, actual.max_picture_id);
|
|
EXPECT_EQ(expected.temporal_idx, actual.temporal_idx);
|
|
EXPECT_EQ(expected.spatial_idx, actual.spatial_idx);
|
|
EXPECT_EQ(expected.gof_idx, actual.gof_idx);
|
|
EXPECT_EQ(expected.tl0_pic_idx, actual.tl0_pic_idx);
|
|
EXPECT_EQ(expected.temporal_up_switch, actual.temporal_up_switch);
|
|
|
|
EXPECT_EQ(expected.num_ref_pics, actual.num_ref_pics);
|
|
for (uint8_t i = 0; i < expected.num_ref_pics; ++i) {
|
|
EXPECT_EQ(expected.pid_diff[i], actual.pid_diff[i]);
|
|
EXPECT_EQ(expected.ref_picture_id[i], actual.ref_picture_id[i]);
|
|
}
|
|
if (expected.ss_data_available) {
|
|
EXPECT_EQ(expected.spatial_layer_resolution_present,
|
|
actual.spatial_layer_resolution_present);
|
|
EXPECT_EQ(expected.num_spatial_layers, actual.num_spatial_layers);
|
|
if (expected.spatial_layer_resolution_present) {
|
|
for (size_t i = 0; i < expected.num_spatial_layers; i++) {
|
|
EXPECT_EQ(expected.width[i], actual.width[i]);
|
|
EXPECT_EQ(expected.height[i], actual.height[i]);
|
|
}
|
|
}
|
|
EXPECT_EQ(expected.gof.num_frames_in_gof, actual.gof.num_frames_in_gof);
|
|
for (size_t i = 0; i < expected.gof.num_frames_in_gof; i++) {
|
|
EXPECT_EQ(expected.gof.temporal_up_switch[i],
|
|
actual.gof.temporal_up_switch[i]);
|
|
EXPECT_EQ(expected.gof.temporal_idx[i], actual.gof.temporal_idx[i]);
|
|
EXPECT_EQ(expected.gof.num_ref_pics[i], actual.gof.num_ref_pics[i]);
|
|
for (uint8_t j = 0; j < expected.gof.num_ref_pics[i]; j++) {
|
|
EXPECT_EQ(expected.gof.pid_diff[i][j], actual.gof.pid_diff[i][j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void VerifyPayload(const RtpDepacketizer::ParsedPayload& parsed,
|
|
const uint8_t* payload,
|
|
size_t payload_length) {
|
|
EXPECT_EQ(payload, parsed.payload);
|
|
EXPECT_EQ(payload_length, parsed.payload_length);
|
|
EXPECT_THAT(std::vector<uint8_t>(parsed.payload,
|
|
parsed.payload + parsed.payload_length),
|
|
::testing::ElementsAreArray(payload, payload_length));
|
|
}
|
|
|
|
void ParseAndCheckPacket(const uint8_t* packet,
|
|
const RTPVideoHeaderVP9& expected,
|
|
size_t expected_hdr_length,
|
|
size_t expected_length) {
|
|
std::unique_ptr<RtpDepacketizer> depacketizer(new RtpDepacketizerVp9());
|
|
RtpDepacketizer::ParsedPayload parsed;
|
|
ASSERT_TRUE(depacketizer->Parse(&parsed, packet, expected_length));
|
|
EXPECT_EQ(kVideoCodecVP9, parsed.video_header().codec);
|
|
auto& vp9_header =
|
|
absl::get<RTPVideoHeaderVP9>(parsed.video_header().video_type_header);
|
|
VerifyHeader(expected, vp9_header);
|
|
const size_t kExpectedPayloadLength = expected_length - expected_hdr_length;
|
|
VerifyPayload(parsed, packet + expected_hdr_length, kExpectedPayloadLength);
|
|
}
|
|
} // namespace
|
|
|
|
// Payload descriptor for flexible mode
|
|
// 0 1 2 3 4 5 6 7
|
|
// +-+-+-+-+-+-+-+-+
|
|
// |I|P|L|F|B|E|V|Z| (REQUIRED)
|
|
// +-+-+-+-+-+-+-+-+
|
|
// I: |M| PICTURE ID | (RECOMMENDED)
|
|
// +-+-+-+-+-+-+-+-+
|
|
// M: | EXTENDED PID | (RECOMMENDED)
|
|
// +-+-+-+-+-+-+-+-+
|
|
// L: | T |U| S |D| (CONDITIONALLY RECOMMENDED)
|
|
// +-+-+-+-+-+-+-+-+ -|
|
|
// P,F: | P_DIFF |N| (CONDITIONALLY RECOMMENDED) . up to 3 times
|
|
// +-+-+-+-+-+-+-+-+ -|
|
|
// V: | SS |
|
|
// | .. |
|
|
// +-+-+-+-+-+-+-+-+
|
|
//
|
|
// Payload descriptor for non-flexible mode
|
|
// 0 1 2 3 4 5 6 7
|
|
// +-+-+-+-+-+-+-+-+
|
|
// |I|P|L|F|B|E|V|Z| (REQUIRED)
|
|
// +-+-+-+-+-+-+-+-+
|
|
// I: |M| PICTURE ID | (RECOMMENDED)
|
|
// +-+-+-+-+-+-+-+-+
|
|
// M: | EXTENDED PID | (RECOMMENDED)
|
|
// +-+-+-+-+-+-+-+-+
|
|
// L: | T |U| S |D| (CONDITIONALLY RECOMMENDED)
|
|
// +-+-+-+-+-+-+-+-+
|
|
// | TL0PICIDX | (CONDITIONALLY REQUIRED)
|
|
// +-+-+-+-+-+-+-+-+
|
|
// V: | SS |
|
|
// | .. |
|
|
// +-+-+-+-+-+-+-+-+
|
|
|
|
class RtpPacketizerVp9Test : public ::testing::Test {
|
|
protected:
|
|
static constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr;
|
|
static constexpr size_t kMaxPacketSize = 1200;
|
|
|
|
RtpPacketizerVp9Test() : packet_(kNoExtensions, kMaxPacketSize) {}
|
|
void SetUp() override { expected_.InitRTPVideoHeaderVP9(); }
|
|
|
|
RtpPacketToSend packet_;
|
|
std::vector<uint8_t> payload_;
|
|
size_t payload_pos_;
|
|
RTPVideoHeaderVP9 expected_;
|
|
std::unique_ptr<RtpPacketizerVp9> packetizer_;
|
|
size_t num_packets_;
|
|
|
|
void Init(size_t payload_size, size_t packet_size) {
|
|
payload_.assign(payload_size, 7);
|
|
payload_pos_ = 0;
|
|
RtpPacketizer::PayloadSizeLimits limits;
|
|
limits.max_payload_len = packet_size;
|
|
packetizer_.reset(new RtpPacketizerVp9(payload_, limits, expected_));
|
|
num_packets_ = packetizer_->NumPackets();
|
|
}
|
|
|
|
void CheckPayload(const uint8_t* packet,
|
|
size_t start_pos,
|
|
size_t end_pos,
|
|
bool last) {
|
|
for (size_t i = start_pos; i < end_pos; ++i) {
|
|
EXPECT_EQ(packet[i], payload_[payload_pos_++]);
|
|
}
|
|
EXPECT_EQ(last, payload_pos_ == payload_.size());
|
|
}
|
|
|
|
void CreateParseAndCheckPackets(const size_t* expected_hdr_sizes,
|
|
const size_t* expected_sizes,
|
|
size_t expected_num_packets) {
|
|
ASSERT_TRUE(packetizer_.get() != NULL);
|
|
if (expected_num_packets == 0) {
|
|
EXPECT_FALSE(packetizer_->NextPacket(&packet_));
|
|
return;
|
|
}
|
|
EXPECT_EQ(expected_num_packets, num_packets_);
|
|
for (size_t i = 0; i < expected_num_packets; ++i) {
|
|
EXPECT_TRUE(packetizer_->NextPacket(&packet_));
|
|
auto rtp_payload = packet_.payload();
|
|
EXPECT_EQ(expected_sizes[i], rtp_payload.size());
|
|
RTPVideoHeaderVP9 hdr = expected_;
|
|
hdr.beginning_of_frame = (i == 0);
|
|
hdr.end_of_frame = (i + 1) == expected_num_packets;
|
|
ParseAndCheckPacket(rtp_payload.data(), hdr, expected_hdr_sizes[i],
|
|
rtp_payload.size());
|
|
CheckPayload(rtp_payload.data(), expected_hdr_sizes[i],
|
|
rtp_payload.size(), (i + 1) == expected_num_packets);
|
|
expected_.ss_data_available = false;
|
|
}
|
|
}
|
|
};
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestEqualSizedMode_OnePacket) {
|
|
const size_t kFrameSize = 25;
|
|
const size_t kPacketSize = 26;
|
|
Init(kFrameSize, kPacketSize);
|
|
|
|
// One packet:
|
|
// I:0, P:0, L:0, F:0, B:1, E:1, V:0, Z:0 (1hdr + 25 payload)
|
|
const size_t kExpectedHdrSizes[] = {1};
|
|
const size_t kExpectedSizes[] = {26};
|
|
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
|
|
CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestEqualSizedMode_TwoPackets) {
|
|
const size_t kFrameSize = 27;
|
|
const size_t kPacketSize = 27;
|
|
Init(kFrameSize, kPacketSize);
|
|
|
|
// Two packets:
|
|
// I:0, P:0, L:0, F:0, B:1, E:0, V:0, Z:0 (1hdr + 14 payload)
|
|
// I:0, P:0, L:0, F:0, B:0, E:1, V:0, Z:0 (1hdr + 13 payload)
|
|
const size_t kExpectedHdrSizes[] = {1, 1};
|
|
const size_t kExpectedSizes[] = {14, 15};
|
|
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
|
|
CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestTooShortBufferToFitPayload) {
|
|
const size_t kFrameSize = 1;
|
|
const size_t kPacketSize = 1;
|
|
Init(kFrameSize, kPacketSize); // 1hdr + 1 payload
|
|
|
|
const size_t kExpectedNum = 0;
|
|
CreateParseAndCheckPackets(NULL, NULL, kExpectedNum);
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestOneBytePictureId) {
|
|
const size_t kFrameSize = 30;
|
|
const size_t kPacketSize = 12;
|
|
|
|
expected_.picture_id = kMaxOneBytePictureId; // 2 byte payload descriptor
|
|
expected_.max_picture_id = kMaxOneBytePictureId;
|
|
Init(kFrameSize, kPacketSize);
|
|
|
|
// Three packets:
|
|
// I:1, P:0, L:0, F:0, B:1, E:0, V:0, Z:0 (2hdr + 10 payload)
|
|
// I:1, P:0, L:0, F:0, B:0, E:0, V:0, Z:0 (2hdr + 10 payload)
|
|
// I:1, P:0, L:0, F:0, B:0, E:1, V:0, Z:0 (2hdr + 10 payload)
|
|
const size_t kExpectedHdrSizes[] = {2, 2, 2};
|
|
const size_t kExpectedSizes[] = {12, 12, 12};
|
|
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
|
|
CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestTwoBytePictureId) {
|
|
const size_t kFrameSize = 31;
|
|
const size_t kPacketSize = 13;
|
|
|
|
expected_.picture_id = kMaxTwoBytePictureId; // 3 byte payload descriptor
|
|
Init(kFrameSize, kPacketSize);
|
|
|
|
// Four packets:
|
|
// I:1, P:0, L:0, F:0, B:1, E:0, V:0, Z:0 (3hdr + 8 payload)
|
|
// I:1, P:0, L:0, F:0, B:0, E:0, V:0, Z:0 (3hdr + 8 payload)
|
|
// I:1, P:0, L:0, F:0, B:0, E:0, V:0, Z:0 (3hdr + 8 payload)
|
|
// I:1, P:0, L:0, F:0, B:0, E:1, V:0, Z:0 (3hdr + 7 payload)
|
|
const size_t kExpectedHdrSizes[] = {3, 3, 3, 3};
|
|
const size_t kExpectedSizes[] = {10, 11, 11, 11};
|
|
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
|
|
CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestLayerInfoWithNonFlexibleMode) {
|
|
const size_t kFrameSize = 30;
|
|
const size_t kPacketSize = 25;
|
|
|
|
expected_.temporal_idx = 3;
|
|
expected_.temporal_up_switch = true; // U
|
|
expected_.num_spatial_layers = 3;
|
|
expected_.spatial_idx = 2;
|
|
expected_.inter_layer_predicted = true; // D
|
|
expected_.tl0_pic_idx = 117;
|
|
Init(kFrameSize, kPacketSize);
|
|
|
|
// Two packets:
|
|
// | I:0, P:0, L:1, F:0, B:1, E:0, V:0 Z:0 | (3hdr + 15 payload)
|
|
// L: | T:3, U:1, S:2, D:1 | TL0PICIDX:117 |
|
|
// | I:0, P:0, L:1, F:0, B:0, E:1, V:0 Z:0 | (3hdr + 15 payload)
|
|
// L: | T:3, U:1, S:2, D:1 | TL0PICIDX:117 |
|
|
const size_t kExpectedHdrSizes[] = {3, 3};
|
|
const size_t kExpectedSizes[] = {18, 18};
|
|
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
|
|
CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestLayerInfoWithFlexibleMode) {
|
|
const size_t kFrameSize = 21;
|
|
const size_t kPacketSize = 23;
|
|
|
|
expected_.flexible_mode = true;
|
|
expected_.temporal_idx = 3;
|
|
expected_.temporal_up_switch = true; // U
|
|
expected_.num_spatial_layers = 3;
|
|
expected_.spatial_idx = 2;
|
|
expected_.inter_layer_predicted = false; // D
|
|
Init(kFrameSize, kPacketSize);
|
|
|
|
// One packet:
|
|
// I:0, P:0, L:1, F:1, B:1, E:1, V:0 (2hdr + 21 payload)
|
|
// L: T:3, U:1, S:2, D:0
|
|
const size_t kExpectedHdrSizes[] = {2};
|
|
const size_t kExpectedSizes[] = {23};
|
|
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
|
|
CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestRefIdx) {
|
|
const size_t kFrameSize = 16;
|
|
const size_t kPacketSize = 21;
|
|
|
|
expected_.inter_pic_predicted = true; // P
|
|
expected_.flexible_mode = true; // F
|
|
expected_.picture_id = 2;
|
|
expected_.max_picture_id = kMaxOneBytePictureId;
|
|
|
|
expected_.num_ref_pics = 3;
|
|
expected_.pid_diff[0] = 1;
|
|
expected_.pid_diff[1] = 3;
|
|
expected_.pid_diff[2] = 127;
|
|
expected_.ref_picture_id[0] = 1; // 2 - 1 = 1
|
|
expected_.ref_picture_id[1] = 127; // (kMaxPictureId + 1) + 2 - 3 = 127
|
|
expected_.ref_picture_id[2] = 3; // (kMaxPictureId + 1) + 2 - 127 = 3
|
|
Init(kFrameSize, kPacketSize);
|
|
|
|
// Two packets:
|
|
// I:1, P:1, L:0, F:1, B:1, E:1, V:0, Z:0 (5hdr + 16 payload)
|
|
// I: 2
|
|
// P,F: P_DIFF:1, N:1
|
|
// P_DIFF:3, N:1
|
|
// P_DIFF:127, N:0
|
|
const size_t kExpectedHdrSizes[] = {5};
|
|
const size_t kExpectedSizes[] = {21};
|
|
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
|
|
CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestRefIdxFailsWithoutPictureId) {
|
|
const size_t kFrameSize = 16;
|
|
const size_t kPacketSize = 21;
|
|
|
|
expected_.inter_pic_predicted = true;
|
|
expected_.flexible_mode = true;
|
|
expected_.num_ref_pics = 1;
|
|
expected_.pid_diff[0] = 3;
|
|
Init(kFrameSize, kPacketSize);
|
|
|
|
const size_t kExpectedNum = 0;
|
|
CreateParseAndCheckPackets(NULL, NULL, kExpectedNum);
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestSsDataWithoutSpatialResolutionPresent) {
|
|
const size_t kFrameSize = 21;
|
|
const size_t kPacketSize = 26;
|
|
|
|
expected_.ss_data_available = true;
|
|
expected_.num_spatial_layers = 1;
|
|
expected_.spatial_layer_resolution_present = false;
|
|
expected_.gof.num_frames_in_gof = 1;
|
|
expected_.gof.temporal_idx[0] = 0;
|
|
expected_.gof.temporal_up_switch[0] = true;
|
|
expected_.gof.num_ref_pics[0] = 1;
|
|
expected_.gof.pid_diff[0][0] = 4;
|
|
Init(kFrameSize, kPacketSize);
|
|
|
|
// One packet:
|
|
// I:0, P:0, L:0, F:0, B:1, E:1, V:1, Z:0 (5hdr + 21 payload)
|
|
// N_S:0, Y:0, G:1
|
|
// N_G:1
|
|
// T:0, U:1, R:1 | P_DIFF[0][0]:4
|
|
const size_t kExpectedHdrSizes[] = {5};
|
|
const size_t kExpectedSizes[] = {26};
|
|
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
|
|
CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestSsDataWithoutGbitPresent) {
|
|
const size_t kFrameSize = 21;
|
|
const size_t kPacketSize = 23;
|
|
|
|
expected_.ss_data_available = true;
|
|
expected_.num_spatial_layers = 1;
|
|
expected_.spatial_layer_resolution_present = false;
|
|
expected_.gof.num_frames_in_gof = 0;
|
|
Init(kFrameSize, kPacketSize);
|
|
|
|
// One packet:
|
|
// I:0, P:0, L:0, F:0, B:1, E:1, V:1, Z:0 (2hdr + 21 payload)
|
|
// N_S:0, Y:0, G:0
|
|
const size_t kExpectedHdrSizes[] = {2};
|
|
const size_t kExpectedSizes[] = {23};
|
|
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
|
|
CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestSsData) {
|
|
const size_t kFrameSize = 21;
|
|
const size_t kPacketSize = 40;
|
|
|
|
expected_.ss_data_available = true;
|
|
expected_.num_spatial_layers = 2;
|
|
expected_.spatial_layer_resolution_present = true;
|
|
expected_.width[0] = 640;
|
|
expected_.width[1] = 1280;
|
|
expected_.height[0] = 360;
|
|
expected_.height[1] = 720;
|
|
expected_.gof.num_frames_in_gof = 3;
|
|
expected_.gof.temporal_idx[0] = 0;
|
|
expected_.gof.temporal_idx[1] = 1;
|
|
expected_.gof.temporal_idx[2] = 2;
|
|
expected_.gof.temporal_up_switch[0] = true;
|
|
expected_.gof.temporal_up_switch[1] = true;
|
|
expected_.gof.temporal_up_switch[2] = false;
|
|
expected_.gof.num_ref_pics[0] = 0;
|
|
expected_.gof.num_ref_pics[1] = 3;
|
|
expected_.gof.num_ref_pics[2] = 2;
|
|
expected_.gof.pid_diff[1][0] = 5;
|
|
expected_.gof.pid_diff[1][1] = 6;
|
|
expected_.gof.pid_diff[1][2] = 7;
|
|
expected_.gof.pid_diff[2][0] = 8;
|
|
expected_.gof.pid_diff[2][1] = 9;
|
|
Init(kFrameSize, kPacketSize);
|
|
|
|
// One packet:
|
|
// I:0, P:0, L:0, F:0, B:1, E:1, V:1, Z:0 (19hdr + 21 payload)
|
|
// N_S:1, Y:1, G:1
|
|
// WIDTH:640 // 2 bytes
|
|
// HEIGHT:360 // 2 bytes
|
|
// WIDTH:1280 // 2 bytes
|
|
// HEIGHT:720 // 2 bytes
|
|
// N_G:3
|
|
// T:0, U:1, R:0
|
|
// T:1, U:1, R:3 | P_DIFF[1][0]:5 | P_DIFF[1][1]:6 | P_DIFF[1][2]:7
|
|
// T:2, U:0, R:2 | P_DIFF[2][0]:8 | P_DIFF[2][0]:9
|
|
const size_t kExpectedHdrSizes[] = {19};
|
|
const size_t kExpectedSizes[] = {40};
|
|
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
|
|
CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestSsDataDoesNotFitInAveragePacket) {
|
|
const size_t kFrameSize = 24;
|
|
const size_t kPacketSize = 20;
|
|
|
|
expected_.ss_data_available = true;
|
|
expected_.num_spatial_layers = 2;
|
|
expected_.spatial_layer_resolution_present = true;
|
|
expected_.width[0] = 640;
|
|
expected_.width[1] = 1280;
|
|
expected_.height[0] = 360;
|
|
expected_.height[1] = 720;
|
|
expected_.gof.num_frames_in_gof = 3;
|
|
expected_.gof.temporal_idx[0] = 0;
|
|
expected_.gof.temporal_idx[1] = 1;
|
|
expected_.gof.temporal_idx[2] = 2;
|
|
expected_.gof.temporal_up_switch[0] = true;
|
|
expected_.gof.temporal_up_switch[1] = true;
|
|
expected_.gof.temporal_up_switch[2] = false;
|
|
expected_.gof.num_ref_pics[0] = 0;
|
|
expected_.gof.num_ref_pics[1] = 3;
|
|
expected_.gof.num_ref_pics[2] = 2;
|
|
expected_.gof.pid_diff[1][0] = 5;
|
|
expected_.gof.pid_diff[1][1] = 6;
|
|
expected_.gof.pid_diff[1][2] = 7;
|
|
expected_.gof.pid_diff[2][0] = 8;
|
|
expected_.gof.pid_diff[2][1] = 9;
|
|
Init(kFrameSize, kPacketSize);
|
|
|
|
// Three packets:
|
|
// I:0, P:0, L:0, F:0, B:1, E:1, V:1, Z:0 (19hdr + 1 payload)
|
|
// N_S:1, Y:1, G:1
|
|
// WIDTH:640 // 2 bytes
|
|
// HEIGHT:360 // 2 bytes
|
|
// WIDTH:1280 // 2 bytes
|
|
// HEIGHT:720 // 2 bytes
|
|
// N_G:3
|
|
// T:0, U:1, R:0
|
|
// T:1, U:1, R:3 | P_DIFF[1][0]:5 | P_DIFF[1][1]:6 | P_DIFF[1][2]:7
|
|
// T:2, U:0, R:2 | P_DIFF[2][0]:8 | P_DIFF[2][0]:9
|
|
// Last two packets 1 bytes vp9 hdrs and the rest of payload 14 and 9 bytes.
|
|
const size_t kExpectedHdrSizes[] = {19, 1, 1};
|
|
const size_t kExpectedSizes[] = {20, 15, 10};
|
|
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
|
|
CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, EndOfPictureSetsSetMarker) {
|
|
const size_t kFrameSize = 10;
|
|
RtpPacketizer::PayloadSizeLimits limits;
|
|
limits.max_payload_len = 8;
|
|
const uint8_t kFrame[kFrameSize] = {7};
|
|
|
|
RTPVideoHeaderVP9 vp9_header;
|
|
vp9_header.InitRTPVideoHeaderVP9();
|
|
vp9_header.flexible_mode = true;
|
|
vp9_header.num_spatial_layers = 3;
|
|
|
|
RtpPacketToSend packet(kNoExtensions);
|
|
|
|
// Drop top layer and ensure that marker bit is set on last encoded layer.
|
|
for (size_t spatial_idx = 0; spatial_idx < vp9_header.num_spatial_layers - 1;
|
|
++spatial_idx) {
|
|
const bool end_of_picture =
|
|
spatial_idx + 1 == vp9_header.num_spatial_layers - 1;
|
|
vp9_header.spatial_idx = spatial_idx;
|
|
vp9_header.end_of_picture = end_of_picture;
|
|
RtpPacketizerVp9 packetizer(kFrame, limits, vp9_header);
|
|
ASSERT_TRUE(packetizer.NextPacket(&packet));
|
|
EXPECT_FALSE(packet.Marker());
|
|
ASSERT_TRUE(packetizer.NextPacket(&packet));
|
|
EXPECT_EQ(packet.Marker(), end_of_picture);
|
|
}
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestGeneratesMinimumNumberOfPackets) {
|
|
const size_t kFrameSize = 10;
|
|
RtpPacketizer::PayloadSizeLimits limits;
|
|
limits.max_payload_len = 8;
|
|
// Calculated by hand. One packet can contain
|
|
// |kPacketSize| - |kVp9MinDiscriptorSize| = 6 bytes of the frame payload,
|
|
// thus to fit 10 bytes two packets are required.
|
|
const size_t kMinNumberOfPackets = 2;
|
|
const uint8_t kFrame[kFrameSize] = {7};
|
|
|
|
RTPVideoHeaderVP9 vp9_header;
|
|
vp9_header.InitRTPVideoHeaderVP9();
|
|
|
|
RtpPacketToSend packet(kNoExtensions);
|
|
|
|
RtpPacketizerVp9 packetizer(kFrame, limits, vp9_header);
|
|
EXPECT_EQ(packetizer.NumPackets(), kMinNumberOfPackets);
|
|
ASSERT_TRUE(packetizer.NextPacket(&packet));
|
|
EXPECT_FALSE(packet.Marker());
|
|
ASSERT_TRUE(packetizer.NextPacket(&packet));
|
|
EXPECT_TRUE(packet.Marker());
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestRespectsLastPacketReductionLen) {
|
|
const size_t kFrameSize = 10;
|
|
RtpPacketizer::PayloadSizeLimits limits;
|
|
limits.max_payload_len = 8;
|
|
limits.last_packet_reduction_len = 5;
|
|
// Calculated by hand. VP9 payload descriptor is 2 bytes. Like in the test
|
|
// above, 1 packet is not enough. 2 packets can contain
|
|
// 2*(|kPacketSize| - |kVp9MinDiscriptorSize|) - |kLastPacketReductionLen| = 7
|
|
// But three packets are enough, since they have capacity of 3*(8-2)-5=13
|
|
// bytes.
|
|
const size_t kMinNumberOfPackets = 3;
|
|
const uint8_t kFrame[kFrameSize] = {7};
|
|
|
|
RTPVideoHeaderVP9 vp9_header;
|
|
vp9_header.InitRTPVideoHeaderVP9();
|
|
vp9_header.flexible_mode = true;
|
|
|
|
RtpPacketToSend packet(kNoExtensions);
|
|
|
|
RtpPacketizerVp9 packetizer0(kFrame, limits, vp9_header);
|
|
EXPECT_EQ(packetizer0.NumPackets(), kMinNumberOfPackets);
|
|
ASSERT_TRUE(packetizer0.NextPacket(&packet));
|
|
EXPECT_FALSE(packet.Marker());
|
|
ASSERT_TRUE(packetizer0.NextPacket(&packet));
|
|
EXPECT_FALSE(packet.Marker());
|
|
ASSERT_TRUE(packetizer0.NextPacket(&packet));
|
|
EXPECT_TRUE(packet.Marker());
|
|
}
|
|
|
|
TEST_F(RtpPacketizerVp9Test, TestNonRefForInterLayerPred) {
|
|
const size_t kFrameSize = 25;
|
|
const size_t kPacketSize = 26;
|
|
|
|
expected_.non_ref_for_inter_layer_pred = true;
|
|
Init(kFrameSize, kPacketSize);
|
|
|
|
// I:0, P:0, L:0, F:0, B:1, E:1, V:0, Z:1 (1hdr + 25 payload)
|
|
const size_t kExpectedHdrSizes[] = {1};
|
|
const size_t kExpectedSizes[] = {26};
|
|
const size_t kExpectedNum = GTEST_ARRAY_SIZE_(kExpectedSizes);
|
|
CreateParseAndCheckPackets(kExpectedHdrSizes, kExpectedSizes, kExpectedNum);
|
|
}
|
|
|
|
class RtpDepacketizerVp9Test : public ::testing::Test {
|
|
protected:
|
|
RtpDepacketizerVp9Test() : depacketizer_(new RtpDepacketizerVp9()) {}
|
|
|
|
void SetUp() override { expected_.InitRTPVideoHeaderVP9(); }
|
|
|
|
RTPVideoHeaderVP9 expected_;
|
|
std::unique_ptr<RtpDepacketizer> depacketizer_;
|
|
};
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseBasicHeader) {
|
|
const uint8_t kHeaderLength = 1;
|
|
uint8_t packet[4] = {0};
|
|
packet[0] = 0x0C; // I:0 P:0 L:0 F:0 B:1 E:1 V:0 Z:0
|
|
expected_.beginning_of_frame = true;
|
|
expected_.end_of_frame = true;
|
|
ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet));
|
|
}
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseOneBytePictureId) {
|
|
const uint8_t kHeaderLength = 2;
|
|
uint8_t packet[10] = {0};
|
|
packet[0] = 0x80; // I:1 P:0 L:0 F:0 B:0 E:0 V:0 Z:0
|
|
packet[1] = kMaxOneBytePictureId;
|
|
|
|
expected_.picture_id = kMaxOneBytePictureId;
|
|
expected_.max_picture_id = kMaxOneBytePictureId;
|
|
ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet));
|
|
}
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseTwoBytePictureId) {
|
|
const uint8_t kHeaderLength = 3;
|
|
uint8_t packet[10] = {0};
|
|
packet[0] = 0x80; // I:1 P:0 L:0 F:0 B:0 E:0 V:0 Z:0
|
|
packet[1] = 0x80 | ((kMaxTwoBytePictureId >> 8) & 0x7F);
|
|
packet[2] = kMaxTwoBytePictureId & 0xFF;
|
|
|
|
expected_.picture_id = kMaxTwoBytePictureId;
|
|
expected_.max_picture_id = kMaxTwoBytePictureId;
|
|
ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet));
|
|
}
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseLayerInfoWithNonFlexibleMode) {
|
|
const uint8_t kHeaderLength = 3;
|
|
const uint8_t kTemporalIdx = 2;
|
|
const uint8_t kUbit = 1;
|
|
const uint8_t kSpatialIdx = 1;
|
|
const uint8_t kDbit = 1;
|
|
const uint8_t kTl0PicIdx = 17;
|
|
uint8_t packet[13] = {0};
|
|
packet[0] = 0x20; // I:0 P:0 L:1 F:0 B:0 E:0 V:0 Z:0
|
|
packet[1] = (kTemporalIdx << 5) | (kUbit << 4) | (kSpatialIdx << 1) | kDbit;
|
|
packet[2] = kTl0PicIdx;
|
|
|
|
// T:2 U:1 S:1 D:1
|
|
// TL0PICIDX:17
|
|
expected_.temporal_idx = kTemporalIdx;
|
|
expected_.temporal_up_switch = kUbit ? true : false;
|
|
expected_.spatial_idx = kSpatialIdx;
|
|
expected_.inter_layer_predicted = kDbit ? true : false;
|
|
expected_.tl0_pic_idx = kTl0PicIdx;
|
|
ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet));
|
|
}
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseLayerInfoWithFlexibleMode) {
|
|
const uint8_t kHeaderLength = 2;
|
|
const uint8_t kTemporalIdx = 2;
|
|
const uint8_t kUbit = 1;
|
|
const uint8_t kSpatialIdx = 0;
|
|
const uint8_t kDbit = 0;
|
|
uint8_t packet[13] = {0};
|
|
packet[0] = 0x38; // I:0 P:0 L:1 F:1 B:1 E:0 V:0 Z:0
|
|
packet[1] = (kTemporalIdx << 5) | (kUbit << 4) | (kSpatialIdx << 1) | kDbit;
|
|
|
|
// I:0 P:0 L:1 F:1 B:1 E:0 V:0 Z:0
|
|
// L: T:2 U:1 S:0 D:0
|
|
expected_.beginning_of_frame = true;
|
|
expected_.flexible_mode = true;
|
|
expected_.temporal_idx = kTemporalIdx;
|
|
expected_.temporal_up_switch = kUbit ? true : false;
|
|
expected_.spatial_idx = kSpatialIdx;
|
|
expected_.inter_layer_predicted = kDbit ? true : false;
|
|
ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet));
|
|
}
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseRefIdx) {
|
|
const uint8_t kHeaderLength = 6;
|
|
const int16_t kPictureId = 17;
|
|
const uint8_t kPdiff1 = 17;
|
|
const uint8_t kPdiff2 = 18;
|
|
const uint8_t kPdiff3 = 127;
|
|
uint8_t packet[13] = {0};
|
|
packet[0] = 0xD8; // I:1 P:1 L:0 F:1 B:1 E:0 V:0 Z:0
|
|
packet[1] = 0x80 | ((kPictureId >> 8) & 0x7F); // Two byte pictureID.
|
|
packet[2] = kPictureId;
|
|
packet[3] = (kPdiff1 << 1) | 1; // P_DIFF N:1
|
|
packet[4] = (kPdiff2 << 1) | 1; // P_DIFF N:1
|
|
packet[5] = (kPdiff3 << 1) | 0; // P_DIFF N:0
|
|
|
|
// I:1 P:1 L:0 F:1 B:1 E:0 V:0 Z:0
|
|
// I: PICTURE ID:17
|
|
// I:
|
|
// P,F: P_DIFF:17 N:1 => refPicId = 17 - 17 = 0
|
|
// P,F: P_DIFF:18 N:1 => refPicId = (kMaxPictureId + 1) + 17 - 18 = 0x7FFF
|
|
// P,F: P_DIFF:127 N:0 => refPicId = (kMaxPictureId + 1) + 17 - 127 = 32658
|
|
expected_.beginning_of_frame = true;
|
|
expected_.inter_pic_predicted = true;
|
|
expected_.flexible_mode = true;
|
|
expected_.picture_id = kPictureId;
|
|
expected_.num_ref_pics = 3;
|
|
expected_.pid_diff[0] = kPdiff1;
|
|
expected_.pid_diff[1] = kPdiff2;
|
|
expected_.pid_diff[2] = kPdiff3;
|
|
expected_.ref_picture_id[0] = 0;
|
|
expected_.ref_picture_id[1] = 0x7FFF;
|
|
expected_.ref_picture_id[2] = 32658;
|
|
ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet));
|
|
}
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseRefIdxFailsWithNoPictureId) {
|
|
const uint8_t kPdiff = 3;
|
|
uint8_t packet[13] = {0};
|
|
packet[0] = 0x58; // I:0 P:1 L:0 F:1 B:1 E:0 V:0 Z:0
|
|
packet[1] = (kPdiff << 1); // P,F: P_DIFF:3 N:0
|
|
|
|
RtpDepacketizer::ParsedPayload parsed;
|
|
EXPECT_FALSE(depacketizer_->Parse(&parsed, packet, sizeof(packet)));
|
|
}
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseRefIdxFailsWithTooManyRefPics) {
|
|
const uint8_t kPdiff = 3;
|
|
uint8_t packet[13] = {0};
|
|
packet[0] = 0xD8; // I:1 P:1 L:0 F:1 B:1 E:0 V:0 Z:0
|
|
packet[1] = kMaxOneBytePictureId; // I: PICTURE ID:127
|
|
packet[2] = (kPdiff << 1) | 1; // P,F: P_DIFF:3 N:1
|
|
packet[3] = (kPdiff << 1) | 1; // P,F: P_DIFF:3 N:1
|
|
packet[4] = (kPdiff << 1) | 1; // P,F: P_DIFF:3 N:1
|
|
packet[5] = (kPdiff << 1) | 0; // P,F: P_DIFF:3 N:0
|
|
|
|
RtpDepacketizer::ParsedPayload parsed;
|
|
EXPECT_FALSE(depacketizer_->Parse(&parsed, packet, sizeof(packet)));
|
|
}
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseSsData) {
|
|
const uint8_t kHeaderLength = 6;
|
|
const uint8_t kYbit = 0;
|
|
const size_t kNs = 2;
|
|
const size_t kNg = 2;
|
|
uint8_t packet[23] = {0};
|
|
packet[0] = 0x0A; // I:0 P:0 L:0 F:0 B:1 E:0 V:1 Z:0
|
|
packet[1] = ((kNs - 1) << 5) | (kYbit << 4) | (1 << 3); // N_S Y G:1 -
|
|
packet[2] = kNg; // N_G
|
|
packet[3] = (0 << 5) | (1 << 4) | (0 << 2) | 0; // T:0 U:1 R:0 -
|
|
packet[4] = (2 << 5) | (0 << 4) | (1 << 2) | 0; // T:2 U:0 R:1 -
|
|
packet[5] = 33;
|
|
|
|
expected_.beginning_of_frame = true;
|
|
expected_.ss_data_available = true;
|
|
expected_.num_spatial_layers = kNs;
|
|
expected_.spatial_layer_resolution_present = kYbit ? true : false;
|
|
expected_.gof.num_frames_in_gof = kNg;
|
|
expected_.gof.temporal_idx[0] = 0;
|
|
expected_.gof.temporal_idx[1] = 2;
|
|
expected_.gof.temporal_up_switch[0] = true;
|
|
expected_.gof.temporal_up_switch[1] = false;
|
|
expected_.gof.num_ref_pics[0] = 0;
|
|
expected_.gof.num_ref_pics[1] = 1;
|
|
expected_.gof.pid_diff[1][0] = 33;
|
|
ParseAndCheckPacket(packet, expected_, kHeaderLength, sizeof(packet));
|
|
}
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseFirstPacketInKeyFrame) {
|
|
uint8_t packet[2] = {0};
|
|
packet[0] = 0x08; // I:0 P:0 L:0 F:0 B:1 E:0 V:0 Z:0
|
|
|
|
RtpDepacketizer::ParsedPayload parsed;
|
|
ASSERT_TRUE(depacketizer_->Parse(&parsed, packet, sizeof(packet)));
|
|
EXPECT_EQ(VideoFrameType::kVideoFrameKey, parsed.video_header().frame_type);
|
|
EXPECT_TRUE(parsed.video_header().is_first_packet_in_frame);
|
|
}
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseLastPacketInDeltaFrame) {
|
|
uint8_t packet[2] = {0};
|
|
packet[0] = 0x44; // I:0 P:1 L:0 F:0 B:0 E:1 V:0 Z:0
|
|
|
|
RtpDepacketizer::ParsedPayload parsed;
|
|
ASSERT_TRUE(depacketizer_->Parse(&parsed, packet, sizeof(packet)));
|
|
EXPECT_EQ(VideoFrameType::kVideoFrameDelta, parsed.video_header().frame_type);
|
|
EXPECT_FALSE(parsed.video_header().is_first_packet_in_frame);
|
|
}
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseResolution) {
|
|
const uint16_t kWidth[2] = {640, 1280};
|
|
const uint16_t kHeight[2] = {360, 720};
|
|
uint8_t packet[20] = {0};
|
|
packet[0] = 0x0A; // I:0 P:0 L:0 F:0 B:1 E:0 V:1 Z:0
|
|
packet[1] = (1 << 5) | (1 << 4) | 0; // N_S:1 Y:1 G:0
|
|
packet[2] = kWidth[0] >> 8;
|
|
packet[3] = kWidth[0] & 0xFF;
|
|
packet[4] = kHeight[0] >> 8;
|
|
packet[5] = kHeight[0] & 0xFF;
|
|
packet[6] = kWidth[1] >> 8;
|
|
packet[7] = kWidth[1] & 0xFF;
|
|
packet[8] = kHeight[1] >> 8;
|
|
packet[9] = kHeight[1] & 0xFF;
|
|
|
|
RtpDepacketizer::ParsedPayload parsed;
|
|
ASSERT_TRUE(depacketizer_->Parse(&parsed, packet, sizeof(packet)));
|
|
EXPECT_EQ(kWidth[0], parsed.video_header().width);
|
|
EXPECT_EQ(kHeight[0], parsed.video_header().height);
|
|
}
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseFailsForNoPayloadLength) {
|
|
uint8_t packet[1] = {0};
|
|
RtpDepacketizer::ParsedPayload parsed;
|
|
EXPECT_FALSE(depacketizer_->Parse(&parsed, packet, 0));
|
|
}
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseFailsForTooShortBufferToFitPayload) {
|
|
const uint8_t kHeaderLength = 1;
|
|
uint8_t packet[kHeaderLength] = {0};
|
|
RtpDepacketizer::ParsedPayload parsed;
|
|
EXPECT_FALSE(depacketizer_->Parse(&parsed, packet, sizeof(packet)));
|
|
}
|
|
|
|
TEST_F(RtpDepacketizerVp9Test, ParseNonRefForInterLayerPred) {
|
|
uint8_t packet[2] = {0};
|
|
|
|
packet[0] = 0x08; // I:0 P:0 L:0 F:0 B:1 E:0 V:0 Z:0
|
|
expected_.beginning_of_frame = true;
|
|
expected_.non_ref_for_inter_layer_pred = false;
|
|
ParseAndCheckPacket(packet, expected_, 1, sizeof(packet));
|
|
|
|
packet[0] = 0x05; // I:0 P:0 L:0 F:0 B:0 E:1 V:0 Z:1
|
|
expected_.beginning_of_frame = false;
|
|
expected_.end_of_frame = true;
|
|
expected_.non_ref_for_inter_layer_pred = true;
|
|
ParseAndCheckPacket(packet, expected_, 1, sizeof(packet));
|
|
}
|
|
|
|
} // namespace webrtc
|