Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(91)

Side by Side Diff: media/formats/mp4/avc_unittest.cc

Issue 379983002: Fix AnnexB validation logic to work with encrypted content. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698