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