| /* |
| * Copyright (c) 2019 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_depacketizer_av1.h" |
| |
| #include "test/gtest.h" |
| |
| namespace webrtc { |
| namespace { |
| // Signals number of the OBU (fragments) in the packet. |
| constexpr uint8_t kObuCountAny = 0b0000'0000; |
| constexpr uint8_t kObuCountOne = 0b0001'0000; |
| constexpr uint8_t kObuCountTwo = 0b0010'0000; |
| |
| constexpr uint8_t kObuHeaderSequenceHeader = 0b0'0001'000; |
| constexpr uint8_t kObuHeaderTemporalDelimiter = 0b0'0010'000; |
| constexpr uint8_t kObuHeaderFrame = 0b0'0110'000; |
| |
| TEST(RtpDepacketizerAv1Test, ParsePassFullRtpPayloadAsCodecPayload) { |
| const uint8_t packet[] = {(uint8_t{1} << 7) | kObuCountOne, 1, 2, 3, 4}; |
| RtpDepacketizerAv1 depacketizer; |
| RtpDepacketizer::ParsedPayload parsed; |
| ASSERT_TRUE(depacketizer.Parse(&parsed, packet, sizeof(packet))); |
| EXPECT_EQ(parsed.payload_length, sizeof(packet)); |
| EXPECT_TRUE(parsed.payload == packet); |
| } |
| |
| TEST(RtpDepacketizerAv1Test, ParseTreatsContinuationFlagAsNotBeginningOfFrame) { |
| const uint8_t packet[] = { |
| (uint8_t{1} << 7) | kObuCountOne, |
| kObuHeaderFrame}; // Value doesn't matter since it is a |
| // continuation of the OBU from previous packet. |
| RtpDepacketizerAv1 depacketizer; |
| RtpDepacketizer::ParsedPayload parsed; |
| ASSERT_TRUE(depacketizer.Parse(&parsed, packet, sizeof(packet))); |
| EXPECT_FALSE(parsed.video.is_first_packet_in_frame); |
| } |
| |
| TEST(RtpDepacketizerAv1Test, ParseTreatsNoContinuationFlagAsBeginningOfFrame) { |
| const uint8_t packet[] = {(uint8_t{0} << 7) | kObuCountOne, kObuHeaderFrame}; |
| RtpDepacketizerAv1 depacketizer; |
| RtpDepacketizer::ParsedPayload parsed; |
| ASSERT_TRUE(depacketizer.Parse(&parsed, packet, sizeof(packet))); |
| EXPECT_TRUE(parsed.video.is_first_packet_in_frame); |
| } |
| |
| TEST(RtpDepacketizerAv1Test, ParseTreatsWillContinueFlagAsNotEndOfFrame) { |
| const uint8_t packet[] = {(uint8_t{1} << 6) | kObuCountOne, kObuHeaderFrame}; |
| RtpDepacketizerAv1 depacketizer; |
| RtpDepacketizer::ParsedPayload parsed; |
| ASSERT_TRUE(depacketizer.Parse(&parsed, packet, sizeof(packet))); |
| EXPECT_FALSE(parsed.video.is_last_packet_in_frame); |
| } |
| |
| TEST(RtpDepacketizerAv1Test, ParseTreatsNoWillContinueFlagAsEndOfFrame) { |
| const uint8_t packet[] = {(uint8_t{0} << 6) | kObuCountOne, kObuHeaderFrame}; |
| RtpDepacketizerAv1 depacketizer; |
| RtpDepacketizer::ParsedPayload parsed; |
| ASSERT_TRUE(depacketizer.Parse(&parsed, packet, sizeof(packet))); |
| EXPECT_TRUE(parsed.video.is_last_packet_in_frame); |
| } |
| |
| TEST(RtpDepacketizerAv1Test, ParseTreatsStartOfSequenceHeaderAsKeyFrame) { |
| const uint8_t packet[] = {kObuCountOne, kObuHeaderSequenceHeader}; |
| RtpDepacketizerAv1 depacketizer; |
| RtpDepacketizer::ParsedPayload parsed; |
| ASSERT_TRUE(depacketizer.Parse(&parsed, packet, sizeof(packet))); |
| EXPECT_TRUE(parsed.video.is_first_packet_in_frame); |
| EXPECT_TRUE(parsed.video.frame_type == VideoFrameType::kVideoFrameKey); |
| } |
| |
| TEST(RtpDepacketizerAv1Test, ParseTreatsNotStartOfFrameAsDeltaFrame) { |
| const uint8_t packet[] = { |
| (uint8_t{1} << 7) | kObuCountOne, |
| // Byte that look like start of sequence header, but since it is not start |
| // of an OBU, it is actually not a start of sequence header. |
| kObuHeaderSequenceHeader}; |
| RtpDepacketizerAv1 depacketizer; |
| RtpDepacketizer::ParsedPayload parsed; |
| ASSERT_TRUE(depacketizer.Parse(&parsed, packet, sizeof(packet))); |
| EXPECT_FALSE(parsed.video.is_first_packet_in_frame); |
| EXPECT_TRUE(parsed.video.frame_type == VideoFrameType::kVideoFrameDelta); |
| } |
| |
| TEST(RtpDepacketizerAv1Test, |
| ParseTreatsStartOfFrameWithoutSequenceHeaderAsDeltaFrame) { |
| const uint8_t packet[] = {kObuCountOne, kObuHeaderFrame}; |
| RtpDepacketizerAv1 depacketizer; |
| RtpDepacketizer::ParsedPayload parsed; |
| ASSERT_TRUE(depacketizer.Parse(&parsed, packet, sizeof(packet))); |
| EXPECT_TRUE(parsed.video.is_first_packet_in_frame); |
| EXPECT_TRUE(parsed.video.frame_type == VideoFrameType::kVideoFrameDelta); |
| } |
| |
| TEST(RtpDepacketizerAv1Test, ParseFindsSequenceHeaderBehindFragmentSize1) { |
| const uint8_t packet[] = {kObuCountAny, |
| 1, // size of the next fragment |
| kObuHeaderSequenceHeader}; |
| RtpDepacketizerAv1 depacketizer; |
| RtpDepacketizer::ParsedPayload parsed; |
| ASSERT_TRUE(depacketizer.Parse(&parsed, packet, sizeof(packet))); |
| EXPECT_TRUE(parsed.video.frame_type == VideoFrameType::kVideoFrameKey); |
| } |
| |
| TEST(RtpDepacketizerAv1Test, ParseFindsSequenceHeaderBehindFragmentSize2) { |
| const uint8_t packet[] = {kObuCountTwo, |
| 2, // size of the next fragment |
| kObuHeaderSequenceHeader, |
| 42, // SH payload. |
| kObuHeaderFrame}; |
| RtpDepacketizerAv1 depacketizer; |
| RtpDepacketizer::ParsedPayload parsed; |
| ASSERT_TRUE(depacketizer.Parse(&parsed, packet, sizeof(packet))); |
| EXPECT_TRUE(parsed.video.frame_type == VideoFrameType::kVideoFrameKey); |
| } |
| |
| TEST(RtpDepacketizerAv1Test, |
| ParseFindsSequenceHeaderBehindMultiByteFragmentSize) { |
| const uint8_t packet[] = {kObuCountTwo, |
| 0b1000'0101, // leb128 encoded value of 5 |
| 0b1000'0000, // using 3 bytes |
| 0b0000'0000, // to encode the value. |
| kObuHeaderSequenceHeader, |
| 8, // 4 bytes of SH payload. |
| 0, |
| 0, |
| 0, |
| kObuHeaderFrame}; |
| RtpDepacketizerAv1 depacketizer; |
| RtpDepacketizer::ParsedPayload parsed; |
| ASSERT_TRUE(depacketizer.Parse(&parsed, packet, sizeof(packet))); |
| EXPECT_TRUE(parsed.video.frame_type == VideoFrameType::kVideoFrameKey); |
| } |
| |
| TEST(RtpDepacketizerAv1Test, ParseFindsSequenceHeaderBehindTemporalDelimiter) { |
| const uint8_t packet[] = {kObuCountTwo, |
| 1, // size of the next fragment |
| kObuHeaderTemporalDelimiter, |
| kObuHeaderSequenceHeader, |
| 8, // 4 bytes of SH payload. |
| 0, |
| 0, |
| 0}; |
| RtpDepacketizerAv1 depacketizer; |
| RtpDepacketizer::ParsedPayload parsed; |
| ASSERT_TRUE(depacketizer.Parse(&parsed, packet, sizeof(packet))); |
| EXPECT_TRUE(parsed.video.frame_type == VideoFrameType::kVideoFrameKey); |
| } |
| |
| TEST(RtpDepacketizerAv1Test, |
| ParseFindsSequenceHeaderBehindTemporalDelimiterAndSize) { |
| const uint8_t packet[] = {kObuCountAny, |
| 1, // size of the next fragment |
| kObuHeaderTemporalDelimiter, |
| 5, // size of the next fragment |
| kObuHeaderSequenceHeader, |
| 8, // 4 bytes of SH payload. |
| 0, |
| 0, |
| 0, |
| 1, // size of the next fragment |
| kObuHeaderFrame}; |
| RtpDepacketizerAv1 depacketizer; |
| RtpDepacketizer::ParsedPayload parsed; |
| ASSERT_TRUE(depacketizer.Parse(&parsed, packet, sizeof(packet))); |
| EXPECT_TRUE(parsed.video.frame_type == VideoFrameType::kVideoFrameKey); |
| } |
| |
| TEST(RtpDepacketizerAv1Test, ParseSkipsEmptyFragments) { |
| static_assert(kObuHeaderSequenceHeader == 8, ""); |
| const uint8_t packet[] = {kObuCountAny, |
| 0, // size of the next fragment |
| 8, // size of the next fragment that look like SH |
| kObuHeaderFrame, |
| 1, |
| 2, |
| 3, |
| 4, |
| 5, |
| 6, |
| 7}; |
| RtpDepacketizerAv1 depacketizer; |
| RtpDepacketizer::ParsedPayload parsed; |
| ASSERT_TRUE(depacketizer.Parse(&parsed, packet, sizeof(packet))); |
| EXPECT_TRUE(parsed.video.frame_type == VideoFrameType::kVideoFrameDelta); |
| } |
| |
| } // namespace |
| } // namespace webrtc |