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 |