tor-browser

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

sps_vui_rewriter_unittest.cc (15665B)


      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/sps_vui_rewriter.h"
     12 
     13 #include <cstddef>
     14 #include <cstdint>
     15 #include <optional>
     16 #include <tuple>
     17 
     18 #include "api/array_view.h"
     19 #include "api/video/color_space.h"
     20 #include "common_video/h264/h264_common.h"
     21 #include "common_video/h264/sps_parser.h"
     22 #include "rtc_base/bit_buffer.h"
     23 #include "rtc_base/buffer.h"
     24 #include "rtc_base/logging.h"
     25 #include "test/gmock.h"
     26 #include "test/gtest.h"
     27 
     28 namespace webrtc {
     29 
     30 namespace {
     31 enum SpsMode {
     32  kNoRewriteRequired_VuiOptimal,
     33  kRewriteRequired_NoVui,
     34  kRewriteRequired_NoBitstreamRestriction,
     35  kRewriteRequired_VuiSuboptimal,
     36 };
     37 
     38 constexpr size_t kSpsBufferMaxSize = 256;
     39 constexpr size_t kWidth = 640;
     40 constexpr size_t kHeight = 480;
     41 
     42 constexpr uint8_t kStartSequence[] = {0x00, 0x00, 0x00, 0x01};
     43 constexpr uint8_t kAud[] = {H264::NaluType::kAud, 0x09, 0x10};
     44 constexpr uint8_t kSpsNaluType[] = {H264::NaluType::kSps};
     45 constexpr uint8_t kIdr1[] = {H264::NaluType::kIdr, 0xFF, 0x00, 0x00, 0x04};
     46 constexpr uint8_t kIdr2[] = {H264::NaluType::kIdr, 0xFF, 0x00, 0x11};
     47 
     48 struct VuiHeader {
     49  uint32_t vui_parameters_present_flag = 0;
     50  uint32_t bitstream_restriction_flag = 0;
     51  uint32_t max_num_reorder_frames = 0;
     52  uint32_t max_dec_frame_buffering = 0;
     53  uint32_t video_signal_type_present_flag = 0;
     54  uint32_t video_full_range_flag = 0;
     55  uint32_t colour_description_present_flag = 0;
     56  uint8_t colour_primaries = 0;
     57  uint8_t transfer_characteristics = 0;
     58  uint8_t matrix_coefficients = 0;
     59 };
     60 
     61 const VuiHeader kVuiNotPresent;
     62 
     63 const VuiHeader kVuiNoBitstreamRestriction = {
     64    .vui_parameters_present_flag = 1,
     65 };
     66 
     67 const VuiHeader kVuiNoFrameBuffering = {
     68    .vui_parameters_present_flag = 1,
     69    .bitstream_restriction_flag = 1,
     70    .max_dec_frame_buffering = 1,
     71 };
     72 
     73 const VuiHeader kVuiFrameBuffering = {
     74    .vui_parameters_present_flag = 1,
     75    .bitstream_restriction_flag = 1,
     76    .max_num_reorder_frames = 3,
     77    .max_dec_frame_buffering = 3,
     78 };
     79 
     80 const VuiHeader kVuiNoVideoSignalType = {
     81    .vui_parameters_present_flag = 1,
     82    .bitstream_restriction_flag = 1,
     83    .max_dec_frame_buffering = 1,
     84 };
     85 
     86 const VuiHeader kVuiLimitedRangeNoColourDescription = {
     87    .vui_parameters_present_flag = 1,
     88    .bitstream_restriction_flag = 1,
     89    .max_dec_frame_buffering = 1,
     90    .video_signal_type_present_flag = 1,
     91 };
     92 
     93 const VuiHeader kVuiFullRangeNoColourDescription = {
     94    .vui_parameters_present_flag = 1,
     95    .bitstream_restriction_flag = 1,
     96    .max_dec_frame_buffering = 1,
     97    .video_signal_type_present_flag = 1,
     98    .video_full_range_flag = 1,
     99 };
    100 
    101 const VuiHeader kVuiLimitedRangeBt709Color = {
    102    .vui_parameters_present_flag = 1,
    103    .bitstream_restriction_flag = 1,
    104    .max_dec_frame_buffering = 1,
    105    .video_signal_type_present_flag = 1,
    106    .colour_description_present_flag = 1,
    107    .colour_primaries = 1,
    108    .transfer_characteristics = 1,
    109    .matrix_coefficients = 1,
    110 };
    111 
    112 const ColorSpace kColorSpaceH264Default(ColorSpace::PrimaryID::kUnspecified,
    113                                        ColorSpace::TransferID::kUnspecified,
    114                                        ColorSpace::MatrixID::kUnspecified,
    115                                        ColorSpace::RangeID::kLimited);
    116 
    117 const ColorSpace kColorSpacePrimariesBt709(ColorSpace::PrimaryID::kBT709,
    118                                           ColorSpace::TransferID::kUnspecified,
    119                                           ColorSpace::MatrixID::kUnspecified,
    120                                           ColorSpace::RangeID::kLimited);
    121 
    122 const ColorSpace kColorSpaceTransferBt709(ColorSpace::PrimaryID::kUnspecified,
    123                                          ColorSpace::TransferID::kBT709,
    124                                          ColorSpace::MatrixID::kUnspecified,
    125                                          ColorSpace::RangeID::kLimited);
    126 
    127 const ColorSpace kColorSpaceMatrixBt709(ColorSpace::PrimaryID::kUnspecified,
    128                                        ColorSpace::TransferID::kUnspecified,
    129                                        ColorSpace::MatrixID::kBT709,
    130                                        ColorSpace::RangeID::kLimited);
    131 
    132 const ColorSpace kColorSpaceFullRange(ColorSpace::PrimaryID::kBT709,
    133                                      ColorSpace::TransferID::kUnspecified,
    134                                      ColorSpace::MatrixID::kUnspecified,
    135                                      ColorSpace::RangeID::kFull);
    136 
    137 const ColorSpace kColorSpaceBt709LimitedRange(ColorSpace::PrimaryID::kBT709,
    138                                              ColorSpace::TransferID::kBT709,
    139                                              ColorSpace::MatrixID::kBT709,
    140                                              ColorSpace::RangeID::kLimited);
    141 }  // namespace
    142 
    143 // Generates a fake SPS with basically everything empty and with characteristics
    144 // based off SpsMode.
    145 // Pass in a buffer of at least kSpsBufferMaxSize.
    146 // The fake SPS that this generates also always has at least one emulation byte
    147 // at offset 2, since the first two bytes are always 0, and has a 0x3 as the
    148 // level_idc, to make sure the parser doesn't eat all 0x3 bytes.
    149 void GenerateFakeSps(const VuiHeader& vui, Buffer* out_buffer) {
    150  uint8_t rbsp[kSpsBufferMaxSize] = {0};
    151  BitBufferWriter writer(rbsp, kSpsBufferMaxSize);
    152  // Profile byte.
    153  writer.WriteUInt8(0);
    154  // Constraint sets and reserved zero bits.
    155  writer.WriteUInt8(0);
    156  // level_idc.
    157  writer.WriteUInt8(3);
    158  // seq_paramter_set_id.
    159  writer.WriteExponentialGolomb(0);
    160  // Profile is not special, so we skip all the chroma format settings.
    161 
    162  // Now some bit magic.
    163  // log2_max_frame_num_minus4: ue(v). 0 is fine.
    164  writer.WriteExponentialGolomb(0);
    165  // pic_order_cnt_type: ue(v).
    166  writer.WriteExponentialGolomb(0);
    167  // log2_max_pic_order_cnt_lsb_minus4: ue(v). 0 is fine.
    168  writer.WriteExponentialGolomb(0);
    169 
    170  // max_num_ref_frames: ue(v). Use 1, to make optimal/suboptimal more obvious.
    171  writer.WriteExponentialGolomb(1);
    172  // gaps_in_frame_num_value_allowed_flag: u(1).
    173  writer.WriteBits(0, 1);
    174  // Next are width/height. First, calculate the mbs/map_units versions.
    175  uint16_t width_in_mbs_minus1 = (kWidth + 15) / 16 - 1;
    176 
    177  // For the height, we're going to define frame_mbs_only_flag, so we need to
    178  // divide by 2. See the parser for the full calculation.
    179  uint16_t height_in_map_units_minus1 = ((kHeight + 15) / 16 - 1) / 2;
    180  // Write each as ue(v).
    181  writer.WriteExponentialGolomb(width_in_mbs_minus1);
    182  writer.WriteExponentialGolomb(height_in_map_units_minus1);
    183  // frame_mbs_only_flag: u(1). Needs to be false.
    184  writer.WriteBits(0, 1);
    185  // mb_adaptive_frame_field_flag: u(1).
    186  writer.WriteBits(0, 1);
    187  // direct_8x8_inferene_flag: u(1).
    188  writer.WriteBits(0, 1);
    189  // frame_cropping_flag: u(1). 1, so we can supply crop.
    190  writer.WriteBits(1, 1);
    191  // Now we write the left/right/top/bottom crop. For simplicity, we'll put all
    192  // the crop at the left/top.
    193  // We picked a 4:2:0 format, so the crops are 1/2 the pixel crop values.
    194  // Left/right.
    195  writer.WriteExponentialGolomb(((16 - (kWidth % 16)) % 16) / 2);
    196  writer.WriteExponentialGolomb(0);
    197  // Top/bottom.
    198  writer.WriteExponentialGolomb(((16 - (kHeight % 16)) % 16) / 2);
    199  writer.WriteExponentialGolomb(0);
    200 
    201  // Finally! The VUI.
    202  // vui_parameters_present_flag: u(1)
    203  writer.WriteBits(vui.vui_parameters_present_flag, 1);
    204  if (vui.vui_parameters_present_flag) {
    205    // aspect_ratio_info_present_flag, overscan_info_present_flag. Both u(1).
    206    writer.WriteBits(0, 2);
    207 
    208    writer.WriteBits(vui.video_signal_type_present_flag, 1);
    209    if (vui.video_signal_type_present_flag) {
    210      // video_format: u(3). 5 = Unspecified
    211      writer.WriteBits(5, 3);
    212      writer.WriteBits(vui.video_full_range_flag, 1);
    213      writer.WriteBits(vui.colour_description_present_flag, 1);
    214      if (vui.colour_description_present_flag) {
    215        writer.WriteUInt8(vui.colour_primaries);
    216        writer.WriteUInt8(vui.transfer_characteristics);
    217        writer.WriteUInt8(vui.matrix_coefficients);
    218      }
    219    }
    220 
    221    // chroma_loc_info_present_flag, timing_info_present_flag,
    222    // nal_hrd_parameters_present_flag, vcl_hrd_parameters_present_flag,
    223    // pic_struct_present_flag, All u(1)
    224    writer.WriteBits(0, 5);
    225 
    226    writer.WriteBits(vui.bitstream_restriction_flag, 1);
    227    if (vui.bitstream_restriction_flag) {
    228      // Write some defaults. Shouldn't matter for parsing, though.
    229      // motion_vectors_over_pic_boundaries_flag: u(1)
    230      writer.WriteBits(1, 1);
    231      // max_bytes_per_pic_denom: ue(v)
    232      writer.WriteExponentialGolomb(2);
    233      // max_bits_per_mb_denom: ue(v)
    234      writer.WriteExponentialGolomb(1);
    235      // log2_max_mv_length_horizontal: ue(v)
    236      // log2_max_mv_length_vertical: ue(v)
    237      writer.WriteExponentialGolomb(16);
    238      writer.WriteExponentialGolomb(16);
    239 
    240      // Next are the limits we care about.
    241      writer.WriteExponentialGolomb(vui.max_num_reorder_frames);
    242      writer.WriteExponentialGolomb(vui.max_dec_frame_buffering);
    243    }
    244  }
    245 
    246  // Get the number of bytes written (including the last partial byte).
    247  size_t byte_count, bit_offset;
    248  writer.GetCurrentOffset(&byte_count, &bit_offset);
    249  if (bit_offset > 0) {
    250    byte_count++;
    251  }
    252 
    253  H264::WriteRbsp(MakeArrayView(rbsp, byte_count), out_buffer);
    254 }
    255 
    256 void TestSps(const VuiHeader& vui,
    257             const ColorSpace* color_space,
    258             SpsVuiRewriter::ParseResult expected_parse_result) {
    259  LogMessage::LogToDebug(LS_VERBOSE);
    260  Buffer original_sps;
    261  GenerateFakeSps(vui, &original_sps);
    262 
    263  std::optional<SpsParser::SpsState> sps;
    264  Buffer rewritten_sps;
    265  SpsVuiRewriter::ParseResult result = SpsVuiRewriter::ParseAndRewriteSps(
    266      original_sps, &sps, color_space, &rewritten_sps,
    267      SpsVuiRewriter::Direction::kIncoming);
    268  EXPECT_EQ(expected_parse_result, result);
    269  ASSERT_TRUE(sps);
    270  EXPECT_EQ(sps->width, kWidth);
    271  EXPECT_EQ(sps->height, kHeight);
    272  if (vui.vui_parameters_present_flag) {
    273    EXPECT_EQ(sps->vui_params_present, 1u);
    274  }
    275 
    276  if (result == SpsVuiRewriter::ParseResult::kVuiRewritten) {
    277    // Ensure that added/rewritten SPS is parsable.
    278    Buffer tmp;
    279    result = SpsVuiRewriter::ParseAndRewriteSps(
    280        rewritten_sps, &sps, nullptr, &tmp,
    281        SpsVuiRewriter::Direction::kIncoming);
    282    EXPECT_EQ(SpsVuiRewriter::ParseResult::kVuiOk, result);
    283    ASSERT_TRUE(sps);
    284    EXPECT_EQ(sps->width, kWidth);
    285    EXPECT_EQ(sps->height, kHeight);
    286    EXPECT_EQ(sps->vui_params_present, 1u);
    287  }
    288 }
    289 
    290 class SpsVuiRewriterTest : public ::testing::Test,
    291                           public ::testing::WithParamInterface<
    292                               ::testing::tuple<VuiHeader,
    293                                                const ColorSpace*,
    294                                                SpsVuiRewriter::ParseResult>> {
    295 };
    296 
    297 TEST_P(SpsVuiRewriterTest, RewriteVui) {
    298  VuiHeader vui = ::testing::get<0>(GetParam());
    299  const ColorSpace* color_space = ::testing::get<1>(GetParam());
    300  SpsVuiRewriter::ParseResult expected_parse_result =
    301      ::testing::get<2>(GetParam());
    302  TestSps(vui, color_space, expected_parse_result);
    303 }
    304 
    305 INSTANTIATE_TEST_SUITE_P(
    306    All,
    307    SpsVuiRewriterTest,
    308    ::testing::Values(
    309        std::make_tuple(kVuiNoFrameBuffering,
    310                        nullptr,
    311                        SpsVuiRewriter::ParseResult::kVuiOk),
    312        std::make_tuple(kVuiNoVideoSignalType,
    313                        &kColorSpaceH264Default,
    314                        SpsVuiRewriter::ParseResult::kVuiOk),
    315        std::make_tuple(kVuiLimitedRangeBt709Color,
    316                        &kColorSpaceBt709LimitedRange,
    317                        SpsVuiRewriter::ParseResult::kVuiOk),
    318        std::make_tuple(kVuiNotPresent,
    319                        nullptr,
    320                        SpsVuiRewriter::ParseResult::kVuiRewritten),
    321        std::make_tuple(kVuiNoBitstreamRestriction,
    322                        nullptr,
    323                        SpsVuiRewriter::ParseResult::kVuiRewritten),
    324        std::make_tuple(kVuiFrameBuffering,
    325                        nullptr,
    326                        SpsVuiRewriter::ParseResult::kVuiRewritten),
    327        std::make_tuple(kVuiLimitedRangeNoColourDescription,
    328                        &kColorSpaceFullRange,
    329                        SpsVuiRewriter::ParseResult::kVuiRewritten),
    330        std::make_tuple(kVuiNoVideoSignalType,
    331                        &kColorSpacePrimariesBt709,
    332                        SpsVuiRewriter::ParseResult::kVuiRewritten),
    333        std::make_tuple(kVuiNoVideoSignalType,
    334                        &kColorSpaceTransferBt709,
    335                        SpsVuiRewriter::ParseResult::kVuiRewritten),
    336        std::make_tuple(kVuiNoVideoSignalType,
    337                        &kColorSpaceMatrixBt709,
    338                        SpsVuiRewriter::ParseResult::kVuiRewritten),
    339        std::make_tuple(kVuiFullRangeNoColourDescription,
    340                        &kColorSpaceH264Default,
    341                        SpsVuiRewriter::ParseResult::kVuiRewritten),
    342        std::make_tuple(kVuiLimitedRangeBt709Color,
    343                        &kColorSpaceH264Default,
    344                        SpsVuiRewriter::ParseResult::kVuiRewritten)));
    345 
    346 TEST(SpsVuiRewriterOutgoingVuiTest, ParseOutgoingBitstreamOptimalVui) {
    347  LogMessage::LogToDebug(LS_VERBOSE);
    348 
    349  Buffer optimal_sps;
    350  GenerateFakeSps(kVuiNoFrameBuffering, &optimal_sps);
    351 
    352  Buffer buffer;
    353  buffer.AppendData(kStartSequence);
    354  buffer.AppendData(optimal_sps);
    355  buffer.AppendData(kStartSequence);
    356  buffer.AppendData(kIdr1);
    357 
    358  EXPECT_THAT(SpsVuiRewriter::ParseOutgoingBitstreamAndRewrite(buffer, nullptr),
    359              ::testing::ElementsAreArray(buffer));
    360 }
    361 
    362 TEST(SpsVuiRewriterOutgoingVuiTest, ParseOutgoingBitstreamNoVui) {
    363  LogMessage::LogToDebug(LS_VERBOSE);
    364 
    365  Buffer sps;
    366  GenerateFakeSps(kVuiNotPresent, &sps);
    367 
    368  Buffer buffer;
    369  buffer.AppendData(kStartSequence);
    370  buffer.AppendData(kIdr1);
    371  buffer.AppendData(kStartSequence);
    372  buffer.AppendData(kSpsNaluType);
    373  buffer.AppendData(sps);
    374  buffer.AppendData(kStartSequence);
    375  buffer.AppendData(kIdr2);
    376 
    377  Buffer optimal_sps;
    378  GenerateFakeSps(kVuiNoFrameBuffering, &optimal_sps);
    379 
    380  Buffer expected_buffer;
    381  expected_buffer.AppendData(kStartSequence);
    382  expected_buffer.AppendData(kIdr1);
    383  expected_buffer.AppendData(kStartSequence);
    384  expected_buffer.AppendData(kSpsNaluType);
    385  expected_buffer.AppendData(optimal_sps);
    386  expected_buffer.AppendData(kStartSequence);
    387  expected_buffer.AppendData(kIdr2);
    388 
    389  EXPECT_THAT(SpsVuiRewriter::ParseOutgoingBitstreamAndRewrite(buffer, nullptr),
    390              ::testing::ElementsAreArray(expected_buffer));
    391 }
    392 
    393 TEST(SpsVuiRewriterOutgoingAudTest, ParseOutgoingBitstreamWithAud) {
    394  LogMessage::LogToDebug(LS_VERBOSE);
    395 
    396  Buffer optimal_sps;
    397  GenerateFakeSps(kVuiNoFrameBuffering, &optimal_sps);
    398 
    399  Buffer buffer;
    400  buffer.AppendData(kStartSequence);
    401  buffer.AppendData(kAud);
    402  buffer.AppendData(kStartSequence);
    403  buffer.AppendData(optimal_sps);
    404  buffer.AppendData(kStartSequence);
    405  buffer.AppendData(kIdr1);
    406 
    407  Buffer expected_buffer;
    408  expected_buffer.AppendData(kStartSequence);
    409  expected_buffer.AppendData(optimal_sps);
    410  expected_buffer.AppendData(kStartSequence);
    411  expected_buffer.AppendData(kIdr1);
    412 
    413  EXPECT_THAT(SpsVuiRewriter::ParseOutgoingBitstreamAndRewrite(buffer, nullptr),
    414              ::testing::ElementsAreArray(expected_buffer));
    415 }
    416 }  // namespace webrtc