Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(332)

Side by Side Diff: media/formats/mp4/avc_unittest.cc

Issue 246853005: Fix SPS/PPS insertion logic in MP4StreamParser. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address CR comments. Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <string.h> 5 #include <string.h>
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/strings/string_util.h"
9 #include "media/base/decrypt_config.h"
8 #include "media/base/stream_parser_buffer.h" 10 #include "media/base/stream_parser_buffer.h"
11 #include "media/filters/h264_parser.h"
9 #include "media/formats/mp4/avc.h" 12 #include "media/formats/mp4/avc.h"
10 #include "media/formats/mp4/box_definitions.h" 13 #include "media/formats/mp4/box_definitions.h"
11 #include "testing/gtest/include/gtest/gtest.h" 14 #include "testing/gtest/include/gtest/gtest.h"
12 15
13 namespace media { 16 namespace media {
14 namespace mp4 { 17 namespace mp4 {
15 18
16 static const uint8 kNALU1[] = { 0x01, 0x02, 0x03 }; 19 static const uint8 kNALU1[] = { 0x01, 0x02, 0x03 };
17 static const uint8 kNALU2[] = { 0x04, 0x05, 0x06, 0x07 }; 20 static const uint8 kNALU2[] = { 0x04, 0x05, 0x06, 0x07 };
18 static const uint8 kExpected[] = { 21 static const uint8 kExpected[] = {
19 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 22 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03,
20 0x00, 0x00, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07 }; 23 0x00, 0x00, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07 };
21 24
22 static const uint8 kExpectedParamSets[] = { 25 static const uint8 kExpectedParamSets[] = {
23 0x00, 0x00, 0x00, 0x01, 0x67, 0x12, 26 0x00, 0x00, 0x00, 0x01, 0x67, 0x12,
24 0x00, 0x00, 0x00, 0x01, 0x67, 0x34, 27 0x00, 0x00, 0x00, 0x01, 0x67, 0x34,
25 0x00, 0x00, 0x00, 0x01, 0x68, 0x56, 0x78}; 28 0x00, 0x00, 0x00, 0x01, 0x68, 0x56, 0x78};
26 29
30 static H264NALU::Type StringToNALUType(const std::string& name) {
31 if (name == "P")
32 return H264NALU::kNonIDRSlice;
33
34 if (name == "I")
35 return H264NALU::kIDRSlice;
36
37 if (name == "SEI")
38 return H264NALU::kSEIMessage;
39
40 if (name == "SPS")
41 return H264NALU::kSPS;
42
43 if (name == "SPSExt")
44 return H264NALU::kSPSExt;
45
46 if (name == "PPS")
47 return H264NALU::kPPS;
48
49 if (name == "AUD")
50 return H264NALU::kAUD;
51
52 if (name == "EOSeq")
53 return H264NALU::kEOSeq;
54
55 if (name == "EOStr")
56 return H264NALU::kEOStream;
57
58 if (name == "FILL")
59 return H264NALU::kFiller;
60
61 if (name == "R14")
62 return H264NALU::kReserved14;
63
64 CHECK(false) << "Unexpected name: " << name;
65 return H264NALU::kUnspecified;
66 }
67
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";
98
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;
108 };
109
110 return "UnsupportedType";
111 }
112
113 void StringToAnnexB(const std::string& str, std::vector<uint8>* buffer,
114 std::vector<SubsampleEntry>* subsamples) {
115 DCHECK(!str.empty());
116
117 std::vector<std::string> tokens;
118 EXPECT_GT(Tokenize(str, " ", &tokens), 0u);
119
120 buffer->clear();
121 for (size_t i = 0; i < tokens.size(); ++i) {
122 SubsampleEntry entry;
123 size_t start = buffer->size();
124
125 // Write the start code.
126 buffer->push_back(0x00);
127 buffer->push_back(0x00);
128 buffer->push_back(0x00);
129 buffer->push_back(0x01);
130
131 // Write NALU type.
132 buffer->push_back(StringToNALUType(tokens[i]));
133
134 entry.clear_bytes = buffer->size() - start;
135
136 // Write junk for the payload since the current code doesn't
137 // actually look at it.
138 buffer->push_back(0x32);
139 buffer->push_back(0x12);
140 buffer->push_back(0x67);
141
142 entry.cypher_bytes = buffer->size() - start - entry.clear_bytes;
143
144 if (subsamples) {
145 subsamples->push_back(entry);
146 }
147 }
148 }
149
150 std::string AnnexBToString(const std::vector<uint8>& buffer) {
151 std::stringstream ss;
152
153 H264Parser parser;
154 parser.SetStream(&buffer[0], buffer.size());
155
156 H264NALU nalu;
157 bool first = true;
158 while (parser.AdvanceToNextNALU(&nalu) == H264Parser::kOk) {
159 if (!first)
160 ss << " ";
161 else
162 first = false;
163
164 ss << NALUTypeToString(nalu.nal_unit_type);
165 }
166 return ss.str();
167 }
168
27 class AVCConversionTest : public testing::TestWithParam<int> { 169 class AVCConversionTest : public testing::TestWithParam<int> {
28 protected: 170 protected:
29 void MakeInputForLength(int length_size, std::vector<uint8>* buf) { 171 void WriteLength(int length_size, int length, std::vector<uint8>* buf) {
30 buf->clear(); 172 DCHECK_GE(length, 0);
31 for (int i = 1; i < length_size; i++) 173 DCHECK_LE(length, 255);
32 buf->push_back(0);
33 buf->push_back(sizeof(kNALU1));
34 buf->insert(buf->end(), kNALU1, kNALU1 + sizeof(kNALU1));
35 174
36 for (int i = 1; i < length_size; i++) 175 for (int i = 1; i < length_size; i++)
37 buf->push_back(0); 176 buf->push_back(0);
38 buf->push_back(sizeof(kNALU2)); 177 buf->push_back(length);
178 }
179
180 void MakeInputForLength(int length_size, std::vector<uint8>* buf) {
181 buf->clear();
182
183 WriteLength(length_size, sizeof(kNALU1), buf);
184 buf->insert(buf->end(), kNALU1, kNALU1 + sizeof(kNALU1));
185
186 WriteLength(length_size, sizeof(kNALU2), buf);
39 buf->insert(buf->end(), kNALU2, kNALU2 + sizeof(kNALU2)); 187 buf->insert(buf->end(), kNALU2, kNALU2 + sizeof(kNALU2));
40 } 188 }
189
41 }; 190 };
42 191
43 TEST_P(AVCConversionTest, ParseCorrectly) { 192 TEST_P(AVCConversionTest, ParseCorrectly) {
44 std::vector<uint8> buf; 193 std::vector<uint8> buf;
45 MakeInputForLength(GetParam(), &buf); 194 MakeInputForLength(GetParam(), &buf);
46 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); 195 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
196 EXPECT_TRUE(AVC::IsValidAnnexB(buf));
47 EXPECT_EQ(buf.size(), sizeof(kExpected)); 197 EXPECT_EQ(buf.size(), sizeof(kExpected));
48 EXPECT_EQ(0, memcmp(kExpected, &buf[0], sizeof(kExpected))); 198 EXPECT_EQ(0, memcmp(kExpected, &buf[0], sizeof(kExpected)));
199 EXPECT_EQ("P SDC", AnnexBToString(buf));
200 }
201
202 // Intentionally write NALU sizes that are larger than the buffer.
203 TEST_P(AVCConversionTest, NALUSizeTooLarge) {
204 std::vector<uint8> buf;
205 WriteLength(GetParam(), 10 * sizeof(kNALU1), &buf);
206 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1));
207 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
208 }
209
210 TEST_P(AVCConversionTest, NALUSizeIsZero) {
211 std::vector<uint8> buf;
212 WriteLength(GetParam(), 0, &buf);
213
214 WriteLength(GetParam(), sizeof(kNALU1), &buf);
215 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1));
216
217 WriteLength(GetParam(), 0, &buf);
218
219 WriteLength(GetParam(), sizeof(kNALU2), &buf);
220 buf.insert(buf.end(), kNALU2, kNALU2 + sizeof(kNALU2));
221
222 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
49 } 223 }
50 224
51 TEST_P(AVCConversionTest, ParsePartial) { 225 TEST_P(AVCConversionTest, ParsePartial) {
52 std::vector<uint8> buf; 226 std::vector<uint8> buf;
53 MakeInputForLength(GetParam(), &buf); 227 MakeInputForLength(GetParam(), &buf);
54 buf.pop_back(); 228 buf.pop_back();
55 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); 229 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
56 // This tests a buffer ending in the middle of a NAL length. For length size 230 // This tests a buffer ending in the middle of a NAL length. For length size
57 // of one, this can't happen, so we skip that case. 231 // of one, this can't happen, so we skip that case.
58 if (GetParam() != 1) { 232 if (GetParam() != 1) {
(...skipping 19 matching lines...) Expand all
78 avc_config.sps_list[0].push_back(0x67); 252 avc_config.sps_list[0].push_back(0x67);
79 avc_config.sps_list[0].push_back(0x12); 253 avc_config.sps_list[0].push_back(0x12);
80 avc_config.sps_list[1].push_back(0x67); 254 avc_config.sps_list[1].push_back(0x67);
81 avc_config.sps_list[1].push_back(0x34); 255 avc_config.sps_list[1].push_back(0x34);
82 avc_config.pps_list.resize(1); 256 avc_config.pps_list.resize(1);
83 avc_config.pps_list[0].push_back(0x68); 257 avc_config.pps_list[0].push_back(0x68);
84 avc_config.pps_list[0].push_back(0x56); 258 avc_config.pps_list[0].push_back(0x56);
85 avc_config.pps_list[0].push_back(0x78); 259 avc_config.pps_list[0].push_back(0x78);
86 260
87 std::vector<uint8> buf; 261 std::vector<uint8> buf;
88 EXPECT_TRUE(AVC::ConvertConfigToAnnexB(avc_config, &buf)); 262 std::vector<SubsampleEntry> subsamples;
263 EXPECT_TRUE(AVC::ConvertConfigToAnnexB(avc_config, &buf, &subsamples));
89 EXPECT_EQ(0, memcmp(kExpectedParamSets, &buf[0], 264 EXPECT_EQ(0, memcmp(kExpectedParamSets, &buf[0],
90 sizeof(kExpectedParamSets))); 265 sizeof(kExpectedParamSets)));
266 EXPECT_EQ("SPS SPS PPS", AnnexBToString(buf));
267 }
268
269 // Verify that we can round trip string -> Annex B -> string.
270 TEST_F(AVCConversionTest, StringConversionFunctions) {
271 std::string str =
272 "AUD SPS SPSExt SPS PPS SEI SEI R14 I P FILL EOSeq EOStr";
273 std::vector<uint8> buf;
274 StringToAnnexB(str, &buf, NULL);
275
276 EXPECT_TRUE(AVC::IsValidAnnexB(buf));
277
278 EXPECT_EQ(str, AnnexBToString(buf));
279 }
280
281 TEST_F(AVCConversionTest, ValidAnnexBConstructs) {
282 const char* test_cases[] = {
283 "I",
284 "I I I I",
285 "AUD I",
286 "AUD SPS PPS I",
287 "I EOSeq",
288 "I EOSeq EOStr",
289 "I EOStr",
290 "P",
291 "P P P P",
292 "AUD SPS PPS P",
293 "SEI SEI I",
294 "SEI SEI R14 I",
295 "SPS SPSExt SPS PPS I P",
296 "R14 SEI I",
297 };
298
299 for (size_t i = 0; i < arraysize(test_cases); ++i) {
300 std::vector<uint8> buf;
301 StringToAnnexB(test_cases[i], &buf, NULL);
302 EXPECT_TRUE(AVC::IsValidAnnexB(buf)) << "'" << test_cases[i] << "' failed";
303 }
304 }
305
306 TEST_F(AVCConversionTest, InvalidAnnexBConstructs) {
307 static const char* test_cases[] = {
308 "AUD", // No VCL present.
309 "SPS PPS", // No VCL present.
310 "SPS PPS AUD I", // Parameter sets must come after AUD.
311 "SPSExt SPS P", // SPS must come before SPSExt.
312 "SPS PPS SPSExt P", // SPSExt must follow an SPS.
313 "EOSeq", // EOSeq must come after a VCL.
314 "EOStr", // EOStr must come after a VCL.
315 "I EOStr EOSeq", // EOSeq must come before EOStr.
316 "I R14", // Reserved14-18 must come before first VCL.
317 "I SEI", // SEI must come before first VCL.
318 "P SPS P", // SPS after first VCL would indicate a new access unit.
319 };
320
321 for (size_t i = 0; i < arraysize(test_cases); ++i) {
322 std::vector<uint8> buf;
323 StringToAnnexB(test_cases[i], &buf, NULL);
324 EXPECT_FALSE(AVC::IsValidAnnexB(buf)) << "'" << test_cases[i] << "' failed";
325 }
326 }
327
328 typedef struct {
329 const char* input;
330 const char* expected;
331 } InsertTestCases;
332
333 TEST_F(AVCConversionTest, InsertParamSetsAnnexB) {
334 static const InsertTestCases test_cases[] = {
335 { "I", "SPS SPS PPS I" },
336 { "AUD I", "AUD SPS SPS PPS I" },
337
338 // Cases where param sets in |avc_config| are placed before
339 // the existing ones.
340 { "SPS PPS I", "SPS SPS PPS SPS PPS I" },
341 { "AUD SPS PPS I", "AUD SPS SPS PPS SPS PPS I" }, // Note: params placed
342 // after AUD.
343 };
344
345 AVCDecoderConfigurationRecord avc_config;
346 avc_config.sps_list.resize(2);
347 avc_config.sps_list[0].push_back(0x67);
348 avc_config.sps_list[0].push_back(0x12);
349 avc_config.sps_list[1].push_back(0x67);
350 avc_config.sps_list[1].push_back(0x34);
351 avc_config.pps_list.resize(1);
352 avc_config.pps_list[0].push_back(0x68);
353 avc_config.pps_list[0].push_back(0x56);
354 avc_config.pps_list[0].push_back(0x78);
355
356 for (size_t i = 0; i < arraysize(test_cases); ++i) {
357 std::vector<uint8> buf;
358 std::vector<SubsampleEntry> subsamples;
359
360 StringToAnnexB(test_cases[i].input, &buf, &subsamples);
361
362 EXPECT_TRUE(AVC::InsertParamSetsAnnexB(avc_config, &buf, &subsamples))
363 << "'" << test_cases[i].input << "' insert failed.";
364 EXPECT_TRUE(AVC::IsValidAnnexB(buf))
365 << "'" << test_cases[i].input << "' created invalid AnnexB.";
366 EXPECT_EQ(test_cases[i].expected, AnnexBToString(buf))
367 << "'" << test_cases[i].input << "' generated unexpected output.";
368 }
91 } 369 }
92 370
93 } // namespace mp4 371 } // namespace mp4
94 } // namespace media 372 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698