OLD | NEW |
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 Loading... |
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 |
OLD | NEW |