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
));
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
));
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
));
260 TEST_P(AVCConversionTest
, ParsePartial
) {
261 std::vector
<uint8
> buf
;
262 MakeInputForLength(GetParam(), &buf
);
264 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf
));
265 // This tests a buffer ending in the middle of a NAL length. For length size
266 // of one, this can't happen, so we skip that case.
267 if (GetParam() != 1) {
268 MakeInputForLength(GetParam(), &buf
);
269 buf
.erase(buf
.end() - (sizeof(kNALU2
) + 1), buf
.end());
270 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf
));
274 TEST_P(AVCConversionTest
, ParseEmpty
) {
275 std::vector
<uint8
> buf
;
276 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf
));
277 EXPECT_EQ(0u, buf
.size());
280 INSTANTIATE_TEST_CASE_P(AVCConversionTestValues
,
282 ::testing::Values(1, 2, 4));
284 TEST_F(AVCConversionTest
, ConvertConfigToAnnexB
) {
285 AVCDecoderConfigurationRecord avc_config
;
286 avc_config
.sps_list
.resize(2);
287 avc_config
.sps_list
[0].push_back(0x67);
288 avc_config
.sps_list
[0].push_back(0x12);
289 avc_config
.sps_list
[1].push_back(0x67);
290 avc_config
.sps_list
[1].push_back(0x34);
291 avc_config
.pps_list
.resize(1);
292 avc_config
.pps_list
[0].push_back(0x68);
293 avc_config
.pps_list
[0].push_back(0x56);
294 avc_config
.pps_list
[0].push_back(0x78);
296 std::vector
<uint8
> buf
;
297 std::vector
<SubsampleEntry
> subsamples
;
298 EXPECT_TRUE(AVC::ConvertConfigToAnnexB(avc_config
, &buf
));
299 EXPECT_EQ(0, memcmp(kExpectedParamSets
, &buf
[0],
300 sizeof(kExpectedParamSets
)));
301 EXPECT_EQ("SPS,SPS,PPS", AnnexBToString(buf
, subsamples
));
304 // Verify that we can round trip string -> Annex B -> string.
305 TEST_F(AVCConversionTest
, StringConversionFunctions
) {
307 "AUD SPS SPSExt SPS PPS SEI SEI R14 I P FILL EOSeq EOStr";
308 std::vector
<uint8
> buf
;
309 std::vector
<SubsampleEntry
> subsamples
;
310 StringToAnnexB(str
, &buf
, &subsamples
);
311 EXPECT_TRUE(AVC::IsValidAnnexB(buf
, subsamples
));
313 EXPECT_EQ(str
, AnnexBToString(buf
, subsamples
));
316 TEST_F(AVCConversionTest
, ValidAnnexBConstructs
) {
317 const char* test_cases
[] = {
330 "SPS SPSExt SPS PPS I P",
337 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
338 std::vector
<uint8
> buf
;
339 std::vector
<SubsampleEntry
> subsamples
;
340 StringToAnnexB(test_cases
[i
], &buf
, NULL
);
341 EXPECT_TRUE(AVC::IsValidAnnexB(buf
, subsamples
)) << "'" << test_cases
[i
]
346 TEST_F(AVCConversionTest
, InvalidAnnexBConstructs
) {
347 static const char* test_cases
[] = {
348 "AUD", // No VCL present.
349 "AUD,SEI", // No VCL present.
350 "SPS PPS", // No VCL present.
351 "SPS PPS AUD I", // Parameter sets must come after AUD.
352 "SPSExt SPS P", // SPS must come before SPSExt.
353 "SPS PPS SPSExt P", // SPSExt must follow an SPS.
354 "EOSeq", // EOSeq must come after a VCL.
355 "EOStr", // EOStr must come after a VCL.
356 "I EOStr EOSeq", // EOSeq must come before EOStr.
357 "I R14", // Reserved14-18 must come before first VCL.
358 "I SEI", // SEI must come before first VCL.
359 "P SPS P", // SPS after first VCL would indicate a new access unit.
362 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
363 std::vector
<uint8
> buf
;
364 std::vector
<SubsampleEntry
> subsamples
;
365 StringToAnnexB(test_cases
[i
], &buf
, NULL
);
366 EXPECT_FALSE(AVC::IsValidAnnexB(buf
, subsamples
)) << "'" << test_cases
[i
]
373 const char* expected
;
376 TEST_F(AVCConversionTest
, InsertParamSetsAnnexB
) {
377 static const InsertTestCases test_cases
[] = {
378 { "I", "SPS,SPS,PPS,I" },
379 { "AUD I", "AUD SPS,SPS,PPS,I" },
381 // Cases where param sets in |avc_config| are placed before
382 // the existing ones.
383 { "SPS,PPS,I", "SPS,SPS,PPS,SPS,PPS,I" },
384 { "AUD,SPS,PPS,I", "AUD,SPS,SPS,PPS,SPS,PPS,I" }, // Note: params placed
387 // One or more NALUs might follow AUD in the first subsample, we need to
388 // handle this correctly. Params should be inserted right after AUD.
389 { "AUD,SEI I", "AUD,SPS,SPS,PPS,SEI I" },
392 AVCDecoderConfigurationRecord avc_config
;
393 avc_config
.sps_list
.resize(2);
394 avc_config
.sps_list
[0].push_back(0x67);
395 avc_config
.sps_list
[0].push_back(0x12);
396 avc_config
.sps_list
[1].push_back(0x67);
397 avc_config
.sps_list
[1].push_back(0x34);
398 avc_config
.pps_list
.resize(1);
399 avc_config
.pps_list
[0].push_back(0x68);
400 avc_config
.pps_list
[0].push_back(0x56);
401 avc_config
.pps_list
[0].push_back(0x78);
403 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
404 std::vector
<uint8
> buf
;
405 std::vector
<SubsampleEntry
> subsamples
;
407 StringToAnnexB(test_cases
[i
].input
, &buf
, &subsamples
);
409 EXPECT_TRUE(AVC::InsertParamSetsAnnexB(avc_config
, &buf
, &subsamples
))
410 << "'" << test_cases
[i
].input
<< "' insert failed.";
411 EXPECT_TRUE(AVC::IsValidAnnexB(buf
, subsamples
))
412 << "'" << test_cases
[i
].input
<< "' created invalid AnnexB.";
413 EXPECT_EQ(test_cases
[i
].expected
, AnnexBToString(buf
, subsamples
))
414 << "'" << test_cases
[i
].input
<< "' generated unexpected output.";