| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <string.h> | 5 #include <string.h> |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/strings/string_util.h" | 8 #include "base/strings/string_util.h" |
| 9 #include "media/base/decrypt_config.h" | 9 #include "media/base/decrypt_config.h" |
| 10 #include "media/base/stream_parser_buffer.h" | 10 #include "media/base/stream_parser_buffer.h" |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 | 112 |
| 113 static void WriteStartCodeAndNALUType(std::vector<uint8>* buffer, | 113 static void WriteStartCodeAndNALUType(std::vector<uint8>* buffer, |
| 114 const std::string& nal_unit_type) { | 114 const std::string& nal_unit_type) { |
| 115 buffer->push_back(0x00); | 115 buffer->push_back(0x00); |
| 116 buffer->push_back(0x00); | 116 buffer->push_back(0x00); |
| 117 buffer->push_back(0x00); | 117 buffer->push_back(0x00); |
| 118 buffer->push_back(0x01); | 118 buffer->push_back(0x01); |
| 119 buffer->push_back(StringToNALUType(nal_unit_type)); | 119 buffer->push_back(StringToNALUType(nal_unit_type)); |
| 120 } | 120 } |
| 121 | 121 |
| 122 // Input string should be one or more NALU types separated with spaces or |
| 123 // commas. NALU grouped together and separated by commas are placed into the |
| 124 // same subsample, NALU groups separated by spaces are placed into separate |
| 125 // subsamples. |
| 126 // For example: input string "SPS PPS I" produces Annex B buffer containing |
| 127 // SPS, PPS and I NALUs, each in a separate subsample. While input string |
| 128 // "SPS,PPS I" produces Annex B buffer where the first subsample contains SPS |
| 129 // and PPS NALUs and the second subsample contains the I-slice NALU. |
| 130 // The output buffer will contain a valid-looking Annex B (it's valid-looking in |
| 131 // the sense that it has start codes and correct NALU types, but the actual NALU |
| 132 // payload is junk). |
| 122 void StringToAnnexB(const std::string& str, std::vector<uint8>* buffer, | 133 void StringToAnnexB(const std::string& str, std::vector<uint8>* buffer, |
| 123 std::vector<SubsampleEntry>* subsamples) { | 134 std::vector<SubsampleEntry>* subsamples) { |
| 124 DCHECK(!str.empty()); | 135 DCHECK(!str.empty()); |
| 125 | 136 |
| 126 std::vector<std::string> tokens; | 137 std::vector<std::string> subsample_specs; |
| 127 EXPECT_GT(Tokenize(str, " ", &tokens), 0u); | 138 EXPECT_GT(Tokenize(str, " ", &subsample_specs), 0u); |
| 128 | 139 |
| 129 buffer->clear(); | 140 buffer->clear(); |
| 130 for (size_t i = 0; i < tokens.size(); ++i) { | 141 for (size_t i = 0; i < subsample_specs.size(); ++i) { |
| 131 SubsampleEntry entry; | 142 SubsampleEntry entry; |
| 132 size_t start = buffer->size(); | 143 size_t start = buffer->size(); |
| 133 | 144 |
| 134 WriteStartCodeAndNALUType(buffer, tokens[i]); | 145 std::vector<std::string> subsample_nalus; |
| 146 EXPECT_GT(Tokenize(subsample_specs[i], ",", &subsample_nalus), 0u); |
| 147 for (size_t j = 0; j < subsample_nalus.size(); ++j) { |
| 148 WriteStartCodeAndNALUType(buffer, subsample_nalus[j]); |
| 149 |
| 150 // Write junk for the payload since the current code doesn't |
| 151 // actually look at it. |
| 152 buffer->push_back(0x32); |
| 153 buffer->push_back(0x12); |
| 154 buffer->push_back(0x67); |
| 155 } |
| 135 | 156 |
| 136 entry.clear_bytes = buffer->size() - start; | 157 entry.clear_bytes = buffer->size() - start; |
| 137 | 158 |
| 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) { | 159 if (subsamples) { |
| 145 // Simulate the encrypted bits containing something that looks | 160 // Simulate the encrypted bits containing something that looks |
| 146 // like a SPS NALU. | 161 // like a SPS NALU. |
| 147 WriteStartCodeAndNALUType(buffer, "SPS"); | 162 WriteStartCodeAndNALUType(buffer, "SPS"); |
| 148 } | 163 } |
| 149 | 164 |
| 150 entry.cypher_bytes = buffer->size() - start - entry.clear_bytes; | 165 entry.cypher_bytes = buffer->size() - start - entry.clear_bytes; |
| 151 | 166 |
| 152 if (subsamples) { | 167 if (subsamples) { |
| 153 subsamples->push_back(entry); | 168 subsamples->push_back(entry); |
| 154 } | 169 } |
| 155 } | 170 } |
| 156 } | 171 } |
| 157 | 172 |
| 173 int FindSubsampleIndex(const std::vector<uint8>& buffer, |
| 174 const std::vector<SubsampleEntry>* subsamples, |
| 175 const uint8* ptr) { |
| 176 DCHECK(ptr >= &buffer[0]); |
| 177 DCHECK(ptr <= &buffer[buffer.size()-1]); |
| 178 if (!subsamples || subsamples->empty()) |
| 179 return 0; |
| 180 |
| 181 const uint8* p = &buffer[0]; |
| 182 for (size_t i = 0; i < subsamples->size(); ++i) { |
| 183 p += (*subsamples)[i].clear_bytes + (*subsamples)[i].cypher_bytes; |
| 184 if (p > ptr) { |
| 185 return i; |
| 186 } |
| 187 } |
| 188 NOTREACHED(); |
| 189 return 0; |
| 190 } |
| 191 |
| 158 std::string AnnexBToString(const std::vector<uint8>& buffer, | 192 std::string AnnexBToString(const std::vector<uint8>& buffer, |
| 159 const std::vector<SubsampleEntry>& subsamples) { | 193 const std::vector<SubsampleEntry>& subsamples) { |
| 160 std::stringstream ss; | 194 std::stringstream ss; |
| 161 | 195 |
| 162 H264Parser parser; | 196 H264Parser parser; |
| 163 parser.SetEncryptedStream(&buffer[0], buffer.size(), subsamples); | 197 parser.SetEncryptedStream(&buffer[0], buffer.size(), subsamples); |
| 164 | 198 |
| 165 H264NALU nalu; | 199 H264NALU nalu; |
| 166 bool first = true; | 200 bool first = true; |
| 201 size_t current_subsample_index = 0; |
| 167 while (parser.AdvanceToNextNALU(&nalu) == H264Parser::kOk) { | 202 while (parser.AdvanceToNextNALU(&nalu) == H264Parser::kOk) { |
| 168 if (!first) | 203 size_t subsample_index = FindSubsampleIndex(buffer, &subsamples, nalu.data); |
| 169 ss << " "; | 204 if (!first) { |
| 170 else | 205 ss << (subsample_index == current_subsample_index ? "," : " "); |
| 206 } else { |
| 207 DCHECK_EQ(subsample_index, current_subsample_index); |
| 171 first = false; | 208 first = false; |
| 209 } |
| 172 | 210 |
| 173 ss << NALUTypeToString(nalu.nal_unit_type); | 211 ss << NALUTypeToString(nalu.nal_unit_type); |
| 212 current_subsample_index = subsample_index; |
| 174 } | 213 } |
| 175 return ss.str(); | 214 return ss.str(); |
| 176 } | 215 } |
| 177 | 216 |
| 178 class AVCConversionTest : public testing::TestWithParam<int> { | 217 class AVCConversionTest : public testing::TestWithParam<int> { |
| 179 protected: | 218 protected: |
| 180 void WriteLength(int length_size, int length, std::vector<uint8>* buf) { | 219 void WriteLength(int length_size, int length, std::vector<uint8>* buf) { |
| 181 DCHECK_GE(length, 0); | 220 DCHECK_GE(length, 0); |
| 182 DCHECK_LE(length, 255); | 221 DCHECK_LE(length, 255); |
| 183 | 222 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 199 }; | 238 }; |
| 200 | 239 |
| 201 TEST_P(AVCConversionTest, ParseCorrectly) { | 240 TEST_P(AVCConversionTest, ParseCorrectly) { |
| 202 std::vector<uint8> buf; | 241 std::vector<uint8> buf; |
| 203 std::vector<SubsampleEntry> subsamples; | 242 std::vector<SubsampleEntry> subsamples; |
| 204 MakeInputForLength(GetParam(), &buf); | 243 MakeInputForLength(GetParam(), &buf); |
| 205 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); | 244 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); |
| 206 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)); | 245 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)); |
| 207 EXPECT_EQ(buf.size(), sizeof(kExpected)); | 246 EXPECT_EQ(buf.size(), sizeof(kExpected)); |
| 208 EXPECT_EQ(0, memcmp(kExpected, &buf[0], sizeof(kExpected))); | 247 EXPECT_EQ(0, memcmp(kExpected, &buf[0], sizeof(kExpected))); |
| 209 EXPECT_EQ("P SDC", AnnexBToString(buf, subsamples)); | 248 EXPECT_EQ("P,SDC", AnnexBToString(buf, subsamples)); |
| 210 } | 249 } |
| 211 | 250 |
| 212 // Intentionally write NALU sizes that are larger than the buffer. | 251 // Intentionally write NALU sizes that are larger than the buffer. |
| 213 TEST_P(AVCConversionTest, NALUSizeTooLarge) { | 252 TEST_P(AVCConversionTest, NALUSizeTooLarge) { |
| 214 std::vector<uint8> buf; | 253 std::vector<uint8> buf; |
| 215 WriteLength(GetParam(), 10 * sizeof(kNALU1), &buf); | 254 WriteLength(GetParam(), 10 * sizeof(kNALU1), &buf); |
| 216 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1)); | 255 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1)); |
| 217 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); | 256 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); |
| 218 } | 257 } |
| 219 | 258 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 "I EOSeq", | 336 "I EOSeq", |
| 298 "I EOSeq EOStr", | 337 "I EOSeq EOStr", |
| 299 "I EOStr", | 338 "I EOStr", |
| 300 "P", | 339 "P", |
| 301 "P P P P", | 340 "P P P P", |
| 302 "AUD SPS PPS P", | 341 "AUD SPS PPS P", |
| 303 "SEI SEI I", | 342 "SEI SEI I", |
| 304 "SEI SEI R14 I", | 343 "SEI SEI R14 I", |
| 305 "SPS SPSExt SPS PPS I P", | 344 "SPS SPSExt SPS PPS I P", |
| 306 "R14 SEI I", | 345 "R14 SEI I", |
| 346 "AUD,I", |
| 347 "AUD,SEI I", |
| 348 "AUD,SEI,SPS,PPS,I" |
| 307 }; | 349 }; |
| 308 | 350 |
| 309 for (size_t i = 0; i < arraysize(test_cases); ++i) { | 351 for (size_t i = 0; i < arraysize(test_cases); ++i) { |
| 310 std::vector<uint8> buf; | 352 std::vector<uint8> buf; |
| 311 std::vector<SubsampleEntry> subsamples; | 353 std::vector<SubsampleEntry> subsamples; |
| 312 StringToAnnexB(test_cases[i], &buf, NULL); | 354 StringToAnnexB(test_cases[i], &buf, NULL); |
| 313 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)) << "'" << test_cases[i] | 355 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)) << "'" << test_cases[i] |
| 314 << "' failed"; | 356 << "' failed"; |
| 315 } | 357 } |
| 316 } | 358 } |
| 317 | 359 |
| 318 TEST_F(AVCConversionTest, InvalidAnnexBConstructs) { | 360 TEST_F(AVCConversionTest, InvalidAnnexBConstructs) { |
| 319 static const char* test_cases[] = { | 361 static const char* test_cases[] = { |
| 320 "AUD", // No VCL present. | 362 "AUD", // No VCL present. |
| 363 "AUD,SEI", // No VCL present. |
| 321 "SPS PPS", // No VCL present. | 364 "SPS PPS", // No VCL present. |
| 322 "SPS PPS AUD I", // Parameter sets must come after AUD. | 365 "SPS PPS AUD I", // Parameter sets must come after AUD. |
| 323 "SPSExt SPS P", // SPS must come before SPSExt. | 366 "SPSExt SPS P", // SPS must come before SPSExt. |
| 324 "SPS PPS SPSExt P", // SPSExt must follow an SPS. | 367 "SPS PPS SPSExt P", // SPSExt must follow an SPS. |
| 325 "EOSeq", // EOSeq must come after a VCL. | 368 "EOSeq", // EOSeq must come after a VCL. |
| 326 "EOStr", // EOStr must come after a VCL. | 369 "EOStr", // EOStr must come after a VCL. |
| 327 "I EOStr EOSeq", // EOSeq must come before EOStr. | 370 "I EOStr EOSeq", // EOSeq must come before EOStr. |
| 328 "I R14", // Reserved14-18 must come before first VCL. | 371 "I R14", // Reserved14-18 must come before first VCL. |
| 329 "I SEI", // SEI must come before first VCL. | 372 "I SEI", // SEI must come before first VCL. |
| 330 "P SPS P", // SPS after first VCL would indicate a new access unit. | 373 "P SPS P", // SPS after first VCL would indicate a new access unit. |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 << "'" << test_cases[i].input << "' insert failed."; | 420 << "'" << test_cases[i].input << "' insert failed."; |
| 378 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)) | 421 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)) |
| 379 << "'" << test_cases[i].input << "' created invalid AnnexB."; | 422 << "'" << test_cases[i].input << "' created invalid AnnexB."; |
| 380 EXPECT_EQ(test_cases[i].expected, AnnexBToString(buf, subsamples)) | 423 EXPECT_EQ(test_cases[i].expected, AnnexBToString(buf, subsamples)) |
| 381 << "'" << test_cases[i].input << "' generated unexpected output."; | 424 << "'" << test_cases[i].input << "' generated unexpected output."; |
| 382 } | 425 } |
| 383 } | 426 } |
| 384 | 427 |
| 385 } // namespace mp4 | 428 } // namespace mp4 |
| 386 } // namespace media | 429 } // namespace media |
| OLD | NEW |