1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <string.h> 6 7 #include "base/basictypes.h" 8 #include "base/strings/string_util.h" 9 #include "media/base/decrypt_config.h" 10 #include "media/base/stream_parser_buffer.h" 11 #include "media/filters/h264_parser.h" 12 #include "media/formats/mp4/avc.h" 13 #include "media/formats/mp4/box_definitions.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 16 namespace media { 17 namespace mp4 { 18 19 static const uint8 kNALU1[] = { 0x01, 0x02, 0x03 }; 20 static const uint8 kNALU2[] = { 0x04, 0x05, 0x06, 0x07 }; 21 static const uint8 kExpected[] = { 22 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 23 0x00, 0x00, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07 }; 24 25 static const uint8 kExpectedParamSets[] = { 26 0x00, 0x00, 0x00, 0x01, 0x67, 0x12, 27 0x00, 0x00, 0x00, 0x01, 0x67, 0x34, 28 0x00, 0x00, 0x00, 0x01, 0x68, 0x56, 0x78}; 29 30 static H264NALU::Type StringToNALUType(const std::string& name) { 31 if (name == "P") 32 return H264NALU::kNonIDRSlice; 33 34 if (name == "I") 35 return H264NALU::kIDRSlice; 36 37 if (name == "SEI") 38 return H264NALU::kSEIMessage; 39 40 if (name == "SPS") 41 return H264NALU::kSPS; 42 43 if (name == "SPSExt") 44 return H264NALU::kSPSExt; 45 46 if (name == "PPS") 47 return H264NALU::kPPS; 48 49 if (name == "AUD") 50 return H264NALU::kAUD; 51 52 if (name == "EOSeq") 53 return H264NALU::kEOSeq; 54 55 if (name == "EOStr") 56 return H264NALU::kEOStream; 57 58 if (name == "FILL") 59 return H264NALU::kFiller; 60 61 if (name == "R14") 62 return H264NALU::kReserved14; 63 64 CHECK(false) << "Unexpected name: " << name; 65 return H264NALU::kUnspecified; 66 } 67 68 static std::string NALUTypeToString(int type) { 69 switch (type) { 70 case H264NALU::kNonIDRSlice: 71 return "P"; 72 case H264NALU::kSliceDataA: 73 return "SDA"; 74 case H264NALU::kSliceDataB: 75 return "SDB"; 76 case H264NALU::kSliceDataC: 77 return "SDC"; 78 case H264NALU::kIDRSlice: 79 return "I"; 80 case H264NALU::kSEIMessage: 81 return "SEI"; 82 case H264NALU::kSPS: 83 return "SPS"; 84 case H264NALU::kSPSExt: 85 return "SPSExt"; 86 case H264NALU::kPPS: 87 return "PPS"; 88 case H264NALU::kAUD: 89 return "AUD"; 90 case H264NALU::kEOSeq: 91 return "EOSeq"; 92 case H264NALU::kEOStream: 93 return "EOStr"; 94 case H264NALU::kFiller: 95 return "FILL"; 96 case H264NALU::kReserved14: 97 return "R14"; 98 99 case H264NALU::kUnspecified: 100 case H264NALU::kReserved15: 101 case H264NALU::kReserved16: 102 case H264NALU::kReserved17: 103 case H264NALU::kReserved18: 104 case H264NALU::kCodedSliceAux: 105 case H264NALU::kCodedSliceExtension: 106 CHECK(false) << "Unexpected type: " << type; 107 break; 108 }; 109 110 return "UnsupportedType"; 111 } 112 113 static void WriteStartCodeAndNALUType(std::vector<uint8>* buffer, 114 const std::string& nal_unit_type) { 115 buffer->push_back(0x00); 116 buffer->push_back(0x00); 117 buffer->push_back(0x00); 118 buffer->push_back(0x01); 119 buffer->push_back(StringToNALUType(nal_unit_type)); 120 } 121 122 void StringToAnnexB(const std::string& str, std::vector<uint8>* buffer, 123 std::vector<SubsampleEntry>* subsamples) { 124 DCHECK(!str.empty()); 125 126 std::vector<std::string> tokens; 127 EXPECT_GT(Tokenize(str, " ", &tokens), 0u); 128 129 buffer->clear(); 130 for (size_t i = 0; i < tokens.size(); ++i) { 131 SubsampleEntry entry; 132 size_t start = buffer->size(); 133 134 WriteStartCodeAndNALUType(buffer, tokens[i]); 135 136 entry.clear_bytes = buffer->size() - start; 137 138 // Write junk for the payload since the current code doesn't 139 // actually look at it. 140 buffer->push_back(0x32); 141 buffer->push_back(0x12); 142 buffer->push_back(0x67); 143 144 if (subsamples) { 145 // Simulate the encrypted bits containing something that looks 146 // like a SPS NALU. 147 WriteStartCodeAndNALUType(buffer, "SPS"); 148 } 149 150 entry.cypher_bytes = buffer->size() - start - entry.clear_bytes; 151 152 if (subsamples) { 153 subsamples->push_back(entry); 154 } 155 } 156 } 157 158 std::string AnnexBToString(const std::vector<uint8>& buffer, 159 const std::vector<SubsampleEntry>& subsamples) { 160 std::stringstream ss; 161 162 H264Parser parser; 163 parser.SetEncryptedStream(&buffer[0], buffer.size(), subsamples); 164 165 H264NALU nalu; 166 bool first = true; 167 while (parser.AdvanceToNextNALU(&nalu) == H264Parser::kOk) { 168 if (!first) 169 ss << " "; 170 else 171 first = false; 172 173 ss << NALUTypeToString(nalu.nal_unit_type); 174 } 175 return ss.str(); 176 } 177 178 class AVCConversionTest : public testing::TestWithParam<int> { 179 protected: 180 void WriteLength(int length_size, int length, std::vector<uint8>* buf) { 181 DCHECK_GE(length, 0); 182 DCHECK_LE(length, 255); 183 184 for (int i = 1; i < length_size; i++) 185 buf->push_back(0); 186 buf->push_back(length); 187 } 188 189 void MakeInputForLength(int length_size, std::vector<uint8>* buf) { 190 buf->clear(); 191 192 WriteLength(length_size, sizeof(kNALU1), buf); 193 buf->insert(buf->end(), kNALU1, kNALU1 + sizeof(kNALU1)); 194 195 WriteLength(length_size, sizeof(kNALU2), buf); 196 buf->insert(buf->end(), kNALU2, kNALU2 + sizeof(kNALU2)); 197 } 198 199 }; 200 201 TEST_P(AVCConversionTest, ParseCorrectly) { 202 std::vector<uint8> buf; 203 std::vector<SubsampleEntry> subsamples; 204 MakeInputForLength(GetParam(), &buf); 205 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); 206 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)); 207 EXPECT_EQ(buf.size(), sizeof(kExpected)); 208 EXPECT_EQ(0, memcmp(kExpected, &buf[0], sizeof(kExpected))); 209 EXPECT_EQ("P SDC", AnnexBToString(buf, subsamples)); 210 } 211 212 // Intentionally write NALU sizes that are larger than the buffer. 213 TEST_P(AVCConversionTest, NALUSizeTooLarge) { 214 std::vector<uint8> buf; 215 WriteLength(GetParam(), 10 * sizeof(kNALU1), &buf); 216 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1)); 217 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); 218 } 219 220 TEST_P(AVCConversionTest, NALUSizeIsZero) { 221 std::vector<uint8> buf; 222 WriteLength(GetParam(), 0, &buf); 223 224 WriteLength(GetParam(), sizeof(kNALU1), &buf); 225 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1)); 226 227 WriteLength(GetParam(), 0, &buf); 228 229 WriteLength(GetParam(), sizeof(kNALU2), &buf); 230 buf.insert(buf.end(), kNALU2, kNALU2 + sizeof(kNALU2)); 231 232 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); 233 } 234 235 TEST_P(AVCConversionTest, ParsePartial) { 236 std::vector<uint8> buf; 237 MakeInputForLength(GetParam(), &buf); 238 buf.pop_back(); 239 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); 240 // This tests a buffer ending in the middle of a NAL length. For length size 241 // of one, this can't happen, so we skip that case. 242 if (GetParam() != 1) { 243 MakeInputForLength(GetParam(), &buf); 244 buf.erase(buf.end() - (sizeof(kNALU2) + 1), buf.end()); 245 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); 246 } 247 } 248 249 TEST_P(AVCConversionTest, ParseEmpty) { 250 std::vector<uint8> buf; 251 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); 252 EXPECT_EQ(0u, buf.size()); 253 } 254 255 INSTANTIATE_TEST_CASE_P(AVCConversionTestValues, 256 AVCConversionTest, 257 ::testing::Values(1, 2, 4)); 258 259 TEST_F(AVCConversionTest, ConvertConfigToAnnexB) { 260 AVCDecoderConfigurationRecord avc_config; 261 avc_config.sps_list.resize(2); 262 avc_config.sps_list[0].push_back(0x67); 263 avc_config.sps_list[0].push_back(0x12); 264 avc_config.sps_list[1].push_back(0x67); 265 avc_config.sps_list[1].push_back(0x34); 266 avc_config.pps_list.resize(1); 267 avc_config.pps_list[0].push_back(0x68); 268 avc_config.pps_list[0].push_back(0x56); 269 avc_config.pps_list[0].push_back(0x78); 270 271 std::vector<uint8> buf; 272 std::vector<SubsampleEntry> subsamples; 273 EXPECT_TRUE(AVC::ConvertConfigToAnnexB(avc_config, &buf, &subsamples)); 274 EXPECT_EQ(0, memcmp(kExpectedParamSets, &buf[0], 275 sizeof(kExpectedParamSets))); 276 EXPECT_EQ("SPS SPS PPS", AnnexBToString(buf, subsamples)); 277 } 278 279 // Verify that we can round trip string -> Annex B -> string. 280 TEST_F(AVCConversionTest, StringConversionFunctions) { 281 std::string str = 282 "AUD SPS SPSExt SPS PPS SEI SEI R14 I P FILL EOSeq EOStr"; 283 std::vector<uint8> buf; 284 std::vector<SubsampleEntry> subsamples; 285 StringToAnnexB(str, &buf, &subsamples); 286 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)); 287 288 EXPECT_EQ(str, AnnexBToString(buf, subsamples)); 289 } 290 291 TEST_F(AVCConversionTest, ValidAnnexBConstructs) { 292 const char* test_cases[] = { 293 "I", 294 "I I I I", 295 "AUD I", 296 "AUD SPS PPS I", 297 "I EOSeq", 298 "I EOSeq EOStr", 299 "I EOStr", 300 "P", 301 "P P P P", 302 "AUD SPS PPS P", 303 "SEI SEI I", 304 "SEI SEI R14 I", 305 "SPS SPSExt SPS PPS I P", 306 "R14 SEI I", 307 }; 308 309 for (size_t i = 0; i < arraysize(test_cases); ++i) { 310 std::vector<uint8> buf; 311 std::vector<SubsampleEntry> subsamples; 312 StringToAnnexB(test_cases[i], &buf, NULL); 313 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)) << "'" << test_cases[i] 314 << "' failed"; 315 } 316 } 317 318 TEST_F(AVCConversionTest, InvalidAnnexBConstructs) { 319 static const char* test_cases[] = { 320 "AUD", // No VCL present. 321 "SPS PPS", // No VCL present. 322 "SPS PPS AUD I", // Parameter sets must come after AUD. 323 "SPSExt SPS P", // SPS must come before SPSExt. 324 "SPS PPS SPSExt P", // SPSExt must follow an SPS. 325 "EOSeq", // EOSeq must come after a VCL. 326 "EOStr", // EOStr must come after a VCL. 327 "I EOStr EOSeq", // EOSeq must come before EOStr. 328 "I R14", // Reserved14-18 must come before first VCL. 329 "I SEI", // SEI must come before first VCL. 330 "P SPS P", // SPS after first VCL would indicate a new access unit. 331 }; 332 333 for (size_t i = 0; i < arraysize(test_cases); ++i) { 334 std::vector<uint8> buf; 335 std::vector<SubsampleEntry> subsamples; 336 StringToAnnexB(test_cases[i], &buf, NULL); 337 EXPECT_FALSE(AVC::IsValidAnnexB(buf, subsamples)) << "'" << test_cases[i] 338 << "' failed"; 339 } 340 } 341 342 typedef struct { 343 const char* input; 344 const char* expected; 345 } InsertTestCases; 346 347 TEST_F(AVCConversionTest, InsertParamSetsAnnexB) { 348 static const InsertTestCases test_cases[] = { 349 { "I", "SPS SPS PPS I" }, 350 { "AUD I", "AUD SPS SPS PPS I" }, 351 352 // Cases where param sets in |avc_config| are placed before 353 // the existing ones. 354 { "SPS PPS I", "SPS SPS PPS SPS PPS I" }, 355 { "AUD SPS PPS I", "AUD SPS SPS PPS SPS PPS I" }, // Note: params placed 356 // after AUD. 357 }; 358 359 AVCDecoderConfigurationRecord avc_config; 360 avc_config.sps_list.resize(2); 361 avc_config.sps_list[0].push_back(0x67); 362 avc_config.sps_list[0].push_back(0x12); 363 avc_config.sps_list[1].push_back(0x67); 364 avc_config.sps_list[1].push_back(0x34); 365 avc_config.pps_list.resize(1); 366 avc_config.pps_list[0].push_back(0x68); 367 avc_config.pps_list[0].push_back(0x56); 368 avc_config.pps_list[0].push_back(0x78); 369 370 for (size_t i = 0; i < arraysize(test_cases); ++i) { 371 std::vector<uint8> buf; 372 std::vector<SubsampleEntry> subsamples; 373 374 StringToAnnexB(test_cases[i].input, &buf, &subsamples); 375 376 EXPECT_TRUE(AVC::InsertParamSetsAnnexB(avc_config, &buf, &subsamples)) 377 << "'" << test_cases[i].input << "' insert failed."; 378 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)) 379 << "'" << test_cases[i].input << "' created invalid AnnexB."; 380 EXPECT_EQ(test_cases[i].expected, AnnexBToString(buf, subsamples)) 381 << "'" << test_cases[i].input << "' generated unexpected output."; 382 } 383 } 384 385 } // namespace mp4 386 } // namespace media 387