xref: /aosp_15_r20/external/webrtc/common_video/h264/pps_parser_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "common_video/h264/pps_parser.h"
12 
13 #include "common_video/h264/h264_common.h"
14 #include "rtc_base/bit_buffer.h"
15 #include "rtc_base/buffer.h"
16 #include "rtc_base/checks.h"
17 #include "test/gtest.h"
18 
19 namespace webrtc {
20 
21 namespace {
22 // Contains enough of the image slice to contain slice QP.
23 const uint8_t kH264BitstreamChunk[] = {
24     0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x80, 0x20, 0xda, 0x01, 0x40, 0x16,
25     0xe8, 0x06, 0xd0, 0xa1, 0x35, 0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x06,
26     0xe2, 0x00, 0x00, 0x00, 0x01, 0x65, 0xb8, 0x40, 0xf0, 0x8c, 0x03, 0xf2,
27     0x75, 0x67, 0xad, 0x41, 0x64, 0x24, 0x0e, 0xa0, 0xb2, 0x12, 0x1e, 0xf8,
28 };
29 const size_t kPpsBufferMaxSize = 256;
30 const uint32_t kIgnored = 0;
31 }  // namespace
32 
WritePps(const PpsParser::PpsState & pps,int slice_group_map_type,int num_slice_groups,int pic_size_in_map_units,rtc::Buffer * out_buffer)33 void WritePps(const PpsParser::PpsState& pps,
34               int slice_group_map_type,
35               int num_slice_groups,
36               int pic_size_in_map_units,
37               rtc::Buffer* out_buffer) {
38   uint8_t data[kPpsBufferMaxSize] = {0};
39   rtc::BitBufferWriter bit_buffer(data, kPpsBufferMaxSize);
40 
41   // pic_parameter_set_id: ue(v)
42   bit_buffer.WriteExponentialGolomb(pps.id);
43   // seq_parameter_set_id: ue(v)
44   bit_buffer.WriteExponentialGolomb(pps.sps_id);
45   // entropy_coding_mode_flag: u(1)
46   bit_buffer.WriteBits(pps.entropy_coding_mode_flag, 1);
47   // bottom_field_pic_order_in_frame_present_flag: u(1)
48   bit_buffer.WriteBits(pps.bottom_field_pic_order_in_frame_present_flag ? 1 : 0,
49                        1);
50   // num_slice_groups_minus1: ue(v)
51   RTC_CHECK_GT(num_slice_groups, 0);
52   bit_buffer.WriteExponentialGolomb(num_slice_groups - 1);
53 
54   if (num_slice_groups > 1) {
55     // slice_group_map_type: ue(v)
56     bit_buffer.WriteExponentialGolomb(slice_group_map_type);
57     switch (slice_group_map_type) {
58       case 0:
59         for (int i = 0; i < num_slice_groups; ++i) {
60           // run_length_minus1[iGroup]: ue(v)
61           bit_buffer.WriteExponentialGolomb(kIgnored);
62         }
63         break;
64       case 2:
65         for (int i = 0; i < num_slice_groups; ++i) {
66           // top_left[iGroup]: ue(v)
67           bit_buffer.WriteExponentialGolomb(kIgnored);
68           // bottom_right[iGroup]: ue(v)
69           bit_buffer.WriteExponentialGolomb(kIgnored);
70         }
71         break;
72       case 3:
73       case 4:
74       case 5:
75         // slice_group_change_direction_flag: u(1)
76         bit_buffer.WriteBits(kIgnored, 1);
77         // slice_group_change_rate_minus1: ue(v)
78         bit_buffer.WriteExponentialGolomb(kIgnored);
79         break;
80       case 6: {
81         bit_buffer.WriteExponentialGolomb(pic_size_in_map_units - 1);
82 
83         uint32_t slice_group_id_bits = 0;
84         // If num_slice_groups is not a power of two an additional bit is
85         // required
86         // to account for the ceil() of log2() below.
87         if ((num_slice_groups & (num_slice_groups - 1)) != 0)
88           ++slice_group_id_bits;
89         while (num_slice_groups > 0) {
90           num_slice_groups >>= 1;
91           ++slice_group_id_bits;
92         }
93 
94         for (int i = 0; i < pic_size_in_map_units; ++i) {
95           // slice_group_id[i]: u(v)
96           // Represented by ceil(log2(num_slice_groups_minus1 + 1)) bits.
97           bit_buffer.WriteBits(kIgnored, slice_group_id_bits);
98         }
99         break;
100       }
101       default:
102         RTC_DCHECK_NOTREACHED();
103     }
104   }
105 
106   // num_ref_idx_l0_default_active_minus1: ue(v)
107   bit_buffer.WriteExponentialGolomb(kIgnored);
108   // num_ref_idx_l1_default_active_minus1: ue(v)
109   bit_buffer.WriteExponentialGolomb(kIgnored);
110   // weighted_pred_flag: u(1)
111   bit_buffer.WriteBits(pps.weighted_pred_flag ? 1 : 0, 1);
112   // weighted_bipred_idc: u(2)
113   bit_buffer.WriteBits(pps.weighted_bipred_idc, 2);
114 
115   // pic_init_qp_minus26: se(v)
116   bit_buffer.WriteSignedExponentialGolomb(pps.pic_init_qp_minus26);
117   // pic_init_qs_minus26: se(v)
118   bit_buffer.WriteExponentialGolomb(kIgnored);
119   // chroma_qp_index_offset: se(v)
120   bit_buffer.WriteExponentialGolomb(kIgnored);
121   // deblocking_filter_control_present_flag: u(1)
122   // constrained_intra_pred_flag: u(1)
123   bit_buffer.WriteBits(kIgnored, 2);
124   // redundant_pic_cnt_present_flag: u(1)
125   bit_buffer.WriteBits(pps.redundant_pic_cnt_present_flag, 1);
126 
127   size_t byte_offset;
128   size_t bit_offset;
129   bit_buffer.GetCurrentOffset(&byte_offset, &bit_offset);
130   if (bit_offset > 0) {
131     bit_buffer.WriteBits(0, 8 - bit_offset);
132     bit_buffer.GetCurrentOffset(&byte_offset, &bit_offset);
133   }
134 
135   H264::WriteRbsp(data, byte_offset, out_buffer);
136 }
137 
138 class PpsParserTest : public ::testing::Test {
139  public:
PpsParserTest()140   PpsParserTest() {}
~PpsParserTest()141   ~PpsParserTest() override {}
142 
RunTest()143   void RunTest() {
144     VerifyParsing(generated_pps_, 0, 1, 0);
145     const int kMaxSliceGroups = 17;  // Arbitrarily large.
146     const int kMaxMapType = 6;
147     int slice_group_bits = 0;
148     for (int slice_group = 2; slice_group < kMaxSliceGroups; ++slice_group) {
149       if ((slice_group & (slice_group - 1)) == 0) {
150         // Slice group at a new power of two - increase slice_group_bits.
151         ++slice_group_bits;
152       }
153       for (int map_type = 0; map_type <= kMaxMapType; ++map_type) {
154         if (map_type == 1) {
155           // TODO(sprang): Implement support for dispersed slice group map type.
156           // See 8.2.2.2 Specification for dispersed slice group map type.
157           continue;
158         } else if (map_type == 6) {
159           int max_pic_size = 1 << slice_group_bits;
160           for (int pic_size = 1; pic_size < max_pic_size; ++pic_size)
161             VerifyParsing(generated_pps_, map_type, slice_group, pic_size);
162         } else {
163           VerifyParsing(generated_pps_, map_type, slice_group, 0);
164         }
165       }
166     }
167   }
168 
VerifyParsing(const PpsParser::PpsState & pps,int slice_group_map_type,int num_slice_groups,int pic_size_in_map_units)169   void VerifyParsing(const PpsParser::PpsState& pps,
170                      int slice_group_map_type,
171                      int num_slice_groups,
172                      int pic_size_in_map_units) {
173     buffer_.Clear();
174     WritePps(pps, slice_group_map_type, num_slice_groups, pic_size_in_map_units,
175              &buffer_);
176     parsed_pps_ = PpsParser::ParsePps(buffer_.data(), buffer_.size());
177     ASSERT_TRUE(parsed_pps_);
178     EXPECT_EQ(pps.bottom_field_pic_order_in_frame_present_flag,
179               parsed_pps_->bottom_field_pic_order_in_frame_present_flag);
180     EXPECT_EQ(pps.weighted_pred_flag, parsed_pps_->weighted_pred_flag);
181     EXPECT_EQ(pps.weighted_bipred_idc, parsed_pps_->weighted_bipred_idc);
182     EXPECT_EQ(pps.entropy_coding_mode_flag,
183               parsed_pps_->entropy_coding_mode_flag);
184     EXPECT_EQ(pps.redundant_pic_cnt_present_flag,
185               parsed_pps_->redundant_pic_cnt_present_flag);
186     EXPECT_EQ(pps.pic_init_qp_minus26, parsed_pps_->pic_init_qp_minus26);
187     EXPECT_EQ(pps.id, parsed_pps_->id);
188     EXPECT_EQ(pps.sps_id, parsed_pps_->sps_id);
189   }
190 
191   PpsParser::PpsState generated_pps_;
192   rtc::Buffer buffer_;
193   absl::optional<PpsParser::PpsState> parsed_pps_;
194 };
195 
TEST_F(PpsParserTest,ZeroPps)196 TEST_F(PpsParserTest, ZeroPps) {
197   RunTest();
198 }
199 
TEST_F(PpsParserTest,MaxPps)200 TEST_F(PpsParserTest, MaxPps) {
201   generated_pps_.bottom_field_pic_order_in_frame_present_flag = true;
202   generated_pps_.pic_init_qp_minus26 = 25;
203   generated_pps_.redundant_pic_cnt_present_flag = 1;  // 1 bit value.
204   generated_pps_.weighted_bipred_idc = (1 << 2) - 1;  // 2 bit value.
205   generated_pps_.weighted_pred_flag = true;
206   generated_pps_.entropy_coding_mode_flag = true;
207   generated_pps_.id = 2;
208   generated_pps_.sps_id = 1;
209   RunTest();
210 
211   generated_pps_.pic_init_qp_minus26 = -25;
212   RunTest();
213 }
214 
TEST_F(PpsParserTest,PpsIdFromSlice)215 TEST_F(PpsParserTest, PpsIdFromSlice) {
216   absl::optional<uint32_t> pps_id = PpsParser::ParsePpsIdFromSlice(
217       kH264BitstreamChunk, sizeof(kH264BitstreamChunk));
218   ASSERT_TRUE(pps_id);
219   EXPECT_EQ(2u, *pps_id);
220 }
221 
222 }  // namespace webrtc
223