tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pps_parser_unittest.cc (8984B)


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