| 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 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 case H264NALU::kReserved18: | 103 case H264NALU::kReserved18: |
| 104 case H264NALU::kCodedSliceAux: | 104 case H264NALU::kCodedSliceAux: |
| 105 case H264NALU::kCodedSliceExtension: | 105 case H264NALU::kCodedSliceExtension: |
| 106 CHECK(false) << "Unexpected type: " << type; | 106 CHECK(false) << "Unexpected type: " << type; |
| 107 break; | 107 break; |
| 108 }; | 108 }; |
| 109 | 109 |
| 110 return "UnsupportedType"; | 110 return "UnsupportedType"; |
| 111 } | 111 } |
| 112 | 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 |
| 113 void StringToAnnexB(const std::string& str, std::vector<uint8>* buffer, | 122 void StringToAnnexB(const std::string& str, std::vector<uint8>* buffer, |
| 114 std::vector<SubsampleEntry>* subsamples) { | 123 std::vector<SubsampleEntry>* subsamples) { |
| 115 DCHECK(!str.empty()); | 124 DCHECK(!str.empty()); |
| 116 | 125 |
| 117 std::vector<std::string> tokens; | 126 std::vector<std::string> tokens; |
| 118 EXPECT_GT(Tokenize(str, " ", &tokens), 0u); | 127 EXPECT_GT(Tokenize(str, " ", &tokens), 0u); |
| 119 | 128 |
| 120 buffer->clear(); | 129 buffer->clear(); |
| 121 for (size_t i = 0; i < tokens.size(); ++i) { | 130 for (size_t i = 0; i < tokens.size(); ++i) { |
| 122 SubsampleEntry entry; | 131 SubsampleEntry entry; |
| 123 size_t start = buffer->size(); | 132 size_t start = buffer->size(); |
| 124 | 133 |
| 125 // Write the start code. | 134 WriteStartCodeAndNALUType(buffer, tokens[i]); |
| 126 buffer->push_back(0x00); | |
| 127 buffer->push_back(0x00); | |
| 128 buffer->push_back(0x00); | |
| 129 buffer->push_back(0x01); | |
| 130 | |
| 131 // Write NALU type. | |
| 132 buffer->push_back(StringToNALUType(tokens[i])); | |
| 133 | 135 |
| 134 entry.clear_bytes = buffer->size() - start; | 136 entry.clear_bytes = buffer->size() - start; |
| 135 | 137 |
| 136 // Write junk for the payload since the current code doesn't | 138 // Write junk for the payload since the current code doesn't |
| 137 // actually look at it. | 139 // actually look at it. |
| 138 buffer->push_back(0x32); | 140 buffer->push_back(0x32); |
| 139 buffer->push_back(0x12); | 141 buffer->push_back(0x12); |
| 140 buffer->push_back(0x67); | 142 buffer->push_back(0x67); |
| 141 | 143 |
| 144 if (subsamples) { |
| 145 // Simulate the encrypted bits containing something that looks |
| 146 // like a SPS NALU. |
| 147 WriteStartCodeAndNALUType(buffer, "SPS"); |
| 148 } |
| 149 |
| 142 entry.cypher_bytes = buffer->size() - start - entry.clear_bytes; | 150 entry.cypher_bytes = buffer->size() - start - entry.clear_bytes; |
| 143 | 151 |
| 144 if (subsamples) { | 152 if (subsamples) { |
| 145 subsamples->push_back(entry); | 153 subsamples->push_back(entry); |
| 146 } | 154 } |
| 147 } | 155 } |
| 148 } | 156 } |
| 149 | 157 |
| 150 std::string AnnexBToString(const std::vector<uint8>& buffer) { | 158 std::string AnnexBToString(const std::vector<uint8>& buffer, |
| 159 const std::vector<SubsampleEntry>& subsamples) { |
| 151 std::stringstream ss; | 160 std::stringstream ss; |
| 152 | 161 |
| 153 H264Parser parser; | 162 H264Parser parser; |
| 154 parser.SetStream(&buffer[0], buffer.size()); | 163 parser.SetEncryptedStream(&buffer[0], buffer.size(), subsamples); |
| 155 | 164 |
| 156 H264NALU nalu; | 165 H264NALU nalu; |
| 157 bool first = true; | 166 bool first = true; |
| 158 while (parser.AdvanceToNextNALU(&nalu) == H264Parser::kOk) { | 167 while (parser.AdvanceToNextNALU(&nalu) == H264Parser::kOk) { |
| 159 if (!first) | 168 if (!first) |
| 160 ss << " "; | 169 ss << " "; |
| 161 else | 170 else |
| 162 first = false; | 171 first = false; |
| 163 | 172 |
| 164 ss << NALUTypeToString(nalu.nal_unit_type); | 173 ss << NALUTypeToString(nalu.nal_unit_type); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 184 buf->insert(buf->end(), kNALU1, kNALU1 + sizeof(kNALU1)); | 193 buf->insert(buf->end(), kNALU1, kNALU1 + sizeof(kNALU1)); |
| 185 | 194 |
| 186 WriteLength(length_size, sizeof(kNALU2), buf); | 195 WriteLength(length_size, sizeof(kNALU2), buf); |
| 187 buf->insert(buf->end(), kNALU2, kNALU2 + sizeof(kNALU2)); | 196 buf->insert(buf->end(), kNALU2, kNALU2 + sizeof(kNALU2)); |
| 188 } | 197 } |
| 189 | 198 |
| 190 }; | 199 }; |
| 191 | 200 |
| 192 TEST_P(AVCConversionTest, ParseCorrectly) { | 201 TEST_P(AVCConversionTest, ParseCorrectly) { |
| 193 std::vector<uint8> buf; | 202 std::vector<uint8> buf; |
| 203 std::vector<SubsampleEntry> subsamples; |
| 194 MakeInputForLength(GetParam(), &buf); | 204 MakeInputForLength(GetParam(), &buf); |
| 195 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); | 205 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); |
| 196 EXPECT_TRUE(AVC::IsValidAnnexB(buf)); | 206 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)); |
| 197 EXPECT_EQ(buf.size(), sizeof(kExpected)); | 207 EXPECT_EQ(buf.size(), sizeof(kExpected)); |
| 198 EXPECT_EQ(0, memcmp(kExpected, &buf[0], sizeof(kExpected))); | 208 EXPECT_EQ(0, memcmp(kExpected, &buf[0], sizeof(kExpected))); |
| 199 EXPECT_EQ("P SDC", AnnexBToString(buf)); | 209 EXPECT_EQ("P SDC", AnnexBToString(buf, subsamples)); |
| 200 } | 210 } |
| 201 | 211 |
| 202 // Intentionally write NALU sizes that are larger than the buffer. | 212 // Intentionally write NALU sizes that are larger than the buffer. |
| 203 TEST_P(AVCConversionTest, NALUSizeTooLarge) { | 213 TEST_P(AVCConversionTest, NALUSizeTooLarge) { |
| 204 std::vector<uint8> buf; | 214 std::vector<uint8> buf; |
| 205 WriteLength(GetParam(), 10 * sizeof(kNALU1), &buf); | 215 WriteLength(GetParam(), 10 * sizeof(kNALU1), &buf); |
| 206 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1)); | 216 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1)); |
| 207 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); | 217 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); |
| 208 } | 218 } |
| 209 | 219 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 avc_config.pps_list.resize(1); | 266 avc_config.pps_list.resize(1); |
| 257 avc_config.pps_list[0].push_back(0x68); | 267 avc_config.pps_list[0].push_back(0x68); |
| 258 avc_config.pps_list[0].push_back(0x56); | 268 avc_config.pps_list[0].push_back(0x56); |
| 259 avc_config.pps_list[0].push_back(0x78); | 269 avc_config.pps_list[0].push_back(0x78); |
| 260 | 270 |
| 261 std::vector<uint8> buf; | 271 std::vector<uint8> buf; |
| 262 std::vector<SubsampleEntry> subsamples; | 272 std::vector<SubsampleEntry> subsamples; |
| 263 EXPECT_TRUE(AVC::ConvertConfigToAnnexB(avc_config, &buf, &subsamples)); | 273 EXPECT_TRUE(AVC::ConvertConfigToAnnexB(avc_config, &buf, &subsamples)); |
| 264 EXPECT_EQ(0, memcmp(kExpectedParamSets, &buf[0], | 274 EXPECT_EQ(0, memcmp(kExpectedParamSets, &buf[0], |
| 265 sizeof(kExpectedParamSets))); | 275 sizeof(kExpectedParamSets))); |
| 266 EXPECT_EQ("SPS SPS PPS", AnnexBToString(buf)); | 276 EXPECT_EQ("SPS SPS PPS", AnnexBToString(buf, subsamples)); |
| 267 } | 277 } |
| 268 | 278 |
| 269 // Verify that we can round trip string -> Annex B -> string. | 279 // Verify that we can round trip string -> Annex B -> string. |
| 270 TEST_F(AVCConversionTest, StringConversionFunctions) { | 280 TEST_F(AVCConversionTest, StringConversionFunctions) { |
| 271 std::string str = | 281 std::string str = |
| 272 "AUD SPS SPSExt SPS PPS SEI SEI R14 I P FILL EOSeq EOStr"; | 282 "AUD SPS SPSExt SPS PPS SEI SEI R14 I P FILL EOSeq EOStr"; |
| 273 std::vector<uint8> buf; | 283 std::vector<uint8> buf; |
| 274 StringToAnnexB(str, &buf, NULL); | 284 std::vector<SubsampleEntry> subsamples; |
| 285 StringToAnnexB(str, &buf, &subsamples); |
| 286 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)); |
| 275 | 287 |
| 276 EXPECT_TRUE(AVC::IsValidAnnexB(buf)); | 288 EXPECT_EQ(str, AnnexBToString(buf, subsamples)); |
| 277 | |
| 278 EXPECT_EQ(str, AnnexBToString(buf)); | |
| 279 } | 289 } |
| 280 | 290 |
| 281 TEST_F(AVCConversionTest, ValidAnnexBConstructs) { | 291 TEST_F(AVCConversionTest, ValidAnnexBConstructs) { |
| 282 const char* test_cases[] = { | 292 const char* test_cases[] = { |
| 283 "I", | 293 "I", |
| 284 "I I I I", | 294 "I I I I", |
| 285 "AUD I", | 295 "AUD I", |
| 286 "AUD SPS PPS I", | 296 "AUD SPS PPS I", |
| 287 "I EOSeq", | 297 "I EOSeq", |
| 288 "I EOSeq EOStr", | 298 "I EOSeq EOStr", |
| 289 "I EOStr", | 299 "I EOStr", |
| 290 "P", | 300 "P", |
| 291 "P P P P", | 301 "P P P P", |
| 292 "AUD SPS PPS P", | 302 "AUD SPS PPS P", |
| 293 "SEI SEI I", | 303 "SEI SEI I", |
| 294 "SEI SEI R14 I", | 304 "SEI SEI R14 I", |
| 295 "SPS SPSExt SPS PPS I P", | 305 "SPS SPSExt SPS PPS I P", |
| 296 "R14 SEI I", | 306 "R14 SEI I", |
| 297 }; | 307 }; |
| 298 | 308 |
| 299 for (size_t i = 0; i < arraysize(test_cases); ++i) { | 309 for (size_t i = 0; i < arraysize(test_cases); ++i) { |
| 300 std::vector<uint8> buf; | 310 std::vector<uint8> buf; |
| 311 std::vector<SubsampleEntry> subsamples; |
| 301 StringToAnnexB(test_cases[i], &buf, NULL); | 312 StringToAnnexB(test_cases[i], &buf, NULL); |
| 302 EXPECT_TRUE(AVC::IsValidAnnexB(buf)) << "'" << test_cases[i] << "' failed"; | 313 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)) << "'" << test_cases[i] |
| 314 << "' failed"; |
| 303 } | 315 } |
| 304 } | 316 } |
| 305 | 317 |
| 306 TEST_F(AVCConversionTest, InvalidAnnexBConstructs) { | 318 TEST_F(AVCConversionTest, InvalidAnnexBConstructs) { |
| 307 static const char* test_cases[] = { | 319 static const char* test_cases[] = { |
| 308 "AUD", // No VCL present. | 320 "AUD", // No VCL present. |
| 309 "SPS PPS", // No VCL present. | 321 "SPS PPS", // No VCL present. |
| 310 "SPS PPS AUD I", // Parameter sets must come after AUD. | 322 "SPS PPS AUD I", // Parameter sets must come after AUD. |
| 311 "SPSExt SPS P", // SPS must come before SPSExt. | 323 "SPSExt SPS P", // SPS must come before SPSExt. |
| 312 "SPS PPS SPSExt P", // SPSExt must follow an SPS. | 324 "SPS PPS SPSExt P", // SPSExt must follow an SPS. |
| 313 "EOSeq", // EOSeq must come after a VCL. | 325 "EOSeq", // EOSeq must come after a VCL. |
| 314 "EOStr", // EOStr must come after a VCL. | 326 "EOStr", // EOStr must come after a VCL. |
| 315 "I EOStr EOSeq", // EOSeq must come before EOStr. | 327 "I EOStr EOSeq", // EOSeq must come before EOStr. |
| 316 "I R14", // Reserved14-18 must come before first VCL. | 328 "I R14", // Reserved14-18 must come before first VCL. |
| 317 "I SEI", // SEI must come before first VCL. | 329 "I SEI", // SEI must come before first VCL. |
| 318 "P SPS P", // SPS after first VCL would indicate a new access unit. | 330 "P SPS P", // SPS after first VCL would indicate a new access unit. |
| 319 }; | 331 }; |
| 320 | 332 |
| 321 for (size_t i = 0; i < arraysize(test_cases); ++i) { | 333 for (size_t i = 0; i < arraysize(test_cases); ++i) { |
| 322 std::vector<uint8> buf; | 334 std::vector<uint8> buf; |
| 335 std::vector<SubsampleEntry> subsamples; |
| 323 StringToAnnexB(test_cases[i], &buf, NULL); | 336 StringToAnnexB(test_cases[i], &buf, NULL); |
| 324 EXPECT_FALSE(AVC::IsValidAnnexB(buf)) << "'" << test_cases[i] << "' failed"; | 337 EXPECT_FALSE(AVC::IsValidAnnexB(buf, subsamples)) << "'" << test_cases[i] |
| 338 << "' failed"; |
| 325 } | 339 } |
| 326 } | 340 } |
| 327 | 341 |
| 328 typedef struct { | 342 typedef struct { |
| 329 const char* input; | 343 const char* input; |
| 330 const char* expected; | 344 const char* expected; |
| 331 } InsertTestCases; | 345 } InsertTestCases; |
| 332 | 346 |
| 333 TEST_F(AVCConversionTest, InsertParamSetsAnnexB) { | 347 TEST_F(AVCConversionTest, InsertParamSetsAnnexB) { |
| 334 static const InsertTestCases test_cases[] = { | 348 static const InsertTestCases test_cases[] = { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 354 avc_config.pps_list[0].push_back(0x78); | 368 avc_config.pps_list[0].push_back(0x78); |
| 355 | 369 |
| 356 for (size_t i = 0; i < arraysize(test_cases); ++i) { | 370 for (size_t i = 0; i < arraysize(test_cases); ++i) { |
| 357 std::vector<uint8> buf; | 371 std::vector<uint8> buf; |
| 358 std::vector<SubsampleEntry> subsamples; | 372 std::vector<SubsampleEntry> subsamples; |
| 359 | 373 |
| 360 StringToAnnexB(test_cases[i].input, &buf, &subsamples); | 374 StringToAnnexB(test_cases[i].input, &buf, &subsamples); |
| 361 | 375 |
| 362 EXPECT_TRUE(AVC::InsertParamSetsAnnexB(avc_config, &buf, &subsamples)) | 376 EXPECT_TRUE(AVC::InsertParamSetsAnnexB(avc_config, &buf, &subsamples)) |
| 363 << "'" << test_cases[i].input << "' insert failed."; | 377 << "'" << test_cases[i].input << "' insert failed."; |
| 364 EXPECT_TRUE(AVC::IsValidAnnexB(buf)) | 378 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)) |
| 365 << "'" << test_cases[i].input << "' created invalid AnnexB."; | 379 << "'" << test_cases[i].input << "' created invalid AnnexB."; |
| 366 EXPECT_EQ(test_cases[i].expected, AnnexBToString(buf)) | 380 EXPECT_EQ(test_cases[i].expected, AnnexBToString(buf, subsamples)) |
| 367 << "'" << test_cases[i].input << "' generated unexpected output."; | 381 << "'" << test_cases[i].input << "' generated unexpected output."; |
| 368 } | 382 } |
| 369 } | 383 } |
| 370 | 384 |
| 371 } // namespace mp4 | 385 } // namespace mp4 |
| 372 } // namespace media | 386 } // namespace media |
| OLD | NEW |