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.
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"
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
) {
32 return H264NALU::kNonIDRSlice
;
35 return H264NALU::kIDRSlice
;
38 return H264NALU::kSEIMessage
;
41 return H264NALU::kSPS
;
44 return H264NALU::kSPSExt
;
47 return H264NALU::kPPS
;
50 return H264NALU::kAUD
;
53 return H264NALU::kEOSeq
;
56 return H264NALU::kEOStream
;
59 return H264NALU::kFiller
;
62 return H264NALU::kReserved14
;
64 CHECK(false) << "Unexpected name: " << name
;
65 return H264NALU::kUnspecified
;
68 static std::string
NALUTypeToString(int type
) {
70 case H264NALU::kNonIDRSlice
:
72 case H264NALU::kSliceDataA
:
74 case H264NALU::kSliceDataB
:
76 case H264NALU::kSliceDataC
:
78 case H264NALU::kIDRSlice
:
80 case H264NALU::kSEIMessage
:
84 case H264NALU::kSPSExt
:
90 case H264NALU::kEOSeq
:
92 case H264NALU::kEOStream
:
94 case H264NALU::kFiller
:
96 case H264NALU::kReserved14
:
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
;
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
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
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);
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
;
160 // Simulate the encrypted bits containing something that looks
162 WriteStartCodeAndNALUType(buffer
, "SPS");
165 entry
.cypher_bytes
= buffer
->size() - start
- entry
.clear_bytes
;
168 subsamples
->push_back(entry
);
173 std::string
AnnexBToString(const std::vector
<uint8
>& buffer
,
174 const std::vector
<SubsampleEntry
>& subsamples
) {
175 std::stringstream ss
;
178 parser
.SetEncryptedStream(&buffer
[0], buffer
.size(), subsamples
);
182 size_t current_subsample_index
= 0;
183 while (parser
.AdvanceToNextNALU(&nalu
) == H264Parser::kOk
) {
184 size_t subsample_index
= AVC::FindSubsampleIndex(buffer
, &subsamples
,
187 ss
<< (subsample_index
== current_subsample_index
? "," : " ");
189 DCHECK_EQ(subsample_index
, current_subsample_index
);
193 ss
<< NALUTypeToString(nalu
.nal_unit_type
);
194 current_subsample_index
= subsample_index
;
199 class AVCConversionTest
: public testing::TestWithParam
<int> {
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
++)
207 buf
->push_back(length
);
210 void MakeInputForLength(int length_size
, std::vector
<uint8
>* buf
) {
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
);
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
,
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
) {
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
[] = {
326 "SPS SPSExt SPS PPS I P",
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
]
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
]
369 const char* expected
;
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
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.";