text: /*
   *  Copyright (c) 2011 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.
   */
  
  /*
   * This file conatins unit tests for the RtpUtility.
   */
  
  #include "testing/gtest/include/gtest/gtest.h"
  #include "webrtc/modules/rtp_rtcp/source/rtp_format_vp8.h"
  #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
  #include "webrtc/typedefs.h"
  
  namespace webrtc {
  
  using RtpUtility::RTPPayloadParser;
  using RtpUtility::RTPPayload;
  using RtpUtility::RTPPayloadVP8;
  
  // Payload descriptor
  //       0 1 2 3 4 5 6 7
  //      +-+-+-+-+-+-+-+-+
  //      |X|R|N|S|PartID | (REQUIRED)
  //      +-+-+-+-+-+-+-+-+
  // X:   |I|L|T|K|  RSV  | (OPTIONAL)
  //      +-+-+-+-+-+-+-+-+
  // I:   |   PictureID   | (OPTIONAL)
  //      +-+-+-+-+-+-+-+-+
  // L:   |   TL0PICIDX   | (OPTIONAL)
  //      +-+-+-+-+-+-+-+-+
  // T/K: |TID:Y| KEYIDX  | (OPTIONAL)
  //      +-+-+-+-+-+-+-+-+
  //
  // Payload header
  //       0 1 2 3 4 5 6 7
  //      +-+-+-+-+-+-+-+-+
  //      |Size0|H| VER |P|
  //      +-+-+-+-+-+-+-+-+
  //      |     Size1     |
  //      +-+-+-+-+-+-+-+-+
  //      |     Size2     |
  //      +-+-+-+-+-+-+-+-+
  //      | Bytes 4..N of |
  //      | VP8 payload   |
  //      :               :
  //      +-+-+-+-+-+-+-+-+
  //      | OPTIONAL RTP  |
  //      | padding       |
  //      :               :
  //      +-+-+-+-+-+-+-+-+
  
  void VerifyBasicHeader(const RTPPayloadVP8 &header,
                         bool N, bool S, int PartID) {
    EXPECT_EQ(N, header.nonReferenceFrame);
    EXPECT_EQ(S, header.beginningOfPartition);
    EXPECT_EQ(PartID, header.partitionID);
  }
  
  void VerifyExtensions(const RTPPayloadVP8 &header,
                        bool I, bool L, bool T, bool K) {
    EXPECT_EQ(I, header.hasPictureID);
    EXPECT_EQ(L, header.hasTl0PicIdx);
    EXPECT_EQ(T, header.hasTID);
    EXPECT_EQ(K, header.hasKeyIdx);
  }
  
  TEST(ParseVP8Test, BasicHeader) {
    uint8_t payload[4] = {0};
    payload[0] = 0x14;  // Binary 0001 0100; S = 1, PartID = 4.
    payload[1] = 0x01;  // P frame.
  
    RTPPayloadParser rtpPayloadParser(kRtpVideoVp8, payload, 4);
  
    RTPPayload parsedPacket;
    ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket));
  
    EXPECT_EQ(RtpUtility::kPFrame, parsedPacket.frameType);
    EXPECT_EQ(kRtpVideoVp8, parsedPacket.type);
  
    VerifyBasicHeader(parsedPacket.info.VP8, 0 /*N*/, 1 /*S*/, 4 /*PartID*/);
    VerifyExtensions(parsedPacket.info.VP8, 0 /*I*/, 0 /*L*/, 0 /*T*/, 0 /*K*/);
  
    EXPECT_EQ(payload + 1, parsedPacket.info.VP8.data);
    EXPECT_EQ(4 - 1, parsedPacket.info.VP8.dataLength);
  }
  
  TEST(ParseVP8Test, PictureID) {
    uint8_t payload[10] = {0};
    payload[0] = 0xA0;
    payload[1] = 0x80;
    payload[2] = 17;
  
    RTPPayloadParser rtpPayloadParser(kRtpVideoVp8, payload, 10);
  
    RTPPayload parsedPacket;
    ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket));
  
    EXPECT_EQ(RtpUtility::kPFrame, parsedPacket.frameType);
    EXPECT_EQ(kRtpVideoVp8, parsedPacket.type);
  
    VerifyBasicHeader(parsedPacket.info.VP8, 1 /*N*/, 0 /*S*/, 0 /*PartID*/);
    VerifyExtensions(parsedPacket.info.VP8, 1 /*I*/, 0 /*L*/, 0 /*T*/, 0 /*K*/);
  
    EXPECT_EQ(17, parsedPacket.info.VP8.pictureID);
  
    EXPECT_EQ(payload + 3, parsedPacket.info.VP8.data);
    EXPECT_EQ(10 - 3, parsedPacket.info.VP8.dataLength);
  
  
    // Re-use payload, but change to long PictureID.
    payload[2] = 0x80 | 17;
    payload[3] = 17;
    RTPPayloadParser rtpPayloadParser2(kRtpVideoVp8, payload, 10);
  
    ASSERT_TRUE(rtpPayloadParser2.Parse(parsedPacket));
  
    VerifyBasicHeader(parsedPacket.info.VP8, 1 /*N*/, 0 /*S*/, 0 /*PartID*/);
    VerifyExtensions(parsedPacket.info.VP8, 1 /*I*/, 0 /*L*/, 0 /*T*/, 0 /*K*/);
  
    EXPECT_EQ((17<<8) + 17, parsedPacket.info.VP8.pictureID);
  
    EXPECT_EQ(payload + 4, parsedPacket.info.VP8.data);
    EXPECT_EQ(10 - 4, parsedPacket.info.VP8.dataLength);
  }
  
  TEST(ParseVP8Test, Tl0PicIdx) {
    uint8_t payload[13] = {0};
    payload[0] = 0x90;
    payload[1] = 0x40;
    payload[2] = 17;
  
    RTPPayloadParser rtpPayloadParser(kRtpVideoVp8, payload, 13);
  
    RTPPayload parsedPacket;
    ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket));
  
    EXPECT_EQ(RtpUtility::kIFrame, parsedPacket.frameType);
    EXPECT_EQ(kRtpVideoVp8, parsedPacket.type);
  
    VerifyBasicHeader(parsedPacket.info.VP8, 0 /*N*/, 1 /*S*/, 0 /*PartID*/);
    VerifyExtensions(parsedPacket.info.VP8, 0 /*I*/, 1 /*L*/, 0 /*T*/, 0 /*K*/);
  
    EXPECT_EQ(17, parsedPacket.info.VP8.tl0PicIdx);
  
    EXPECT_EQ(payload + 3, parsedPacket.info.VP8.data);
    EXPECT_EQ(13 - 3, parsedPacket.info.VP8.dataLength);
  }
  
  TEST(ParseVP8Test, TIDAndLayerSync) {
    uint8_t payload[10] = {0};
    payload[0] = 0x88;
    payload[1] = 0x20;
    payload[2] = 0x80;  // TID(2) + LayerSync(false)
  
    RTPPayloadParser rtpPayloadParser(kRtpVideoVp8, payload, 10);
  
    RTPPayload parsedPacket;
    ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket));
  
    EXPECT_EQ(RtpUtility::kPFrame, parsedPacket.frameType);
    EXPECT_EQ(kRtpVideoVp8, parsedPacket.type);
  
    VerifyBasicHeader(parsedPacket.info.VP8, 0 /*N*/, 0 /*S*/, 8 /*PartID*/);
    VerifyExtensions(parsedPacket.info.VP8, 0 /*I*/, 0 /*L*/, 1 /*T*/, 0 /*K*/);
  
    EXPECT_EQ(2, parsedPacket.info.VP8.tID);
    EXPECT_FALSE(parsedPacket.info.VP8.layerSync);
  
    EXPECT_EQ(payload + 3, parsedPacket.info.VP8.data);
    EXPECT_EQ(10 - 3, parsedPacket.info.VP8.dataLength);
  }
  
  TEST(ParseVP8Test, KeyIdx) {
    uint8_t payload[10] = {0};
    payload[0] = 0x88;
    payload[1] = 0x10;  // K = 1.
    payload[2] = 0x11;  // KEYIDX = 17 decimal.
  
    RTPPayloadParser rtpPayloadParser(kRtpVideoVp8, payload, 10);
  
    RTPPayload parsedPacket;
    ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket));
  
    EXPECT_EQ(RtpUtility::kPFrame, parsedPacket.frameType);
    EXPECT_EQ(kRtpVideoVp8, parsedPacket.type);
  
    VerifyBasicHeader(parsedPacket.info.VP8, 0 /*N*/, 0 /*S*/, 8 /*PartID*/);
    VerifyExtensions(parsedPacket.info.VP8, 0 /*I*/, 0 /*L*/, 0 /*T*/, 1 /*K*/);
  
    EXPECT_EQ(17, parsedPacket.info.VP8.keyIdx);
  
    EXPECT_EQ(payload + 3, parsedPacket.info.VP8.data);
    EXPECT_EQ(10 - 3, parsedPacket.info.VP8.dataLength);
  }
  
  TEST(ParseVP8Test, MultipleExtensions) {
    uint8_t payload[10] = {0};
    payload[0] = 0x88;
    payload[1] = 0x80 | 0x40 | 0x20 | 0x10;
    payload[2] = 0x80 | 17;    // PictureID, high 7 bits.
    payload[3] = 17;           // PictureID, low 8 bits.
    payload[4] = 42;           // Tl0PicIdx.
    payload[5] = 0x40 | 0x20 | 0x11;  // TID(1) + LayerSync(true) + KEYIDX(17).
  
    RTPPayloadParser rtpPayloadParser(kRtpVideoVp8, payload, 10);
  
    RTPPayload parsedPacket;
    ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket));
  
    EXPECT_EQ(RtpUtility::kPFrame, parsedPacket.frameType);
    EXPECT_EQ(kRtpVideoVp8, parsedPacket.type);
  
    VerifyBasicHeader(parsedPacket.info.VP8, 0 /*N*/, 0 /*S*/, 8 /*PartID*/);
    VerifyExtensions(parsedPacket.info.VP8, 1 /*I*/, 1 /*L*/, 1 /*T*/, 1 /*K*/);
  
    EXPECT_EQ((17<<8) + 17, parsedPacket.info.VP8.pictureID);
    EXPECT_EQ(42, parsedPacket.info.VP8.tl0PicIdx);
    EXPECT_EQ(1, parsedPacket.info.VP8.tID);
    EXPECT_EQ(17, parsedPacket.info.VP8.keyIdx);
  
    EXPECT_EQ(payload + 6, parsedPacket.info.VP8.data);
    EXPECT_EQ(10 - 6, parsedPacket.info.VP8.dataLength);
  }
  
  TEST(ParseVP8Test, TooShortHeader) {
    uint8_t payload[4] = {0};
    payload[0] = 0x88;
    payload[1] = 0x80 | 0x40 | 0x20 | 0x10;  // All extensions are enabled...
    payload[2] = 0x80 | 17;  // ... but only 2 bytes PictureID is provided.
    payload[3] = 17;  // PictureID, low 8 bits.
  
    RTPPayloadParser rtpPayloadParser(kRtpVideoVp8, payload, 4);
  
    RTPPayload parsedPacket;
    EXPECT_FALSE(rtpPayloadParser.Parse(parsedPacket));
  }
  
  TEST(ParseVP8Test, TestWithPacketizer) {
    uint8_t payload[10] = {0};
    uint8_t packet[20] = {0};
    RTPVideoHeaderVP8 inputHeader;
    inputHeader.nonReference = true;
    inputHeader.pictureId = 300;
    inputHeader.temporalIdx = 1;
    inputHeader.layerSync = false;
    inputHeader.tl0PicIdx = kNoTl0PicIdx;  // Disable.
    inputHeader.keyIdx = 31;
    RtpPacketizerVp8 packetizer(inputHeader, 20);
    packetizer.SetPayloadData(payload, 10, NULL);
    bool last;
    size_t send_bytes;
    ASSERT_TRUE(packetizer.NextPacket(packet, &send_bytes, &last));
    ASSERT_TRUE(last);
  
    RTPPayloadParser rtpPayloadParser(kRtpVideoVp8, packet, send_bytes);
  
    RTPPayload parsedPacket;
    ASSERT_TRUE(rtpPayloadParser.Parse(parsedPacket));
  
    EXPECT_EQ(RtpUtility::kIFrame, parsedPacket.frameType);
    EXPECT_EQ(kRtpVideoVp8, parsedPacket.type);
  
    VerifyBasicHeader(parsedPacket.info.VP8,
                      inputHeader.nonReference /*N*/,
                      1 /*S*/,
                      0 /*PartID*/);
    VerifyExtensions(parsedPacket.info.VP8,
                     1 /*I*/,
                     0 /*L*/,
                     1 /*T*/,
                     1 /*K*/);
  
    EXPECT_EQ(inputHeader.pictureId, parsedPacket.info.VP8.pictureID);
    EXPECT_EQ(inputHeader.temporalIdx, parsedPacket.info.VP8.tID);
    EXPECT_EQ(inputHeader.layerSync, parsedPacket.info.VP8.layerSync);
    EXPECT_EQ(inputHeader.keyIdx, parsedPacket.info.VP8.keyIdx);
  
    EXPECT_EQ(packet + 5, parsedPacket.info.VP8.data);
    EXPECT_EQ(send_bytes - 5, parsedPacket.info.VP8.dataLength);
  }
  
  }  // namespace
  