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