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

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: Add a bunch of tests 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"
8 #include "media/base/stream_parser_buffer.h" 9 #include "media/base/stream_parser_buffer.h"
10 #include "media/filters/h264_parser.h"
9 #include "media/formats/mp4/avc.h" 11 #include "media/formats/mp4/avc.h"
10 #include "media/formats/mp4/box_definitions.h" 12 #include "media/formats/mp4/box_definitions.h"
11 #include "testing/gtest/include/gtest/gtest.h" 13 #include "testing/gtest/include/gtest/gtest.h"
12 14
13 namespace media { 15 namespace media {
14 namespace mp4 { 16 namespace mp4 {
15 17
16 static const uint8 kNALU1[] = { 0x01, 0x02, 0x03 }; 18 static const uint8 kNALU1[] = { 0x01, 0x02, 0x03 };
17 static const uint8 kNALU2[] = { 0x04, 0x05, 0x06, 0x07 }; 19 static const uint8 kNALU2[] = { 0x04, 0x05, 0x06, 0x07 };
18 static const uint8 kExpected[] = { 20 static const uint8 kExpected[] = {
19 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 21 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03,
20 0x00, 0x00, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07 }; 22 0x00, 0x00, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07 };
21 23
22 static const uint8 kExpectedParamSets[] = { 24 static const uint8 kExpectedParamSets[] = {
23 0x00, 0x00, 0x00, 0x01, 0x67, 0x12, 25 0x00, 0x00, 0x00, 0x01, 0x67, 0x12,
24 0x00, 0x00, 0x00, 0x01, 0x67, 0x34, 26 0x00, 0x00, 0x00, 0x01, 0x67, 0x34,
25 0x00, 0x00, 0x00, 0x01, 0x68, 0x56, 0x78}; 27 0x00, 0x00, 0x00, 0x01, 0x68, 0x56, 0x78};
26 28
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 NOTREACHED() << "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 default:
99 NOTREACHED() << "Unexpected type: " << type;
100 return "UnsupportedType";
101 };
102
103 NOTREACHED() << "Unexpected type: " << type;
104 return "UnsupportedType";
105 }
106
107 void StringToAnnexB(const std::string& str, std::vector<uint8>* buffer) {
108 DCHECK(!str.empty());
109
110 std::vector<std::string> tokens;
111 EXPECT_GT(Tokenize(str, " ", &tokens), 0u);
112
113 buffer->clear();
114 for (size_t i = 0; i < tokens.size(); ++i) {
115 // Write the start code.
116 buffer->push_back(0x00);
117 buffer->push_back(0x00);
118 buffer->push_back(0x00);
119 buffer->push_back(0x01);
120
121 // Write NALU type.
122 buffer->push_back(StringToNALUType(tokens[i]));
123
124 // Write junk for the payload since the current code doesn't
125 // actually look at it.
126 buffer->push_back(0x32);
127 buffer->push_back(0x12);
128 buffer->push_back(0x67);
129 }
130 }
131
132 std::string AnnexBToString(const std::vector<uint8>& buffer) {
133 std::stringstream ss;
134
135 H264Parser parser;
136 parser.SetStream(&buffer[0], buffer.size());
137
138 H264NALU nalu;
139 bool first = true;
140 while (parser.AdvanceToNextNALU(&nalu) == H264Parser::kOk) {
141 if (!first)
142 ss << " ";
143 else
144 first = false;
145
146 ss << NALUTypeToString(nalu.nal_unit_type);
147 }
148 return ss.str();
149 }
150
27 class AVCConversionTest : public testing::TestWithParam<int> { 151 class AVCConversionTest : public testing::TestWithParam<int> {
28 protected: 152 protected:
29 void MakeInputForLength(int length_size, std::vector<uint8>* buf) { 153 void WriteLength(int length_size, int length, std::vector<uint8>* buf) {
30 buf->clear(); 154 DCHECK_GE(length, 0);
31 for (int i = 1; i < length_size; i++) 155 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 156
36 for (int i = 1; i < length_size; i++) 157 for (int i = 1; i < length_size; i++)
37 buf->push_back(0); 158 buf->push_back(0);
38 buf->push_back(sizeof(kNALU2)); 159 buf->push_back(length);
160 }
161
162 void MakeInputForLength(int length_size, std::vector<uint8>* buf) {
163 buf->clear();
164
165 WriteLength(length_size, sizeof(kNALU1), buf);
166 buf->insert(buf->end(), kNALU1, kNALU1 + sizeof(kNALU1));
167
168 WriteLength(length_size, sizeof(kNALU2), buf);
39 buf->insert(buf->end(), kNALU2, kNALU2 + sizeof(kNALU2)); 169 buf->insert(buf->end(), kNALU2, kNALU2 + sizeof(kNALU2));
40 } 170 }
171
41 }; 172 };
42 173
43 TEST_P(AVCConversionTest, ParseCorrectly) { 174 TEST_P(AVCConversionTest, ParseCorrectly) {
44 std::vector<uint8> buf; 175 std::vector<uint8> buf;
45 MakeInputForLength(GetParam(), &buf); 176 MakeInputForLength(GetParam(), &buf);
46 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); 177 EXPECT_TRUE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
178 EXPECT_TRUE(AVC::IsValidAnnexB(buf));
47 EXPECT_EQ(buf.size(), sizeof(kExpected)); 179 EXPECT_EQ(buf.size(), sizeof(kExpected));
48 EXPECT_EQ(0, memcmp(kExpected, &buf[0], sizeof(kExpected))); 180 EXPECT_EQ(0, memcmp(kExpected, &buf[0], sizeof(kExpected)));
181 EXPECT_EQ("P SDC", AnnexBToString(buf));
182 }
183
184 // Intentionally write NALU sizes that are larger than the buffer.
185 TEST_P(AVCConversionTest, NALUSizeTooLarge) {
186 std::vector<uint8> buf;
187 WriteLength(GetParam(), 10 * sizeof(kNALU1), &buf);
188 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1));
189 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
190 }
191
192 TEST_P(AVCConversionTest, NALUSizeIsZero) {
193 std::vector<uint8> buf;
194 WriteLength(GetParam(), 0, &buf);
195
196 WriteLength(GetParam(), sizeof(kNALU1), &buf);
197 buf.insert(buf.end(), kNALU1, kNALU1 + sizeof(kNALU1));
198
199 WriteLength(GetParam(), 0, &buf);
200
201 WriteLength(GetParam(), sizeof(kNALU2), &buf);
202 buf.insert(buf.end(), kNALU2, kNALU2 + sizeof(kNALU2));
203
204 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
49 } 205 }
50 206
51 TEST_P(AVCConversionTest, ParsePartial) { 207 TEST_P(AVCConversionTest, ParsePartial) {
52 std::vector<uint8> buf; 208 std::vector<uint8> buf;
53 MakeInputForLength(GetParam(), &buf); 209 MakeInputForLength(GetParam(), &buf);
54 buf.pop_back(); 210 buf.pop_back();
55 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf)); 211 EXPECT_FALSE(AVC::ConvertFrameToAnnexB(GetParam(), &buf));
56 // This tests a buffer ending in the middle of a NAL length. For length size 212 // 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. 213 // of one, this can't happen, so we skip that case.
58 if (GetParam() != 1) { 214 if (GetParam() != 1) {
(...skipping 22 matching lines...) Expand all
81 avc_config.sps_list[1].push_back(0x34); 237 avc_config.sps_list[1].push_back(0x34);
82 avc_config.pps_list.resize(1); 238 avc_config.pps_list.resize(1);
83 avc_config.pps_list[0].push_back(0x68); 239 avc_config.pps_list[0].push_back(0x68);
84 avc_config.pps_list[0].push_back(0x56); 240 avc_config.pps_list[0].push_back(0x56);
85 avc_config.pps_list[0].push_back(0x78); 241 avc_config.pps_list[0].push_back(0x78);
86 242
87 std::vector<uint8> buf; 243 std::vector<uint8> buf;
88 EXPECT_TRUE(AVC::ConvertConfigToAnnexB(avc_config, &buf)); 244 EXPECT_TRUE(AVC::ConvertConfigToAnnexB(avc_config, &buf));
89 EXPECT_EQ(0, memcmp(kExpectedParamSets, &buf[0], 245 EXPECT_EQ(0, memcmp(kExpectedParamSets, &buf[0],
90 sizeof(kExpectedParamSets))); 246 sizeof(kExpectedParamSets)));
247 EXPECT_EQ("SPS SPS PPS", AnnexBToString(buf));
248 }
249
250 // Verify that we can round trip string -> Annex B -> string.
251 TEST_F(AVCConversionTest, StringConversionFunctions) {
252 std::string str =
253 "AUD SPS SPSExt SPS PPS SEI SEI R14 I P FILL EOSeq EOStr";
254 std::vector<uint8> buf;
255
256 StringToAnnexB(str, &buf);
257
258 EXPECT_TRUE(AVC::IsValidAnnexB(buf));
259
260 EXPECT_EQ(str, AnnexBToString(buf));
261 }
262
263 TEST_F(AVCConversionTest, ValidAnnexBConstructs) {
264 const char* test_cases[] = {
265 "I",
266 "I I I I",
267 "AUD I",
268 "AUD SPS PPS I",
269 "I EOSeq",
270 "I EOSeq EOStr",
271 "I EOStr",
272 "P",
273 "P P P P",
274 "AUD SPS PPS P",
275 "SEI SEI I",
276 "SEI SEI R14 I",
277 "SPS SPSExt SPS PPS I P",
278 };
279
280 for (size_t i = 0; i < arraysize(test_cases); ++i) {
281 std::vector<uint8> buf;
282 StringToAnnexB(test_cases[i], &buf);
283 EXPECT_TRUE(AVC::IsValidAnnexB(buf)) << "'" <<test_cases[i] << "' failed";
284 }
285 }
286
287 TEST_F(AVCConversionTest, InvalidAnnexBConstructs) {
288 const char* test_cases[] = {
289 "SPS PPS AUD I", // Parame sets must come after AUD.
290 "PPS SPS", // SPS must come before PPS.
291 "SPSExt SPS", // SPS must come before SPSExt.
292 "SPS PPS SPSExt", // SPSExt must follow an SPS.
293 "EOSeq", // EOSeq must come after a VCL.
294 "EOStr", // EOStr must come after a VCL.
295 "I EOStr EOSeq", // EOSeq must come before EOStr.
296 "P P SPS", // SPS must come before a VCL.
297 "R14 SEI", // Reserved14-18 must come after SEI.
298 "SEI I R14", // Reserved14-18 must come before VCL.
299 };
300
301 for (size_t i = 0; i < arraysize(test_cases); ++i) {
302 std::vector<uint8> buf;
303 StringToAnnexB(test_cases[i], &buf);
304 EXPECT_FALSE(AVC::IsValidAnnexB(buf)) << "'" <<test_cases[i] << "' failed";
305 }
306 }
307
308 TEST_F(AVCConversionTest, InsertParamSetsAnnexB) {
309 typedef struct {
310 const char* input;
311 const char* expected;
312 } InsertTestCases;
313
314 InsertTestCases test_cases[] = {
315 { "I", "SPS SPS PPS I" },
316 { "AUD I", "AUD SPS SPS PPS I" },
317 { "SPS PPS I", "SPS PPS I" }, // Skip insert since params already exist.
318 { "AUD SPS PPS I", "AUD SPS PPS I" }, // Skip insert since params
319 // already exist.
320 };
321
322 AVCDecoderConfigurationRecord avc_config;
323 avc_config.sps_list.resize(2);
324 avc_config.sps_list[0].push_back(0x67);
325 avc_config.sps_list[0].push_back(0x12);
326 avc_config.sps_list[1].push_back(0x67);
327 avc_config.sps_list[1].push_back(0x34);
328 avc_config.pps_list.resize(1);
329 avc_config.pps_list[0].push_back(0x68);
330 avc_config.pps_list[0].push_back(0x56);
331 avc_config.pps_list[0].push_back(0x78);
332
333 for (size_t i = 0; i < arraysize(test_cases); ++i) {
334 std::vector<uint8> buf;
335 StringToAnnexB(test_cases[i].input, &buf);
336
337 EXPECT_TRUE(AVC::InsertParamSetsAnnexB(avc_config, &buf))
338 << "'" << test_cases[i].input << "' insert failed.";
339 EXPECT_TRUE(AVC::IsValidAnnexB(buf))
340 << "'" << test_cases[i].input << "' created invalid AnnexB.";
341 EXPECT_EQ(test_cases[i].expected, AnnexBToString(buf))
342 << "'" << test_cases[i].input << "' generated unexpected output.";
343 }
344
91 } 345 }
92 346
93 } // namespace mp4 347 } // namespace mp4
94 } // namespace media 348 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698