1 /*
2 * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/rtp_rtcp/source/video_rtp_depacketizer_vp8.h"
12
13 #include "api/array_view.h"
14 #include "modules/rtp_rtcp/source/rtp_format_vp8.h"
15 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
16 #include "rtc_base/copy_on_write_buffer.h"
17 #include "test/gmock.h"
18 #include "test/gtest.h"
19
20 // VP8 payload descriptor
21 // https://datatracker.ietf.org/doc/html/rfc7741#section-4.2
22 //
23 // 0 1 2 3 4 5 6 7
24 // +-+-+-+-+-+-+-+-+
25 // |X|R|N|S|R| PID | (REQUIRED)
26 // +-+-+-+-+-+-+-+-+
27 // X: |I|L|T|K| RSV | (OPTIONAL)
28 // +-+-+-+-+-+-+-+-+
29 // I: |M| PictureID | (OPTIONAL)
30 // +-+-+-+-+-+-+-+-+
31 // | PictureID |
32 // +-+-+-+-+-+-+-+-+
33 // L: | TL0PICIDX | (OPTIONAL)
34 // +-+-+-+-+-+-+-+-+
35 // T/K: |TID|Y| KEYIDX | (OPTIONAL)
36 // +-+-+-+-+-+-+-+-+
37 //
38 // VP8 payload header. Considered part of the actual payload, sent to decoder.
39 // https://datatracker.ietf.org/doc/html/rfc7741#section-4.3
40 //
41 // 0 1 2 3 4 5 6 7
42 // +-+-+-+-+-+-+-+-+
43 // |Size0|H| VER |P|
44 // +-+-+-+-+-+-+-+-+
45 // : ... :
46 // +-+-+-+-+-+-+-+-+
47
48 namespace webrtc {
49 namespace {
50
TEST(VideoRtpDepacketizerVp8Test,BasicHeader)51 TEST(VideoRtpDepacketizerVp8Test, BasicHeader) {
52 uint8_t packet[4] = {0};
53 packet[0] = 0b0001'0100; // S = 1, partition ID = 4.
54 packet[1] = 0x01; // P frame.
55
56 RTPVideoHeader video_header;
57 int offset = VideoRtpDepacketizerVp8::ParseRtpPayload(packet, &video_header);
58
59 EXPECT_EQ(offset, 1);
60 EXPECT_EQ(video_header.frame_type, VideoFrameType::kVideoFrameDelta);
61 EXPECT_EQ(video_header.codec, kVideoCodecVP8);
62 const auto& vp8_header =
63 absl::get<RTPVideoHeaderVP8>(video_header.video_type_header);
64 EXPECT_FALSE(vp8_header.nonReference);
65 EXPECT_TRUE(vp8_header.beginningOfPartition);
66 EXPECT_EQ(vp8_header.partitionId, 4);
67 EXPECT_EQ(vp8_header.pictureId, kNoPictureId);
68 EXPECT_EQ(vp8_header.tl0PicIdx, kNoTl0PicIdx);
69 EXPECT_EQ(vp8_header.temporalIdx, kNoTemporalIdx);
70 EXPECT_EQ(vp8_header.keyIdx, kNoKeyIdx);
71 }
72
TEST(VideoRtpDepacketizerVp8Test,OneBytePictureID)73 TEST(VideoRtpDepacketizerVp8Test, OneBytePictureID) {
74 const uint8_t kPictureId = 17;
75 uint8_t packet[10] = {0};
76 packet[0] = 0b1010'0000;
77 packet[1] = 0b1000'0000;
78 packet[2] = kPictureId;
79
80 RTPVideoHeader video_header;
81 int offset = VideoRtpDepacketizerVp8::ParseRtpPayload(packet, &video_header);
82
83 EXPECT_EQ(offset, 3);
84 const auto& vp8_header =
85 absl::get<RTPVideoHeaderVP8>(video_header.video_type_header);
86 EXPECT_EQ(vp8_header.pictureId, kPictureId);
87 }
88
TEST(VideoRtpDepacketizerVp8Test,TwoBytePictureID)89 TEST(VideoRtpDepacketizerVp8Test, TwoBytePictureID) {
90 const uint16_t kPictureId = 0x1234;
91 uint8_t packet[10] = {0};
92 packet[0] = 0b1010'0000;
93 packet[1] = 0b1000'0000;
94 packet[2] = 0x80 | 0x12;
95 packet[3] = 0x34;
96
97 RTPVideoHeader video_header;
98 int offset = VideoRtpDepacketizerVp8::ParseRtpPayload(packet, &video_header);
99
100 EXPECT_EQ(offset, 4);
101 const auto& vp8_header =
102 absl::get<RTPVideoHeaderVP8>(video_header.video_type_header);
103 EXPECT_EQ(vp8_header.pictureId, kPictureId);
104 }
105
TEST(VideoRtpDepacketizerVp8Test,Tl0PicIdx)106 TEST(VideoRtpDepacketizerVp8Test, Tl0PicIdx) {
107 const uint8_t kTl0PicIdx = 17;
108 uint8_t packet[13] = {0};
109 packet[0] = 0b1000'0000;
110 packet[1] = 0b0100'0000;
111 packet[2] = kTl0PicIdx;
112
113 RTPVideoHeader video_header;
114 int offset = VideoRtpDepacketizerVp8::ParseRtpPayload(packet, &video_header);
115
116 EXPECT_EQ(offset, 3);
117 const auto& vp8_header =
118 absl::get<RTPVideoHeaderVP8>(video_header.video_type_header);
119 EXPECT_EQ(vp8_header.tl0PicIdx, kTl0PicIdx);
120 }
121
TEST(VideoRtpDepacketizerVp8Test,TIDAndLayerSync)122 TEST(VideoRtpDepacketizerVp8Test, TIDAndLayerSync) {
123 uint8_t packet[10] = {0};
124 packet[0] = 0b1000'0000;
125 packet[1] = 0b0010'0000;
126 packet[2] = 0b10'0'00000; // TID(2) + LayerSync(false)
127
128 RTPVideoHeader video_header;
129 int offset = VideoRtpDepacketizerVp8::ParseRtpPayload(packet, &video_header);
130
131 EXPECT_EQ(offset, 3);
132 const auto& vp8_header =
133 absl::get<RTPVideoHeaderVP8>(video_header.video_type_header);
134 EXPECT_EQ(vp8_header.temporalIdx, 2);
135 EXPECT_FALSE(vp8_header.layerSync);
136 }
137
TEST(VideoRtpDepacketizerVp8Test,KeyIdx)138 TEST(VideoRtpDepacketizerVp8Test, KeyIdx) {
139 const uint8_t kKeyIdx = 17;
140 uint8_t packet[10] = {0};
141 packet[0] = 0b1000'0000;
142 packet[1] = 0b0001'0000;
143 packet[2] = kKeyIdx;
144
145 RTPVideoHeader video_header;
146 int offset = VideoRtpDepacketizerVp8::ParseRtpPayload(packet, &video_header);
147
148 EXPECT_EQ(offset, 3);
149 const auto& vp8_header =
150 absl::get<RTPVideoHeaderVP8>(video_header.video_type_header);
151 EXPECT_EQ(vp8_header.keyIdx, kKeyIdx);
152 }
153
TEST(VideoRtpDepacketizerVp8Test,MultipleExtensions)154 TEST(VideoRtpDepacketizerVp8Test, MultipleExtensions) {
155 uint8_t packet[10] = {0};
156 packet[0] = 0b1010'0110; // X and N bit set, partition ID = 6
157 packet[1] = 0b1111'0000;
158 packet[2] = 0x80 | 0x12; // PictureID, high 7 bits.
159 packet[3] = 0x34; // PictureID, low 8 bits.
160 packet[4] = 42; // Tl0PicIdx.
161 packet[5] = 0b01'1'10001;
162
163 RTPVideoHeader video_header;
164 int offset = VideoRtpDepacketizerVp8::ParseRtpPayload(packet, &video_header);
165
166 EXPECT_EQ(offset, 6);
167 const auto& vp8_header =
168 absl::get<RTPVideoHeaderVP8>(video_header.video_type_header);
169 EXPECT_TRUE(vp8_header.nonReference);
170 EXPECT_EQ(vp8_header.partitionId, 0b0110);
171 EXPECT_EQ(vp8_header.pictureId, 0x1234);
172 EXPECT_EQ(vp8_header.tl0PicIdx, 42);
173 EXPECT_EQ(vp8_header.temporalIdx, 1);
174 EXPECT_TRUE(vp8_header.layerSync);
175 EXPECT_EQ(vp8_header.keyIdx, 0b10001);
176 }
177
TEST(VideoRtpDepacketizerVp8Test,TooShortHeader)178 TEST(VideoRtpDepacketizerVp8Test, TooShortHeader) {
179 uint8_t packet[4] = {0};
180 packet[0] = 0b1000'0000;
181 packet[1] = 0b1111'0000; // All extensions are enabled...
182 packet[2] = 0x80 | 17; // ... but only 2 bytes PictureID is provided.
183 packet[3] = 17; // PictureID, low 8 bits.
184
185 RTPVideoHeader unused;
186 EXPECT_EQ(VideoRtpDepacketizerVp8::ParseRtpPayload(packet, &unused), 0);
187 }
188
TEST(VideoRtpDepacketizerVp8Test,WithPacketizer)189 TEST(VideoRtpDepacketizerVp8Test, WithPacketizer) {
190 uint8_t data[10] = {0};
191 RtpPacketToSend packet(/*extenions=*/nullptr);
192 RTPVideoHeaderVP8 input_header;
193 input_header.nonReference = true;
194 input_header.pictureId = 300;
195 input_header.temporalIdx = 1;
196 input_header.layerSync = false;
197 input_header.tl0PicIdx = kNoTl0PicIdx; // Disable.
198 input_header.keyIdx = 31;
199 RtpPacketizerVp8 packetizer(data, /*limits=*/{}, input_header);
200 EXPECT_EQ(packetizer.NumPackets(), 1u);
201 ASSERT_TRUE(packetizer.NextPacket(&packet));
202
203 VideoRtpDepacketizerVp8 depacketizer;
204 absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> parsed =
205 depacketizer.Parse(packet.PayloadBuffer());
206 ASSERT_TRUE(parsed);
207
208 EXPECT_EQ(parsed->video_header.codec, kVideoCodecVP8);
209 const auto& vp8_header =
210 absl::get<RTPVideoHeaderVP8>(parsed->video_header.video_type_header);
211 EXPECT_EQ(vp8_header.nonReference, input_header.nonReference);
212 EXPECT_EQ(vp8_header.pictureId, input_header.pictureId);
213 EXPECT_EQ(vp8_header.tl0PicIdx, input_header.tl0PicIdx);
214 EXPECT_EQ(vp8_header.temporalIdx, input_header.temporalIdx);
215 EXPECT_EQ(vp8_header.layerSync, input_header.layerSync);
216 EXPECT_EQ(vp8_header.keyIdx, input_header.keyIdx);
217 }
218
TEST(VideoRtpDepacketizerVp8Test,ReferencesInputCopyOnWriteBuffer)219 TEST(VideoRtpDepacketizerVp8Test, ReferencesInputCopyOnWriteBuffer) {
220 constexpr size_t kHeaderSize = 5;
221 uint8_t packet[16] = {0};
222 packet[0] = 0b1000'0000;
223 packet[1] = 0b1111'0000; // with all extensions,
224 packet[2] = 15; // and one-byte picture id.
225
226 rtc::CopyOnWriteBuffer rtp_payload(packet);
227 VideoRtpDepacketizerVp8 depacketizer;
228 absl::optional<VideoRtpDepacketizer::ParsedRtpPayload> parsed =
229 depacketizer.Parse(rtp_payload);
230 ASSERT_TRUE(parsed);
231
232 EXPECT_EQ(parsed->video_payload.size(), rtp_payload.size() - kHeaderSize);
233 // Compare pointers to check there was no copy on write buffer unsharing.
234 EXPECT_EQ(parsed->video_payload.cdata(), rtp_payload.cdata() + kHeaderSize);
235 }
236
TEST(VideoRtpDepacketizerVp8Test,FailsOnEmptyPayload)237 TEST(VideoRtpDepacketizerVp8Test, FailsOnEmptyPayload) {
238 rtc::ArrayView<const uint8_t> empty;
239 RTPVideoHeader video_header;
240 EXPECT_EQ(VideoRtpDepacketizerVp8::ParseRtpPayload(empty, &video_header), 0);
241 }
242
243 } // namespace
244 } // namespace webrtc
245