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

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: Address CR comment Created 6 years, 4 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
« no previous file with comments | « media/formats/mp4/avc.cc ('k') | media/formats/mp4/mp4_stream_parser.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 }
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
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
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
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
OLDNEW
« no previous file with comments | « media/formats/mp4/avc.cc ('k') | media/formats/mp4/mp4_stream_parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698