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,int length)172 uint32_t HeifHvccBox::GetWord(const std::vector<uint8_t>& nalu, int length)
173 {
174 uint32_t res = 0;
175 for (int i = 0; i < length && pos_ < boxBitLength_; ++i, ++pos_) {
176 int32_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 int 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 int32_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 spsConfig_.nalUnitType = GetWord(nalUnits, NALU_TYPE_ID_SIZE);
205 return ParseSpsSyntax(nalUnits);
206 }
207
GetNaluData(const std::vector<HvccNalArray> & nalArrays,int8_t naluId)208 std::vector<uint8_t> HeifHvccBox::GetNaluData(const std::vector<HvccNalArray> &nalArrays,
209 int8_t naluId)
210 {
211 for (auto HvccNalunit : nalArrays) {
212 if (HvccNalunit.nalUnitType == naluId && (!HvccNalunit.nalUnits.empty())) {
213 return HvccNalunit.nalUnits[0];
214 }
215 }
216 return std::vector<uint8_t>();
217 }
218
ProcessBoxData(std::vector<uint8_t> & nalu)219 void HeifHvccBox::ProcessBoxData(std::vector<uint8_t> &nalu)
220 {
221 uint32_t naluSize = nalu.size();
222 std::vector<int> indicesToDelete;
223 for (int i = UINT16_BYTES_NUM; i < naluSize; ++i) {
224 if (nalu[i - UINT8_BYTES_NUM] == 0x00 &&
225 nalu[i - SKIP_DOUBLE_DATA_PROCESS_BYTE] == 0x00 && nalu[i] == 0x03) {
226 indicesToDelete.push_back(i);
227 }
228 }
229 for (auto it = indicesToDelete.rbegin(); it != indicesToDelete.rend(); ++it) {
230 nalu.erase(nalu.begin() + *it);
231 }
232 }
233
ParserHvccColorRangeFlag(const std::vector<HvccNalArray> & nalArrays)234 void HeifHvccBox::ParserHvccColorRangeFlag(const std::vector<HvccNalArray> &nalArrays)
235 {
236 auto spsBox = GetNaluData(nalArrays, SPS_BOX_TYPE);
237 ProcessBoxData(spsBox);
238 ParseNalUnitAnalysisSps(spsBox);
239 }
240
ProfileTierLevel(std::vector<uint8_t> & nalUnits,int32_t profilePresentFlag,int32_t maxNumSubLayerMinus1)241 void HeifHvccBox::ProfileTierLevel(std::vector<uint8_t> &nalUnits, int32_t profilePresentFlag,
242 int32_t maxNumSubLayerMinus1)
243 {
244 std::vector<int32_t> generalProfileCompatibilityFlags;
245 std::vector<int32_t> subLayerProfilePresentFlag;
246 std::vector<int32_t> subLayerLevelPresentFlags;
247 std::vector<int32_t> subLayerProfileIdcs;
248 std::vector<std::vector<int32_t>> subLayerProfileCompatibilityFlags;
249 if (profilePresentFlag) {
250 GetWord(nalUnits, READ_BIT_NUM_FLAG); // general_profile_idc
251
252 for (int j = 0; j < READ_GENERAL_PROFILE_IDC_NUM; ++j) {
253 int32_t flag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
254 generalProfileCompatibilityFlags.push_back(flag);
255 }
256 GetWord(nalUnits, READ_BYTE_NUM_FLAG);
257 GetWord(nalUnits, READ_BYTE_NUM_FLAG);
258 GetWord(nalUnits, READ_GENERAL_PROFILE_IDC_NUM);
259 }
260 GetWord(nalUnits, READ_BYTE_NUM_FLAG);
261 subLayerProfilePresentFlag.resize(maxNumSubLayerMinus1);
262 for (int i = 0; i < maxNumSubLayerMinus1; ++i) {
263 subLayerProfilePresentFlag[i] = GetWord(nalUnits, READ_BIT_NUM_FLAG);
264 subLayerLevelPresentFlags.push_back(GetWord(nalUnits, READ_BIT_NUM_FLAG));
265 }
266
267 if (maxNumSubLayerMinus1 > 0) {
268 for (int i = maxNumSubLayerMinus1; i < READ_BYTE_NUM_FLAG; ++i) {
269 GetWord(nalUnits, READ_BIT_NUM_FLAG);
270 GetWord(nalUnits, READ_BIT_NUM_FLAG);
271 }
272 }
273
274 subLayerProfileIdcs.resize(maxNumSubLayerMinus1);
275 subLayerProfileCompatibilityFlags.resize(maxNumSubLayerMinus1,
276 std::vector<int32_t>(GENERAL_PROFILE_SIZE));
277 for (int i = 0; i < maxNumSubLayerMinus1; i++) {
278 if (subLayerProfilePresentFlag[i]) {
279 GetWord(nalUnits, SUB_LAYER_PRESENT_PROFILE_SIZE);
280 subLayerProfileIdcs[i] = GetWord(nalUnits, SUB_LAYER_PROFILE_IDC_SIZE);
281 for (int j = 0; j < GENERAL_PROFILE_SIZE; ++j) {
282 subLayerProfileCompatibilityFlags[i][j] = GetWord(nalUnits, READ_BIT_NUM_FLAG);
283 }
284
285 // skip sub_layer_profile_idcs judge;
286 GetWord(nalUnits, READ_SUB_LAYER_PROFILE_IDCS);
287 }
288 if (subLayerLevelPresentFlags[i]) {
289 GetWord(nalUnits, READ_BYTE_NUM_FLAG);
290 }
291 }
292 }
293
ParseNalUnitAnalysisSps(std::vector<uint8_t> & nalUnits)294 bool HeifHvccBox::ParseNalUnitAnalysisSps(std::vector<uint8_t> &nalUnits)
295 {
296 boxBitLength_ = nalUnits.size() * BIT_DEPTH_DIFF;
297 spsConfig_.forbiddenZeroBit = GetWord(nalUnits, READ_BIT_NUM_FLAG);
298 spsConfig_.nuhTemporalIdPlus1 = GetWord(nalUnits, NUM_TEMPORAL_ID_SIZE);
299 spsConfig_.nalUnitType = GetWord(nalUnits, NALU_TYPE_ID_SIZE);
300 GetWord(nalUnits, SUB_LAYER_MINUS);
301 return ParseSpsSyntax(nalUnits);
302 }
303
ParseSpsSyntax(std::vector<uint8_t> & nalUnits)304 bool HeifHvccBox::ParseSpsSyntax(std::vector<uint8_t> &nalUnits)
305 {
306 //General sequence parameter set RBSP syntax
307 spsConfig_.spsVideoParameterSetId = GetWord(nalUnits, GENERAL_PROFILE_SIZE);
308 spsConfig_.spsMaxSubLayersMinus1 = GetWord(nalUnits, SUB_LAYER_MINUS);
309 spsConfig_.spsTemporalIdNestingFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
310
311 //go to profile_tier_level parser
312 ProfileTierLevel(nalUnits,
313 spsConfig_.spsTemporalIdNestingFlag,
314 spsConfig_.spsMaxSubLayersMinus1);
315
316 spsConfig_.spsVideoParameterSetId = GetGolombCode(nalUnits);
317 spsConfig_.chromaFormatIdc = GetGolombCode(nalUnits);
318 if (static_cast<int>(spsConfig_.chromaFormatIdc) == SUB_LAYER_MINUS) {
319 spsConfig_.separateColourPlaneFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
320 }
321 spsConfig_.picWidthInLumaSamples = GetGolombCode(nalUnits);
322 spsConfig_.picHeightInLumaSamples = GetGolombCode(nalUnits);
323 spsConfig_.conformanceWindowFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
324 if (static_cast<int>(spsConfig_.conformanceWindowFlag) == READ_BIT_NUM_FLAG) {
325 spsConfig_.confWinLefOffset = GetGolombCode(nalUnits);
326 spsConfig_.confWinRightOffset = GetGolombCode(nalUnits);
327 spsConfig_.confWinTopOffset = GetGolombCode(nalUnits);
328 spsConfig_.confWinBottomOffset = GetGolombCode(nalUnits);
329 }
330 spsConfig_.bitDepthLumaMinus8 = GetGolombCode(nalUnits);
331 spsConfig_.bitDepthChromaMinus8 = GetGolombCode(nalUnits);
332 spsConfig_.log2MaxPicOrderCntLsbMinus4 = GetGolombCode(nalUnits);
333 spsConfig_.spsSubLayerOrderingInfoPresentFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
334 int i = spsConfig_.spsSubLayerOrderingInfoPresentFlag ? 0 : static_cast<int>(spsConfig_.spsMaxSubLayersMinus1);
335 for (; i <= spsConfig_.spsMaxSubLayersMinus1; i++) {
336 GetGolombCode(nalUnits);
337 GetGolombCode(nalUnits);
338 GetGolombCode(nalUnits);
339 }
340 GetGolombCode(nalUnits);
341 GetGolombCode(nalUnits);
342 GetGolombCode(nalUnits);
343 GetGolombCode(nalUnits);
344 GetGolombCode(nalUnits);
345 GetGolombCode(nalUnits);
346 return ParseSpsSyntaxScalingList(nalUnits);
347 }
348
ReadGolombCodesForSizeId(std::vector<uint8_t> & nalUnits,int sizeId)349 void HeifHvccBox::ReadGolombCodesForSizeId(std::vector<uint8_t> &nalUnits, int sizeId)
350 {
351 uint8_t minCoefNum = READ_BIT_NUM_FLAG << (GENERAL_PROFILE_SIZE + (static_cast<uint8_t>(sizeId)
352 << READ_BIT_NUM_FLAG));
353 int coefNum = MAX_COEF_NUM < minCoefNum ? MAX_COEF_NUM : minCoefNum;
354 if (sizeId > READ_BIT_NUM_FLAG) {
355 GetGolombCode(nalUnits);
356 }
357 for (int i = 0; i < coefNum; i++) {
358 GetGolombCode(nalUnits);
359 }
360 }
361
ParseSpsScallListData(std::vector<uint8_t> & nalUnits)362 void HeifHvccBox::ParseSpsScallListData(std::vector<uint8_t> &nalUnits)
363 {
364 for (int sizeId = 0; sizeId < GENERAL_PROFILE_SIZE; ++sizeId) {
365 for (int matrixId = 0; matrixId < NUM_TEMPORAL_ID_SIZE;
366 matrixId += ((sizeId == SUB_LAYER_MINUS) ? SUB_LAYER_MINUS : READ_BIT_NUM_FLAG)) {
367 uint8_t tmpFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
368 if (!tmpFlag) {
369 GetGolombCode(nalUnits);
370 } else {
371 ReadGolombCodesForSizeId(nalUnits, sizeId);
372 }
373 }
374 }
375 }
376
ParseSpsVuiParameter(std::vector<uint8_t> & nalUnits)377 bool HeifHvccBox::ParseSpsVuiParameter(std::vector<uint8_t> &nalUnits)
378 {
379 int8_t aspectRatioInfoPresentFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
380 if (aspectRatioInfoPresentFlag) {
381 int32_t aspectRatioIdc = GetWord(nalUnits, READ_BYTE_NUM_FLAG);
382 if (static_cast<int>(aspectRatioIdc) == EXTENDED_SAR) {
383 GetWord(nalUnits, READ_BIT_NUM_FLAG);
384 }
385 }
386 int8_t overscanInfoPresentFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
387 if (overscanInfoPresentFlag) {
388 GetWord(nalUnits, GENERAL_PROFILE_SIZE);
389 }
390 int8_t videoSignalTypePresentFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
391 if (videoSignalTypePresentFlag) {
392 GetWord(nalUnits, SUB_LAYER_MINUS);
393 spsConfig_.videoRangeFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
394 }
395 return true;
396 }
397
ParseSpsSyntaxScalingList(std::vector<uint8_t> & nalUnits)398 bool HeifHvccBox::ParseSpsSyntaxScalingList(std::vector<uint8_t> &nalUnits)
399 {
400 spsConfig_.scalingListEnabeldFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
401 if (static_cast<int>(spsConfig_.scalingListEnabeldFlag) == READ_BIT_NUM_FLAG) {
402 spsConfig_.scalingListEnabeldFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
403 if (spsConfig_.scalingListEnabeldFlag) {
404 ParseSpsScallListData(nalUnits);
405 }
406 }
407 GetWord(nalUnits, READ_BIT_NUM_FLAG);
408 GetWord(nalUnits, READ_BIT_NUM_FLAG);
409 spsConfig_.pcmEnabledFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
410 if (static_cast<int>(spsConfig_.pcmEnabledFlag) == READ_BIT_NUM_FLAG) {
411 GetWord(nalUnits, PCM_ENABLED_FLAG);
412 GetWord(nalUnits, PCM_ENABLED_FLAG);
413 GetGolombCode(nalUnits);
414 GetGolombCode(nalUnits);
415 GetWord(nalUnits, READ_BIT_NUM_FLAG);
416 }
417 spsConfig_.numShortTermRefPicSets = GetGolombCode(nalUnits);
418 spsConfig_.longTermRefPicsPresentFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
419 if (spsConfig_.longTermRefPicsPresentFlag == READ_BIT_NUM_FLAG) {
420 int32_t numLongTermRefPicSps = GetGolombCode(nalUnits);
421 for (int i = 0; i < numLongTermRefPicSps; i++) {
422 // itRefPicPocLsbSps[i] is equal to log2MaxPicOrderCntLsbMinus4 + 4.
423 GetWord(nalUnits, spsConfig_.log2MaxPicOrderCntLsbMinus4 + GENERAL_PROFILE_SIZE);
424 GetWord(nalUnits, READ_BIT_NUM_FLAG);
425 }
426 }
427 GetWord(nalUnits, READ_BIT_NUM_FLAG);
428 GetWord(nalUnits, READ_BIT_NUM_FLAG);
429 spsConfig_.vuiParameterPresentFlag = GetWord(nalUnits, READ_BIT_NUM_FLAG);
430 if (static_cast<int>(spsConfig_.vuiParameterPresentFlag) == READ_BIT_NUM_FLAG) {
431 return ParseSpsVuiParameter(nalUnits);
432 }
433 return false; // Skip parsing subsequent content
434 }
435 } // namespace ImagePlugin
436 } // namespace OHOS
437