github.com/bluenviron/mediacommon@v1.9.3/pkg/codecs/h264/sps.go (about) 1 package h264 2 3 import ( 4 "fmt" 5 6 "github.com/bluenviron/mediacommon/pkg/bits" 7 ) 8 9 const ( 10 maxRefFrames = 255 11 ) 12 13 func readScalingList(buf []byte, pos *int, size int) ([]int32, bool, error) { 14 lastScale := int32(8) 15 nextScale := int32(8) 16 scalingList := make([]int32, size) 17 var useDefaultScalingMatrixFlag bool 18 19 for j := 0; j < size; j++ { 20 if nextScale != 0 { 21 deltaScale, err := bits.ReadGolombSigned(buf, pos) 22 if err != nil { 23 return nil, false, err 24 } 25 26 nextScale = (lastScale + deltaScale + 256) % 256 27 useDefaultScalingMatrixFlag = (j == 0 && nextScale == 0) 28 } 29 30 if nextScale == 0 { 31 scalingList[j] = lastScale 32 } else { 33 scalingList[j] = nextScale 34 } 35 36 lastScale = scalingList[j] 37 } 38 39 return scalingList, useDefaultScalingMatrixFlag, nil 40 } 41 42 // SPS_HRD is a hypotetical reference decoder. 43 type SPS_HRD struct { //nolint:revive 44 CpbCntMinus1 uint32 45 BitRateScale uint8 46 CpbSizeScale uint8 47 BitRateValueMinus1 []uint32 48 CpbSizeValueMinus1 []uint32 49 CbrFlag []bool 50 InitialCpbRemovalDelayLengthMinus1 uint8 51 CpbRemovalDelayLengthMinus1 uint8 52 DpbOutputDelayLengthMinus1 uint8 53 TimeOffsetLength uint8 54 } 55 56 func (h *SPS_HRD) unmarshal(buf []byte, pos *int) error { 57 var err error 58 h.CpbCntMinus1, err = bits.ReadGolombUnsigned(buf, pos) 59 if err != nil { 60 return err 61 } 62 63 err = bits.HasSpace(buf, *pos, 8) 64 if err != nil { 65 return err 66 } 67 68 h.BitRateScale = uint8(bits.ReadBitsUnsafe(buf, pos, 4)) 69 h.CpbSizeScale = uint8(bits.ReadBitsUnsafe(buf, pos, 4)) 70 71 for i := uint32(0); i <= h.CpbCntMinus1; i++ { 72 v, err := bits.ReadGolombUnsigned(buf, pos) 73 if err != nil { 74 return err 75 } 76 h.BitRateValueMinus1 = append(h.BitRateValueMinus1, v) 77 78 v, err = bits.ReadGolombUnsigned(buf, pos) 79 if err != nil { 80 return err 81 } 82 h.CpbSizeValueMinus1 = append(h.CpbSizeValueMinus1, v) 83 84 vb, err := bits.ReadFlag(buf, pos) 85 if err != nil { 86 return err 87 } 88 h.CbrFlag = append(h.CbrFlag, vb) 89 } 90 91 err = bits.HasSpace(buf, *pos, 5+5+5+5) 92 if err != nil { 93 return err 94 } 95 96 h.InitialCpbRemovalDelayLengthMinus1 = uint8(bits.ReadBitsUnsafe(buf, pos, 5)) 97 h.CpbRemovalDelayLengthMinus1 = uint8(bits.ReadBitsUnsafe(buf, pos, 5)) 98 h.DpbOutputDelayLengthMinus1 = uint8(bits.ReadBitsUnsafe(buf, pos, 5)) 99 h.TimeOffsetLength = uint8(bits.ReadBitsUnsafe(buf, pos, 5)) 100 101 return nil 102 } 103 104 // SPS_TimingInfo is a timing info. 105 type SPS_TimingInfo struct { //nolint:revive 106 NumUnitsInTick uint32 107 TimeScale uint32 108 FixedFrameRateFlag bool 109 } 110 111 func (t *SPS_TimingInfo) unmarshal(buf []byte, pos *int) error { 112 err := bits.HasSpace(buf, *pos, 32+32+1) 113 if err != nil { 114 return err 115 } 116 117 t.NumUnitsInTick = uint32(bits.ReadBitsUnsafe(buf, pos, 32)) 118 t.TimeScale = uint32(bits.ReadBitsUnsafe(buf, pos, 32)) 119 t.FixedFrameRateFlag = bits.ReadFlagUnsafe(buf, pos) 120 121 return nil 122 } 123 124 // SPS_BitstreamRestriction are bitstream restriction infos. 125 type SPS_BitstreamRestriction struct { //nolint:revive 126 MotionVectorsOverPicBoundariesFlag bool 127 MaxBytesPerPicDenom uint32 128 MaxBitsPerMbDenom uint32 129 Log2MaxMvLengthHorizontal uint32 130 Log2MaxMvLengthVertical uint32 131 MaxNumReorderFrames uint32 132 MaxDecFrameBuffering uint32 133 } 134 135 func (r *SPS_BitstreamRestriction) unmarshal(buf []byte, pos *int) error { 136 var err error 137 r.MotionVectorsOverPicBoundariesFlag, err = bits.ReadFlag(buf, pos) 138 if err != nil { 139 return err 140 } 141 142 r.MaxBytesPerPicDenom, err = bits.ReadGolombUnsigned(buf, pos) 143 if err != nil { 144 return err 145 } 146 147 r.MaxBitsPerMbDenom, err = bits.ReadGolombUnsigned(buf, pos) 148 if err != nil { 149 return err 150 } 151 152 r.Log2MaxMvLengthHorizontal, err = bits.ReadGolombUnsigned(buf, pos) 153 if err != nil { 154 return err 155 } 156 157 r.Log2MaxMvLengthVertical, err = bits.ReadGolombUnsigned(buf, pos) 158 if err != nil { 159 return err 160 } 161 162 r.MaxNumReorderFrames, err = bits.ReadGolombUnsigned(buf, pos) 163 if err != nil { 164 return err 165 } 166 167 r.MaxDecFrameBuffering, err = bits.ReadGolombUnsigned(buf, pos) 168 if err != nil { 169 return err 170 } 171 172 return nil 173 } 174 175 // SPS_VUI is a video usability information. 176 type SPS_VUI struct { //nolint:revive 177 AspectRatioInfoPresentFlag bool 178 179 // AspectRatioInfoPresentFlag == true 180 AspectRatioIdc uint8 181 SarWidth uint16 182 SarHeight uint16 183 184 OverscanInfoPresentFlag bool 185 186 // OverscanInfoPresentFlag == true 187 OverscanAppropriateFlag bool 188 VideoSignalTypePresentFlag bool 189 190 // VideoSignalTypePresentFlag == true 191 VideoFormat uint8 192 VideoFullRangeFlag bool 193 ColourDescriptionPresentFlag bool 194 195 // ColourDescriptionPresentFlag == true 196 ColourPrimaries uint8 197 TransferCharacteristics uint8 198 MatrixCoefficients uint8 199 200 ChromaLocInfoPresentFlag bool 201 202 // ChromaLocInfoPresentFlag == true 203 ChromaSampleLocTypeTopField uint32 204 ChromaSampleLocTypeBottomField uint32 205 206 TimingInfo *SPS_TimingInfo 207 NalHRD *SPS_HRD 208 VclHRD *SPS_HRD 209 210 LowDelayHrdFlag bool 211 PicStructPresentFlag bool 212 BitstreamRestriction *SPS_BitstreamRestriction 213 } 214 215 func (v *SPS_VUI) unmarshal(buf []byte, pos *int) error { 216 var err error 217 v.AspectRatioInfoPresentFlag, err = bits.ReadFlag(buf, pos) 218 if err != nil { 219 return err 220 } 221 222 if v.AspectRatioInfoPresentFlag { 223 tmp, err := bits.ReadBits(buf, pos, 8) 224 if err != nil { 225 return err 226 } 227 v.AspectRatioIdc = uint8(tmp) 228 229 if v.AspectRatioIdc == 255 { // Extended_SAR 230 err := bits.HasSpace(buf, *pos, 32) 231 if err != nil { 232 return err 233 } 234 235 v.SarWidth = uint16(bits.ReadBitsUnsafe(buf, pos, 16)) 236 v.SarHeight = uint16(bits.ReadBitsUnsafe(buf, pos, 16)) 237 } 238 } 239 240 v.OverscanInfoPresentFlag, err = bits.ReadFlag(buf, pos) 241 if err != nil { 242 return err 243 } 244 245 if v.OverscanInfoPresentFlag { 246 v.OverscanAppropriateFlag, err = bits.ReadFlag(buf, pos) 247 if err != nil { 248 return err 249 } 250 } 251 252 v.VideoSignalTypePresentFlag, err = bits.ReadFlag(buf, pos) 253 if err != nil { 254 return err 255 } 256 257 if v.VideoSignalTypePresentFlag { 258 err := bits.HasSpace(buf, *pos, 5) 259 if err != nil { 260 return err 261 } 262 263 v.VideoFormat = uint8(bits.ReadBitsUnsafe(buf, pos, 3)) 264 v.VideoFullRangeFlag = bits.ReadFlagUnsafe(buf, pos) 265 v.ColourDescriptionPresentFlag = bits.ReadFlagUnsafe(buf, pos) 266 267 if v.ColourDescriptionPresentFlag { 268 err := bits.HasSpace(buf, *pos, 24) 269 if err != nil { 270 return err 271 } 272 273 v.ColourPrimaries = uint8(bits.ReadBitsUnsafe(buf, pos, 8)) 274 v.TransferCharacteristics = uint8(bits.ReadBitsUnsafe(buf, pos, 8)) 275 v.MatrixCoefficients = uint8(bits.ReadBitsUnsafe(buf, pos, 8)) 276 } 277 } 278 279 v.ChromaLocInfoPresentFlag, err = bits.ReadFlag(buf, pos) 280 if err != nil { 281 return err 282 } 283 284 if v.ChromaLocInfoPresentFlag { 285 v.ChromaSampleLocTypeTopField, err = bits.ReadGolombUnsigned(buf, pos) 286 if err != nil { 287 return err 288 } 289 290 v.ChromaSampleLocTypeBottomField, err = bits.ReadGolombUnsigned(buf, pos) 291 if err != nil { 292 return err 293 } 294 } 295 296 timingInfoPresentFlag, err := bits.ReadFlag(buf, pos) 297 if err != nil { 298 return err 299 } 300 301 if timingInfoPresentFlag { 302 v.TimingInfo = &SPS_TimingInfo{} 303 err := v.TimingInfo.unmarshal(buf, pos) 304 if err != nil { 305 return err 306 } 307 } 308 309 nalHrdParametersPresentFlag, err := bits.ReadFlag(buf, pos) 310 if err != nil { 311 return err 312 } 313 314 if nalHrdParametersPresentFlag { 315 v.NalHRD = &SPS_HRD{} 316 err := v.NalHRD.unmarshal(buf, pos) 317 if err != nil { 318 return err 319 } 320 } 321 322 vclHrdParametersPresentFlag, err := bits.ReadFlag(buf, pos) 323 if err != nil { 324 return err 325 } 326 327 if vclHrdParametersPresentFlag { 328 v.VclHRD = &SPS_HRD{} 329 err := v.VclHRD.unmarshal(buf, pos) 330 if err != nil { 331 return err 332 } 333 } 334 335 if nalHrdParametersPresentFlag || vclHrdParametersPresentFlag { 336 v.LowDelayHrdFlag, err = bits.ReadFlag(buf, pos) 337 if err != nil { 338 return err 339 } 340 } 341 342 v.PicStructPresentFlag, err = bits.ReadFlag(buf, pos) 343 if err != nil { 344 return err 345 } 346 347 bitstreamRestrictionFlag, err := bits.ReadFlag(buf, pos) 348 if err != nil { 349 return err 350 } 351 352 if bitstreamRestrictionFlag { 353 v.BitstreamRestriction = &SPS_BitstreamRestriction{} 354 err := v.BitstreamRestriction.unmarshal(buf, pos) 355 if err != nil { 356 return err 357 } 358 } 359 360 return nil 361 } 362 363 // SPS_FrameCropping is the frame cropping part of a SPS. 364 type SPS_FrameCropping struct { //nolint:revive 365 LeftOffset uint32 366 RightOffset uint32 367 TopOffset uint32 368 BottomOffset uint32 369 } 370 371 func (c *SPS_FrameCropping) unmarshal(buf []byte, pos *int) error { 372 var err error 373 c.LeftOffset, err = bits.ReadGolombUnsigned(buf, pos) 374 if err != nil { 375 return err 376 } 377 378 c.RightOffset, err = bits.ReadGolombUnsigned(buf, pos) 379 if err != nil { 380 return err 381 } 382 383 c.TopOffset, err = bits.ReadGolombUnsigned(buf, pos) 384 if err != nil { 385 return err 386 } 387 388 c.BottomOffset, err = bits.ReadGolombUnsigned(buf, pos) 389 if err != nil { 390 return err 391 } 392 393 return nil 394 } 395 396 // SPS is a H264 sequence parameter set. 397 // Specification: ITU-T Rec. H.264, 7.3.2.1.1 398 type SPS struct { 399 ProfileIdc uint8 400 ConstraintSet0Flag bool 401 ConstraintSet1Flag bool 402 ConstraintSet2Flag bool 403 ConstraintSet3Flag bool 404 ConstraintSet4Flag bool 405 ConstraintSet5Flag bool 406 LevelIdc uint8 407 ID uint32 408 409 // only for selected ProfileIdcs 410 ChromaFormatIdc uint32 411 SeparateColourPlaneFlag bool 412 BitDepthLumaMinus8 uint32 413 BitDepthChromaMinus8 uint32 414 QpprimeYZeroTransformBypassFlag bool 415 416 // seqScalingListPresentFlag == true 417 ScalingList4x4 [][]int32 418 UseDefaultScalingMatrix4x4Flag []bool 419 ScalingList8x8 [][]int32 420 UseDefaultScalingMatrix8x8Flag []bool 421 422 Log2MaxFrameNumMinus4 uint32 423 PicOrderCntType uint32 424 425 // PicOrderCntType == 0 426 Log2MaxPicOrderCntLsbMinus4 uint32 427 428 // PicOrderCntType == 1 429 DeltaPicOrderAlwaysZeroFlag bool 430 OffsetForNonRefPic int32 431 OffsetForTopToBottomField int32 432 OffsetForRefFrames []int32 433 434 MaxNumRefFrames uint32 435 GapsInFrameNumValueAllowedFlag bool 436 PicWidthInMbsMinus1 uint32 437 PicHeightInMapUnitsMinus1 uint32 438 FrameMbsOnlyFlag bool 439 440 // FrameMbsOnlyFlag == false 441 MbAdaptiveFrameFieldFlag bool 442 443 Direct8x8InferenceFlag bool 444 FrameCropping *SPS_FrameCropping 445 VUI *SPS_VUI 446 } 447 448 // Unmarshal decodes a SPS from bytes. 449 func (s *SPS) Unmarshal(buf []byte) error { 450 if len(buf) < 1 { 451 return fmt.Errorf("not enough bits") 452 } 453 454 if NALUType(buf[0]&0x1F) != NALUTypeSPS { 455 return fmt.Errorf("not a SPS") 456 } 457 458 buf = EmulationPreventionRemove(buf[1:]) 459 460 if len(buf) < 3 { 461 return fmt.Errorf("not enough bits") 462 } 463 464 s.ProfileIdc = buf[0] 465 s.ConstraintSet0Flag = (buf[1] >> 7) == 1 466 s.ConstraintSet1Flag = (buf[1] >> 6 & 0x01) == 1 467 s.ConstraintSet2Flag = (buf[1] >> 5 & 0x01) == 1 468 s.ConstraintSet3Flag = (buf[1] >> 4 & 0x01) == 1 469 s.ConstraintSet4Flag = (buf[1] >> 3 & 0x01) == 1 470 s.ConstraintSet5Flag = (buf[1] >> 2 & 0x01) == 1 471 s.LevelIdc = buf[2] 472 473 buf = buf[3:] 474 pos := 0 475 476 var err error 477 s.ID, err = bits.ReadGolombUnsigned(buf, &pos) 478 if err != nil { 479 return err 480 } 481 482 switch s.ProfileIdc { 483 case 100, 110, 122, 244, 44, 83, 86, 118, 128, 138, 139, 134, 135: 484 s.ChromaFormatIdc, err = bits.ReadGolombUnsigned(buf, &pos) 485 if err != nil { 486 return err 487 } 488 489 if s.ChromaFormatIdc == 3 { 490 s.SeparateColourPlaneFlag, err = bits.ReadFlag(buf, &pos) 491 if err != nil { 492 return err 493 } 494 } else { 495 s.SeparateColourPlaneFlag = false 496 } 497 498 s.BitDepthLumaMinus8, err = bits.ReadGolombUnsigned(buf, &pos) 499 if err != nil { 500 return err 501 } 502 503 s.BitDepthChromaMinus8, err = bits.ReadGolombUnsigned(buf, &pos) 504 if err != nil { 505 return err 506 } 507 508 s.QpprimeYZeroTransformBypassFlag, err = bits.ReadFlag(buf, &pos) 509 if err != nil { 510 return err 511 } 512 513 seqScalingMatrixPresentFlag, err := bits.ReadFlag(buf, &pos) 514 if err != nil { 515 return err 516 } 517 518 if seqScalingMatrixPresentFlag { 519 var lim int 520 if s.ChromaFormatIdc != 3 { 521 lim = 8 522 } else { 523 lim = 12 524 } 525 526 for i := 0; i < lim; i++ { 527 seqScalingListPresentFlag, err := bits.ReadFlag(buf, &pos) 528 if err != nil { 529 return err 530 } 531 532 if seqScalingListPresentFlag { 533 if i < 6 { 534 scalingList, useDefaultScalingMatrixFlag, err := readScalingList(buf, &pos, 16) 535 if err != nil { 536 return err 537 } 538 539 s.ScalingList4x4 = append(s.ScalingList4x4, scalingList) 540 s.UseDefaultScalingMatrix4x4Flag = append(s.UseDefaultScalingMatrix4x4Flag, 541 useDefaultScalingMatrixFlag) 542 } else { 543 scalingList, useDefaultScalingMatrixFlag, err := readScalingList(buf, &pos, 64) 544 if err != nil { 545 return err 546 } 547 548 s.ScalingList8x8 = append(s.ScalingList8x8, scalingList) 549 s.UseDefaultScalingMatrix8x8Flag = append(s.UseDefaultScalingMatrix8x8Flag, 550 useDefaultScalingMatrixFlag) 551 } 552 } 553 } 554 } 555 556 default: 557 s.ChromaFormatIdc = 1 558 s.SeparateColourPlaneFlag = false 559 s.BitDepthLumaMinus8 = 0 560 s.BitDepthChromaMinus8 = 0 561 s.QpprimeYZeroTransformBypassFlag = false 562 } 563 564 s.Log2MaxFrameNumMinus4, err = bits.ReadGolombUnsigned(buf, &pos) 565 if err != nil { 566 return err 567 } 568 569 s.PicOrderCntType, err = bits.ReadGolombUnsigned(buf, &pos) 570 if err != nil { 571 return err 572 } 573 574 switch s.PicOrderCntType { 575 case 0: 576 s.Log2MaxPicOrderCntLsbMinus4, err = bits.ReadGolombUnsigned(buf, &pos) 577 if err != nil { 578 return err 579 } 580 581 s.DeltaPicOrderAlwaysZeroFlag = false 582 s.OffsetForNonRefPic = 0 583 s.OffsetForTopToBottomField = 0 584 s.OffsetForRefFrames = nil 585 586 case 1: 587 s.Log2MaxPicOrderCntLsbMinus4 = 0 588 589 s.DeltaPicOrderAlwaysZeroFlag, err = bits.ReadFlag(buf, &pos) 590 if err != nil { 591 return err 592 } 593 594 s.OffsetForNonRefPic, err = bits.ReadGolombSigned(buf, &pos) 595 if err != nil { 596 return err 597 } 598 599 s.OffsetForTopToBottomField, err = bits.ReadGolombSigned(buf, &pos) 600 if err != nil { 601 return err 602 } 603 604 numRefFramesInPicOrderCntCycle, err := bits.ReadGolombUnsigned(buf, &pos) 605 if err != nil { 606 return err 607 } 608 609 if numRefFramesInPicOrderCntCycle > maxRefFrames { 610 return fmt.Errorf("num_ref_frames_in_pic_order_cnt_cycle exceeds %d", maxRefFrames) 611 } 612 613 s.OffsetForRefFrames = make([]int32, numRefFramesInPicOrderCntCycle) 614 for i := uint32(0); i < numRefFramesInPicOrderCntCycle; i++ { 615 v, err := bits.ReadGolombSigned(buf, &pos) 616 if err != nil { 617 return err 618 } 619 620 s.OffsetForRefFrames[i] = v 621 } 622 623 case 2: 624 s.Log2MaxPicOrderCntLsbMinus4 = 0 625 s.DeltaPicOrderAlwaysZeroFlag = false 626 s.OffsetForNonRefPic = 0 627 s.OffsetForTopToBottomField = 0 628 s.OffsetForRefFrames = nil 629 630 default: 631 return fmt.Errorf("invalid pic_order_cnt_type: %d", s.PicOrderCntType) 632 } 633 634 s.MaxNumRefFrames, err = bits.ReadGolombUnsigned(buf, &pos) 635 if err != nil { 636 return err 637 } 638 639 s.GapsInFrameNumValueAllowedFlag, err = bits.ReadFlag(buf, &pos) 640 if err != nil { 641 return err 642 } 643 644 s.PicWidthInMbsMinus1, err = bits.ReadGolombUnsigned(buf, &pos) 645 if err != nil { 646 return err 647 } 648 649 s.PicHeightInMapUnitsMinus1, err = bits.ReadGolombUnsigned(buf, &pos) 650 if err != nil { 651 return err 652 } 653 654 s.FrameMbsOnlyFlag, err = bits.ReadFlag(buf, &pos) 655 if err != nil { 656 return err 657 } 658 659 if !s.FrameMbsOnlyFlag { 660 s.MbAdaptiveFrameFieldFlag, err = bits.ReadFlag(buf, &pos) 661 if err != nil { 662 return err 663 } 664 } else { 665 s.MbAdaptiveFrameFieldFlag = false 666 } 667 668 s.Direct8x8InferenceFlag, err = bits.ReadFlag(buf, &pos) 669 if err != nil { 670 return err 671 } 672 673 frameCroppingFlag, err := bits.ReadFlag(buf, &pos) 674 if err != nil { 675 return err 676 } 677 678 if frameCroppingFlag { 679 s.FrameCropping = &SPS_FrameCropping{} 680 err := s.FrameCropping.unmarshal(buf, &pos) 681 if err != nil { 682 return err 683 } 684 } else { 685 s.FrameCropping = nil 686 } 687 688 vuiParametersPresentFlag, err := bits.ReadFlag(buf, &pos) 689 if err != nil { 690 return err 691 } 692 693 if vuiParametersPresentFlag { 694 s.VUI = &SPS_VUI{} 695 err := s.VUI.unmarshal(buf, &pos) 696 if err != nil { 697 return err 698 } 699 } else { 700 s.VUI = nil 701 } 702 703 return nil 704 } 705 706 // Width returns the video width. 707 func (s SPS) Width() int { 708 var subWidthC uint32 709 switch { 710 case s.ChromaFormatIdc == 1 && !s.SeparateColourPlaneFlag: 711 subWidthC = 2 712 713 case s.ChromaFormatIdc == 2 && !s.SeparateColourPlaneFlag: 714 subWidthC = 2 715 716 case s.ChromaFormatIdc == 3 && !s.SeparateColourPlaneFlag: 717 subWidthC = 1 718 } 719 720 var chromaArrayType uint32 721 if !s.SeparateColourPlaneFlag { 722 chromaArrayType = s.ChromaFormatIdc 723 } else { 724 chromaArrayType = 0 725 } 726 727 var cropUnitX uint32 728 if chromaArrayType == 0 { 729 cropUnitX = 0 730 } else { 731 cropUnitX = subWidthC 732 } 733 734 picWidthInSamplesL := ((s.PicWidthInMbsMinus1 + 1) * 16) 735 736 if s.FrameCropping != nil { 737 return int(picWidthInSamplesL - cropUnitX*(s.FrameCropping.LeftOffset+s.FrameCropping.RightOffset)) 738 } 739 740 return int(picWidthInSamplesL) 741 } 742 743 // Height returns the video height. 744 func (s SPS) Height() int { 745 var subHeightC uint32 746 switch { 747 case s.ChromaFormatIdc == 1 && !s.SeparateColourPlaneFlag: 748 subHeightC = 2 749 750 case s.ChromaFormatIdc == 2 && !s.SeparateColourPlaneFlag: 751 subHeightC = 1 752 753 case s.ChromaFormatIdc == 3 && !s.SeparateColourPlaneFlag: 754 subHeightC = 1 755 } 756 757 var frameMbsOnlyFlagUint32 uint32 758 if s.FrameMbsOnlyFlag { 759 frameMbsOnlyFlagUint32 = 1 760 } 761 762 var chromaArrayType uint32 763 if !s.SeparateColourPlaneFlag { 764 chromaArrayType = s.ChromaFormatIdc 765 } else { 766 chromaArrayType = 0 767 } 768 769 var cropUnitY uint32 770 if chromaArrayType == 0 { 771 cropUnitY = 2 - frameMbsOnlyFlagUint32 772 } else { 773 cropUnitY = subHeightC * (2 - frameMbsOnlyFlagUint32) 774 } 775 776 frameHeightInMbs := (2 - frameMbsOnlyFlagUint32) * (s.PicHeightInMapUnitsMinus1 + 1) 777 778 if s.FrameCropping != nil { 779 return int(16*frameHeightInMbs - cropUnitY*(s.FrameCropping.TopOffset+s.FrameCropping.BottomOffset)) 780 } 781 782 picHeightInMbs := frameHeightInMbs // / (1 + s.FieldPicFlag) 783 picHeightInSamplesL := picHeightInMbs * 16 784 785 return int(picHeightInSamplesL) 786 } 787 788 // FPS returns the frames per second of the video. 789 func (s SPS) FPS() float64 { 790 if s.VUI == nil || s.VUI.TimingInfo == nil { 791 return 0 792 } 793 794 return float64(s.VUI.TimingInfo.TimeScale) / (2 * float64(s.VUI.TimingInfo.NumUnitsInTick)) 795 }