TestByteStreams.cpp (57351B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 6 7 #include "AnnexB.h" 8 #include "BufferReader.h" 9 #include "ByteWriter.h" 10 #include "H264.h" 11 #include "H265.h" 12 #include "gtest/gtest.h" 13 14 namespace mozilla { 15 16 // Create AVCC style extra data (the contents on an AVCC box). Note 17 // NALLengthSize will be 4 so AVCC samples need to set their data up 18 // accordingly. 19 static already_AddRefed<MediaByteBuffer> GetExtraData() { 20 // Extra data with 21 // - baseline profile(0x42 == 66). 22 // - constraint flags 0 and 1 set(0xc0) -- normal for baseline profile. 23 // - level 4.0 (0x28 == 40). 24 // - 1280 * 720 resolution. 25 return H264::CreateExtraData(0x42, 0xc0, H264_LEVEL{0x28}, {1280, 720}); 26 } 27 28 // Create an AVCC style sample with requested size in bytes. This sample is 29 // setup to contain a single NAL (in practice samples can contain many). The 30 // sample sets its NAL size to aSampleSize - 4 and stores that size in the first 31 // 4 bytes. Aside from the NAL size at the start, the data is uninitialized 32 // (beware)! aSampleSize is a uint32_t as samples larger than can be expressed 33 // by a uint32_t are not to spec. 34 static already_AddRefed<MediaRawData> GetAvccSample(uint32_t aSampleSize) { 35 if (aSampleSize < 4) { 36 // Stop tests asking for insane samples. 37 EXPECT_FALSE(true) << "Samples should be requested with sane sizes"; 38 } 39 nsTArray<uint8_t> sampleData; 40 41 // Write the NAL size. 42 ByteWriter<BigEndian> writer(sampleData); 43 EXPECT_TRUE(writer.WriteU32(aSampleSize - 4)); 44 45 // Write the 'NAL'. Beware, this data is uninitialized. 46 sampleData.AppendElements(static_cast<size_t>(aSampleSize) - 4); 47 RefPtr<MediaRawData> rawData = 48 new MediaRawData{sampleData.Elements(), sampleData.Length()}; 49 EXPECT_NE(rawData->Data(), nullptr); 50 51 // Set extra data. 52 rawData->mExtraData = GetExtraData(); 53 return rawData.forget(); 54 } 55 56 static const uint8_t sHvccBytesBuffer[] = { 57 1 /* version */, 58 1 /* general_profile_space/general_tier_flag/general_profile_idc */, 59 0x60 /* general_profile_compatibility_flags 1/4 */, 60 0 /* general_profile_compatibility_flags 2/4 */, 61 0 /* general_profile_compatibility_flags 3/4 */, 62 0 /* general_profile_compatibility_flags 4/4 */, 63 0x90 /* general_constraint_indicator_flags 1/6 */, 64 0 /* general_constraint_indicator_flags 2/6 */, 65 0 /* general_constraint_indicator_flags 3/6 */, 66 0 /* general_constraint_indicator_flags 4/6 */, 67 0 /* general_constraint_indicator_flags 5/6 */, 68 0 /* general_constraint_indicator_flags 6/6 */, 69 0x5A /* general_level_idc */, 70 0 /* min_spatial_segmentation_idc 1/2 */, 71 0 /* min_spatial_segmentation_idc 2/2 */, 72 0 /* parallelismType */, 73 1 /* chroma_format_idc */, 74 0 /* bit_depth_luma_minus8 */, 75 0 /* bit_depth_chroma_minus8 */, 76 0 /* avgFrameRate 1/2 */, 77 0 /* avgFrameRate 2/2 */, 78 0x0F /* constantFrameRate/numTemporalLayers/temporalIdNested/lengthSizeMinusOne 79 */ 80 , 81 2 /* numOfArrays */, 82 /* SPS Array */ 83 0x21 /* NAL_unit_type (SPS) */, 84 0 /* numNalus 1/2 */, 85 1 /* numNalus 2/2 */, 86 87 /* SPS */ 88 0 /* nalUnitLength 1/2 */, 89 8 /* nalUnitLength 2/2 (header + rsbp) */, 90 0x42 /* NALU header 1/2 */, 91 0 /* NALU header 2/2 */, 92 0 /* rbsp 1/6 */, 93 0 /* rbsp 2/6 */, 94 0 /* rbsp 3/6 */, 95 0 /* rbsp 4/6 */, 96 0 /* rbsp 5/6 */, 97 0 /* rbsp 6/6 */, 98 99 /* PPS Array */ 100 0x22 /* NAL_unit_type (PPS) */, 101 0 /* numNalus 1/2 */, 102 1 /* numNalus 2/2 */, 103 104 /* PPS */ 105 0 /* nalUnitLength 1/2 */, 106 3 /* nalUnitLength 2/2 (header + rsbp) */, 107 0x44 /* NALU header 1/2 */, 108 0 /* NALU header 2/2 */, 109 0 /* rbsp */, 110 }; 111 112 // Create a HVCC sample, which contain fake data, in given size. 113 static already_AddRefed<MediaRawData> GetHVCCSample(uint32_t aSampleSize) { 114 if (aSampleSize < 4) { 115 // Stop tests asking for insane samples. 116 EXPECT_FALSE(true) << "Samples should be requested with sane sizes"; 117 } 118 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 119 extradata->AppendElements(sHvccBytesBuffer, std::size(sHvccBytesBuffer)); 120 121 // Write the NAL size. 122 nsTArray<uint8_t> sampleData; 123 ByteWriter<BigEndian> writer(sampleData); 124 EXPECT_TRUE(writer.WriteU32(aSampleSize - 4)); // Assume it's a 4 bytes NALU 125 126 // Fill fake empty data 127 for (uint32_t idx = 0; idx < aSampleSize - 4; idx++) { 128 sampleData.AppendElement(0); 129 } 130 RefPtr<MediaRawData> rawData = 131 new MediaRawData{sampleData.Elements(), sampleData.Length()}; 132 EXPECT_NE(rawData->Data(), nullptr); 133 EXPECT_EQ(rawData->Size(), aSampleSize); 134 rawData->mExtraData = extradata; 135 return rawData.forget(); 136 } 137 138 // Create a HVCC sample by using given data in given size. 139 static already_AddRefed<MediaRawData> GetHVCCSample( 140 const uint8_t* aData, const uint32_t aDataLength) { 141 if (aDataLength < 4) { 142 // Stop tests asking for insane samples. 143 EXPECT_FALSE(true) << "Samples should be requested with sane sizes"; 144 } 145 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 146 extradata->AppendElements(sHvccBytesBuffer, std::size(sHvccBytesBuffer)); 147 148 // Write the NAL size. 149 nsTArray<uint8_t> sampleData; 150 ByteWriter<BigEndian> writer(sampleData); 151 EXPECT_TRUE(writer.WriteU32(aDataLength)); // Assume it's a 4 bytes NALU 152 sampleData.AppendElements(aData, aDataLength); 153 154 RefPtr<MediaRawData> rawData = 155 new MediaRawData{sampleData.Elements(), sampleData.Length()}; 156 EXPECT_NE(rawData->Data(), nullptr); 157 EXPECT_EQ(rawData->Size(), aDataLength + 4); 158 rawData->mExtraData = extradata; 159 return rawData.forget(); 160 } 161 162 // Create a HVCC samples by given NALUs. 163 static already_AddRefed<MediaRawData> GetHVCCSamples( 164 const nsTArray<Span<const uint8_t>>& aNALUs) { 165 nsTArray<uint8_t> data; 166 ByteWriter<BigEndian> writer(data); 167 168 size_t totalSize = 0; 169 170 for (const auto& nalu : aNALUs) { 171 if (nalu.size() < 2) { 172 // NAL unit header is at least 2 bytes. 173 EXPECT_FALSE(true) << "Samples should be requested with sane sizes"; 174 return nullptr; 175 } 176 totalSize += nalu.size(); 177 EXPECT_TRUE(writer.WriteU32(nalu.size())); // Assume it's a 4 bytes NALU 178 data.AppendElements(nalu.data(), nalu.size()); 179 } 180 181 RefPtr<MediaRawData> rawData = 182 new MediaRawData{data.Elements(), data.Length()}; 183 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 184 extradata->AppendElements(sHvccBytesBuffer, std::size(sHvccBytesBuffer)); 185 rawData->mExtraData = extradata; 186 187 EXPECT_NE(rawData->Data(), nullptr); 188 EXPECT_EQ(rawData->Size(), totalSize + 4 * aNALUs.Length()); 189 return rawData.forget(); 190 } 191 192 // Test that conversion from AVCC to AnnexB works as expected. 193 TEST(AnnexB, AVCCToAnnexBConversion) 194 { 195 RefPtr<MediaRawData> rawData{GetAvccSample(128)}; 196 197 { 198 // Test conversion of data when not adding SPS works as expected. 199 RefPtr<MediaRawData> rawDataClone = rawData->Clone(); 200 Result<Ok, nsresult> result = 201 AnnexB::ConvertAVCCSampleToAnnexB(rawDataClone, /* aAddSps */ false); 202 EXPECT_TRUE(result.isOk()) << "Conversion should succeed"; 203 EXPECT_EQ(rawDataClone->Size(), rawData->Size()) 204 << "AnnexB sample should be the same size as the AVCC sample -- the 4 " 205 "byte NAL length data (AVCC) is replaced with 4 bytes of NAL " 206 "separator (AnnexB)"; 207 EXPECT_TRUE(AnnexB::IsAnnexB(*rawDataClone)) 208 << "The sample should be AnnexB following conversion"; 209 } 210 211 { 212 // Test that the SPS data is not added if the frame is not a keyframe. 213 RefPtr<MediaRawData> rawDataClone = rawData->Clone(); 214 rawDataClone->mKeyframe = 215 false; // false is the default, but let's be sure. 216 Result<Ok, nsresult> result = 217 AnnexB::ConvertAVCCSampleToAnnexB(rawDataClone, /* aAddSps */ true); 218 EXPECT_TRUE(result.isOk()) << "Conversion should succeed"; 219 EXPECT_EQ(rawDataClone->Size(), rawData->Size()) 220 << "AnnexB sample should be the same size as the AVCC sample -- the 4 " 221 "byte NAL length data (AVCC) is replaced with 4 bytes of NAL " 222 "separator (AnnexB) and SPS data is not added as the frame is not a " 223 "keyframe"; 224 EXPECT_TRUE(AnnexB::IsAnnexB(*rawDataClone)) 225 << "The sample should be AnnexB following conversion"; 226 } 227 228 { 229 // Test that the SPS data is added to keyframes. 230 RefPtr<MediaRawData> rawDataClone = rawData->Clone(); 231 rawDataClone->mKeyframe = true; 232 Result<Ok, nsresult> result = 233 AnnexB::ConvertAVCCSampleToAnnexB(rawDataClone, /* aAddSps */ true); 234 EXPECT_TRUE(result.isOk()) << "Conversion should succeed"; 235 EXPECT_GT(rawDataClone->Size(), rawData->Size()) 236 << "AnnexB sample should be larger than the AVCC sample because we've " 237 "added SPS data"; 238 EXPECT_TRUE(AnnexB::IsAnnexB(*rawDataClone)) 239 << "The sample should be AnnexB following conversion"; 240 // We could verify the SPS and PPS data we add, but we don't have great 241 // tooling to do so. Consider doing so in future. 242 } 243 244 { 245 // Test conversion involving subsample encryption doesn't overflow vlaues. 246 const uint32_t sampleSize = UINT16_MAX * 2; 247 RefPtr<MediaRawData> rawCryptoData{GetAvccSample(sampleSize)}; 248 // Need to be a keyframe to test prepending SPS + PPS to sample. 249 rawCryptoData->mKeyframe = true; 250 UniquePtr<MediaRawDataWriter> rawDataWriter = rawCryptoData->CreateWriter(); 251 252 rawDataWriter->mCrypto.mCryptoScheme = CryptoScheme::Cenc; 253 254 // We want to check that the clear size doesn't overflow during conversion. 255 // This size originates in a uint16_t, but since it can grow during AnnexB 256 // we cover it here. 257 const uint16_t clearSize = UINT16_MAX - 10; 258 // Set a clear size very close to uint16_t max value. 259 rawDataWriter->mCrypto.mPlainSizes.AppendElement(clearSize); 260 rawDataWriter->mCrypto.mEncryptedSizes.AppendElement(sampleSize - 261 clearSize); 262 263 RefPtr<MediaRawData> rawCryptoDataClone = rawCryptoData->Clone(); 264 Result<Ok, nsresult> result = AnnexB::ConvertAVCCSampleToAnnexB( 265 rawCryptoDataClone, /* aAddSps */ true); 266 EXPECT_TRUE(result.isOk()) << "Conversion should succeed"; 267 EXPECT_GT(rawCryptoDataClone->Size(), rawCryptoData->Size()) 268 << "AnnexB sample should be larger than the AVCC sample because we've " 269 "added SPS data"; 270 EXPECT_GT(rawCryptoDataClone->mCrypto.mPlainSizes[0], 271 rawCryptoData->mCrypto.mPlainSizes[0]) 272 << "Conversion should have increased clear data sizes without overflow"; 273 EXPECT_EQ(rawCryptoDataClone->mCrypto.mEncryptedSizes[0], 274 rawCryptoData->mCrypto.mEncryptedSizes[0]) 275 << "Conversion should not affect encrypted sizes"; 276 EXPECT_TRUE(AnnexB::IsAnnexB(*rawCryptoDataClone)) 277 << "The sample should be AnnexB following conversion"; 278 } 279 } 280 281 TEST(AnnexB, HVCCToAnnexBConversion) 282 { 283 RefPtr<MediaRawData> rawData{GetHVCCSample(128)}; 284 { 285 // Test conversion of data when not adding SPS works as expected. 286 RefPtr<MediaRawData> rawDataClone = rawData->Clone(); 287 Result<Ok, nsresult> result = 288 AnnexB::ConvertHVCCSampleToAnnexB(rawDataClone, /* aAddSps */ false); 289 EXPECT_TRUE(result.isOk()) << "Conversion should succeed"; 290 EXPECT_EQ(rawDataClone->Size(), rawData->Size()) 291 << "AnnexB sample should be the same size as the HVCC sample -- the 4 " 292 "byte NAL length data (HVCC) is replaced with 4 bytes of NAL " 293 "separator (AnnexB)"; 294 EXPECT_TRUE(AnnexB::IsAnnexB(*rawDataClone)) 295 << "The sample should be AnnexB following conversion"; 296 } 297 { 298 // Test that the SPS data is not added if the frame is not a keyframe. 299 RefPtr<MediaRawData> rawDataClone = rawData->Clone(); 300 rawDataClone->mKeyframe = 301 false; // false is the default, but let's be sure. 302 Result<Ok, nsresult> result = 303 AnnexB::ConvertHVCCSampleToAnnexB(rawDataClone, /* aAddSps */ true); 304 EXPECT_TRUE(result.isOk()) << "Conversion should succeed"; 305 EXPECT_EQ(rawDataClone->Size(), rawData->Size()) 306 << "AnnexB sample should be the same size as the HVCC sample -- the 4 " 307 "byte NAL length data (HVCC) is replaced with 4 bytes of NAL " 308 "separator (AnnexB) and SPS data is not added as the frame is not a " 309 "keyframe"; 310 EXPECT_TRUE(AnnexB::IsAnnexB(*rawDataClone)) 311 << "The sample should be AnnexB following conversion"; 312 } 313 { 314 // Test that the SPS data is added to keyframes. 315 RefPtr<MediaRawData> rawDataClone = rawData->Clone(); 316 rawDataClone->mKeyframe = true; 317 Result<Ok, nsresult> result = 318 AnnexB::ConvertHVCCSampleToAnnexB(rawDataClone, /* aAddSps */ true); 319 EXPECT_TRUE(result.isOk()) << "Conversion should succeed"; 320 EXPECT_GT(rawDataClone->Size(), rawData->Size()) 321 << "AnnexB sample should be larger than the HVCC sample because we've " 322 "added SPS data"; 323 EXPECT_TRUE(AnnexB::IsAnnexB(*rawDataClone)) 324 << "The sample should be AnnexB following conversion"; 325 // We could verify the SPS and PPS data we add, but we don't have great 326 // tooling to do so. Consider doing so in future. 327 } 328 { 329 // Test conversion involving subsample encryption doesn't overflow values. 330 const uint32_t sampleSize = UINT16_MAX * 2; 331 RefPtr<MediaRawData> rawCryptoData{GetHVCCSample(sampleSize)}; 332 // Need to be a keyframe to test prepending SPS + PPS to sample. 333 rawCryptoData->mKeyframe = true; 334 UniquePtr<MediaRawDataWriter> rawDataWriter = rawCryptoData->CreateWriter(); 335 336 rawDataWriter->mCrypto.mCryptoScheme = CryptoScheme::Cenc; 337 338 // We want to check that the clear size doesn't overflow during conversion. 339 // This size originates in a uint16_t, but since it can grow during AnnexB 340 // we cover it here. 341 const uint16_t clearSize = UINT16_MAX - 10; 342 // Set a clear size very close to uint16_t max value. 343 rawDataWriter->mCrypto.mPlainSizes.AppendElement(clearSize); 344 rawDataWriter->mCrypto.mEncryptedSizes.AppendElement(sampleSize - 345 clearSize); 346 347 RefPtr<MediaRawData> rawCryptoDataClone = rawCryptoData->Clone(); 348 Result<Ok, nsresult> result = AnnexB::ConvertHVCCSampleToAnnexB( 349 rawCryptoDataClone, /* aAddSps */ true); 350 EXPECT_TRUE(result.isOk()) << "Conversion should succeed"; 351 EXPECT_GT(rawCryptoDataClone->Size(), rawCryptoData->Size()) 352 << "AnnexB sample should be larger than the HVCC sample because we've " 353 "added SPS data"; 354 EXPECT_GT(rawCryptoDataClone->mCrypto.mPlainSizes[0], 355 rawCryptoData->mCrypto.mPlainSizes[0]) 356 << "Conversion should have increased clear data sizes without overflow"; 357 EXPECT_EQ(rawCryptoDataClone->mCrypto.mEncryptedSizes[0], 358 rawCryptoData->mCrypto.mEncryptedSizes[0]) 359 << "Conversion should not affect encrypted sizes"; 360 EXPECT_TRUE(AnnexB::IsAnnexB(*rawCryptoDataClone)) 361 << "The sample should be AnnexB following conversion"; 362 } 363 } 364 365 TEST(H264, AVCCParsingSuccess) 366 { 367 { 368 // AVCC without SPS, PPS and SPSExt 369 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 370 uint8_t avccBytesBuffer[] = { 371 1 /* version */, 372 0x64 /* profile (High) */, 373 0 /* profile compat (0) */, 374 40 /* level (40) */, 375 0xfc | 3 /* nal size - 1 */, 376 0xe0 /* num SPS (0) */, 377 0 /* num PPS (0) */ 378 }; 379 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 380 auto res = AVCCConfig::Parse(extradata); 381 EXPECT_TRUE(res.isOk()); 382 const auto avcc = res.unwrap(); 383 EXPECT_EQ(avcc.mConfigurationVersion, 1); 384 EXPECT_EQ(avcc.mAVCProfileIndication, 0x64); 385 EXPECT_EQ(avcc.mProfileCompatibility, 0); 386 EXPECT_EQ(avcc.mAVCLevelIndication, 40); 387 EXPECT_EQ(avcc.NALUSize(), 4); 388 EXPECT_EQ(avcc.NumSPS(), 0u); 389 EXPECT_EQ(avcc.NumPPS(), 0u); 390 EXPECT_TRUE(avcc.mChromaFormat.isNothing()); 391 EXPECT_TRUE(avcc.mBitDepthLumaMinus8.isNothing()); 392 EXPECT_TRUE(avcc.mBitDepthChromaMinus8.isNothing()); 393 EXPECT_EQ(avcc.NumSPSExt(), 0u); 394 EXPECT_EQ(avcc.mSPSExts.Length(), 0u); 395 } 396 { 397 // AVCC with SPS, PPS but no chroma format, lumn/chrom bit depth and SPSExt. 398 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 399 const uint8_t avccBytesBuffer[] = { 400 // configurationVersion 401 0x01, 402 // AVCProfileIndication (e.g., High Profile = 100) 403 0x64, 404 // profile_compatibility 405 0x00, 406 // AVCLevelIndication 407 0x1E, 408 // 6 bits reserved (111111) + 2 bits lengthSizeMinusOne (3 -> 4 bytes) 409 0xFF, 410 // 3 bits reserved (111) + 5 bits numOfSPS (1) 411 0xE1, 412 // SPS[0] length = 0x0004 413 0x00, 414 0x04, 415 // SPS NAL unit (fake) 416 0x67, 417 0x64, 418 0x00, 419 0x1F, 420 // numOfPPS = 1 421 0x01, 422 // PPS[0] length = 0x0002 423 0x00, 424 0x02, 425 // PPS NAL unit (fake) 426 0x68, 427 0xCE, 428 }; 429 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 430 auto res = AVCCConfig::Parse(extradata); 431 EXPECT_TRUE(res.isOk()); 432 const auto avcc = res.unwrap(); 433 EXPECT_EQ(avcc.mConfigurationVersion, 1); 434 EXPECT_EQ(avcc.mAVCProfileIndication, 0x64); 435 EXPECT_EQ(avcc.mProfileCompatibility, 0); 436 EXPECT_EQ(avcc.mAVCLevelIndication, 0x1E); 437 EXPECT_EQ(avcc.NALUSize(), 4); 438 EXPECT_EQ(avcc.NumSPS(), 1u); 439 EXPECT_EQ(avcc.NumPPS(), 1u); 440 EXPECT_TRUE(avcc.mChromaFormat.isNothing()); 441 EXPECT_TRUE(avcc.mBitDepthLumaMinus8.isNothing()); 442 EXPECT_TRUE(avcc.mBitDepthChromaMinus8.isNothing()); 443 EXPECT_EQ(avcc.NumSPSExt(), 0u); 444 EXPECT_EQ(avcc.mSPSExts.Length(), 0u); 445 } 446 { 447 // AVCC with SPS, PPS and SPSExt. 448 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 449 const uint8_t avccBytesBuffer[] = { 450 // configurationVersion 451 0x01, 452 // AVCProfileIndication (e.g., High Profile = 100) 453 0x64, 454 // profile_compatibility 455 0x00, 456 // AVCLevelIndication 457 0x1E, 458 // 6 bits reserved (111111) + 2 bits lengthSizeMinusOne (3 -> 4 bytes) 459 0xFF, 460 // 3 bits reserved (111) + 5 bits numOfSPS (1) 461 0xE1, 462 // SPS[0] length = 0x0004 463 0x00, 0x04, 464 // SPS NAL unit (fake) 465 0x67, 0x64, 0x00, 0x1F, 466 // numOfPPS = 1 467 0x01, 468 // PPS[0] length = 0x0002 469 0x00, 0x02, 470 // PPS NAL unit (fake) 471 0x68, 0xCE, 472 // 6 bits reserved (111111) + 2 bits chroma_format (0 -> 4:2:0) 473 0xFC, 474 // 5 bits reserved (11111) + 3 bits bit_depth_luma_minus8 (0 -> 8-bit) 475 0xF8, 476 // 5 bits reserved (11111) + 3 bits bit_depth_chroma_minus8 (0 -> 8-bit) 477 0xF8, 478 // numOfSPSext = 1 479 0x01, 480 // SPS Ext[0] length = 0x0003 481 0x00, 0x03, 482 // SPS Ext NAL unit (fake) 483 0x6D, 0xB2, 0x20}; 484 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 485 auto res = AVCCConfig::Parse(extradata); 486 EXPECT_TRUE(res.isOk()); 487 const auto avcc = res.unwrap(); 488 EXPECT_EQ(avcc.mConfigurationVersion, 1); 489 EXPECT_EQ(avcc.mAVCProfileIndication, 0x64); 490 EXPECT_EQ(avcc.mProfileCompatibility, 0); 491 EXPECT_EQ(avcc.mAVCLevelIndication, 0x1E); 492 EXPECT_EQ(avcc.NALUSize(), 4); 493 EXPECT_EQ(avcc.NumSPS(), 1u); 494 EXPECT_EQ(avcc.NumPPS(), 1u); 495 EXPECT_EQ(*avcc.mChromaFormat, 0); 496 EXPECT_EQ(*avcc.mBitDepthLumaMinus8, 0); 497 EXPECT_EQ(*avcc.mBitDepthChromaMinus8, 0); 498 EXPECT_EQ(avcc.NumSPSExt(), 1u); 499 } 500 // Following part are optional, fail to parse them won't cause an actual error 501 { 502 // SPS Ext length = 0x0004, but only provides 2 bytes of data 503 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 504 const uint8_t avccBytesBuffer[] = { 505 0x01, // configurationVersion 506 0x64, 0x00, 0x1E, // High profile 507 0xFF, // reserved + lengthSizeMinusOne 508 0xE1, // reserved + 1 SPS 509 0x00, 0x01, // SPS length = 1 510 0x67, // SPS NAL 511 0x01, // 1 PPS 512 0x00, 0x01, // PPS length = 1 513 0x68, // PPS NAL 514 0xFC, // expect at least 32 bits but not enough 515 }; 516 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 517 auto res = AVCCConfig::Parse(extradata); 518 EXPECT_TRUE(res.isOk()); 519 const auto avcc = res.unwrap(); 520 EXPECT_EQ(avcc.mConfigurationVersion, 1); 521 EXPECT_EQ(avcc.mAVCProfileIndication, 0x64); 522 EXPECT_EQ(avcc.mProfileCompatibility, 0); 523 EXPECT_EQ(avcc.mAVCLevelIndication, 0x1E); 524 EXPECT_EQ(avcc.NALUSize(), 4); 525 EXPECT_EQ(avcc.NumSPS(), 1u); 526 EXPECT_EQ(avcc.NumPPS(), 1u); 527 EXPECT_TRUE(avcc.mChromaFormat.isNothing()); 528 EXPECT_TRUE(avcc.mBitDepthLumaMinus8.isNothing()); 529 EXPECT_TRUE(avcc.mBitDepthChromaMinus8.isNothing()); 530 EXPECT_EQ(avcc.NumSPSExt(), 0u); 531 } 532 { 533 // SPS Ext length = 0x0004, but only provides 2 bytes of data 534 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 535 const uint8_t avccBytesBuffer[] = { 536 0x01, // configurationVersion 537 0x64, 0x00, 0x1E, // High profile 538 0xFF, // reserved + lengthSizeMinusOne 539 0xE1, // reserved + 1 SPS 540 0x00, 0x01, // SPS length = 1 541 0x67, // SPS NAL 542 0x01, // 1 PPS 543 0x00, 0x01, // PPS length = 1 544 0x68, // PPS NAL 545 0xFC, // reserved + chroma_format=0 546 0xF8, // reserved + bit_depth_luma_minus8=0 547 0xF8, // reserved + bit_depth_chroma_minus8=0 548 0x01, // numOfSPSExt = 1 549 0x00, 0x04, // SPS Ext length = 4 550 0x6A, 0x01 // Only 2 bytes of SPSExt NAL 551 }; 552 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 553 auto res = AVCCConfig::Parse(extradata); 554 EXPECT_TRUE(res.isOk()); 555 const auto avcc = res.unwrap(); 556 EXPECT_EQ(avcc.mConfigurationVersion, 1); 557 EXPECT_EQ(avcc.mAVCProfileIndication, 0x64); 558 EXPECT_EQ(avcc.mProfileCompatibility, 0); 559 EXPECT_EQ(avcc.mAVCLevelIndication, 0x1E); 560 EXPECT_EQ(avcc.NALUSize(), 4); 561 EXPECT_EQ(avcc.NumSPS(), 1u); 562 EXPECT_EQ(avcc.NumPPS(), 1u); 563 EXPECT_EQ(*avcc.mChromaFormat, 0); 564 EXPECT_EQ(*avcc.mBitDepthLumaMinus8, 0); 565 EXPECT_EQ(*avcc.mBitDepthChromaMinus8, 0); 566 EXPECT_EQ(avcc.NumSPSExt(), 0u); 567 } 568 { 569 // Insuffient data, wrong SPSEXT length 570 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 571 const uint8_t avccBytesBuffer[] = { 572 0x01, // configurationVersion 573 0x64, 0x00, 0x1E, // High profile 574 0xFF, // reserved + lengthSizeMinusOne 575 0xE1, // reserved + 1 SPS 576 0x00, 0x01, // SPS length = 1 577 0x67, // SPS NAL 578 0x01, // 1 PPS 579 0x00, 0x01, // PPS length = 1 580 0x68, // PPS NAL 581 0xFC, // reserved + chroma_format=0 582 0xF8, // reserved + bit_depth_luma_minus8=0 583 0xF8, // reserved + bit_depth_chroma_minus8=0 584 0x01, // numOfSPSExt = 1 585 0x00, // Wrong SPS Ext length, should be 16 bits 586 }; 587 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 588 auto res = AVCCConfig::Parse(extradata); 589 EXPECT_TRUE(res.isOk()); 590 const auto avcc = res.unwrap(); 591 EXPECT_EQ(avcc.mConfigurationVersion, 1); 592 EXPECT_EQ(avcc.mAVCProfileIndication, 0x64); 593 EXPECT_EQ(avcc.mProfileCompatibility, 0); 594 EXPECT_EQ(avcc.mAVCLevelIndication, 0x1E); 595 EXPECT_EQ(avcc.NALUSize(), 4); 596 EXPECT_EQ(avcc.NumSPS(), 1u); 597 EXPECT_EQ(avcc.NumPPS(), 1u); 598 EXPECT_EQ(*avcc.mChromaFormat, 0); 599 EXPECT_EQ(*avcc.mBitDepthLumaMinus8, 0); 600 EXPECT_EQ(*avcc.mBitDepthChromaMinus8, 0); 601 EXPECT_EQ(avcc.NumSPSExt(), 0u); 602 } 603 { 604 // Expect SPSExt payload, but the payload is an incorrect NALU type 605 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 606 const uint8_t avccBytesBuffer[] = { 607 0x01, // configurationVersion 608 0x64, 0x00, 0x1E, // High profile 609 0xFF, // reserved + lengthSizeMinusOne 610 0xE1, // reserved + 1 SPS 611 0x00, 0x01, // SPS length = 1 612 0x67, // SPS NAL 613 0x01, // 1 PPS 614 0x00, 0x01, // PPS length = 1 615 0x68, // PPS NAL 616 0xFC, // reserved + chroma_format=0 617 0xF8, // reserved + bit_depth_luma_minus8=0 618 0xF8, // reserved + bit_depth_chroma_minus8=0 619 0x01, // numOfSPSExt = 1 620 0x00, 0x03, // SPS Ext[0] length = 0x0003 621 0x77, 0xB2, 0x20, // Expect SPSExt, but wrong NALU type 622 }; 623 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 624 auto res = AVCCConfig::Parse(extradata); 625 EXPECT_TRUE(res.isOk()); 626 const auto avcc = res.unwrap(); 627 EXPECT_EQ(avcc.mConfigurationVersion, 1); 628 EXPECT_EQ(avcc.mAVCProfileIndication, 0x64); 629 EXPECT_EQ(avcc.mProfileCompatibility, 0); 630 EXPECT_EQ(avcc.mAVCLevelIndication, 0x1E); 631 EXPECT_EQ(avcc.NALUSize(), 4); 632 EXPECT_EQ(avcc.NumSPS(), 1u); 633 EXPECT_EQ(avcc.NumPPS(), 1u); 634 EXPECT_EQ(*avcc.mChromaFormat, 0); 635 EXPECT_EQ(*avcc.mBitDepthLumaMinus8, 0); 636 EXPECT_EQ(*avcc.mBitDepthChromaMinus8, 0); 637 EXPECT_EQ(avcc.NumSPSExt(), 0u); 638 } 639 } 640 641 TEST(H264, AVCCParsingFailure) 642 { 643 { 644 // Incorrect version 645 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 646 uint8_t avccBytesBuffer[] = { 647 2 /* version */, 648 0x64 /* profile (High) */, 649 0 /* profile compat (0) */, 650 40 /* level (40) */, 651 0xfc | 3 /* nal size - 1 */, 652 0xe0 /* num SPS (0) */, 653 0 /* num PPS (0) */ 654 }; 655 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 656 auto avcc = AVCCConfig::Parse(extradata); 657 EXPECT_TRUE(avcc.isErr()); 658 } 659 { 660 // Insuffient data (lacking of PPS) 661 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 662 uint8_t avccBytesBuffer[] = { 663 1 /* version */, 664 0x64 /* profile (High) */, 665 0 /* profile compat (0) */, 666 40 /* level (40) */, 667 0xfc | 3 /* nal size - 1 */, 668 0xe0 /* num SPS (0) */, 669 }; 670 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 671 auto avcc = AVCCConfig::Parse(extradata); 672 EXPECT_TRUE(avcc.isErr()); 673 } 674 { 675 // Insuffient data, wrong SPS length 676 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 677 const uint8_t avccBytesBuffer[] = { 678 0x01, // configurationVersion 679 0x64, 0x00, 0x1E, // profile, compat, level 680 0xFF, // reserved + lengthSizeMinusOne (2 bits) 681 0xE1, // reserved + 1 SPS 682 0x00, // Wrong SPS length, should be 16 bits 683 }; 684 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 685 auto res = AVCCConfig::Parse(extradata); 686 EXPECT_TRUE(res.isErr()); 687 } 688 { 689 // SPS length = 0x0004, but only provides 2 bytes of data 690 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 691 const uint8_t avccBytesBuffer[] = { 692 0x01, // configurationVersion 693 0x64, 0x00, 0x1E, // profile, compat, level 694 0xFF, // reserved + lengthSizeMinusOne (2 bits) 695 0xE1, // reserved + 1 SPS 696 0x00, 0x04, // SPS length = 4 697 0x67, 0x42 // Only 2 bytes of SPS payload (should be 4) 698 }; 699 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 700 auto res = AVCCConfig::Parse(extradata); 701 EXPECT_TRUE(res.isErr()); 702 } 703 { 704 // Expect SPS payload, but the payload is an incorrect NALU type 705 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 706 const uint8_t avccBytesBuffer[] = { 707 0x01, // configurationVersion 708 0x64, 0x00, 0x1E, // profile, compat, level 709 0xFF, // reserved + lengthSizeMinusOne (2 bits) 710 0xE1, // reserved + 1 SPS 711 0x00, 0x02, // SPS length = 2 712 0x55, 0xCE, // Expect SPS, but wrong NALU type 713 }; 714 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 715 auto res = AVCCConfig::Parse(extradata); 716 EXPECT_TRUE(res.isErr()); 717 } 718 { 719 // Missing numOfPictureParameterSets 720 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 721 const uint8_t avccBytesBuffer[] = { 722 0x01, // configurationVersion 723 0x64, 0x00, 0x1E, // profile, compat, level 724 0xFF, // reserved + lengthSizeMinusOne 725 0xE1, // reserved + 1 SPS 726 0x00, 0x02, // SPS length = 2 727 0x67, 0x42, // SPS NAL 728 }; 729 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 730 auto res = AVCCConfig::Parse(extradata); 731 EXPECT_TRUE(res.isErr()); 732 } 733 { 734 // PPS length = 0x0003, but only provides 1 byte of data 735 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 736 const uint8_t avccBytesBuffer[] = { 737 0x01, // configurationVersion 738 0x64, 0x00, 0x1E, // profile, compat, level 739 0xFF, // reserved + lengthSizeMinusOne 740 0xE1, // reserved + 1 SPS 741 0x00, 0x02, // SPS length = 2 742 0x67, 0x42, // SPS NAL 743 0x01, // 1 PPS 744 0x00, 0x03, // PPS length = 3 745 0x68 // Only 1 byte instead of 3 746 }; 747 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 748 auto res = AVCCConfig::Parse(extradata); 749 EXPECT_TRUE(res.isErr()); 750 } 751 { 752 // Insufficient data, wrong PPS length 753 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 754 const uint8_t avccBytesBuffer[] = { 755 0x01, // configurationVersion 756 0x64, 0x00, 0x1E, // profile, compat, level 757 0xFF, // reserved + lengthSizeMinusOne 758 0xE1, // reserved + 1 SPS 759 0x00, 0x02, // SPS length = 2 760 0x67, 0x42, // SPS NAL 761 0x01, // 1 PPS 762 0x00 // Wrong PPS length, should be 16 bits 763 }; 764 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 765 auto res = AVCCConfig::Parse(extradata); 766 EXPECT_TRUE(res.isErr()); 767 } 768 { 769 // Expect PPS payload, but the payload is an incorrect NALU type 770 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 771 const uint8_t avccBytesBuffer[] = { 772 0x01, // configurationVersion 773 0x64, 0x00, 0x1E, // High profile 774 0xFF, // reserved + lengthSizeMinusOne 775 0xE1, // reserved + 1 SPS 776 0x00, 0x01, // SPS length = 1 777 0x67, // SPS NAL 778 0x01, // 1 PPS 779 0x00, 0x01, // PPS length = 1 780 0x70 // Expect PPS, but wrong NALU type 781 }; 782 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 783 auto res = AVCCConfig::Parse(extradata); 784 EXPECT_TRUE(res.isErr()); 785 } 786 } 787 788 TEST(H264, CreateNewExtraData) 789 { 790 // First create an AVCC config without sps, pps 791 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 792 const uint8_t avccBytesBuffer[] = { 793 0x01, // configurationVersion 794 0x64, // AVCProfileIndication (High Profile = 100) 795 0x00, // profile_compatibility 796 0x1E, // AVCLevelIndication (Level 3.0) 797 0xFF, // 6 bits reserved (111111) + 2 bits lengthSizeMinusOne (3 -> 4 798 // bytes) 799 0xE0, // 3 bits reserved (111) + 5 bits numOfSPS = 0 800 0x00, // numOfPPS = 0 801 0xFC, // 6 bits reserved (111111) + 2 bits chroma_format = 0 (4:2:0) 802 0xF8, // 5 bits reserved (11111) + 3 bits bit_depth_luma_minus8 = 0 803 // (8-bit) 804 0xF8, // 5 bits reserved (11111) + 3 bits bit_depth_chroma_minus8 = 0 805 // (8-bit) 806 0x00 // numOfSequenceParameterSetExt = 0 807 }; 808 extradata->AppendElements(avccBytesBuffer, std::size(avccBytesBuffer)); 809 auto res = AVCCConfig::Parse(extradata); 810 EXPECT_TRUE(res.isOk()); 811 auto avcc = res.unwrap(); 812 EXPECT_EQ(avcc.NumSPS(), 0u); 813 EXPECT_EQ(avcc.NumPPS(), 0u); 814 815 // Create new extradata with 1 SPS 816 const uint8_t sps[] = { 817 0x67, 818 0x64, 819 0x00, 820 0x1F, 821 }; 822 H264NALU spsNALU = H264NALU(sps, std::size(sps)); 823 avcc.mSPSs.AppendElement(spsNALU); 824 extradata = avcc.CreateNewExtraData(); 825 res = AVCCConfig::Parse(extradata); 826 EXPECT_TRUE(res.isOk()); 827 avcc = res.unwrap(); 828 EXPECT_EQ(avcc.NumSPS(), 1u); 829 EXPECT_EQ(avcc.NumPPS(), 0u); 830 831 // Create new extradata with 1 SPS and 1 PPS 832 const uint8_t pps[] = { 833 0x68, 834 0xCE, 835 }; 836 H264NALU ppsNALU = H264NALU(pps, std::size(pps)); 837 avcc.mPPSs.AppendElement(ppsNALU); 838 extradata = avcc.CreateNewExtraData(); 839 res = AVCCConfig::Parse(extradata); 840 EXPECT_TRUE(res.isOk()); 841 avcc = res.unwrap(); 842 EXPECT_EQ(avcc.NumSPS(), 1u); 843 EXPECT_EQ(avcc.NumPPS(), 1u); 844 845 // Create new extradata with 2 SPS and 1 PPS 846 avcc.mSPSs.AppendElement(spsNALU); 847 extradata = avcc.CreateNewExtraData(); 848 res = AVCCConfig::Parse(extradata); 849 EXPECT_TRUE(res.isOk()); 850 avcc = res.unwrap(); 851 EXPECT_EQ(avcc.NumSPS(), 2u); 852 EXPECT_EQ(avcc.NumPPS(), 1u); 853 854 // Create new extradata with 2 SPS and 2 PPS 855 avcc.mPPSs.AppendElement(ppsNALU); 856 extradata = avcc.CreateNewExtraData(); 857 res = AVCCConfig::Parse(extradata); 858 EXPECT_TRUE(res.isOk()); 859 avcc = res.unwrap(); 860 EXPECT_EQ(avcc.NumSPS(), 2u); 861 EXPECT_EQ(avcc.NumPPS(), 2u); 862 863 // Besides SPS and PPS, let's ensure chroma_format, bit_depth_luma_minus8 and 864 // bit_depth_chroma_minus8 are preserved correctly as well 865 EXPECT_EQ(*avcc.mChromaFormat, 0); 866 EXPECT_EQ(*avcc.mBitDepthLumaMinus8, 0); 867 EXPECT_EQ(*avcc.mBitDepthChromaMinus8, 0); 868 869 // Use a wrong attribute, which will generate an invalid config 870 avcc.mConfigurationVersion = 5; 871 extradata = avcc.CreateNewExtraData(); 872 res = AVCCConfig::Parse(extradata); 873 EXPECT_TRUE(res.isErr()); 874 } 875 876 TEST(H264, AnnexBExtractExtraDataForAVCC) 877 { 878 // First create an AnnexB config 879 const uint8_t annexBBytesBuffer[]{// AnnexB delimiter 880 0x00, 0x00, 0x00, 0x01, 881 // SPS NAL unit 882 0x67, 0x64, 0x00, 0x1F, 883 // AnnexB delimiter 884 0x00, 0x00, 0x00, 0x01, 885 // PPS NAL unit 886 0x68, 0xCE}; 887 auto annexBExtradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 888 annexBExtradata->AppendElements(annexBBytesBuffer, 889 std::size(annexBBytesBuffer)); 890 891 // Extract the AVCC extradata from the AnnexB bytestream 892 auto avccExtradata = AnnexB::ExtractExtraDataForAVCC(*annexBExtradata); 893 ASSERT_TRUE(!!avccExtradata); 894 895 // Now parse that extradata to make sure it matches the original AnnexB 896 auto res = AVCCConfig::Parse(avccExtradata); 897 ASSERT_TRUE(res.isOk()); 898 auto avcc = res.unwrap(); 899 EXPECT_EQ(avcc.NumSPS(), 1u); 900 EXPECT_EQ(avcc.NumSPSExt(), 0u); 901 EXPECT_EQ(avcc.NumPPS(), 1u); 902 EXPECT_EQ(avcc.NALUSize(), 4); 903 EXPECT_EQ(avcc.mConfigurationVersion, 1u); 904 EXPECT_EQ(avcc.mAVCProfileIndication, 100u); 905 EXPECT_EQ(avcc.mProfileCompatibility, 0u); 906 EXPECT_EQ(avcc.mAVCLevelIndication, 31u); 907 } 908 909 TEST(H265, HVCCParsingSuccess) 910 { 911 { 912 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 913 uint8_t hvccBytesBuffer[] = { 914 1 /* version */, 915 1 /* general_profile_space/general_tier_flag/general_profile_idc */, 916 0x60 /* general_profile_compatibility_flags 1/4 */, 917 0 /* general_profile_compatibility_flags 2/4 */, 918 0 /* general_profile_compatibility_flags 3/4 */, 919 0 /* general_profile_compatibility_flags 4/4 */, 920 0x90 /* general_constraint_indicator_flags 1/6 */, 921 0 /* general_constraint_indicator_flags 2/6 */, 922 0 /* general_constraint_indicator_flags 3/6 */, 923 0 /* general_constraint_indicator_flags 4/6 */, 924 0 /* general_constraint_indicator_flags 5/6 */, 925 0 /* general_constraint_indicator_flags 6/6 */, 926 0x5A /* general_level_idc */, 927 0 /* min_spatial_segmentation_idc 1/2 */, 928 0 /* min_spatial_segmentation_idc 2/2 */, 929 0 /* parallelismType */, 930 1 /* chroma_format_idc */, 931 0 /* bit_depth_luma_minus8 */, 932 0 /* bit_depth_chroma_minus8 */, 933 0 /* avgFrameRate 1/2 */, 934 0 /* avgFrameRate 2/2 */, 935 0x0F /* constantFrameRate/numTemporalLayers/temporalIdNested/lengthSizeMinusOne 936 */ 937 , 938 0 /* numOfArrays */, 939 }; 940 extradata->AppendElements(hvccBytesBuffer, std::size(hvccBytesBuffer)); 941 auto rv = HVCCConfig::Parse(extradata); 942 EXPECT_TRUE(rv.isOk()); 943 auto hvcc = rv.unwrap(); 944 EXPECT_EQ(hvcc.configurationVersion, 1); 945 EXPECT_EQ(hvcc.general_profile_space, 0); 946 EXPECT_EQ(hvcc.general_tier_flag, false); 947 EXPECT_EQ(hvcc.general_profile_idc, 1); 948 EXPECT_EQ(hvcc.general_profile_compatibility_flags, (uint32_t)0x60000000); 949 EXPECT_EQ(hvcc.general_constraint_indicator_flags, 950 (uint64_t)0x900000000000); 951 EXPECT_EQ(hvcc.general_level_idc, 0x5A); 952 EXPECT_EQ(hvcc.min_spatial_segmentation_idc, 0); 953 EXPECT_EQ(hvcc.parallelismType, 0); 954 EXPECT_EQ(hvcc.chroma_format_idc, 1); 955 EXPECT_EQ(hvcc.bit_depth_luma_minus8, 0); 956 EXPECT_EQ(hvcc.bit_depth_chroma_minus8, 0); 957 EXPECT_EQ(hvcc.avgFrameRate, 0); 958 EXPECT_EQ(hvcc.constantFrameRate, 0); 959 EXPECT_EQ(hvcc.numTemporalLayers, 1); 960 EXPECT_EQ(hvcc.temporalIdNested, true); 961 EXPECT_EQ(hvcc.NALUSize(), 4); 962 EXPECT_EQ(hvcc.mNALUs.Length(), uint32_t(0)); 963 } 964 { 965 // Multple NALUs 966 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 967 uint8_t hvccBytesBuffer[] = { 968 1 /* version */, 969 1 /* general_profile_space/general_tier_flag/general_profile_idc */, 970 0x60 /* general_profile_compatibility_flags 1/4 */, 971 0 /* general_profile_compatibility_flags 2/4 */, 972 0 /* general_profile_compatibility_flags 3/4 */, 973 0 /* general_profile_compatibility_flags 4/4 */, 974 0x90 /* general_constraint_indicator_flags 1/6 */, 975 0 /* general_constraint_indicator_flags 2/6 */, 976 0 /* general_constraint_indicator_flags 3/6 */, 977 0 /* general_constraint_indicator_flags 4/6 */, 978 0 /* general_constraint_indicator_flags 5/6 */, 979 0 /* general_constraint_indicator_flags 6/6 */, 980 0x5A /* general_level_idc */, 981 0 /* min_spatial_segmentation_idc 1/2 */, 982 0 /* min_spatial_segmentation_idc 2/2 */, 983 0 /* parallelismType */, 984 1 /* chroma_format_idc */, 985 0 /* bit_depth_luma_minus8 */, 986 0 /* bit_depth_chroma_minus8 */, 987 0 /* avgFrameRate 1/2 */, 988 0 /* avgFrameRate 2/2 */, 989 0x0F /* constantFrameRate/numTemporalLayers/temporalIdNested/lengthSizeMinusOne 990 */ 991 , 992 2 /* numOfArrays */, 993 /* SPS Array */ 994 0x21 /* NAL_unit_type (SPS) */, 995 0 /* numNalus 1/2 */, 996 1 /* numNalus 2/2 */, 997 998 /* SPS */ 999 0 /* nalUnitLength 1/2 */, 1000 8 /* nalUnitLength 2/2 (header + rsbp) */, 1001 0x42 /* NALU header 1/2 */, 1002 0 /* NALU header 2/2 */, 1003 0 /* rbsp 1/6 */, 1004 0 /* rbsp 2/6 */, 1005 0 /* rbsp 3/6 */, 1006 0 /* rbsp 4/6 */, 1007 0 /* rbsp 5/6 */, 1008 0 /* rbsp 6/6 */, 1009 1010 /* PPS Array */ 1011 0x22 /* NAL_unit_type (PPS) */, 1012 0 /* numNalus 1/2 */, 1013 2 /* numNalus 2/2 */, 1014 1015 /* PPS 1 */ 1016 0 /* nalUnitLength 1/2 */, 1017 3 /* nalUnitLength 2/2 (header + rsbp) */, 1018 0x44 /* NALU header 1/2 */, 1019 0 /* NALU header 2/2 */, 1020 0 /* rbsp */, 1021 1022 /* PPS 2 */ 1023 0 /* nalUnitLength 1/2 */, 1024 3 /* nalUnitLength 2/2 (header + rsbp) */, 1025 0x44 /* NALU header 1/2 */, 1026 0 /* NALU header 2/2 */, 1027 0 /* rbsp */, 1028 }; 1029 extradata->AppendElements(hvccBytesBuffer, std::size(hvccBytesBuffer)); 1030 auto rv = HVCCConfig::Parse(extradata); 1031 EXPECT_TRUE(rv.isOk()); 1032 auto hvcc = rv.unwrap(); 1033 // Check NALU, it should contain 1 SPS and 2 PPS. 1034 EXPECT_EQ(hvcc.mNALUs.Length(), uint32_t(3)); 1035 EXPECT_EQ(hvcc.mNALUs[0].mNalUnitType, H265NALU::NAL_TYPES::SPS_NUT); 1036 EXPECT_EQ(hvcc.mNALUs[0].mNuhLayerId, 0); 1037 EXPECT_EQ(hvcc.mNALUs[0].mNuhTemporalIdPlus1, 0); 1038 EXPECT_EQ(hvcc.mNALUs[0].IsSPS(), true); 1039 EXPECT_EQ(hvcc.mNALUs[0].mNALU.Length(), 8u); 1040 1041 EXPECT_EQ(hvcc.mNALUs[1].mNalUnitType, H265NALU::NAL_TYPES::PPS_NUT); 1042 EXPECT_EQ(hvcc.mNALUs[1].mNuhLayerId, 0); 1043 EXPECT_EQ(hvcc.mNALUs[1].mNuhTemporalIdPlus1, 0); 1044 EXPECT_EQ(hvcc.mNALUs[1].IsSPS(), false); 1045 EXPECT_EQ(hvcc.mNALUs[1].mNALU.Length(), 3u); 1046 1047 EXPECT_EQ(hvcc.mNALUs[2].mNalUnitType, H265NALU::NAL_TYPES::PPS_NUT); 1048 EXPECT_EQ(hvcc.mNALUs[2].mNuhLayerId, 0); 1049 EXPECT_EQ(hvcc.mNALUs[2].mNuhTemporalIdPlus1, 0); 1050 EXPECT_EQ(hvcc.mNALUs[2].IsSPS(), false); 1051 EXPECT_EQ(hvcc.mNALUs[2].mNALU.Length(), 3u); 1052 } 1053 } 1054 1055 TEST(H265, HVCCParsingFailure) 1056 { 1057 { 1058 // Incorrect version 1059 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 1060 uint8_t hvccBytesBuffer[] = { 1061 2 /* version */, 1062 1 /* general_profile_space/general_tier_flag/general_profile_idc */, 1063 0x60 /* general_profile_compatibility_flags 1/4 */, 1064 0 /* general_profile_compatibility_flags 2/4 */, 1065 0 /* general_profile_compatibility_flags 3/4 */, 1066 0 /* general_profile_compatibility_flags 4/4 */, 1067 0x90 /* general_constraint_indicator_flags 1/6 */, 1068 0 /* general_constraint_indicator_flags 2/6 */, 1069 0 /* general_constraint_indicator_flags 3/6 */, 1070 0 /* general_constraint_indicator_flags 4/6 */, 1071 0 /* general_constraint_indicator_flags 5/6 */, 1072 0 /* general_constraint_indicator_flags 6/6 */, 1073 0x5A /* general_level_idc */, 1074 0 /* min_spatial_segmentation_idc 1/2 */, 1075 0 /* min_spatial_segmentation_idc 2/2 */, 1076 0 /* parallelismType */, 1077 1 /* chroma_format_idc */, 1078 0 /* bit_depth_luma_minus8 */, 1079 0 /* bit_depth_chroma_minus8 */, 1080 0 /* avgFrameRate 1/2 */, 1081 0 /* avgFrameRate 2/2 */, 1082 0x0F /* constantFrameRate/numTemporalLayers/temporalIdNested/lengthSizeMinusOne 1083 */ 1084 , 1085 0 /* numOfArrays */, 1086 }; 1087 extradata->AppendElements(hvccBytesBuffer, std::size(hvccBytesBuffer)); 1088 auto avcc = HVCCConfig::Parse(extradata); 1089 EXPECT_TRUE(avcc.isErr()); 1090 } 1091 { 1092 // Insuffient data 1093 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 1094 uint8_t hvccBytesBuffer[] = { 1095 1 /* version */, 1096 1 /* general_profile_space/general_tier_flag/general_profile_idc */, 1097 0x60 /* general_profile_compatibility_flags 1/4 */, 1098 0 /* general_profile_compatibility_flags 2/4 */, 1099 0 /* general_profile_compatibility_flags 3/4 */, 1100 0 /* general_profile_compatibility_flags 4/4 */, 1101 0x90 /* general_constraint_indicator_flags 1/6 */, 1102 0 /* general_constraint_indicator_flags 2/6 */, 1103 0 /* general_constraint_indicator_flags 3/6 */, 1104 0 /* general_constraint_indicator_flags 4/6 */, 1105 0 /* general_constraint_indicator_flags 5/6 */, 1106 0 /* general_constraint_indicator_flags 6/6 */, 1107 0x5A /* general_level_idc */ 1108 }; 1109 extradata->AppendElements(hvccBytesBuffer, std::size(hvccBytesBuffer)); 1110 auto avcc = HVCCConfig::Parse(extradata); 1111 EXPECT_TRUE(avcc.isErr()); 1112 } 1113 } 1114 1115 TEST(H265, HVCCToAnnexB) 1116 { 1117 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 1118 uint8_t hvccBytesBuffer[] = { 1119 1 /* version */, 1120 1 /* general_profile_space/general_tier_flag/general_profile_idc */, 1121 0x60 /* general_profile_compatibility_flags 1/4 */, 1122 0 /* general_profile_compatibility_flags 2/4 */, 1123 0 /* general_profile_compatibility_flags 3/4 */, 1124 0 /* general_profile_compatibility_flags 4/4 */, 1125 0x90 /* general_constraint_indicator_flags 1/6 */, 1126 0 /* general_constraint_indicator_flags 2/6 */, 1127 0 /* general_constraint_indicator_flags 3/6 */, 1128 0 /* general_constraint_indicator_flags 4/6 */, 1129 0 /* general_constraint_indicator_flags 5/6 */, 1130 0 /* general_constraint_indicator_flags 6/6 */, 1131 0x5A /* general_level_idc */, 1132 0 /* min_spatial_segmentation_idc 1/2 */, 1133 0 /* min_spatial_segmentation_idc 2/2 */, 1134 0 /* parallelismType */, 1135 1 /* chroma_format_idc */, 1136 0 /* bit_depth_luma_minus8 */, 1137 0 /* bit_depth_chroma_minus8 */, 1138 0 /* avgFrameRate 1/2 */, 1139 0 /* avgFrameRate 2/2 */, 1140 0x0F /* constantFrameRate/numTemporalLayers/temporalIdNested/lengthSizeMinusOne 1141 */ 1142 , 1143 2 /* numOfArrays */, 1144 /* SPS Array */ 1145 0x21 /* NAL_unit_type (SPS) */, 1146 0 /* numNalus 1/2 */, 1147 1 /* numNalus 2/2 */, 1148 1149 /* SPS */ 1150 0 /* nalUnitLength 1/2 */, 1151 3 /* nalUnitLength 2/2 (header + rsbp) */, 1152 0x42 /* NALU header 1/2 */, 1153 0 /* NALU header 2/2 */, 1154 0 /* rbsp */, 1155 1156 /* PPS Array */ 1157 0x22 /* NAL_unit_type (PPS) */, 1158 0 /* numNalus 1/2 */, 1159 1 /* numNalus 2/2 */, 1160 1161 /* PPS */ 1162 0 /* nalUnitLength 1/2 */, 1163 3 /* nalUnitLength 2/2 (header + rsbp) */, 1164 0x44 /* NALU header 1/2 */, 1165 0 /* NALU header 2/2 */, 1166 0 /* rbsp */, 1167 }; 1168 extradata->AppendElements(hvccBytesBuffer, std::size(hvccBytesBuffer)); 1169 1170 // We convert hvcc extra-data to annexb format, then parse each nalu to see if 1171 // they are still correct or not. 1172 const size_t naluBytesSize = 3; // NAL size is 3, see nalUnitLength above 1173 const size_t delimiterBytesSize = 4; // 0x00000001 1174 const size_t naluPlusDelimiterBytesSize = naluBytesSize + delimiterBytesSize; 1175 RefPtr<mozilla::MediaByteBuffer> annexBExtraData = 1176 AnnexB::ConvertHVCCExtraDataToAnnexB(extradata); 1177 // 2 NALU, sps and pps 1178 EXPECT_EQ(annexBExtraData->Length(), naluPlusDelimiterBytesSize * 2); 1179 1180 H265NALU sps( 1181 static_cast<uint8_t*>(annexBExtraData->Elements() + delimiterBytesSize), 1182 naluBytesSize); 1183 EXPECT_EQ(sps.mNalUnitType, H265NALU::NAL_TYPES::SPS_NUT); 1184 EXPECT_EQ(sps.mNuhLayerId, 0); 1185 EXPECT_EQ(sps.mNuhTemporalIdPlus1, 0); 1186 EXPECT_EQ(sps.IsSPS(), true); 1187 EXPECT_EQ(sps.mNALU.Length(), 3u); 1188 1189 H265NALU pps( 1190 static_cast<uint8_t*>(annexBExtraData->Elements() + 1191 naluPlusDelimiterBytesSize + delimiterBytesSize), 1192 naluBytesSize); 1193 EXPECT_EQ(pps.mNalUnitType, H265NALU::NAL_TYPES::PPS_NUT); 1194 EXPECT_EQ(pps.mNuhLayerId, 0); 1195 EXPECT_EQ(pps.mNuhTemporalIdPlus1, 0); 1196 EXPECT_EQ(pps.IsSPS(), false); 1197 EXPECT_EQ(pps.mNALU.Length(), 3u); 1198 } 1199 1200 TEST(H265, AnnexBToHVCC) 1201 { 1202 RefPtr<MediaRawData> rawData{GetHVCCSample(128)}; 1203 RefPtr<MediaRawData> rawDataClone = rawData->Clone(); 1204 Result<Ok, nsresult> result = 1205 AnnexB::ConvertHVCCSampleToAnnexB(rawDataClone, /* aAddSps */ false); 1206 EXPECT_TRUE(result.isOk()) << "HVCC to AnnexB Conversion should succeed"; 1207 EXPECT_TRUE(AnnexB::IsAnnexB(*rawDataClone)) 1208 << "The sample should be AnnexB following conversion"; 1209 1210 auto rv = AnnexB::ConvertSampleToHVCC(rawDataClone); 1211 EXPECT_TRUE(rv.isOk()) << "AnnexB to HVCC Conversion should succeed"; 1212 EXPECT_TRUE(AnnexB::IsHVCC(rawDataClone)) 1213 << "The sample should be HVCC following conversion"; 1214 } 1215 1216 // This is SPS from 'hevc_white_frame.mp4' 1217 static const uint8_t sSps[] = { 1218 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 1219 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x5d, 0xa0, 0x02, 0x00, 0x80, 1220 0x30, 0x16, 0x59, 0x59, 0xa4, 0x93, 0x2b, 0xc0, 0x5a, 0x02, 0x00, 1221 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x3c, 0x10}; 1222 1223 // This is VPS from 'hevc_white_frame.mp4' 1224 static const uint8_t sVps[] = {0x40, 0x01, 0x0C, 0x01, 0xFF, 0xFF, 0x01, 0x60, 1225 0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x03, 1226 0x00, 0x00, 0x03, 0x00, 0x3F, 0x95, 0x98, 0x09}; 1227 1228 // This is PPS from 'hevc_white_frame.mp4' 1229 static const uint8_t sPps[] = {0x44, 0x01, 0xC1, 0x72, 0xB4, 0x62, 0x40}; 1230 1231 TEST(H265, ExtractHVCCExtraData) 1232 { 1233 RefPtr<MediaRawData> rawData{GetHVCCSample(sSps, std::size(sSps))}; 1234 RefPtr<MediaByteBuffer> extradata = H265::ExtractHVCCExtraData(rawData); 1235 EXPECT_TRUE(extradata); 1236 auto rv = HVCCConfig::Parse(extradata); 1237 EXPECT_TRUE(rv.isOk()); 1238 auto hvcc = rv.unwrap(); 1239 EXPECT_EQ(hvcc.mNALUs.Length(), 1u); 1240 EXPECT_EQ(hvcc.mNALUs[0].mNalUnitType, H265NALU::NAL_TYPES::SPS_NUT); 1241 EXPECT_EQ(hvcc.mNALUs[0].mNuhLayerId, 0u); 1242 EXPECT_EQ(hvcc.mNALUs[0].mNuhTemporalIdPlus1, 1); 1243 EXPECT_EQ(hvcc.mNALUs[0].IsSPS(), true); 1244 EXPECT_EQ(hvcc.mNALUs[0].mNALU.Length(), 43u); 1245 1246 nsTArray<Span<const uint8_t>> nalus; 1247 nalus.AppendElement(Span<const uint8_t>{sSps, std::size(sSps)}); 1248 nalus.AppendElement(Span<const uint8_t>{sVps, std::size(sVps)}); 1249 nalus.AppendElement(Span<const uint8_t>{sPps, std::size(sPps)}); 1250 1251 RefPtr<MediaRawData> rawData2{GetHVCCSamples(nalus)}; 1252 RefPtr<MediaByteBuffer> extradata2 = H265::ExtractHVCCExtraData(rawData2); 1253 EXPECT_TRUE(extradata2); 1254 auto rv2 = HVCCConfig::Parse(extradata2); 1255 EXPECT_TRUE(rv2.isOk()); 1256 auto hvcc2 = rv2.unwrap(); 1257 EXPECT_EQ(hvcc2.mNALUs.Length(), 3u); 1258 1259 EXPECT_EQ(hvcc2.mNALUs[0].mNalUnitType, H265NALU::NAL_TYPES::VPS_NUT); 1260 EXPECT_EQ(hvcc2.mNALUs[0].mNuhLayerId, 0u); 1261 EXPECT_EQ(hvcc2.mNALUs[0].mNuhTemporalIdPlus1, 1); 1262 EXPECT_EQ(hvcc2.mNALUs[0].IsVPS(), true); 1263 EXPECT_EQ(hvcc2.mNALUs[0].mNALU.Length(), std::size(sVps)); 1264 1265 EXPECT_EQ(hvcc2.mNALUs[1].mNalUnitType, H265NALU::NAL_TYPES::SPS_NUT); 1266 EXPECT_EQ(hvcc2.mNALUs[1].mNuhLayerId, 0u); 1267 EXPECT_EQ(hvcc2.mNALUs[1].mNuhTemporalIdPlus1, 1); 1268 EXPECT_EQ(hvcc2.mNALUs[1].IsSPS(), true); 1269 EXPECT_EQ(hvcc2.mNALUs[1].mNALU.Length(), std::size(sSps)); 1270 1271 EXPECT_EQ(hvcc2.mNALUs[2].mNalUnitType, H265NALU::NAL_TYPES::PPS_NUT); 1272 EXPECT_EQ(hvcc2.mNALUs[2].mNuhLayerId, 0u); 1273 EXPECT_EQ(hvcc2.mNALUs[2].mNuhTemporalIdPlus1, 1); 1274 EXPECT_EQ(hvcc2.mNALUs[2].IsPPS(), true); 1275 EXPECT_EQ(hvcc2.mNALUs[2].mNALU.Length(), std::size(sPps)); 1276 } 1277 1278 TEST(H265, DecodeSPSFromSPSNALU) 1279 { 1280 H265NALU nalu{sSps, std::size(sSps)}; 1281 auto rv = H265::DecodeSPSFromSPSNALU(nalu); 1282 EXPECT_TRUE(rv.isOk()); 1283 auto sps = rv.unwrap(); 1284 // Examine the value by using HEVCESBrowser. 1285 EXPECT_EQ(sps.sps_video_parameter_set_id, 0u); 1286 EXPECT_EQ(sps.sps_max_sub_layers_minus1, 0u); 1287 EXPECT_EQ(sps.sps_temporal_id_nesting_flag, 1); 1288 EXPECT_EQ(sps.profile_tier_level.general_profile_space, 0u); 1289 EXPECT_EQ(sps.profile_tier_level.general_tier_flag, false); 1290 EXPECT_EQ(sps.profile_tier_level.general_profile_idc, 1u); 1291 EXPECT_EQ(sps.profile_tier_level.general_profile_compatibility_flags, 1292 0x60000000u); 1293 EXPECT_EQ(sps.profile_tier_level.general_progressive_source_flag, true); 1294 EXPECT_EQ(sps.profile_tier_level.general_interlaced_source_flag, false); 1295 EXPECT_EQ(sps.profile_tier_level.general_non_packed_constraint_flag, false); 1296 EXPECT_EQ(sps.profile_tier_level.general_frame_only_constraint_flag, true); 1297 EXPECT_EQ(sps.profile_tier_level.general_level_idc, 93u); 1298 EXPECT_EQ(sps.sps_seq_parameter_set_id, 0u); 1299 EXPECT_EQ(sps.chroma_format_idc, 1u); 1300 EXPECT_EQ(sps.separate_colour_plane_flag, false); 1301 EXPECT_EQ(sps.pic_width_in_luma_samples, 1024u); 1302 EXPECT_EQ(sps.pic_height_in_luma_samples, 768u); 1303 EXPECT_EQ(sps.conformance_window_flag, false); 1304 EXPECT_EQ(sps.bit_depth_luma_minus8, 0u); 1305 EXPECT_EQ(sps.bit_depth_chroma_minus8, 0u); 1306 EXPECT_EQ(sps.log2_max_pic_order_cnt_lsb_minus4, 4u); 1307 EXPECT_EQ(sps.sps_sub_layer_ordering_info_present_flag, true); 1308 EXPECT_EQ(sps.sps_max_dec_pic_buffering_minus1[0], 4u); 1309 EXPECT_EQ(sps.sps_max_num_reorder_pics[0], 2u); 1310 EXPECT_EQ(sps.sps_max_latency_increase_plus1[0], 5u); 1311 EXPECT_EQ(sps.log2_min_luma_coding_block_size_minus3, 0u); 1312 EXPECT_EQ(sps.log2_diff_max_min_luma_coding_block_size, 3u); 1313 EXPECT_EQ(sps.log2_min_luma_transform_block_size_minus2, 0u); 1314 EXPECT_EQ(sps.log2_diff_max_min_luma_transform_block_size, 3u); 1315 EXPECT_EQ(sps.max_transform_hierarchy_depth_inter, 0u); 1316 EXPECT_EQ(sps.max_transform_hierarchy_depth_inter, 0u); 1317 EXPECT_EQ(sps.pcm_enabled_flag, false); 1318 EXPECT_EQ(sps.num_short_term_ref_pic_sets, 0u); 1319 EXPECT_EQ(sps.sps_temporal_mvp_enabled_flag, true); 1320 EXPECT_EQ(sps.strong_intra_smoothing_enabled_flag, true); 1321 EXPECT_TRUE(sps.vui_parameters); 1322 EXPECT_EQ(sps.vui_parameters->video_full_range_flag, false); 1323 1324 // Test public methods 1325 EXPECT_EQ(sps.BitDepthLuma(), 8u); 1326 EXPECT_EQ(sps.BitDepthChroma(), 8u); 1327 const auto imgSize = sps.GetImageSize(); 1328 EXPECT_EQ(imgSize.Width(), 1024); 1329 EXPECT_EQ(imgSize.Height(), 768); 1330 const auto disSize = sps.GetDisplaySize(); 1331 EXPECT_EQ(disSize, imgSize); 1332 EXPECT_EQ(sps.ColorDepth(), gfx::ColorDepth::COLOR_8); 1333 EXPECT_EQ(sps.ColorSpace(), gfx::YUVColorSpace::BT709); 1334 EXPECT_EQ(sps.IsFullColorRange(), false); 1335 EXPECT_EQ(sps.ColorPrimaries(), 2u); 1336 EXPECT_EQ(sps.TransferFunction(), 2u); 1337 } 1338 1339 TEST(H265, SPSIteratorAndCreateNewExtraData) 1340 { 1341 // The fake extradata has 3 NALUs (1 vps, 1 sps and 1 pps). 1342 RefPtr<MediaByteBuffer> extradata = H265::CreateFakeExtraData(); 1343 EXPECT_TRUE(extradata); 1344 auto rv = HVCCConfig::Parse(extradata); 1345 EXPECT_TRUE(rv.isOk()); 1346 auto hvcc = rv.unwrap(); 1347 EXPECT_EQ(hvcc.mNALUs.Length(), 3u); 1348 EXPECT_EQ(hvcc.NumSPS(), 1u); 1349 1350 // SPSIterator should be able to access the SPS 1351 SPSIterator it(hvcc); 1352 auto* sps = *it; 1353 EXPECT_TRUE(sps); 1354 1355 // This SPS should match the one retrieved from the HVCC. 1356 auto spsMaybe = hvcc.GetFirstAvaiableNALU(H265NALU::NAL_TYPES::SPS_NUT); 1357 EXPECT_TRUE(spsMaybe); 1358 auto rv1 = H265::DecodeSPSFromSPSNALU(*sps); 1359 auto rv2 = H265::DecodeSPSFromSPSNALU(spsMaybe.ref()); 1360 EXPECT_TRUE(rv1.isOk()); 1361 EXPECT_TRUE(rv2.isOk()); 1362 EXPECT_EQ(rv1.unwrap(), rv2.unwrap()); 1363 1364 // The iterator becomes invalid after advancing, as there is only one SPS. 1365 EXPECT_FALSE(*(++it)); 1366 1367 // Retrieve other NALUs to test the creation of new extradata. 1368 auto ppsMaybe = hvcc.GetFirstAvaiableNALU(H265NALU::NAL_TYPES::PPS_NUT); 1369 EXPECT_TRUE(ppsMaybe); 1370 auto vpsMaybe = hvcc.GetFirstAvaiableNALU(H265NALU::NAL_TYPES::VPS_NUT); 1371 EXPECT_TRUE(vpsMaybe); 1372 nsTArray<H265NALU> nalus; 1373 nalus.AppendElement(*spsMaybe); 1374 nalus.AppendElement(*ppsMaybe); 1375 nalus.AppendElement(*vpsMaybe); 1376 RefPtr<MediaByteBuffer> newExtradata = H265::CreateNewExtraData(hvcc, nalus); 1377 EXPECT_TRUE(newExtradata); 1378 1379 // The new extradata should match the original extradata. 1380 auto rv3 = HVCCConfig::Parse(extradata); 1381 EXPECT_TRUE(rv3.isOk()); 1382 auto hvcc2 = rv3.unwrap(); 1383 EXPECT_EQ(hvcc.mNALUs.Length(), hvcc2.mNALUs.Length()); 1384 EXPECT_EQ(hvcc.NumSPS(), hvcc2.NumSPS()); 1385 } 1386 1387 TEST(H265, ConfWindowTest) 1388 { 1389 // This sps contains some cropping information, which will crop video from the 1390 // resolution 3840x2176 to 3840x2160. 1391 static const uint8_t sSpsConfWindow[] = { 1392 0x42, 0x01, 0x01, 0x01, 0x40, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 1393 0x00, 0x00, 0x99, 0xA0, 0x01, 0xE0, 0x20, 0x02, 0x20, 0x7C, 0x4E, 0x59, 1394 0x95, 0x29, 0x08, 0x46, 0x46, 0xFF, 0xC3, 0x01, 0x6A, 0x02, 0x02, 0x02, 1395 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0xE3, 0x00, 0x2E, 0xF2, 1396 0x88, 0x00, 0x02, 0x62, 0x5A, 0x00, 0x00, 0x13, 0x12, 0xD0, 0x20}; 1397 1398 H265NALU nalu{sSpsConfWindow, std::size(sSpsConfWindow)}; 1399 auto rv = H265::DecodeSPSFromSPSNALU(nalu); 1400 EXPECT_TRUE(rv.isOk()); 1401 auto sps = rv.unwrap(); 1402 EXPECT_EQ(sps.chroma_format_idc, 1u); 1403 EXPECT_EQ(sps.pic_width_in_luma_samples, 3840u); 1404 EXPECT_EQ(sps.pic_height_in_luma_samples, 2176u); 1405 EXPECT_EQ(sps.conformance_window_flag, true); 1406 EXPECT_EQ(sps.conf_win_left_offset, 0u); 1407 EXPECT_EQ(sps.conf_win_right_offset, 0u); 1408 EXPECT_EQ(sps.conf_win_top_offset, 0u); 1409 EXPECT_EQ(sps.conf_win_bottom_offset, 8u); 1410 1411 const auto imgSize = sps.GetImageSize(); 1412 EXPECT_EQ(imgSize.Width(), 3840); 1413 EXPECT_EQ(imgSize.Height(), 2160); // cropped height 1414 1415 const auto disSize = sps.GetDisplaySize(); 1416 EXPECT_EQ(disSize, imgSize); 1417 } 1418 1419 TEST(H265, ColorPrimariesTest) 1420 { 1421 // This sps contains a BT2020 color primaries information. 1422 static const uint8_t sSPSColorPrimariesBT2020[] = { 1423 0x42, 0x01, 0x01, 0x02, 0x20, 0x00, 0x00, 0x03, 0x00, 0xB0, 0x00, 0x00, 1424 0x03, 0x00, 0x00, 0x03, 0x00, 0xB4, 0xA0, 0x01, 0xF8, 0x20, 0x02, 0xF4, 1425 0x4D, 0x88, 0x17, 0xB9, 0x16, 0x55, 0x35, 0x09, 0x10, 0x09, 0x00, 0x80}; 1426 1427 H265NALU nalu{sSPSColorPrimariesBT2020, std::size(sSPSColorPrimariesBT2020)}; 1428 auto rv = H265::DecodeSPSFromSPSNALU(nalu); 1429 EXPECT_TRUE(rv.isOk()); 1430 auto sps = rv.unwrap(); 1431 EXPECT_EQ(sps.ColorPrimaries(), 9 /* CP_BT2020 */); 1432 } 1433 1434 } // namespace mozilla