Roll leveldb 3f7758:803d69 (v1.17 -> v1.18)
[chromium-blink-merge.git] / media / formats / mp4 / avc_unittest.cc
blobb0aa976a51564488ba0237b87d45ccbd749900cc
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_util.h"
9 #include "media/base/decrypt_config.h"
10 #include "media/base/stream_parser_buffer.h"
11 #include "media/filters/h264_parser.h"
12 #include "media/formats/mp4/avc.h"
13 #include "media/formats/mp4/box_definitions.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 namespace media {
17 namespace mp4 {
19 static const uint8 kNALU1[] = { 0x01, 0x02, 0x03 };
20 static const uint8 kNALU2[] = { 0x04, 0x05, 0x06, 0x07 };
21 static const uint8 kExpected[] = {
22 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03,
23 0x00, 0x00, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07 };
25 static const uint8 kExpectedParamSets[] = {
26 0x00, 0x00, 0x00, 0x01, 0x67, 0x12,
27 0x00, 0x00, 0x00, 0x01, 0x67, 0x34,
28 0x00, 0x00, 0x00, 0x01, 0x68, 0x56, 0x78};
30 static H264NALU::Type StringToNALUType(const std::string& name) {
31 if (name == "P")
32 return H264NALU::kNonIDRSlice;
34 if (name == "I")
35 return H264NALU::kIDRSlice;
37 if (name == "SEI")
38 return H264NALU::kSEIMessage;
40 if (name == "SPS")
41 return H264NALU::kSPS;
43 if (name == "SPSExt")
44 return H264NALU::kSPSExt;
46 if (name == "PPS")
47 return H264NALU::kPPS;
49 if (name == "AUD")
50 return H264NALU::kAUD;
52 if (name == "EOSeq")
53 return H264NALU::kEOSeq;
55 if (name == "EOStr")
56 return H264NALU::kEOStream;
58 if (name == "FILL")
59 return H264NALU::kFiller;
61 if (name == "R14")
62 return H264NALU::kReserved14;
64 CHECK(false) << "Unexpected name: " << name;
65 return H264NALU::kUnspecified;
68 static std::string NALUTypeToString(int type) {
69 switch (type) {
70 case H264NALU::kNonIDRSlice:
71 return "P";
72 case H264NALU::kSliceDataA:
73 return "SDA";
74 case H264NALU::kSliceDataB:
75 return "SDB";
76 case H264NALU::kSliceDataC:
77 return "SDC";
78 case H264NALU::kIDRSlice:
79 return "I";
80 case H264NALU::kSEIMessage:
81 return "SEI";
82 case H264NALU::kSPS:
83 return "SPS";
84 case H264NALU::kSPSExt:
85 return "SPSExt";
86 case H264NALU::kPPS:
87 return "PPS";
88 case H264NALU::kAUD:
89 return "AUD";
90 case H264NALU::kEOSeq:
91 return "EOSeq";
92 case H264NALU::kEOStream:
93 return "EOStr";
94 case H264NALU::kFiller:
95 return "FILL";
96 case H264NALU::kReserved14:
97 return "R14";
99 case H264NALU::kUnspecified:
100 case H264NALU::kReserved15:
101 case H264NALU::kReserved16:
102 case H264NALU::kReserved17:
103 case H264NALU::kReserved18:
104 case H264NALU::kCodedSliceAux:
105 case H264NALU::kCodedSliceExtension:
106 CHECK(false) << "Unexpected type: " << type;
107 break;
110 return "UnsupportedType";
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));
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).
133 void StringToAnnexB(const std::string& str, std::vector<uint8>* buffer,
134 std::vector<SubsampleEntry>* subsamples) {
135 DCHECK(!str.empty());
137 std::vector<std::string> subsample_specs;
138 EXPECT_GT(Tokenize(str, " ", &subsample_specs), 0u);
140 buffer->clear();
141 for (size_t i = 0; i < subsample_specs.size(); ++i) {
142 SubsampleEntry entry;
143 size_t start = buffer->size();
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]);
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);
157 entry.clear_bytes = buffer->size() - start;
159 if (subsamples) {
160 // Simulate the encrypted bits containing something that looks
161 // like a SPS NALU.
162 WriteStartCodeAndNALUType(buffer, "SPS");
165 entry.cypher_bytes = buffer->size() - start - entry.clear_bytes;
167 if (subsamples) {
168 subsamples->push_back(entry);
173 std::string AnnexBToString(const std::vector<uint8>& buffer,
174 const std::vector<SubsampleEntry>& subsamples) {
175 std::stringstream ss;
177 H264Parser parser;
178 parser.SetEncryptedStream(&buffer[0], buffer.size(), subsamples);
180 H264NALU nalu;
181 bool first = true;
182 size_t current_subsample_index = 0;
183 while (parser.AdvanceToNextNALU(&nalu) == H264Parser::kOk) {
184 size_t subsample_index = AVC::FindSubsampleIndex(buffer, &subsamples,
185 nalu.data);
186 if (!first) {
187 ss << (subsample_index == current_subsample_index ? "," : " ");
188 } else {
189 DCHECK_EQ(subsample_index, current_subsample_index);
190 first = false;
193 ss << NALUTypeToString(nalu.nal_unit_type);
194 current_subsample_index = subsample_index;
196 return ss.str();
199 class AVCConversionTest : public testing::TestWithParam<int> {
200 protected:
201 void WriteLength(int length_size, int length, std::vector<uint8>* buf) {
202 DCHECK_GE(length, 0);
203 DCHECK_LE(length, 255);
205 for (int i = 1; i < length_size; i++)
206 buf->push_back(0);
207 buf->push_back(length);
210 void MakeInputForLength(int length_size, std::vector<uint8>* buf) {
211 buf->clear();
213 WriteLength(length_size, sizeof(kNALU1), buf);
214 buf->insert(buf->end(), kNALU1, kNALU1 + sizeof(kNALU1));
216 WriteLength(length_size, sizeof(kNALU2), buf);
217 buf->insert(buf->end(), kNALU2, kNALU2 + sizeof(kNALU2));
222 TEST_P(AVCConversionTest, ParseCorrectly) {
223 std::vector<uint8> buf;
224 std::vector<SubsampleEntry> subsamples;
225 MakeInputForLength(GetParam(), &buf);
226 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
227 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples));
228 EXPECT_EQ(buf.size(), sizeof(kExpected));
229 EXPECT_EQ(0, memcmp(kExpected, &buf[0], sizeof(kExpected)));
230 EXPECT_EQ("P,SDC", AnnexBToString(buf, subsamples));
233 // Intentionally write NALU sizes that are larger than the buffer.
234 TEST_P(AVCConversionTest, NALUSizeTooLarge) {
235 std::vector<uint8> buf;
236 WriteLength(GetParam(), 10 * sizeof(kNALU1), &buf);
237 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1));
238 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
241 TEST_P(AVCConversionTest, NALUSizeIsZero) {
242 std::vector<uint8> buf;
243 WriteLength(GetParam(), 0, &buf);
245 WriteLength(GetParam(), sizeof(kNALU1), &buf);
246 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1));
248 WriteLength(GetParam(), 0, &buf);
250 WriteLength(GetParam(), sizeof(kNALU2), &buf);
251 buf.insert(buf.end(), kNALU2, kNALU2 + sizeof(kNALU2));
253 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
256 TEST_P(AVCConversionTest, ParsePartial) {
257 std::vector<uint8> buf;
258 MakeInputForLength(GetParam(), &buf);
259 buf.pop_back();
260 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
261 // This tests a buffer ending in the middle of a NAL length. For length size
262 // of one, this can't happen, so we skip that case.
263 if (GetParam() != 1) {
264 MakeInputForLength(GetParam(), &buf);
265 buf.erase(buf.end() - (sizeof(kNALU2) + 1), buf.end());
266 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
270 TEST_P(AVCConversionTest, ParseEmpty) {
271 std::vector<uint8> buf;
272 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
273 EXPECT_EQ(0u, buf.size());
276 INSTANTIATE_TEST_CASE_P(AVCConversionTestValues,
277 AVCConversionTest,
278 ::testing::Values(1, 2, 4));
280 TEST_F(AVCConversionTest, ConvertConfigToAnnexB) {
281 AVCDecoderConfigurationRecord avc_config;
282 avc_config.sps_list.resize(2);
283 avc_config.sps_list[0].push_back(0x67);
284 avc_config.sps_list[0].push_back(0x12);
285 avc_config.sps_list[1].push_back(0x67);
286 avc_config.sps_list[1].push_back(0x34);
287 avc_config.pps_list.resize(1);
288 avc_config.pps_list[0].push_back(0x68);
289 avc_config.pps_list[0].push_back(0x56);
290 avc_config.pps_list[0].push_back(0x78);
292 std::vector<uint8> buf;
293 std::vector<SubsampleEntry> subsamples;
294 EXPECT_TRUE(AVC::ConvertConfigToAnnexB(avc_config, &buf));
295 EXPECT_EQ(0, memcmp(kExpectedParamSets, &buf[0],
296 sizeof(kExpectedParamSets)));
297 EXPECT_EQ("SPS,SPS,PPS", AnnexBToString(buf, subsamples));
300 // Verify that we can round trip string -> Annex B -> string.
301 TEST_F(AVCConversionTest, StringConversionFunctions) {
302 std::string str =
303 "AUD SPS SPSExt SPS PPS SEI SEI R14 I P FILL EOSeq EOStr";
304 std::vector<uint8> buf;
305 std::vector<SubsampleEntry> subsamples;
306 StringToAnnexB(str, &buf, &subsamples);
307 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples));
309 EXPECT_EQ(str, AnnexBToString(buf, subsamples));
312 TEST_F(AVCConversionTest, ValidAnnexBConstructs) {
313 const char* test_cases[] = {
314 "I",
315 "I I I I",
316 "AUD I",
317 "AUD SPS PPS I",
318 "I EOSeq",
319 "I EOSeq EOStr",
320 "I EOStr",
321 "P",
322 "P P P P",
323 "AUD SPS PPS P",
324 "SEI SEI I",
325 "SEI SEI R14 I",
326 "SPS SPSExt SPS PPS I P",
327 "R14 SEI I",
328 "AUD,I",
329 "AUD,SEI I",
330 "AUD,SEI,SPS,PPS,I"
333 for (size_t i = 0; i < arraysize(test_cases); ++i) {
334 std::vector<uint8> buf;
335 std::vector<SubsampleEntry> subsamples;
336 StringToAnnexB(test_cases[i], &buf, NULL);
337 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples)) << "'" << test_cases[i]
338 << "' failed";
342 TEST_F(AVCConversionTest, InvalidAnnexBConstructs) {
343 static const char* test_cases[] = {
344 "AUD", // No VCL present.
345 "AUD,SEI", // No VCL present.
346 "SPS PPS", // No VCL present.
347 "SPS PPS AUD I", // Parameter sets must come after AUD.
348 "SPSExt SPS P", // SPS must come before SPSExt.
349 "SPS PPS SPSExt P", // SPSExt must follow an SPS.
350 "EOSeq", // EOSeq must come after a VCL.
351 "EOStr", // EOStr must come after a VCL.
352 "I EOStr EOSeq", // EOSeq must come before EOStr.
353 "I R14", // Reserved14-18 must come before first VCL.
354 "I SEI", // SEI must come before first VCL.
355 "P SPS P", // SPS after first VCL would indicate a new access unit.
358 for (size_t i = 0; i < arraysize(test_cases); ++i) {
359 std::vector<uint8> buf;
360 std::vector<SubsampleEntry> subsamples;
361 StringToAnnexB(test_cases[i], &buf, NULL);
362 EXPECT_FALSE(AVC::IsValidAnnexB(buf, subsamples)) << "'" << test_cases[i]
363 << "' failed";
367 typedef struct {
368 const char* input;
369 const char* expected;
370 } InsertTestCases;
372 TEST_F(AVCConversionTest, InsertParamSetsAnnexB) {
373 static const InsertTestCases test_cases[] = {
374 { "I", "SPS,SPS,PPS,I" },
375 { "AUD I", "AUD SPS,SPS,PPS,I" },
377 // Cases where param sets in |avc_config| are placed before
378 // the existing ones.
379 { "SPS,PPS,I", "SPS,SPS,PPS,SPS,PPS,I" },
380 { "AUD,SPS,PPS,I", "AUD,SPS,SPS,PPS,SPS,PPS,I" }, // Note: params placed
381 // after AUD.
383 // One or more NALUs might follow AUD in the first subsample, we need to
384 // handle this correctly. Params should be inserted right after AUD.
385 { "AUD,SEI I", "AUD,SPS,SPS,PPS,SEI I" },
388 AVCDecoderConfigurationRecord avc_config;
389 avc_config.sps_list.resize(2);
390 avc_config.sps_list[0].push_back(0x67);
391 avc_config.sps_list[0].push_back(0x12);
392 avc_config.sps_list[1].push_back(0x67);
393 avc_config.sps_list[1].push_back(0x34);
394 avc_config.pps_list.resize(1);
395 avc_config.pps_list[0].push_back(0x68);
396 avc_config.pps_list[0].push_back(0x56);
397 avc_config.pps_list[0].push_back(0x78);
399 for (size_t i = 0; i < arraysize(test_cases); ++i) {
400 std::vector<uint8> buf;
401 std::vector<SubsampleEntry> subsamples;
403 StringToAnnexB(test_cases[i].input, &buf, &subsamples);
405 EXPECT_TRUE(AVC::InsertParamSetsAnnexB(avc_config, &buf, &subsamples))
406 << "'" << test_cases[i].input << "' insert failed.";
407 EXPECT_TRUE(AVC::IsValidAnnexB(buf, subsamples))
408 << "'" << test_cases[i].input << "' created invalid AnnexB.";
409 EXPECT_EQ(test_cases[i].expected, AnnexBToString(buf, subsamples))
410 << "'" << test_cases[i].input << "' generated unexpected output.";
414 } // namespace mp4
415 } // namespace media