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