Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / formats / mp4 / avc_unittest.cc
blob19f10f3a602c1b7b9b4be5e5ec122dc8188633c3
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
3 // found in the LICENSE file.
5 #include <string.h>
7 #include "base/basictypes.h"
8 #include "base/strings/string_split.h"
9 #include "base/strings/string_util.h"
10 #include "media/base/decrypt_config.h"
11 #include "media/base/stream_parser_buffer.h"
12 #include "media/filters/h264_parser.h"
13 #include "media/formats/mp4/avc.h"
14 #include "media/formats/mp4/box_definitions.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 namespace media {
18 namespace mp4 {
20 static const uint8 kNALU1[] = { 0x01, 0x02, 0x03 };
21 static const uint8 kNALU2[] = { 0x04, 0x05, 0x06, 0x07 };
22 static const uint8 kExpected[] = {
23 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03,
24 0x00, 0x00, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07 };
26 static const uint8 kExpectedParamSets[] = {
27 0x00, 0x00, 0x00, 0x01, 0x67, 0x12,
28 0x00, 0x00, 0x00, 0x01, 0x67, 0x34,
29 0x00, 0x00, 0x00, 0x01, 0x68, 0x56, 0x78};
31 static H264NALU::Type StringToNALUType(const std::string& name) {
32 if (name == "P")
33 return H264NALU::kNonIDRSlice;
35 if (name == "I")
36 return H264NALU::kIDRSlice;
38 if (name == "SEI")
39 return H264NALU::kSEIMessage;
41 if (name == "SPS")
42 return H264NALU::kSPS;
44 if (name == "SPSExt")
45 return H264NALU::kSPSExt;
47 if (name == "PPS")
48 return H264NALU::kPPS;
50 if (name == "AUD")
51 return H264NALU::kAUD;
53 if (name == "EOSeq")
54 return H264NALU::kEOSeq;
56 if (name == "EOStr")
57 return H264NALU::kEOStream;
59 if (name == "FILL")
60 return H264NALU::kFiller;
62 if (name == "R14")
63 return H264NALU::kReserved14;
65 CHECK(false) << "Unexpected name: " << name;
66 return H264NALU::kUnspecified;
69 static std::string NALUTypeToString(int type) {
70 switch (type) {
71 case H264NALU::kNonIDRSlice:
72 return "P";
73 case H264NALU::kSliceDataA:
74 return "SDA";
75 case H264NALU::kSliceDataB:
76 return "SDB";
77 case H264NALU::kSliceDataC:
78 return "SDC";
79 case H264NALU::kIDRSlice:
80 return "I";
81 case H264NALU::kSEIMessage:
82 return "SEI";
83 case H264NALU::kSPS:
84 return "SPS";
85 case H264NALU::kSPSExt:
86 return "SPSExt";
87 case H264NALU::kPPS:
88 return "PPS";
89 case H264NALU::kAUD:
90 return "AUD";
91 case H264NALU::kEOSeq:
92 return "EOSeq";
93 case H264NALU::kEOStream:
94 return "EOStr";
95 case H264NALU::kFiller:
96 return "FILL";
97 case H264NALU::kReserved14:
98 return "R14";
100 case H264NALU::kUnspecified:
101 case H264NALU::kReserved15:
102 case H264NALU::kReserved16:
103 case H264NALU::kReserved17:
104 case H264NALU::kReserved18:
105 case H264NALU::kCodedSliceAux:
106 case H264NALU::kCodedSliceExtension:
107 CHECK(false) << "Unexpected type: " << type;
108 break;
111 return "UnsupportedType";
114 static void WriteStartCodeAndNALUType(std::vector<uint8>* buffer,
115 const std::string& nal_unit_type) {
116 buffer->push_back(0x00);
117 buffer->push_back(0x00);
118 buffer->push_back(0x00);
119 buffer->push_back(0x01);
120 buffer->push_back(StringToNALUType(nal_unit_type));
123 // Input string should be one or more NALU types separated with spaces or
124 // commas. NALU grouped together and separated by commas are placed into the
125 // same subsample, NALU groups separated by spaces are placed into separate
126 // subsamples.
127 // For example: input string "SPS PPS I" produces Annex B buffer containing
128 // SPS, PPS and I NALUs, each in a separate subsample. While input string
129 // "SPS,PPS I" produces Annex B buffer where the first subsample contains SPS
130 // and PPS NALUs and the second subsample contains the I-slice NALU.
131 // The output buffer will contain a valid-looking Annex B (it's valid-looking in
132 // the sense that it has start codes and correct NALU types, but the actual NALU
133 // payload is junk).
134 void StringToAnnexB(const std::string& str, std::vector<uint8>* buffer,
135 std::vector<SubsampleEntry>* subsamples) {
136 DCHECK(!str.empty());
138 std::vector<std::string> subsample_specs = base::SplitString(
139 str, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
140 EXPECT_GT(subsample_specs.size(), 0u);
142 buffer->clear();
143 for (size_t i = 0; i < subsample_specs.size(); ++i) {
144 SubsampleEntry entry;
145 size_t start = buffer->size();
147 std::vector<std::string> subsample_nalus = base::SplitString(
148 subsample_specs[i], ",", base::KEEP_WHITESPACE,
149 base::SPLIT_WANT_NONEMPTY);
150 EXPECT_GT(subsample_nalus.size(), 0u);
151 for (size_t j = 0; j < subsample_nalus.size(); ++j) {
152 WriteStartCodeAndNALUType(buffer, subsample_nalus[j]);
154 // Write junk for the payload since the current code doesn't
155 // actually look at it.
156 buffer->push_back(0x32);
157 buffer->push_back(0x12);
158 buffer->push_back(0x67);
161 entry.clear_bytes = buffer->size() - start;
163 if (subsamples) {
164 // Simulate the encrypted bits containing something that looks
165 // like a SPS NALU.
166 WriteStartCodeAndNALUType(buffer, "SPS");
169 entry.cypher_bytes = buffer->size() - start - entry.clear_bytes;
171 if (subsamples) {
172 subsamples->push_back(entry);
177 std::string AnnexBToString(const std::vector<uint8>& buffer,
178 const std::vector<SubsampleEntry>& subsamples) {
179 std::stringstream ss;
181 H264Parser parser;
182 parser.SetEncryptedStream(&buffer[0], buffer.size(), subsamples);
184 H264NALU nalu;
185 bool first = true;
186 size_t current_subsample_index = 0;
187 while (parser.AdvanceToNextNALU(&nalu) == H264Parser::kOk) {
188 size_t subsample_index = AVC::FindSubsampleIndex(buffer, &subsamples,
189 nalu.data);
190 if (!first) {
191 ss << (subsample_index == current_subsample_index ? "," : " ");
192 } else {
193 DCHECK_EQ(subsample_index, current_subsample_index);
194 first = false;
197 ss << NALUTypeToString(nalu.nal_unit_type);
198 current_subsample_index = subsample_index;
200 return ss.str();
203 class AVCConversionTest : public testing::TestWithParam<int> {
204 protected:
205 void WriteLength(int length_size, int length, std::vector<uint8>* buf) {
206 DCHECK_GE(length, 0);
207 DCHECK_LE(length, 255);
209 for (int i = 1; i < length_size; i++)
210 buf->push_back(0);
211 buf->push_back(length);
214 void MakeInputForLength(int length_size, std::vector<uint8>* buf) {
215 buf->clear();
217 WriteLength(length_size, sizeof(kNALU1), buf);
218 buf->insert(buf->end(), kNALU1, kNALU1 + sizeof(kNALU1));
220 WriteLength(length_size, sizeof(kNALU2), buf);
221 buf->insert(buf->end(), kNALU2, kNALU2 + sizeof(kNALU2));
226 TEST_P(AVCConversionTest, ParseCorrectly) {
227 std::vector<uint8> buf;
228 std::vector<SubsampleEntry> subsamples;
229 MakeInputForLength(GetParam(), &buf);
230 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf, &subsamples));
231 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples));
232 EXPECT_EQ(buf.size(), sizeof(kExpected));
233 EXPECT_EQ(0, memcmp(kExpected, &buf[0], sizeof(kExpected)));
234 EXPECT_EQ("P,SDC", AnnexBToString(buf, subsamples));
237 // Intentionally write NALU sizes that are larger than the buffer.
238 TEST_P(AVCConversionTest, NALUSizeTooLarge) {
239 std::vector<uint8> buf;
240 WriteLength(GetParam(), 10 * sizeof(kNALU1), &buf);
241 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1));
242 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf, nullptr));
245 TEST_P(AVCConversionTest, NALUSizeIsZero) {
246 std::vector<uint8> buf;
247 WriteLength(GetParam(), 0, &buf);
249 WriteLength(GetParam(), sizeof(kNALU1), &buf);
250 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1));
252 WriteLength(GetParam(), 0, &buf);
254 WriteLength(GetParam(), sizeof(kNALU2), &buf);
255 buf.insert(buf.end(), kNALU2, kNALU2 + sizeof(kNALU2));
257 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf, nullptr));
260 TEST_P(AVCConversionTest, SubsampleSizesUpdatedAfterAnnexBConversion) {
261 std::vector<uint8> buf;
262 std::vector<SubsampleEntry> subsamples;
263 SubsampleEntry subsample;
265 // Write the first subsample, consisting of only one NALU
266 WriteLength(GetParam(), sizeof(kNALU1), &buf);
267 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1));
269 subsample.clear_bytes = GetParam() + sizeof(kNALU1);
270 subsample.cypher_bytes = 0;
271 subsamples.push_back(subsample);
273 // Write the second subsample, containing two NALUs
274 WriteLength(GetParam(), sizeof(kNALU1), &buf);
275 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1));
276 WriteLength(GetParam(), sizeof(kNALU2), &buf);
277 buf.insert(buf.end(), kNALU2, kNALU2 + sizeof(kNALU2));
279 subsample.clear_bytes = 2*GetParam() + sizeof(kNALU1) + sizeof(kNALU2);
280 subsample.cypher_bytes = 0;
281 subsamples.push_back(subsample);
283 // Write the third subsample, containing a single one-byte NALU
284 WriteLength(GetParam(), 1, &buf);
285 buf.push_back(0);
286 subsample.clear_bytes = GetParam() + 1;
287 subsample.cypher_bytes = 0;
288 subsamples.push_back(subsample);
290 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf, &subsamples));
291 EXPECT_EQ(subsamples.size(), 3u);
292 EXPECT_EQ(subsamples[0].clear_bytes, 4 + sizeof(kNALU1));
293 EXPECT_EQ(subsamples[0].cypher_bytes, 0u);
294 EXPECT_EQ(subsamples[1].clear_bytes, 8 + sizeof(kNALU1) + sizeof(kNALU2));
295 EXPECT_EQ(subsamples[1].cypher_bytes, 0u);
296 EXPECT_EQ(subsamples[2].clear_bytes, 4 + 1u);
297 EXPECT_EQ(subsamples[2].cypher_bytes, 0u);
300 TEST_P(AVCConversionTest, ParsePartial) {
301 std::vector<uint8> buf;
302 MakeInputForLength(GetParam(), &buf);
303 buf.pop_back();
304 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf, nullptr));
305 // This tests a buffer ending in the middle of a NAL length. For length size
306 // of one, this can't happen, so we skip that case.
307 if (GetParam() != 1) {
308 MakeInputForLength(GetParam(), &buf);
309 buf.erase(buf.end() - (sizeof(kNALU2) + 1), buf.end());
310 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf, nullptr));
314 TEST_P(AVCConversionTest, ParseEmpty) {
315 std::vector<uint8> buf;
316 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf, nullptr));
317 EXPECT_EQ(0u, buf.size());
320 INSTANTIATE_TEST_CASE_P(AVCConversionTestValues,
321 AVCConversionTest,
322 ::testing::Values(1, 2, 4));
324 TEST_F(AVCConversionTest, ConvertConfigToAnnexB) {
325 AVCDecoderConfigurationRecord avc_config;
326 avc_config.sps_list.resize(2);
327 avc_config.sps_list[0].push_back(0x67);
328 avc_config.sps_list[0].push_back(0x12);
329 avc_config.sps_list[1].push_back(0x67);
330 avc_config.sps_list[1].push_back(0x34);
331 avc_config.pps_list.resize(1);
332 avc_config.pps_list[0].push_back(0x68);
333 avc_config.pps_list[0].push_back(0x56);
334 avc_config.pps_list[0].push_back(0x78);
336 std::vector<uint8> buf;
337 std::vector<SubsampleEntry> subsamples;
338 EXPECT_TRUE(AVC::ConvertConfigToAnnexB(avc_config, &buf));
339 EXPECT_EQ(0, memcmp(kExpectedParamSets, &buf[0],
340 sizeof(kExpectedParamSets)));
341 EXPECT_EQ("SPS,SPS,PPS", AnnexBToString(buf, subsamples));
344 // Verify that we can round trip string -> Annex B -> string.
345 TEST_F(AVCConversionTest, StringConversionFunctions) {
346 std::string str =
347 "AUD SPS SPSExt SPS PPS SEI SEI R14 I P FILL EOSeq EOStr";
348 std::vector<uint8> buf;
349 std::vector<SubsampleEntry> subsamples;
350 StringToAnnexB(str, &buf, &subsamples);
351 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples));
353 EXPECT_EQ(str, AnnexBToString(buf, subsamples));
356 TEST_F(AVCConversionTest, ValidAnnexBConstructs) {
357 const char* test_cases[] = {
358 "I",
359 "I I I I",
360 "AUD I",
361 "AUD SPS PPS I",
362 "I EOSeq",
363 "I EOSeq EOStr",
364 "I EOStr",
365 "P",
366 "P P P P",
367 "AUD SPS PPS P",
368 "SEI SEI I",
369 "SEI SEI R14 I",
370 "SPS SPSExt SPS PPS I P",
371 "R14 SEI I",
372 "AUD,I",
373 "AUD,SEI I",
374 "AUD,SEI,SPS,PPS,I"
377 for (size_t i = 0; i < arraysize(test_cases); ++i) {
378 std::vector<uint8> buf;
379 std::vector<SubsampleEntry> subsamples;
380 StringToAnnexB(test_cases[i], &buf, NULL);
381 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)) << "'" << test_cases[i]
382 << "' failed";
386 TEST_F(AVCConversionTest, InvalidAnnexBConstructs) {
387 static const char* test_cases[] = {
388 "AUD", // No VCL present.
389 "AUD,SEI", // No VCL present.
390 "SPS PPS", // No VCL present.
391 "SPS PPS AUD I", // Parameter sets must come after AUD.
392 "SPSExt SPS P", // SPS must come before SPSExt.
393 "SPS PPS SPSExt P", // SPSExt must follow an SPS.
394 "EOSeq", // EOSeq must come after a VCL.
395 "EOStr", // EOStr must come after a VCL.
396 "I EOStr EOSeq", // EOSeq must come before EOStr.
397 "I R14", // Reserved14-18 must come before first VCL.
398 "I SEI", // SEI must come before first VCL.
399 "P SPS P", // SPS after first VCL would indicate a new access unit.
402 for (size_t i = 0; i < arraysize(test_cases); ++i) {
403 std::vector<uint8> buf;
404 std::vector<SubsampleEntry> subsamples;
405 StringToAnnexB(test_cases[i], &buf, NULL);
406 EXPECT_FALSE(AVC::IsValidAnnexB(buf, subsamples)) << "'" << test_cases[i]
407 << "' failed";
411 typedef struct {
412 const char* input;
413 const char* expected;
414 } InsertTestCases;
416 TEST_F(AVCConversionTest, InsertParamSetsAnnexB) {
417 static const InsertTestCases test_cases[] = {
418 { "I", "SPS,SPS,PPS,I" },
419 { "AUD I", "AUD SPS,SPS,PPS,I" },
421 // Cases where param sets in |avc_config| are placed before
422 // the existing ones.
423 { "SPS,PPS,I", "SPS,SPS,PPS,SPS,PPS,I" },
424 { "AUD,SPS,PPS,I", "AUD,SPS,SPS,PPS,SPS,PPS,I" }, // Note: params placed
425 // after AUD.
427 // One or more NALUs might follow AUD in the first subsample, we need to
428 // handle this correctly. Params should be inserted right after AUD.
429 { "AUD,SEI I", "AUD,SPS,SPS,PPS,SEI I" },
432 AVCDecoderConfigurationRecord avc_config;
433 avc_config.sps_list.resize(2);
434 avc_config.sps_list[0].push_back(0x67);
435 avc_config.sps_list[0].push_back(0x12);
436 avc_config.sps_list[1].push_back(0x67);
437 avc_config.sps_list[1].push_back(0x34);
438 avc_config.pps_list.resize(1);
439 avc_config.pps_list[0].push_back(0x68);
440 avc_config.pps_list[0].push_back(0x56);
441 avc_config.pps_list[0].push_back(0x78);
443 for (size_t i = 0; i < arraysize(test_cases); ++i) {
444 std::vector<uint8> buf;
445 std::vector<SubsampleEntry> subsamples;
447 StringToAnnexB(test_cases[i].input, &buf, &subsamples);
449 EXPECT_TRUE(AVC::InsertParamSetsAnnexB(avc_config, &buf, &subsamples))
450 << "'" << test_cases[i].input << "' insert failed.";
451 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples))
452 << "'" << test_cases[i].input << "' created invalid AnnexB.";
453 EXPECT_EQ(test_cases[i].expected, AnnexBToString(buf, subsamples))
454 << "'" << test_cases[i].input << "' generated unexpected output.";
458 } // namespace mp4
459 } // namespace media