1 /*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "box/item_property_hvcc_box.h"
17
18 static const uint8_t GENGERAL_PROFILE_SPACE_SHIFT = 6;
19 static const uint8_t GENERAL_TIER_FLAG_SHIFT = 5;
20 static const uint8_t CONST_FRMAE_RATE_SHIFT = 6;
21 static const uint8_t NUM_TEMPORAL_LAYERS_SHIFT = 3;
22 static const uint8_t TEMPORAL_ID_NESTED_SHIFT = 2;
23 static const uint8_t ARRAY_COMPLETENESS_SHIFT = 6;
24 static const uint8_t BIT_DEPTH_DIFF = 8;
25 static const uint8_t NAL_UNIT_LENGTH_SIZE_DIFF = 1;
26
27 static const uint8_t SKIP_DOUBLE_DATA_PROCESS_BYTE = 2;
28 static const uint8_t READ_BIT_NUM_FLAG = 1;
29 static const uint8_t READ_BYTE_NUM_FLAG = 8;
30 static const uint8_t READ_GENERAL_PROFILE_IDC_NUM = 32;
31 static const uint8_t READ_SUB_LAYER_PROFILE_IDCS = 48;
32
33 static const uint8_t SPS_BOX_TYPE = 33;
34 static const uint8_t EXTENDED_SAR = 255;
35 static const uint8_t NALU_TYPE_ID_SIZE = 6;
36 static const uint8_t SUB_LAYER_MINUS = 3;
37 static const uint8_t GENERAL_PROFILE_SIZE = 4;
38 static const uint8_t SUB_LAYER_PRESENT_PROFILE_SIZE = 3;
39 static const uint8_t SUB_LAYER_PROFILE_IDC_SIZE = 5;
40 static const uint8_t PCM_ENABLED_FLAG = 4;
41 static const uint8_t NUM_TEMPORAL_ID_SIZE = 6;
42 static const uint8_t MAX_COEF_NUM = 64;
43
44 namespace OHOS {
45 namespace ImagePlugin {
ParseNalUnitArray(HeifStreamReader & reader,std::vector<std::vector<uint8_t>> & nalUnits)46 heif_error HeifHvccBox::ParseNalUnitArray(HeifStreamReader& reader, std::vector<std::vector<uint8_t>>& nalUnits)
47 {
48 int nalUnitNum = reader.Read16();
49 for (int unitIndex = 0; unitIndex < nalUnitNum && !reader.HasError(); ++unitIndex) {
50 int nalUnitSize = reader.Read16();
51 if (!nalUnitSize || !reader.CheckSize(nalUnitSize)) {
52 continue;
53 }
54 std::vector<uint8_t> nalUnit(nalUnitSize);
55 bool res = reader.ReadData(nalUnit.data(), nalUnitSize);
56 if (!res) {
57 return heif_error_eof;
58 }
59 nalUnits.push_back(nalUnit);
60 }
61 return reader.GetError();
62 }
63
ParseContent(HeifStreamReader & reader)64 heif_error HeifHvccBox::ParseContent(HeifStreamReader& reader)
65 {
66 config_.version = reader.Read8();
67 uint8_t tempByte = reader.Read8();
68 config_.generalProfileSpace = (tempByte >> GENGERAL_PROFILE_SPACE_SHIFT) & 0x03;
69 config_.generalTierFlag = (tempByte >> GENERAL_TIER_FLAG_SHIFT) & 0x01;
70 config_.generalProfileIdc = (tempByte & 0x1F);
71 config_.generalProfileCompatibilityFlags = reader.Read32();
72 uint32_t indicatorFlagsPre = reader.Read32();
73 uint16_t indicatorFlagsLast = reader.Read16();
74 config_.generalConstraintIndicatorFlags = uint64_t((indicatorFlagsPre << TWO_BYTES_SHIFT) | indicatorFlagsLast);
75 config_.generalLevelIdc = reader.Read8();
76 config_.minSpatialSegmentationIdc = reader.Read16() & 0x0FFF;
77 config_.parallelismType = reader.Read8() & 0x03;
78 config_.chromaFormat = reader.Read8() & 0x03;
79
80 // box store content is bitDepthLumaMinus8
81 config_.bitDepthLuma = (reader.Read8() & 0x07) + BIT_DEPTH_DIFF;
82 config_.bitDepthChroma = (reader.Read8() & 0x07) + BIT_DEPTH_DIFF;
83 config_.avgFrameRate = reader.Read16();
84
85 tempByte = reader.Read8();
86 config_.constFrameRate = (tempByte >> CONST_FRMAE_RATE_SHIFT) & 0x03;
87 config_.numTemporalLayers = (tempByte >> NUM_TEMPORAL_LAYERS_SHIFT) & 0x07;
88 config_.temporalIdNested = (tempByte >> TEMPORAL_ID_NESTED_SHIFT) & 0x01;
89
90 // box store content is lengthSizeMinus1
91 nalUnitLengthSize_ = static_cast<uint8_t>((tempByte & 0x03) + NAL_UNIT_LENGTH_SIZE_DIFF);
92 int nalArrayNum = reader.Read8();
93 for (int arrayIndex = 0; arrayIndex < nalArrayNum && !reader.HasError(); ++arrayIndex) {
94 tempByte = reader.Read8();
95 HvccNalArray array;
96 array.arrayCompleteness = (tempByte >> ARRAY_COMPLETENESS_SHIFT) & 0x01;
97 array.nalUnitType = (tempByte & 0x3F);
98 heif_error error = ParseNalUnitArray(reader, array.nalUnits);
99 if (error) {
100 return error;
101 }
102 nalArrays_.push_back(std::move(array));
103 }
104 return reader.GetError();
105 }
106
GetHeaders(std::vector<uint8_t> * outData) const107 bool HeifHvccBox::GetHeaders(std::vector<uint8_t>* outData) const
108 {
109 for (const auto& array : nalArrays_) {
110 for (const auto& unit : array.nalUnits) {
111 outData->push_back((unit.size() >> THREE_BYTES_SHIFT) & 0xFF);
112 outData->push_back((unit.size() >> TWO_BYTES_SHIFT) & 0xFF);
113 outData->push_back((unit.size() >> ONE_BYTE_SHIFT) & 0xFF);
114 outData->push_back((unit.size()) & 0xFF);
115 outData->insert(outData->end(), unit.begin(), unit.end());
116 }
117 }
118
119 return true;
120 }
121
AppendNalData(const std::vector<uint8_t> & nalData)122 void HeifHvccBox::AppendNalData(const std::vector<uint8_t>& nalData)
123 {
124 HvccNalArray array;
125 array.arrayCompleteness = 0;
126 array.nalUnitType = uint8_t(nalData[0] >> 1);
127 array.nalUnits.push_back(nalData);
128 nalArrays_.push_back(array);
129 }
130
Write(HeifStreamWriter & writer) const131 heif_error HeifHvccBox::Write(HeifStreamWriter& writer) const
132 {
133 size_t boxStart = ReserveHeader(writer);
134
135 const HvccConfig& config = config_;
136 writer.Write8(config.version);
137 writer.Write8((uint8_t) (((config.generalProfileSpace & 0x03) << GENGERAL_PROFILE_SPACE_SHIFT) |
138 ((config.generalTierFlag & 0x01) << GENERAL_TIER_FLAG_SHIFT) |
139 (config.generalProfileIdc & 0x1F)));
140 writer.Write32(config.generalProfileCompatibilityFlags);
141 writer.Write32((config.generalConstraintIndicatorFlags >> TWO_BYTES_SHIFT) & 0xFFFFFFFF);
142 writer.Write16((config.generalConstraintIndicatorFlags) & 0xFFFF);
143 writer.Write8(config.generalLevelIdc);
144 writer.Write16((config.minSpatialSegmentationIdc & 0x0FFF) | 0xF000);
145 writer.Write8((config.parallelismType & 0x03) | 0xFC);
146 writer.Write8((config.chromaFormat & 0x03) | 0xFC);
147 writer.Write8(((config.bitDepthLuma - BIT_DEPTH_DIFF) & 0x07) | 0xF8);
148 writer.Write8(((config.bitDepthChroma - BIT_DEPTH_DIFF) & 0x07) | 0xF8);
149 writer.Write16(config.avgFrameRate);
150 writer.Write8((uint8_t) (((config.constFrameRate & 0x03) << CONST_FRMAE_RATE_SHIFT) |
151 ((config.numTemporalLayers & 0x07) << NUM_TEMPORAL_LAYERS_SHIFT) |
152 ((config.temporalIdNested & 0x01) << TEMPORAL_ID_NESTED_SHIFT) |
153 ((nalUnitLengthSize_ - NAL_UNIT_LENGTH_SIZE_DIFF) & 0x03)));
154
155 size_t nArrays = nalArrays_.size();
156 writer.Write8((uint8_t) nArrays);
157 for (const HvccNalArray& array : nalArrays_) {
158 writer.Write8((uint8_t) (((array.arrayCompleteness & 0x01) << ARRAY_COMPLETENESS_SHIFT) |
159 (array.nalUnitType & 0x3F)));
160 size_t nUnits = array.nalUnits.size();
161 writer.Write16((uint16_t) nUnits);
162 for (const std::vector<uint8_t>& nalUnit : array.nalUnits) {
163 writer.Write16((uint16_t) nalUnit.size());
164 writer.Write(nalUnit);
165 }
166 }
167
168 WriteCalculatedHeader(writer, boxStart);
169 return heif_error_ok;
170 }
171
GetWord(const std::vector<uint8_t> & nalu,uint32_t length)172 uint32_t HeifHvccBox::GetWord(const std::vector<uint8_t>& nalu, uint32_t length)
173 {
174 uint32_t res = 0;
175 for (uint32_t i = 0; i < length && pos_ < boxBitLength_; ++i, ++pos_) {
176 uint32_t bit = ((nalu[pos_ / BIT_DEPTH_DIFF] >>
177 (BIT_DEPTH_DIFF - BIT_SHIFT - (pos_ % BIT_DEPTH_DIFF)))
178 & 0x01);
179 res <<= BIT_SHIFT;
180 res |= bit;
181 }
182 return res;
183 }
184
GetGolombCode(const std::vector<uint8_t> & nalu)185 uint32_t HeifHvccBox::GetGolombCode(const std::vector<uint8_t> &nalu)
186 {
187 uint32_t zeros = 0;
188 while (pos_ < boxBitLength_ && ((nalu[pos_ / ONE_BYTE_SHIFT] >>
189 (ONE_BYTE_SHIFT - BIT_SHIFT - (pos_ % ONE_BYTE_SHIFT))) &
190 0x01) == 0x00) {
191 zeros++;
192 pos_++;
193 }
194 pos_++;
195 return GetWord(nalu, zeros) + ((BIT_SHIFT << zeros) - BIT_SHIFT);
196 }
197
GetNaluTypeId(std::vector<uint8_t> & nalUnits)198 uint32_t HeifHvccBox::GetNaluTypeId(std::vector<uint8_t> &nalUnits)
199 {
200 if (nalUnits.empty()) {
201 return -1;
202 }
203 GetWord(nalUnits, READ_BIT_NUM_FLAG);
204 return GetWord(nalUnits, NALU_TYPE_ID_SIZE);
205 }
206
GetNaluData(const std::vector<HvccNalArray> & nalArrays,uint8_t naluId)207 std::vector<uint8_t> HeifHvccBox::GetNaluData(const std::vector<HvccNalArray> &nalArrays,
208 uint8_t naluId)
209 {
210 for (auto HvccNalunit : nalArrays) {
211 if (HvccNalunit.nalUnitType == naluId && (!HvccNalunit.nalUnits.empty())) {
212 return HvccNalunit.nalUnits[0];
213 }
214 }
215 return std::vector<uint8_t>();
216 }
217
ProcessBoxData(std::vector<uint8_t> & nalu)218 void HeifHvccBox::ProcessBoxData(std::vector<uint8_t> &nalu)
219 {
220 uint32_t naluSize = nalu.size();
221 std::vector<uint32_t> indicesToDelete;
222 for (uint32_t i = UINT16_BYTES_NUM; i < naluSize; ++i) {
223 if (nalu[i - UINT8_BYTES_NUM] == 0x00 &&
224 nalu[i - SKIP_DOUBLE_DATA_PROCESS_BYTE] == 0x00 && nalu[i] == 0x03) {
225 indicesToDelete.push_back(i);
226 }
227 }
228 for (auto it = indicesToDelete.rbegin(); it != indicesToDelete.rend(); ++it) {
229 nalu.erase(nalu.begin() + *it);
230 }
231 }
232
ParserHvccColorRangeFlag(const std::vector<HvccNalArray> & nalArrays)233 void HeifHvccBox::ParserHvccColorRangeFlag(const std::vector<HvccNalArray> &nalArrays)
234 {
235 auto spsBox = GetNaluData(nalArrays, SPS_BOX_TYPE);
236 ProcessBoxData(spsBox);
237 ParseNalUnitAnalysisSps(spsBox);
238 }
239
ProfileTierLevel(std::vector<uint8_t> & nalUnits,uint32_t profilePresentFlag,uint32_t maxNumSubLayerMinus1)240 void HeifHvccBox::ProfileTierLevel(std::vector<uint8_t> &nalUnits, uint32_t profilePresentFlag,
241 uint32_t maxNumSubLayerMinus1)
242 {
243 std::vector<uint32_t> generalProfileCompatibilityFlags;
244 std::vector<uint32_t> subLayerProfilePresentFlag;
245 std::vector<uint32_t> subLayerLevelPresentFlags;
246 std::vector<uint32_t> subLayerProfileIdcs;
247 std::vector<std::vector<uint32_t>> subLayerProfileCompatibilityFlags;
248 if (profilePresentFlag) {
249 GetWord(nalUnits, READ_BIT_NUM_FLAG); // general_profile_idc
250
251 for (uint32_t j = 0; j < READ_GENERAL_PROFILE_IDC_NUM; ++j) {
252 uint32_t flag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
253 generalProfileCompatibilityFlags.push_back(flag);
254 }
255 GetWord(nalUnits, READ_BYTE_NUM_FLAG);
256 GetWord(nalUnits, READ_BYTE_NUM_FLAG);
257 GetWord(nalUnits, READ_GENERAL_PROFILE_IDC_NUM);
258 }
259 GetWord(nalUnits, READ_BYTE_NUM_FLAG);
260 subLayerProfilePresentFlag.resize(maxNumSubLayerMinus1);
261 for (uint32_t i = 0; i < maxNumSubLayerMinus1; ++i) {
262 subLayerProfilePresentFlag[i] = GetWord(nalUnits, READ_BIT_NUM_FLAG);
263 subLayerLevelPresentFlags.push_back(GetWord(nalUnits, READ_BIT_NUM_FLAG));
264 }
265
266 if (maxNumSubLayerMinus1 > 0) {
267 for (uint32_t i = maxNumSubLayerMinus1; i < READ_BYTE_NUM_FLAG; ++i) {
268 GetWord(nalUnits, READ_BIT_NUM_FLAG);
269 GetWord(nalUnits, READ_BIT_NUM_FLAG);
270 }
271 }
272
273 subLayerProfileIdcs.resize(maxNumSubLayerMinus1);
274 subLayerProfileCompatibilityFlags.resize(maxNumSubLayerMinus1,
275 std::vector<uint32_t>(GENERAL_PROFILE_SIZE));
276 for (uint32_t i = 0; i < maxNumSubLayerMinus1; i++) {
277 if (subLayerProfilePresentFlag[i]) {
278 GetWord(nalUnits, SUB_LAYER_PRESENT_PROFILE_SIZE);
279 subLayerProfileIdcs[i] = GetWord(nalUnits, SUB_LAYER_PROFILE_IDC_SIZE);
280 for (uint32_t j = 0; j < GENERAL_PROFILE_SIZE; ++j) {
281 subLayerProfileCompatibilityFlags[i][j] = GetWord(nalUnits, READ_BIT_NUM_FLAG);
282 }
283
284 // skip sub_layer_profile_idcs judge;
285 GetWord(nalUnits, READ_SUB_LAYER_PROFILE_IDCS);
286 }
287 if (subLayerLevelPresentFlags[i]) {
288 GetWord(nalUnits, READ_BYTE_NUM_FLAG);
289 }
290 }
291 }
292
ParseNalUnitAnalysisSps(std::vector<uint8_t> & nalUnits)293 bool HeifHvccBox::ParseNalUnitAnalysisSps(std::vector<uint8_t> &nalUnits)
294 {
295 boxBitLength_ = nalUnits.size() * BIT_DEPTH_DIFF;
296 spsConfig_.forbiddenZeroBit = GetWord(nalUnits, READ_BIT_NUM_FLAG);
297 spsConfig_.nuhTemporalIdPlus1 = GetWord(nalUnits, NUM_TEMPORAL_ID_SIZE);
298 spsConfig_.nalUnitType = GetWord(nalUnits, NALU_TYPE_ID_SIZE);
299 GetWord(nalUnits, SUB_LAYER_MINUS);
300 return ParseSpsSyntax(nalUnits);
301 }
302
ParseSpsSyntax(std::vector<uint8_t> & nalUnits)303 bool HeifHvccBox::ParseSpsSyntax(std::vector<uint8_t> &nalUnits)
304 {
305 //General sequence parameter set RBSP syntax
306 spsConfig_.spsVideoParameterSetId = GetWord(nalUnits, GENERAL_PROFILE_SIZE);
307 spsConfig_.spsMaxSubLayersMinus1 = GetWord(nalUnits, SUB_LAYER_MINUS);
308 spsConfig_.spsTemporalIdNestingFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
309
310 //go to profile_tier_level parser
311 ProfileTierLevel(nalUnits,
312 spsConfig_.spsTemporalIdNestingFlag,
313 spsConfig_.spsMaxSubLayersMinus1);
314
315 spsConfig_.spsVideoParameterSetId = GetGolombCode(nalUnits);
316 spsConfig_.chromaFormatIdc = GetGolombCode(nalUnits);
317 if (spsConfig_.chromaFormatIdc == SUB_LAYER_MINUS) {
318 spsConfig_.separateColourPlaneFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
319 }
320 spsConfig_.picWidthInLumaSamples = GetGolombCode(nalUnits);
321 spsConfig_.picHeightInLumaSamples = GetGolombCode(nalUnits);
322 spsConfig_.conformanceWindowFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
323 if (spsConfig_.conformanceWindowFlag == READ_BIT_NUM_FLAG) {
324 spsConfig_.confWinLefOffset = GetGolombCode(nalUnits);
325 spsConfig_.confWinRightOffset = GetGolombCode(nalUnits);
326 spsConfig_.confWinTopOffset = GetGolombCode(nalUnits);
327 spsConfig_.confWinBottomOffset = GetGolombCode(nalUnits);
328 }
329 spsConfig_.bitDepthLumaMinus8 = GetGolombCode(nalUnits);
330 spsConfig_.bitDepthChromaMinus8 = GetGolombCode(nalUnits);
331 spsConfig_.log2MaxPicOrderCntLsbMinus4 = GetGolombCode(nalUnits);
332 spsConfig_.spsSubLayerOrderingInfoPresentFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
333 uint32_t i = spsConfig_.spsSubLayerOrderingInfoPresentFlag ? 0 : spsConfig_.spsMaxSubLayersMinus1;
334 for (; i <= spsConfig_.spsMaxSubLayersMinus1; i++) {
335 GetGolombCode(nalUnits);
336 GetGolombCode(nalUnits);
337 GetGolombCode(nalUnits);
338 }
339 GetGolombCode(nalUnits);
340 GetGolombCode(nalUnits);
341 GetGolombCode(nalUnits);
342 GetGolombCode(nalUnits);
343 GetGolombCode(nalUnits);
344 GetGolombCode(nalUnits);
345 return ParseSpsSyntaxScalingList(nalUnits);
346 }
347
ReadGolombCodesForSizeId(std::vector<uint8_t> & nalUnits,uint32_t sizeId)348 void HeifHvccBox::ReadGolombCodesForSizeId(std::vector<uint8_t> &nalUnits, uint32_t sizeId)
349 {
350 uint8_t minCoefNum = READ_BIT_NUM_FLAG << (GENERAL_PROFILE_SIZE + (static_cast<uint8_t>(sizeId)
351 << READ_BIT_NUM_FLAG));
352 uint32_t coefNum = MAX_COEF_NUM < minCoefNum ? MAX_COEF_NUM : minCoefNum;
353 if (sizeId > READ_BIT_NUM_FLAG) {
354 GetGolombCode(nalUnits);
355 }
356 for (uint32_t i = 0; i < coefNum; i++) {
357 GetGolombCode(nalUnits);
358 }
359 }
360
ParseSpsScallListData(std::vector<uint8_t> & nalUnits)361 void HeifHvccBox::ParseSpsScallListData(std::vector<uint8_t> &nalUnits)
362 {
363 for (uint32_t sizeId = 0; sizeId < GENERAL_PROFILE_SIZE; ++sizeId) {
364 for (uint32_t matrixId = 0; matrixId < NUM_TEMPORAL_ID_SIZE;
365 matrixId += ((sizeId == SUB_LAYER_MINUS) ? SUB_LAYER_MINUS : READ_BIT_NUM_FLAG)) {
366 uint32_t tmpFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
367 if (!tmpFlag) {
368 GetGolombCode(nalUnits);
369 } else {
370 ReadGolombCodesForSizeId(nalUnits, sizeId);
371 }
372 }
373 }
374 }
375
ParseSpsVuiParameter(std::vector<uint8_t> & nalUnits)376 bool HeifHvccBox::ParseSpsVuiParameter(std::vector<uint8_t> &nalUnits)
377 {
378 uint8_t aspectRatioInfoPresentFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
379 if (aspectRatioInfoPresentFlag) {
380 uint32_t aspectRatioIdc = GetWord(nalUnits, READ_BYTE_NUM_FLAG);
381 if (aspectRatioIdc == EXTENDED_SAR) {
382 GetWord(nalUnits, READ_BIT_NUM_FLAG);
383 }
384 }
385 uint32_t overscanInfoPresentFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
386 if (overscanInfoPresentFlag) {
387 GetWord(nalUnits, GENERAL_PROFILE_SIZE);
388 }
389 uint32_t videoSignalTypePresentFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
390 if (videoSignalTypePresentFlag) {
391 GetWord(nalUnits, SUB_LAYER_MINUS);
392 spsConfig_.videoRangeFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
393 }
394 return true;
395 }
396
ParseSpsSyntaxScalingList(std::vector<uint8_t> & nalUnits)397 bool HeifHvccBox::ParseSpsSyntaxScalingList(std::vector<uint8_t> &nalUnits)
398 {
399 spsConfig_.scalingListEnabeldFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
400 if (spsConfig_.scalingListEnabeldFlag == READ_BIT_NUM_FLAG) {
401 spsConfig_.scalingListEnabeldFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
402 if (spsConfig_.scalingListEnabeldFlag) {
403 ParseSpsScallListData(nalUnits);
404 }
405 }
406 GetWord(nalUnits, READ_BIT_NUM_FLAG);
407 GetWord(nalUnits, READ_BIT_NUM_FLAG);
408 spsConfig_.pcmEnabledFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
409 if (spsConfig_.pcmEnabledFlag == READ_BIT_NUM_FLAG) {
410 GetWord(nalUnits, PCM_ENABLED_FLAG);
411 GetWord(nalUnits, PCM_ENABLED_FLAG);
412 GetGolombCode(nalUnits);
413 GetGolombCode(nalUnits);
414 GetWord(nalUnits, READ_BIT_NUM_FLAG);
415 }
416 spsConfig_.numShortTermRefPicSets = GetGolombCode(nalUnits);
417 spsConfig_.longTermRefPicsPresentFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
418 if (spsConfig_.longTermRefPicsPresentFlag == READ_BIT_NUM_FLAG) {
419 uint32_t numLongTermRefPicSps = GetGolombCode(nalUnits);
420 for (uint32_t i = 0; i < numLongTermRefPicSps; i++) {
421 // itRefPicPocLsbSps[i] == log2MaxPicOrderCntLsbMinus4 + 4
422 GetWord(nalUnits, spsConfig_.log2MaxPicOrderCntLsbMinus4 + GENERAL_PROFILE_SIZE);
423 GetWord(nalUnits, READ_BIT_NUM_FLAG);
424 }
425 }
426 GetWord(nalUnits, READ_BIT_NUM_FLAG);
427 GetWord(nalUnits, READ_BIT_NUM_FLAG);
428 spsConfig_.vuiParameterPresentFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
429 if (spsConfig_.vuiParameterPresentFlag == READ_BIT_NUM_FLAG) {
430 return ParseSpsVuiParameter(nalUnits);
431 }
432 return false; // Skip parsing subsequent content
433 }
434 } // namespace ImagePlugin
435 } // namespace OHOS
436