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