(sps: Uint8Array)
| 122 | |
| 123 | /** Parses an AVC SPS (Sequence Parameter Set) to extract basic information. */ |
| 124 | export const parseAvcSps = (sps: Uint8Array): AvcSpsInfo | null => { |
| 125 | try { |
| 126 | const bitstream = new Bitstream(removeEmulationPreventionBytes(sps)); |
| 127 | |
| 128 | bitstream.skipBits(1); // forbidden_zero_bit |
| 129 | bitstream.skipBits(2); // nal_ref_idc |
| 130 | const nalUnitType = bitstream.readBits(5); |
| 131 | |
| 132 | if (nalUnitType !== 7) { // SPS NAL unit type is 7 |
| 133 | return null; |
| 134 | } |
| 135 | |
| 136 | const profileIdc = bitstream.readAlignedByte(); |
| 137 | const constraintFlags = bitstream.readAlignedByte(); |
| 138 | const levelIdc = bitstream.readAlignedByte(); |
| 139 | |
| 140 | readExpGolomb(bitstream); // seq_parameter_set_id |
| 141 | |
| 142 | let chromaFormatIdc: number | null = null; |
| 143 | let bitDepthLumaMinus8: number | null = null; |
| 144 | let bitDepthChromaMinus8: number | null = null; |
| 145 | |
| 146 | // Handle high profile chroma_format_idc |
| 147 | if ( |
| 148 | profileIdc === 100 |
| 149 | || profileIdc === 110 |
| 150 | || profileIdc === 122 |
| 151 | || profileIdc === 244 |
| 152 | || profileIdc === 44 |
| 153 | || profileIdc === 83 |
| 154 | || profileIdc === 86 |
| 155 | || profileIdc === 118 |
| 156 | || profileIdc === 128 |
| 157 | ) { |
| 158 | chromaFormatIdc = readExpGolomb(bitstream); |
| 159 | if (chromaFormatIdc === 3) { |
| 160 | bitstream.skipBits(1); // separate_colour_plane_flag |
| 161 | } |
| 162 | bitDepthLumaMinus8 = readExpGolomb(bitstream); |
| 163 | bitDepthChromaMinus8 = readExpGolomb(bitstream); |
| 164 | bitstream.skipBits(1); // qpprime_y_zero_transform_bypass_flag |
| 165 | const seqScalingMatrixPresentFlag = bitstream.readBits(1); |
| 166 | if (seqScalingMatrixPresentFlag) { |
| 167 | for (let i = 0; i < (chromaFormatIdc !== 3 ? 8 : 12); i++) { |
| 168 | const seqScalingListPresentFlag = bitstream.readBits(1); |
| 169 | if (seqScalingListPresentFlag) { |
| 170 | const sizeOfScalingList = i < 6 ? 16 : 64; |
| 171 | let lastScale = 8; |
| 172 | let nextScale = 8; |
| 173 | for (let j = 0; j < sizeOfScalingList; j++) { |
| 174 | if (nextScale !== 0) { |
| 175 | const deltaScale = readSignedExpGolomb(bitstream); |
| 176 | nextScale = (lastScale + deltaScale + 256) % 256; |
| 177 | } |
| 178 | lastScale = nextScale === 0 ? lastScale : nextScale; |
| 179 | } |
| 180 | } |
| 181 | } |
no test coverage detected