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_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"
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
) {
33 return H264NALU::kNonIDRSlice
;
36 return H264NALU::kIDRSlice
;
39 return H264NALU::kSEIMessage
;
42 return H264NALU::kSPS
;
45 return H264NALU::kSPSExt
;
48 return H264NALU::kPPS
;
51 return H264NALU::kAUD
;
54 return H264NALU::kEOSeq
;
57 return H264NALU::kEOStream
;
60 return H264NALU::kFiller
;
63 return H264NALU::kReserved14
;
65 CHECK(false) << "Unexpected name: " << name
;
66 return H264NALU::kUnspecified
;
69 static std::string
NALUTypeToString(int type
) {
71 case H264NALU::kNonIDRSlice
:
73 case H264NALU::kSliceDataA
:
75 case H264NALU::kSliceDataB
:
77 case H264NALU::kSliceDataC
:
79 case H264NALU::kIDRSlice
:
81 case H264NALU::kSEIMessage
:
85 case H264NALU::kSPSExt
:
91 case H264NALU::kEOSeq
:
93 case H264NALU::kEOStream
:
95 case H264NALU::kFiller
:
97 case H264NALU::kReserved14
:
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
;
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
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
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);
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
;
164 // Simulate the encrypted bits containing something that looks
166 WriteStartCodeAndNALUType(buffer
, "SPS");
169 entry
.cypher_bytes
= buffer
->size() - start
- entry
.clear_bytes
;
172 subsamples
->push_back(entry
);
177 std::string
AnnexBToString(const std::vector
<uint8
>& buffer
,
178 const std::vector
<SubsampleEntry
>& subsamples
) {
179 std::stringstream ss
;
182 parser
.SetEncryptedStream(&buffer
[0], buffer
.size(), subsamples
);
186 size_t current_subsample_index
= 0;
187 while (parser
.AdvanceToNextNALU(&nalu
) == H264Parser::kOk
) {
188 size_t subsample_index
= AVC::FindSubsampleIndex(buffer
, &subsamples
,
191 ss
<< (subsample_index
== current_subsample_index
? "," : " ");
193 DCHECK_EQ(subsample_index
, current_subsample_index
);
197 ss
<< NALUTypeToString(nalu
.nal_unit_type
);
198 current_subsample_index
= subsample_index
;
203 class AVCConversionTest
: public testing::TestWithParam
<int> {
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
++)
211 buf
->push_back(length
);
214 void MakeInputForLength(int length_size
, std::vector
<uint8
>* buf
) {
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
);
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
);
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
,
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
) {
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
[] = {
370 "SPS SPSExt SPS PPS I P",
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
]
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
]
413 const char* expected
;
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
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.";