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

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

Issue 626193003: Implement extended syntax for AVC/h264 unit tests (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed code review feedback Created 6 years, 2 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 | « no previous file | no next file » | 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 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 112
113 static void WriteStartCodeAndNALUType(std::vector<uint8>* buffer, 113 static void WriteStartCodeAndNALUType(std::vector<uint8>* buffer,
114 const std::string& nal_unit_type) { 114 const std::string& nal_unit_type) {
115 buffer->push_back(0x00); 115 buffer->push_back(0x00);
116 buffer->push_back(0x00); 116 buffer->push_back(0x00);
117 buffer->push_back(0x00); 117 buffer->push_back(0x00);
118 buffer->push_back(0x01); 118 buffer->push_back(0x01);
119 buffer->push_back(StringToNALUType(nal_unit_type)); 119 buffer->push_back(StringToNALUType(nal_unit_type));
120 } 120 }
121 121
122 // Input string should be one or more NALU types separated with spaces or
123 // commas. NALU grouped together and separated by commas are placed into the
124 // same subsample, NALU groups separated by spaces are placed into separate
125 // subsamples.
126 // For example: input string "SPS PPS I" produces Annex B buffer containing
127 // SPS, PPS and I NALUs, each in a separate subsample. While input string
128 // "SPS,PPS I" produces Annex B buffer where the first subsample contains SPS
129 // and PPS NALUs and the second subsample contains the I-slice NALU.
130 // The output buffer will contain a valid-looking Annex B (it's valid-looking in
131 // the sense that it has start codes and correct NALU types, but the actual NALU
132 // payload is junk).
122 void StringToAnnexB(const std::string& str, std::vector<uint8>* buffer, 133 void StringToAnnexB(const std::string& str, std::vector<uint8>* buffer,
123 std::vector<SubsampleEntry>* subsamples) { 134 std::vector<SubsampleEntry>* subsamples) {
124 DCHECK(!str.empty()); 135 DCHECK(!str.empty());
125 136
126 std::vector<std::string> tokens; 137 std::vector<std::string> subsample_specs;
127 EXPECT_GT(Tokenize(str, " ", &tokens), 0u); 138 EXPECT_GT(Tokenize(str, " ", &subsample_specs), 0u);
128 139
129 buffer->clear(); 140 buffer->clear();
130 for (size_t i = 0; i < tokens.size(); ++i) { 141 for (size_t i = 0; i < subsample_specs.size(); ++i) {
131 SubsampleEntry entry; 142 SubsampleEntry entry;
132 size_t start = buffer->size(); 143 size_t start = buffer->size();
133 144
134 WriteStartCodeAndNALUType(buffer, tokens[i]); 145 std::vector<std::string> subsample_nalus;
146 EXPECT_GT(Tokenize(subsample_specs[i], ",", &subsample_nalus), 0u);
147 for (size_t j = 0; j < subsample_nalus.size(); ++j) {
148 WriteStartCodeAndNALUType(buffer, subsample_nalus[j]);
149
150 // Write junk for the payload since the current code doesn't
151 // actually look at it.
152 buffer->push_back(0x32);
153 buffer->push_back(0x12);
154 buffer->push_back(0x67);
155 }
135 156
136 entry.clear_bytes = buffer->size() - start; 157 entry.clear_bytes = buffer->size() - start;
137 158
138 // Write junk for the payload since the current code doesn't
139 // actually look at it.
140 buffer->push_back(0x32);
141 buffer->push_back(0x12);
142 buffer->push_back(0x67);
143
144 if (subsamples) { 159 if (subsamples) {
145 // Simulate the encrypted bits containing something that looks 160 // Simulate the encrypted bits containing something that looks
146 // like a SPS NALU. 161 // like a SPS NALU.
147 WriteStartCodeAndNALUType(buffer, "SPS"); 162 WriteStartCodeAndNALUType(buffer, "SPS");
148 } 163 }
149 164
150 entry.cypher_bytes = buffer->size() - start - entry.clear_bytes; 165 entry.cypher_bytes = buffer->size() - start - entry.clear_bytes;
151 166
152 if (subsamples) { 167 if (subsamples) {
153 subsamples->push_back(entry); 168 subsamples->push_back(entry);
154 } 169 }
155 } 170 }
156 } 171 }
157 172
173 int FindSubsampleIndex(const std::vector<uint8>& buffer,
174 const std::vector<SubsampleEntry>* subsamples,
175 const uint8* ptr) {
176 DCHECK(ptr >= &buffer[0]);
177 DCHECK(ptr <= &buffer[buffer.size()-1]);
178 if (!subsamples || subsamples->empty())
179 return 0;
180
181 const uint8* p = &buffer[0];
182 for (size_t i = 0; i < subsamples->size(); ++i) {
183 p += (*subsamples)[i].clear_bytes + (*subsamples)[i].cypher_bytes;
184 if (p > ptr) {
185 return i;
186 }
187 }
188 NOTREACHED();
189 return 0;
190 }
191
158 std::string AnnexBToString(const std::vector<uint8>& buffer, 192 std::string AnnexBToString(const std::vector<uint8>& buffer,
159 const std::vector<SubsampleEntry>& subsamples) { 193 const std::vector<SubsampleEntry>& subsamples) {
160 std::stringstream ss; 194 std::stringstream ss;
161 195
162 H264Parser parser; 196 H264Parser parser;
163 parser.SetEncryptedStream(&buffer[0], buffer.size(), subsamples); 197 parser.SetEncryptedStream(&buffer[0], buffer.size(), subsamples);
164 198
165 H264NALU nalu; 199 H264NALU nalu;
166 bool first = true; 200 bool first = true;
201 size_t current_subsample_index = 0;
167 while (parser.AdvanceToNextNALU(&nalu) == H264Parser::kOk) { 202 while (parser.AdvanceToNextNALU(&nalu) == H264Parser::kOk) {
168 if (!first) 203 size_t subsample_index = FindSubsampleIndex(buffer, &subsamples, nalu.data);
169 ss << " "; 204 if (!first) {
170 else 205 ss << (subsample_index == current_subsample_index ? "," : " ");
206 } else {
207 DCHECK_EQ(subsample_index, current_subsample_index);
171 first = false; 208 first = false;
209 }
172 210
173 ss << NALUTypeToString(nalu.nal_unit_type); 211 ss << NALUTypeToString(nalu.nal_unit_type);
212 current_subsample_index = subsample_index;
174 } 213 }
175 return ss.str(); 214 return ss.str();
176 } 215 }
177 216
178 class AVCConversionTest : public testing::TestWithParam<int> { 217 class AVCConversionTest : public testing::TestWithParam<int> {
179 protected: 218 protected:
180 void WriteLength(int length_size, int length, std::vector<uint8>* buf) { 219 void WriteLength(int length_size, int length, std::vector<uint8>* buf) {
181 DCHECK_GE(length, 0); 220 DCHECK_GE(length, 0);
182 DCHECK_LE(length, 255); 221 DCHECK_LE(length, 255);
183 222
(...skipping 15 matching lines...) Expand all
199 }; 238 };
200 239
201 TEST_P(AVCConversionTest, ParseCorrectly) { 240 TEST_P(AVCConversionTest, ParseCorrectly) {
202 std::vector<uint8> buf; 241 std::vector<uint8> buf;
203 std::vector<SubsampleEntry> subsamples; 242 std::vector<SubsampleEntry> subsamples;
204 MakeInputForLength(GetParam(), &buf); 243 MakeInputForLength(GetParam(), &buf);
205 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); 244 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
206 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)); 245 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples));
207 EXPECT_EQ(buf.size(), sizeof(kExpected)); 246 EXPECT_EQ(buf.size(), sizeof(kExpected));
208 EXPECT_EQ(0, memcmp(kExpected, &buf[0], sizeof(kExpected))); 247 EXPECT_EQ(0, memcmp(kExpected, &buf[0], sizeof(kExpected)));
209 EXPECT_EQ("P SDC", AnnexBToString(buf, subsamples)); 248 EXPECT_EQ("P,SDC", AnnexBToString(buf, subsamples));
210 } 249 }
211 250
212 // Intentionally write NALU sizes that are larger than the buffer. 251 // Intentionally write NALU sizes that are larger than the buffer.
213 TEST_P(AVCConversionTest, NALUSizeTooLarge) { 252 TEST_P(AVCConversionTest, NALUSizeTooLarge) {
214 std::vector<uint8> buf; 253 std::vector<uint8> buf;
215 WriteLength(GetParam(), 10 * sizeof(kNALU1), &buf); 254 WriteLength(GetParam(), 10 * sizeof(kNALU1), &buf);
216 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1)); 255 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1));
217 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); 256 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
218 } 257 }
219 258
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 "I EOSeq", 336 "I EOSeq",
298 "I EOSeq EOStr", 337 "I EOSeq EOStr",
299 "I EOStr", 338 "I EOStr",
300 "P", 339 "P",
301 "P P P P", 340 "P P P P",
302 "AUD SPS PPS P", 341 "AUD SPS PPS P",
303 "SEI SEI I", 342 "SEI SEI I",
304 "SEI SEI R14 I", 343 "SEI SEI R14 I",
305 "SPS SPSExt SPS PPS I P", 344 "SPS SPSExt SPS PPS I P",
306 "R14 SEI I", 345 "R14 SEI I",
346 "AUD,I",
347 "AUD,SEI I",
348 "AUD,SEI,SPS,PPS,I"
307 }; 349 };
308 350
309 for (size_t i = 0; i < arraysize(test_cases); ++i) { 351 for (size_t i = 0; i < arraysize(test_cases); ++i) {
310 std::vector<uint8> buf; 352 std::vector<uint8> buf;
311 std::vector<SubsampleEntry> subsamples; 353 std::vector<SubsampleEntry> subsamples;
312 StringToAnnexB(test_cases[i], &buf, NULL); 354 StringToAnnexB(test_cases[i], &buf, NULL);
313 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)) << "'" << test_cases[i] 355 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)) << "'" << test_cases[i]
314 << "' failed"; 356 << "' failed";
315 } 357 }
316 } 358 }
317 359
318 TEST_F(AVCConversionTest, InvalidAnnexBConstructs) { 360 TEST_F(AVCConversionTest, InvalidAnnexBConstructs) {
319 static const char* test_cases[] = { 361 static const char* test_cases[] = {
320 "AUD", // No VCL present. 362 "AUD", // No VCL present.
363 "AUD,SEI", // No VCL present.
321 "SPS PPS", // No VCL present. 364 "SPS PPS", // No VCL present.
322 "SPS PPS AUD I", // Parameter sets must come after AUD. 365 "SPS PPS AUD I", // Parameter sets must come after AUD.
323 "SPSExt SPS P", // SPS must come before SPSExt. 366 "SPSExt SPS P", // SPS must come before SPSExt.
324 "SPS PPS SPSExt P", // SPSExt must follow an SPS. 367 "SPS PPS SPSExt P", // SPSExt must follow an SPS.
325 "EOSeq", // EOSeq must come after a VCL. 368 "EOSeq", // EOSeq must come after a VCL.
326 "EOStr", // EOStr must come after a VCL. 369 "EOStr", // EOStr must come after a VCL.
327 "I EOStr EOSeq", // EOSeq must come before EOStr. 370 "I EOStr EOSeq", // EOSeq must come before EOStr.
328 "I R14", // Reserved14-18 must come before first VCL. 371 "I R14", // Reserved14-18 must come before first VCL.
329 "I SEI", // SEI must come before first VCL. 372 "I SEI", // SEI must come before first VCL.
330 "P SPS P", // SPS after first VCL would indicate a new access unit. 373 "P SPS P", // SPS after first VCL would indicate a new access unit.
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 << "'" << test_cases[i].input << "' insert failed."; 420 << "'" << test_cases[i].input << "' insert failed.";
378 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)) 421 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples))
379 << "'" << test_cases[i].input << "' created invalid AnnexB."; 422 << "'" << test_cases[i].input << "' created invalid AnnexB.";
380 EXPECT_EQ(test_cases[i].expected, AnnexBToString(buf, subsamples)) 423 EXPECT_EQ(test_cases[i].expected, AnnexBToString(buf, subsamples))
381 << "'" << test_cases[i].input << "' generated unexpected output."; 424 << "'" << test_cases[i].input << "' generated unexpected output.";
382 } 425 }
383 } 426 }
384 427
385 } // namespace mp4 428 } // namespace mp4
386 } // namespace media 429 } // namespace media
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698