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