/*
 *  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 <memory>
#include <vector>

#include "webrtc/modules/rtp_rtcp/source/rtp_format_vp9.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "webrtc/test/gmock.h"
#include "webrtc/test/gtest.h"
#include "webrtc/typedefs.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.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 == kNoSpatialIdx ? 0 : 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(kRtpVideoVp9, parsed.type.Video.codec);
  VerifyHeader(expected, parsed.type.Video.codecHeader.VP9);
  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|-| (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|-| (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) {}
  virtual void SetUp() {
    expected_.InitRTPVideoHeaderVP9();
  }

  RtpPacketToSend packet_;
  std::unique_ptr<uint8_t[]> payload_;
  size_t payload_size_;
  size_t payload_pos_;
  RTPVideoHeaderVP9 expected_;
  std::unique_ptr<RtpPacketizerVp9> packetizer_;

  void Init(size_t payload_size, size_t packet_size) {
    payload_.reset(new uint8_t[payload_size]);
    memset(payload_.get(), 7, payload_size);
    payload_size_ = payload_size;
    payload_pos_ = 0;
    packetizer_.reset(new RtpPacketizerVp9(expected_, packet_size));
    packetizer_->SetPayloadData(payload_.get(), payload_size_, NULL);
  }

  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);
    bool last = false;
    if (expected_num_packets == 0) {
      EXPECT_FALSE(packetizer_->NextPacket(&packet_, &last));
      return;
    }
    for (size_t i = 0; i < expected_num_packets; ++i) {
      EXPECT_TRUE(packetizer_->NextPacket(&packet_, &last));
      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 = last;
      ParseAndCheckPacket(rtp_payload.data(), hdr, expected_hdr_sizes[i],
                          rtp_payload.size());
      CheckPayload(rtp_payload.data(), expected_hdr_sizes[i],
                   rtp_payload.size(), last);
    }
    EXPECT_TRUE(last);
  }
};

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  (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  (1hdr + 14 payload)
  // I:0, P:0, L:0, F:0, B:0, E:1, V:0  (1hdr + 13 payload)
  const size_t kExpectedHdrSizes[] = {1, 1};
  const size_t kExpectedSizes[] = {15, 14};
  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 (2hdr + 10 payload)
  // I:1, P:0, L:0, F:0, B:0, E:0, V:0 (2hdr + 10 payload)
  // I:1, P:0, L:0, F:0, B:0, E:1, V: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 (3hdr + 8 payload)
  // I:1, P:0, L:0, F:0, B:0, E:0, V:0 (3hdr + 8 payload)
  // I:1, P:0, L:0, F:0, B:0, E:0, V:0 (3hdr + 8 payload)
  // I:1, P:0, L:0, F:0, B:0, E:1, V:0 (3hdr + 7 payload)
  const size_t kExpectedHdrSizes[] = {3, 3, 3, 3};
  const size_t kExpectedSizes[] = {11, 11, 11, 10};
  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 | (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 | (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 (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 (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 (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 (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, TestOnlyHighestSpatialLayerSetMarker) {
  const size_t kFrameSize = 10;
  const size_t kPacketSize = 9;  // 2 packet per frame.
  const uint8_t kFrame[kFrameSize] = {7};
  const RTPFragmentationHeader* kNoFragmentation = nullptr;

  RTPVideoHeaderVP9 vp9_header;
  vp9_header.InitRTPVideoHeaderVP9();
  vp9_header.flexible_mode = true;
  vp9_header.num_spatial_layers = 3;

  RtpPacketToSend packet(kNoExtensions);
  bool last;

  vp9_header.spatial_idx = 0;
  RtpPacketizerVp9 packetizer0(vp9_header, kPacketSize);
  packetizer0.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation);
  ASSERT_TRUE(packetizer0.NextPacket(&packet, &last));
  EXPECT_FALSE(last);
  EXPECT_FALSE(packet.Marker());
  ASSERT_TRUE(packetizer0.NextPacket(&packet, &last));
  EXPECT_TRUE(last);
  EXPECT_FALSE(packet.Marker());

  vp9_header.spatial_idx = 1;
  RtpPacketizerVp9 packetizer1(vp9_header, kPacketSize);
  packetizer1.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation);
  ASSERT_TRUE(packetizer1.NextPacket(&packet, &last));
  EXPECT_FALSE(last);
  EXPECT_FALSE(packet.Marker());
  ASSERT_TRUE(packetizer1.NextPacket(&packet, &last));
  EXPECT_TRUE(last);
  EXPECT_FALSE(packet.Marker());

  vp9_header.spatial_idx = 2;
  RtpPacketizerVp9 packetizer2(vp9_header, kPacketSize);
  packetizer2.SetPayloadData(kFrame, sizeof(kFrame), kNoFragmentation);
  ASSERT_TRUE(packetizer2.NextPacket(&packet, &last));
  EXPECT_FALSE(last);
  EXPECT_FALSE(packet.Marker());
  ASSERT_TRUE(packetizer2.NextPacket(&packet, &last));
  EXPECT_TRUE(last);
  EXPECT_TRUE(packet.Marker());
}

TEST_F(RtpPacketizerVp9Test, TestBaseLayerProtectionAndStorageType) {
  const size_t kFrameSize = 10;
  const size_t kPacketSize = 12;

  // I:0, P:0, L:1, F:1, B:1, E:1, V:0 (2hdr + 10 payload)
  // L:   T:0, U:0, S:0, D:0
  expected_.flexible_mode = true;
  expected_.temporal_idx = 0;
  Init(kFrameSize, kPacketSize);
  EXPECT_EQ(kProtectedPacket, packetizer_->GetProtectionType());
  EXPECT_EQ(kAllowRetransmission,
            packetizer_->GetStorageType(kRetransmitBaseLayer));
  EXPECT_EQ(kDontRetransmit, packetizer_->GetStorageType(kRetransmitOff));
}

TEST_F(RtpPacketizerVp9Test, TestHigherLayerProtectionAndStorageType) {
  const size_t kFrameSize = 10;
  const size_t kPacketSize = 12;

  // I:0, P:0, L:1, F:1, B:1, E:1, V:0 (2hdr + 10 payload)
  // L:   T:1, U:0, S:0, D:0
  expected_.flexible_mode = true;
  expected_.temporal_idx = 1;
  Init(kFrameSize, kPacketSize);
  EXPECT_EQ(kUnprotectedPacket, packetizer_->GetProtectionType());
  EXPECT_EQ(kDontRetransmit, packetizer_->GetStorageType(kRetransmitBaseLayer));
  EXPECT_EQ(kAllowRetransmission,
            packetizer_->GetStorageType(kRetransmitHigherLayers));
}


class RtpDepacketizerVp9Test : public ::testing::Test {
 protected:
  RtpDepacketizerVp9Test()
      : depacketizer_(new RtpDepacketizerVp9()) {}

  virtual void SetUp() {
    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 R: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 R: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 R: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 R: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 R:0
  packet[1] = (kTemporalIdx << 5) | (kUbit << 4) | (kSpatialIdx << 1) | kDbit;

  // I:0 P:0 L:1 F:1 B:1 E:0 V: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 R: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
  // 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 R: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 R: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 R: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 R:0

  RtpDepacketizer::ParsedPayload parsed;
  ASSERT_TRUE(depacketizer_->Parse(&parsed, packet, sizeof(packet)));
  EXPECT_EQ(kVideoFrameKey, parsed.frame_type);
  EXPECT_TRUE(parsed.type.Video.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 R:0

  RtpDepacketizer::ParsedPayload parsed;
  ASSERT_TRUE(depacketizer_->Parse(&parsed, packet, sizeof(packet)));
  EXPECT_EQ(kVideoFrameDelta, parsed.frame_type);
  EXPECT_FALSE(parsed.type.Video.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 R: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.type.Video.width);
  EXPECT_EQ(kHeight[0], parsed.type.Video.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)));
}

}  // namespace webrtc
