Index: webrtc/modules/video_coding/h264_sps_pps_tracker_unittest.cc |
diff --git a/webrtc/modules/video_coding/h264_sps_pps_tracker_unittest.cc b/webrtc/modules/video_coding/h264_sps_pps_tracker_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..094ac346c6c62cd21117874614183ce7ac4e40e1 |
--- /dev/null |
+++ b/webrtc/modules/video_coding/h264_sps_pps_tracker_unittest.cc |
@@ -0,0 +1,231 @@ |
+/* |
+ * Copyright (c) 2016 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 "webrtc/modules/video_coding/h264_sps_pps_tracker.h" |
+ |
+#include <vector> |
+ |
+#include "webrtc/modules/video_coding/packet.h" |
+#include "webrtc/test/gtest.h" |
+#include "webrtc/common_video/h264/h264_common.h" |
+ |
+namespace webrtc { |
+namespace video_coding { |
+ |
+namespace { |
+// Using an std::initializer_list for easier appending to std::vector. |
+const std::initializer_list<uint8_t> start_code = {0, 0, 0, 1}; |
+} // namespace |
+ |
+class TestH264SpsPpsTracker : public ::testing::Test { |
+ public: |
+ VCMPacket GetDefaultPacket() { |
+ VCMPacket packet; |
+ packet.codec = kVideoCodecH264; |
+ packet.video_header.codecHeader.H264.nalus_length = 0; |
+ packet.video_header.isFirstPacket = false; |
+ packet.video_header.codecHeader.H264.packetization_type = kH264SingleNalu; |
+ |
+ return packet; |
+ } |
+ |
+ void AddSps(VCMPacket* packet, int sps_id, std::vector<uint8_t>* data) { |
+ NaluInfo info; |
+ info.type = H264::NaluType::kSps; |
+ info.sps_id = sps_id; |
+ info.pps_id = -1; |
+ info.offset = data->size(); |
+ info.size = 2; |
+ data->push_back(H264::NaluType::kSps); |
+ data->push_back(sps_id); // The sps data, just a single byte. |
+ |
+ packet->video_header.codecHeader.H264 |
+ .nalus[packet->video_header.codecHeader.H264.nalus_length++] = info; |
+ } |
+ |
+ void AddPps(VCMPacket* packet, |
+ int sps_id, |
+ int pps_id, |
+ std::vector<uint8_t>* data) { |
+ NaluInfo info; |
+ info.type = H264::NaluType::kPps; |
+ info.sps_id = sps_id; |
+ info.pps_id = pps_id; |
+ info.offset = data->size(); |
+ info.size = 2; |
+ data->push_back(H264::NaluType::kPps); |
+ data->push_back(pps_id); // The pps data, just a single byte. |
+ |
+ packet->video_header.codecHeader.H264 |
+ .nalus[packet->video_header.codecHeader.H264.nalus_length++] = info; |
+ } |
+ |
+ void AddIdr(VCMPacket* packet, int pps_id) { |
+ NaluInfo info; |
+ info.type = H264::NaluType::kIdr; |
+ info.sps_id = -1; |
+ info.pps_id = pps_id; |
+ |
+ packet->video_header.codecHeader.H264 |
+ .nalus[packet->video_header.codecHeader.H264.nalus_length++] = info; |
+ } |
+ |
+ protected: |
+ H264SpsPpsTracker tracker_; |
+}; |
+ |
+TEST_F(TestH264SpsPpsTracker, NoNalus) { |
+ uint8_t data[] = {1, 2, 3}; |
+ VCMPacket packet = GetDefaultPacket(); |
+ packet.video_header.codecHeader.H264.packetization_type = kH264FuA; |
+ packet.dataPtr = data; |
+ packet.sizeBytes = sizeof(data); |
+ |
+ EXPECT_TRUE(tracker_.CopyAndFixBitstream(&packet)); |
+ EXPECT_EQ(memcmp(packet.dataPtr, data, sizeof(data)), 0); |
+} |
+ |
+TEST_F(TestH264SpsPpsTracker, NoNalusFirstPacket) { |
+ uint8_t data[] = {1, 2, 3}; |
+ VCMPacket packet = GetDefaultPacket(); |
+ packet.video_header.isFirstPacket = true; |
+ packet.dataPtr = data; |
+ packet.sizeBytes = sizeof(data); |
+ |
+ EXPECT_TRUE(tracker_.CopyAndFixBitstream(&packet)); |
+ std::vector<uint8_t> expected; |
+ expected.insert(expected.end(), start_code); |
+ expected.insert(expected.end(), {1, 2, 3}); |
+ EXPECT_EQ(memcmp(packet.dataPtr, expected.data(), expected.size()), 0); |
+} |
+ |
+TEST_F(TestH264SpsPpsTracker, IdrNoSpsPpsInserted) { |
+ std::vector<uint8_t> data = {1, 2, 3}; |
+ VCMPacket packet = GetDefaultPacket(); |
+ |
+ AddIdr(&packet, 0); |
+ packet.dataPtr = data.data(); |
+ packet.sizeBytes = data.size(); |
+ |
+ EXPECT_TRUE(tracker_.CopyAndFixBitstream(&packet)); |
+ std::vector<uint8_t> expected; |
+ expected.insert(expected.end(), start_code); |
+ expected.insert(expected.end(), {1, 2, 3}); |
+ EXPECT_EQ(memcmp(packet.dataPtr, expected.data(), expected.size()), 0); |
+} |
+ |
+TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoSpsPpsInserted) { |
+ std::vector<uint8_t> data = {1, 2, 3}; |
+ VCMPacket packet = GetDefaultPacket(); |
+ packet.video_header.isFirstPacket = true; |
+ |
+ AddIdr(&packet, 0); |
+ packet.dataPtr = data.data(); |
+ packet.sizeBytes = data.size(); |
+ |
+ EXPECT_FALSE(tracker_.CopyAndFixBitstream(&packet)); |
+} |
+ |
+TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoPpsInserted) { |
+ std::vector<uint8_t> data = {1, 2, 3}; |
+ VCMPacket packet = GetDefaultPacket(); |
+ packet.video_header.isFirstPacket = true; |
+ |
+ AddSps(&packet, 0, &data); |
+ AddIdr(&packet, 0); |
+ packet.dataPtr = data.data(); |
+ packet.sizeBytes = data.size(); |
+ |
+ EXPECT_FALSE(tracker_.CopyAndFixBitstream(&packet)); |
+} |
+ |
+TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoSpsInserted) { |
+ std::vector<uint8_t> data = {1, 2, 3}; |
+ VCMPacket packet = GetDefaultPacket(); |
+ packet.video_header.isFirstPacket = true; |
+ |
+ AddPps(&packet, 0, 0, &data); |
+ AddIdr(&packet, 0); |
+ packet.dataPtr = data.data(); |
+ packet.sizeBytes = data.size(); |
+ |
+ EXPECT_FALSE(tracker_.CopyAndFixBitstream(&packet)); |
+} |
+ |
+TEST_F(TestH264SpsPpsTracker, SpsPpsPacketThenIdrFirstPacket) { |
+ std::vector<uint8_t> data; |
+ VCMPacket sps_pps_packet = GetDefaultPacket(); |
+ |
+ // Insert SPS/PPS |
+ AddSps(&sps_pps_packet, 0, &data); |
+ AddPps(&sps_pps_packet, 0, 1, &data); |
+ sps_pps_packet.dataPtr = data.data(); |
+ sps_pps_packet.sizeBytes = data.size(); |
+ EXPECT_FALSE(tracker_.CopyAndFixBitstream(&sps_pps_packet)); |
+ data.clear(); |
+ |
+ // Insert first packet of the IDR |
+ VCMPacket idr_packet = GetDefaultPacket(); |
+ idr_packet.video_header.isFirstPacket = true; |
+ AddIdr(&idr_packet, 1); |
+ data.insert(data.end(), {1, 2, 3}); |
+ idr_packet.dataPtr = data.data(); |
+ idr_packet.sizeBytes = data.size(); |
+ EXPECT_TRUE(tracker_.CopyAndFixBitstream(&idr_packet)); |
+ |
+ std::vector<uint8_t> expected; |
+ expected.insert(expected.end(), start_code); |
+ expected.insert(expected.end(), {H264::NaluType::kSps, 0}); |
+ expected.insert(expected.end(), start_code); |
+ expected.insert(expected.end(), {H264::NaluType::kPps, 1}); |
+ expected.insert(expected.end(), start_code); |
+ expected.insert(expected.end(), {1, 2, 3}); |
+ EXPECT_EQ(memcmp(idr_packet.dataPtr, expected.data(), expected.size()), 0); |
+} |
+ |
+TEST_F(TestH264SpsPpsTracker, SpsPpsIdrInStapA) { |
+ std::vector<uint8_t> data; |
+ VCMPacket packet = GetDefaultPacket(); |
+ packet.video_header.codecHeader.H264.packetization_type = kH264StapA; |
+ packet.video_header.isFirstPacket = true; // Always true for StapA |
+ |
+ data.insert(data.end(), {0}); // First byte is ignored |
+ data.insert(data.end(), {0, 2}); // Length of segment |
+ AddSps(&packet, 13, &data); |
+ data.insert(data.end(), {0, 2}); // Length of segment |
+ AddPps(&packet, 13, 27, &data); |
+ data.insert(data.end(), {0, 5}); // Length of segment |
+ AddIdr(&packet, 27); |
+ data.insert(data.end(), {1, 2, 3, 2, 1}); |
+ |
+ packet.dataPtr = data.data(); |
+ packet.sizeBytes = data.size(); |
+ EXPECT_TRUE(tracker_.CopyAndFixBitstream(&packet)); |
+ |
+ std::vector<uint8_t> expected; |
+ // The SPS/PPS is repeated because this packet both contains the SPS/PPS |
+ // and it is the first packet of an IDR, which will cause the SPS/PPS to be |
+ // prepended to the bitstream. |
+ expected.insert(expected.end(), start_code); |
+ expected.insert(expected.end(), {H264::NaluType::kSps, 13}); |
+ expected.insert(expected.end(), start_code); |
+ expected.insert(expected.end(), {H264::NaluType::kPps, 27}); |
+ expected.insert(expected.end(), start_code); |
+ expected.insert(expected.end(), {H264::NaluType::kSps, 13}); |
+ expected.insert(expected.end(), start_code); |
+ expected.insert(expected.end(), {H264::NaluType::kPps, 27}); |
+ expected.insert(expected.end(), start_code); |
+ expected.insert(expected.end(), {1, 2, 3, 2, 1}); |
+ |
+ EXPECT_EQ(memcmp(packet.dataPtr, expected.data(), expected.size()), 0); |
+} |
+ |
+} // namespace video_coding |
+} // namespace webrtc |