OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2016 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 "webrtc/modules/video_coding/h264_sps_pps_tracker.h" |
| 12 |
| 13 #include <vector> |
| 14 |
| 15 #include "webrtc/modules/video_coding/packet.h" |
| 16 #include "webrtc/test/gtest.h" |
| 17 #include "webrtc/common_video/h264/h264_common.h" |
| 18 |
| 19 namespace webrtc { |
| 20 namespace video_coding { |
| 21 |
| 22 namespace { |
| 23 // Using an std::initializer_list for easier appending to std::vector. |
| 24 const std::initializer_list<uint8_t> start_code = {0, 0, 0, 1}; |
| 25 } // namespace |
| 26 |
| 27 class TestH264SpsPpsTracker : public ::testing::Test { |
| 28 public: |
| 29 VCMPacket GetDefaultPacket() { |
| 30 VCMPacket packet; |
| 31 packet.codec = kVideoCodecH264; |
| 32 packet.video_header.codecHeader.H264.nalus_length = 0; |
| 33 packet.video_header.isFirstPacket = false; |
| 34 packet.video_header.codecHeader.H264.packetization_type = kH264SingleNalu; |
| 35 |
| 36 return packet; |
| 37 } |
| 38 |
| 39 void AddSps(VCMPacket* packet, int sps_id, std::vector<uint8_t>* data) { |
| 40 NaluInfo info; |
| 41 info.type = H264::NaluType::kSps; |
| 42 info.sps_id = sps_id; |
| 43 info.pps_id = -1; |
| 44 info.offset = data->size(); |
| 45 info.size = 2; |
| 46 data->push_back(H264::NaluType::kSps); |
| 47 data->push_back(sps_id); // The sps data, just a single byte. |
| 48 |
| 49 packet->video_header.codecHeader.H264 |
| 50 .nalus[packet->video_header.codecHeader.H264.nalus_length++] = info; |
| 51 } |
| 52 |
| 53 void AddPps(VCMPacket* packet, |
| 54 int sps_id, |
| 55 int pps_id, |
| 56 std::vector<uint8_t>* data) { |
| 57 NaluInfo info; |
| 58 info.type = H264::NaluType::kPps; |
| 59 info.sps_id = sps_id; |
| 60 info.pps_id = pps_id; |
| 61 info.offset = data->size(); |
| 62 info.size = 2; |
| 63 data->push_back(H264::NaluType::kPps); |
| 64 data->push_back(pps_id); // The pps data, just a single byte. |
| 65 |
| 66 packet->video_header.codecHeader.H264 |
| 67 .nalus[packet->video_header.codecHeader.H264.nalus_length++] = info; |
| 68 } |
| 69 |
| 70 void AddIdr(VCMPacket* packet, int pps_id) { |
| 71 NaluInfo info; |
| 72 info.type = H264::NaluType::kIdr; |
| 73 info.sps_id = -1; |
| 74 info.pps_id = pps_id; |
| 75 |
| 76 packet->video_header.codecHeader.H264 |
| 77 .nalus[packet->video_header.codecHeader.H264.nalus_length++] = info; |
| 78 } |
| 79 |
| 80 protected: |
| 81 H264SpsPpsTracker tracker_; |
| 82 }; |
| 83 |
| 84 TEST_F(TestH264SpsPpsTracker, NoNalus) { |
| 85 uint8_t data[] = {1, 2, 3}; |
| 86 VCMPacket packet = GetDefaultPacket(); |
| 87 packet.video_header.codecHeader.H264.packetization_type = kH264FuA; |
| 88 packet.dataPtr = data; |
| 89 packet.sizeBytes = sizeof(data); |
| 90 |
| 91 EXPECT_TRUE(tracker_.CopyAndFixBitstream(&packet)); |
| 92 EXPECT_EQ(memcmp(packet.dataPtr, data, sizeof(data)), 0); |
| 93 } |
| 94 |
| 95 TEST_F(TestH264SpsPpsTracker, FuAFirstPacket) { |
| 96 uint8_t data[] = {1, 2, 3}; |
| 97 VCMPacket packet = GetDefaultPacket(); |
| 98 packet.video_header.codecHeader.H264.packetization_type = kH264FuA; |
| 99 packet.video_header.isFirstPacket = true; |
| 100 packet.dataPtr = data; |
| 101 packet.sizeBytes = sizeof(data); |
| 102 |
| 103 EXPECT_TRUE(tracker_.CopyAndFixBitstream(&packet)); |
| 104 std::vector<uint8_t> expected; |
| 105 expected.insert(expected.end(), start_code); |
| 106 expected.insert(expected.end(), {1, 2, 3}); |
| 107 EXPECT_EQ(memcmp(packet.dataPtr, expected.data(), expected.size()), 0); |
| 108 } |
| 109 |
| 110 TEST_F(TestH264SpsPpsTracker, NoNalusFirstPacket) { |
| 111 uint8_t data[] = {1, 2, 3}; |
| 112 VCMPacket packet = GetDefaultPacket(); |
| 113 packet.video_header.isFirstPacket = true; |
| 114 packet.dataPtr = data; |
| 115 packet.sizeBytes = sizeof(data); |
| 116 |
| 117 EXPECT_TRUE(tracker_.CopyAndFixBitstream(&packet)); |
| 118 std::vector<uint8_t> expected; |
| 119 expected.insert(expected.end(), start_code); |
| 120 expected.insert(expected.end(), {1, 2, 3}); |
| 121 EXPECT_EQ(memcmp(packet.dataPtr, expected.data(), expected.size()), 0); |
| 122 } |
| 123 |
| 124 TEST_F(TestH264SpsPpsTracker, IdrNoSpsPpsInserted) { |
| 125 std::vector<uint8_t> data = {1, 2, 3}; |
| 126 VCMPacket packet = GetDefaultPacket(); |
| 127 packet.video_header.codecHeader.H264.packetization_type = kH264FuA; |
| 128 |
| 129 AddIdr(&packet, 0); |
| 130 packet.dataPtr = data.data(); |
| 131 packet.sizeBytes = data.size(); |
| 132 |
| 133 EXPECT_TRUE(tracker_.CopyAndFixBitstream(&packet)); |
| 134 EXPECT_EQ(memcmp(packet.dataPtr, data.data(), data.size()), 0); |
| 135 } |
| 136 |
| 137 TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoSpsPpsInserted) { |
| 138 std::vector<uint8_t> data = {1, 2, 3}; |
| 139 VCMPacket packet = GetDefaultPacket(); |
| 140 packet.video_header.isFirstPacket = true; |
| 141 |
| 142 AddIdr(&packet, 0); |
| 143 packet.dataPtr = data.data(); |
| 144 packet.sizeBytes = data.size(); |
| 145 |
| 146 EXPECT_FALSE(tracker_.CopyAndFixBitstream(&packet)); |
| 147 } |
| 148 |
| 149 TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoPpsInserted) { |
| 150 std::vector<uint8_t> data = {1, 2, 3}; |
| 151 VCMPacket packet = GetDefaultPacket(); |
| 152 packet.video_header.isFirstPacket = true; |
| 153 |
| 154 AddSps(&packet, 0, &data); |
| 155 AddIdr(&packet, 0); |
| 156 packet.dataPtr = data.data(); |
| 157 packet.sizeBytes = data.size(); |
| 158 |
| 159 EXPECT_FALSE(tracker_.CopyAndFixBitstream(&packet)); |
| 160 } |
| 161 |
| 162 TEST_F(TestH264SpsPpsTracker, IdrFirstPacketNoSpsInserted) { |
| 163 std::vector<uint8_t> data = {1, 2, 3}; |
| 164 VCMPacket packet = GetDefaultPacket(); |
| 165 packet.video_header.isFirstPacket = true; |
| 166 |
| 167 AddPps(&packet, 0, 0, &data); |
| 168 AddIdr(&packet, 0); |
| 169 packet.dataPtr = data.data(); |
| 170 packet.sizeBytes = data.size(); |
| 171 |
| 172 EXPECT_FALSE(tracker_.CopyAndFixBitstream(&packet)); |
| 173 } |
| 174 |
| 175 TEST_F(TestH264SpsPpsTracker, SpsPpsPacketThenIdrFirstPacket) { |
| 176 std::vector<uint8_t> data; |
| 177 VCMPacket sps_pps_packet = GetDefaultPacket(); |
| 178 |
| 179 // Insert SPS/PPS |
| 180 AddSps(&sps_pps_packet, 0, &data); |
| 181 AddPps(&sps_pps_packet, 0, 1, &data); |
| 182 sps_pps_packet.dataPtr = data.data(); |
| 183 sps_pps_packet.sizeBytes = data.size(); |
| 184 EXPECT_FALSE(tracker_.CopyAndFixBitstream(&sps_pps_packet)); |
| 185 data.clear(); |
| 186 |
| 187 // Insert first packet of the IDR |
| 188 VCMPacket idr_packet = GetDefaultPacket(); |
| 189 idr_packet.video_header.isFirstPacket = true; |
| 190 AddIdr(&idr_packet, 1); |
| 191 data.insert(data.end(), {1, 2, 3}); |
| 192 idr_packet.dataPtr = data.data(); |
| 193 idr_packet.sizeBytes = data.size(); |
| 194 EXPECT_TRUE(tracker_.CopyAndFixBitstream(&idr_packet)); |
| 195 |
| 196 std::vector<uint8_t> expected; |
| 197 expected.insert(expected.end(), start_code); |
| 198 expected.insert(expected.end(), {H264::NaluType::kSps, 0}); |
| 199 expected.insert(expected.end(), start_code); |
| 200 expected.insert(expected.end(), {H264::NaluType::kPps, 1}); |
| 201 expected.insert(expected.end(), start_code); |
| 202 expected.insert(expected.end(), {1, 2, 3}); |
| 203 EXPECT_EQ(memcmp(idr_packet.dataPtr, expected.data(), expected.size()), 0); |
| 204 } |
| 205 |
| 206 TEST_F(TestH264SpsPpsTracker, SpsPpsIdrInStapA) { |
| 207 std::vector<uint8_t> data; |
| 208 VCMPacket packet = GetDefaultPacket(); |
| 209 packet.video_header.codecHeader.H264.packetization_type = kH264StapA; |
| 210 packet.video_header.isFirstPacket = true; // Always true for StapA |
| 211 |
| 212 data.insert(data.end(), {0}); // First byte is ignored |
| 213 data.insert(data.end(), {0, 2}); // Length of segment |
| 214 AddSps(&packet, 13, &data); |
| 215 data.insert(data.end(), {0, 2}); // Length of segment |
| 216 AddPps(&packet, 13, 27, &data); |
| 217 data.insert(data.end(), {0, 5}); // Length of segment |
| 218 AddIdr(&packet, 27); |
| 219 data.insert(data.end(), {1, 2, 3, 2, 1}); |
| 220 |
| 221 packet.dataPtr = data.data(); |
| 222 packet.sizeBytes = data.size(); |
| 223 EXPECT_TRUE(tracker_.CopyAndFixBitstream(&packet)); |
| 224 |
| 225 std::vector<uint8_t> expected; |
| 226 // The SPS/PPS is repeated because this packet both contains the SPS/PPS |
| 227 // and it is the first packet of an IDR, which will cause the SPS/PPS to be |
| 228 // prepended to the bitstream. |
| 229 expected.insert(expected.end(), start_code); |
| 230 expected.insert(expected.end(), {H264::NaluType::kSps, 13}); |
| 231 expected.insert(expected.end(), start_code); |
| 232 expected.insert(expected.end(), {H264::NaluType::kPps, 27}); |
| 233 expected.insert(expected.end(), start_code); |
| 234 expected.insert(expected.end(), {H264::NaluType::kSps, 13}); |
| 235 expected.insert(expected.end(), start_code); |
| 236 expected.insert(expected.end(), {H264::NaluType::kPps, 27}); |
| 237 expected.insert(expected.end(), start_code); |
| 238 expected.insert(expected.end(), {1, 2, 3, 2, 1}); |
| 239 |
| 240 EXPECT_EQ(memcmp(packet.dataPtr, expected.data(), expected.size()), 0); |
| 241 } |
| 242 |
| 243 } // namespace video_coding |
| 244 } // namespace webrtc |
OLD | NEW |