• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //#define LOG_NDEBUG 0
6 #define LOG_TAG "NalParser"
7 
8 #include <v4l2_codec2/common/NalParser.h>
9 
10 #include <algorithm>
11 
12 #include <media/stagefright/foundation/ABitReader.h>
13 #include <utils/Log.h>
14 
15 namespace android {
16 
17 namespace {
18 
19 enum H264ProfileIDC {
20     kProfileIDCAVLC444 = 44,
21     kProfileIDScalableBaseline = 83,
22     kProfileIDScalableHigh = 86,
23     kProfileIDCHigh = 100,
24     kProfileIDHigh10 = 110,
25     kProfileIDSMultiviewHigh = 118,
26     kProfileIDHigh422 = 122,
27     kProfileIDStereoHigh = 128,
28     kProfileIDHigh444Predictive = 244,
29 };
30 
31 constexpr uint32_t kYUV444Idc = 3;
32 
33 // Read unsigned int encoded with exponential-golomb.
parseUE(ABitReader * br)34 uint32_t parseUE(ABitReader* br) {
35     uint32_t numZeroes = 0;
36     while (br->getBits(1) == 0) {
37         ++numZeroes;
38     }
39     uint32_t val = br->getBits(numZeroes);
40     return val + (1u << numZeroes) - 1;
41 }
42 
43 // Read signed int encoded with exponential-golomb.
parseSE(ABitReader * br)44 int32_t parseSE(ABitReader* br) {
45     uint32_t codeNum = parseUE(br);
46     return (codeNum & 1) ? (codeNum + 1) >> 1 : -static_cast<int32_t>(codeNum >> 1);
47 }
48 
49 // Skip a H.264 sequence scaling list in the specified bitstream.
skipScalingList(ABitReader * br,size_t scalingListSize)50 void skipScalingList(ABitReader* br, size_t scalingListSize) {
51     size_t nextScale = 8;
52     size_t lastScale = 8;
53     for (size_t j = 0; j < scalingListSize; ++j) {
54         if (nextScale != 0) {
55             int32_t deltaScale = parseSE(br);  // delta_sl
56             if (deltaScale < -128) {
57                 ALOGW("delta scale (%d) is below range, capping to -128", deltaScale);
58                 deltaScale = -128;
59             } else if (deltaScale > 127) {
60                 ALOGW("delta scale (%d) is above range, capping to 127", deltaScale);
61                 deltaScale = 127;
62             }
63             nextScale = (lastScale + (deltaScale + 256)) % 256;
64         }
65         lastScale = (nextScale == 0) ? lastScale : nextScale;
66     }
67 }
68 
69 // Skip the H.264 sequence scaling matrix in the specified bitstream.
skipScalingMatrix(ABitReader * br,size_t numScalingLists)70 void skipScalingMatrix(ABitReader* br, size_t numScalingLists) {
71     for (size_t i = 0; i < numScalingLists; ++i) {
72         if (br->getBits(1)) {  // seq_scaling_list_present_flag
73             if (i < 6) {
74                 skipScalingList(br, 16);
75             } else {
76                 skipScalingList(br, 64);
77             }
78         }
79     }
80 }
81 
82 }  // namespace
83 
NalParser(const uint8_t * data,size_t length)84 NalParser::NalParser(const uint8_t* data, size_t length)
85       : mCurrNalDataPos(data), mDataEnd(data + length) {
86     mNextNalStartCodePos = findNextStartCodePos();
87 }
88 
locateNextNal()89 bool NalParser::locateNextNal() {
90     if (mNextNalStartCodePos == mDataEnd) return false;
91     mCurrNalDataPos = mNextNalStartCodePos + kNalStartCodeLength;  // skip start code.
92     mNextNalStartCodePos = findNextStartCodePos();
93     return true;
94 }
95 
locateSPS()96 bool NalParser::locateSPS() {
97     while (locateNextNal()) {
98         if (length() == 0) continue;
99         if (type() != kSPSType) continue;
100         return true;
101     }
102 
103     return false;
104 }
105 
data() const106 const uint8_t* NalParser::data() const {
107     return mCurrNalDataPos;
108 }
109 
length() const110 size_t NalParser::length() const {
111     if (mNextNalStartCodePos == mDataEnd) return mDataEnd - mCurrNalDataPos;
112     size_t length = mNextNalStartCodePos - mCurrNalDataPos;
113     // The start code could be 3 or 4 bytes, i.e., 0x000001 or 0x00000001.
114     return *(mNextNalStartCodePos - 1) == 0x00 ? length - 1 : length;
115 }
116 
type() const117 uint8_t NalParser::type() const {
118     // First byte is forbidden_zero_bit (1) + nal_ref_idc (2) + nal_unit_type (5)
119     constexpr uint8_t kNALTypeMask = 0x1f;
120     return *mCurrNalDataPos & kNALTypeMask;
121 }
122 
findNextStartCodePos() const123 const uint8_t* NalParser::findNextStartCodePos() const {
124     return std::search(mCurrNalDataPos, mDataEnd, kNalStartCode,
125                        kNalStartCode + kNalStartCodeLength);
126 }
127 
findCodedColorAspects(ColorAspects * colorAspects)128 bool NalParser::findCodedColorAspects(ColorAspects* colorAspects) {
129     ALOG_ASSERT(colorAspects);
130     ALOG_ASSERT(type() == kSPSType);
131 
132     // Unfortunately we can't directly jump to the Video Usability Information (VUI) parameters that
133     // contain the color aspects. We need to parse the entire SPS header up until the values we
134     // need.
135 
136     // Skip first byte containing type.
137     ABitReader br(mCurrNalDataPos + 1, length() - 1);
138 
139     uint32_t profileIDC = br.getBits(8);  // profile_idc
140     br.skipBits(16);                      // constraint flags + reserved bits + level_idc
141     parseUE(&br);                         // seq_parameter_set_id
142 
143     if (profileIDC == kProfileIDCHigh || profileIDC == kProfileIDHigh10 ||
144         profileIDC == kProfileIDHigh422 || profileIDC == kProfileIDHigh444Predictive ||
145         profileIDC == kProfileIDCAVLC444 || profileIDC == kProfileIDScalableBaseline ||
146         profileIDC == kProfileIDScalableHigh || profileIDC == kProfileIDSMultiviewHigh ||
147         profileIDC == kProfileIDStereoHigh) {
148         uint32_t chromaFormatIDC = parseUE(&br);
149         if (chromaFormatIDC == kYUV444Idc) {  // chroma_format_idc
150             br.skipBits(1);                   // separate_colour_plane_flag
151         }
152         parseUE(&br);    // bit_depth_luma_minus8
153         parseUE(&br);    // bit_depth_chroma_minus8
154         br.skipBits(1);  // lossless_qpprime_y_zero_flag
155 
156         if (br.getBits(1)) {  // seq_scaling_matrix_present_flag
157             const size_t numScalingLists = (chromaFormatIDC != kYUV444Idc) ? 8 : 12;
158             skipScalingMatrix(&br, numScalingLists);
159         }
160     }
161 
162     parseUE(&br);                                   // log2_max_frame_num_minus4
163     uint32_t pictureOrderCountType = parseUE(&br);  // pic_order_cnt_type
164     if (pictureOrderCountType == 0) {
165         parseUE(&br);  // log2_max_pic_order_cnt_lsb_minus4
166     } else if (pictureOrderCountType == 1) {
167         br.skipBits(1);                              // delta_pic_order_always_zero_flag
168         parseSE(&br);                                // offset_for_non_ref_pic
169         parseSE(&br);                                // offset_for_top_to_bottom_field
170         uint32_t numReferenceFrames = parseUE(&br);  // num_ref_frames_in_pic_order_cnt_cycle
171         for (uint32_t i = 0; i < numReferenceFrames; ++i) {
172             parseUE(&br);  // offset_for_ref_frame
173         }
174     }
175 
176     parseUE(&br);          // num_ref_frames
177     br.skipBits(1);        // gaps_in_frame_num_value_allowed_flag
178     parseUE(&br);          // pic_width_in_mbs_minus1
179     parseUE(&br);          // pic_height_in_map_units_minus1
180     if (!br.getBits(1)) {  // frame_mbs_only_flag
181         br.skipBits(1);    // mb_adaptive_frame_field_flag
182     }
183     br.skipBits(1);  // direct_8x8_inference_flag
184 
185     if (br.getBits(1)) {  // frame_cropping_flag
186         parseUE(&br);     // frame_cropping_rect_left_offset
187         parseUE(&br);     // frame_cropping_rect_right_offset
188         parseUE(&br);     // frame_cropping_rect_top_offset
189         parseUE(&br);     // frame_cropping_rect_bottom_offset
190     }
191 
192     if (br.getBits(1)) {                 // vui_parameters_present_flag
193         if (br.getBits(1)) {             // VUI aspect_ratio_info_present_flag
194             if (br.getBits(8) == 255) {  // VUI aspect_ratio_idc == extended sample aspect ratio
195                 br.skipBits(32);         // VUI sar_width + sar_height
196             }
197         }
198 
199         if (br.getBits(1)) {  // VUI overscan_info_present_flag
200             br.skipBits(1);   // VUI overscan_appropriate_flag
201         }
202         if (br.getBits(1)) {                              // VUI video_signal_type_present_flag
203             br.skipBits(3);                               // VUI video_format
204             colorAspects->fullRange = br.getBits(1);      // VUI video_full_range_flag
205             if (br.getBits(1)) {                          // VUI color_description_present_flag
206                 colorAspects->primaries = br.getBits(8);  // VUI colour_primaries
207                 colorAspects->transfer = br.getBits(8);   // VUI transfer_characteristics
208                 colorAspects->coeffs = br.getBits(8);     // VUI matrix_coefficients
209                 return !br.overRead();
210             }
211         }
212     }
213 
214     return false;
215 }
216 
217 }  // namespace android
218