tor-browser

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

h265_sps_parser_unittest.cc (18786B)


      1 /*
      2 *  Copyright (c) 2023 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/h265/h265_sps_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/h265/h265_common.h"
     20 #include "rtc_base/bit_buffer.h"
     21 #include "rtc_base/buffer.h"
     22 #include "test/gtest.h"
     23 
     24 namespace webrtc {
     25 
     26 static constexpr size_t kSpsBufferMaxSize = 256;
     27 
     28 // Generates a fake SPS with basically everything empty but the width/height,
     29 // max_num_sublayer_minus1 and num_short_term_ref_pic_sets.
     30 // Pass in a buffer of at least kSpsBufferMaxSize.
     31 // The fake SPS that this generates also always has at least one emulation byte
     32 // at offset 2, since the first two bytes are always 0, and has a 0x3 as the
     33 // level_idc, to make sure the parser doesn't eat all 0x3 bytes.
     34 // num_short_term_ref_pic_sets is set to 11 followed with 11
     35 // short_term_ref_pic_set data in this fake sps.
     36 void WriteSps(uint16_t width,
     37              uint16_t height,
     38              int id,
     39              uint32_t max_num_sublayer_minus1,
     40              bool sub_layer_ordering_info_present_flag,
     41              bool long_term_ref_pics_present_flag,
     42              Buffer* out_buffer) {
     43  uint8_t rbsp[kSpsBufferMaxSize] = {0};
     44  BitBufferWriter writer(rbsp, kSpsBufferMaxSize);
     45  // sps_video_parameter_set_id
     46  writer.WriteBits(0, 4);
     47  // sps_max_sub_layers_minus1
     48  writer.WriteBits(max_num_sublayer_minus1, 3);
     49  // sps_temporal_id_nesting_flag
     50  writer.WriteBits(1, 1);
     51  // profile_tier_level(profilePresentFlag=1, maxNumSublayersMinus1=0)
     52  // profile-space=0, tier=0, profile-idc=1
     53  writer.WriteBits(0, 2);
     54  writer.WriteBits(0, 1);
     55  writer.WriteBits(1, 5);
     56  // general_prfile_compatibility_flag[32]
     57  writer.WriteBits(0, 32);
     58  // general_progressive_source_flag
     59  writer.WriteBits(1, 1);
     60  // general_interlace_source_flag
     61  writer.WriteBits(0, 1);
     62  // general_non_packed_constraint_flag
     63  writer.WriteBits(0, 1);
     64  // general_frame_only_constraint_flag
     65  writer.WriteBits(1, 1);
     66  // general_reserved_zero_7bits
     67  writer.WriteBits(0, 7);
     68  // general_one_picture_only_flag
     69  writer.WriteBits(0, 1);
     70  // general_reserved_zero_35bits
     71  writer.WriteBits(0, 35);
     72  // general_inbld_flag
     73  writer.WriteBits(0, 1);
     74  // general_level_idc
     75  writer.WriteBits(93, 8);
     76  // if max_sub_layers_minus1 >=1, read the sublayer profile information
     77  std::vector<uint32_t> sub_layer_profile_present_flags;
     78  std::vector<uint32_t> sub_layer_level_present_flags;
     79  for (uint32_t i = 0; i < max_num_sublayer_minus1; i++) {
     80    // sublayer_profile_present_flag and sublayer_level_presnet_flag:  u(2)
     81    writer.WriteBits(1, 1);
     82    writer.WriteBits(1, 1);
     83    sub_layer_profile_present_flags.push_back(1);
     84    sub_layer_level_present_flags.push_back(1);
     85  }
     86  if (max_num_sublayer_minus1 > 0) {
     87    for (uint32_t j = max_num_sublayer_minus1; j < 8; j++) {
     88      // reserved 2 bits: u(2)
     89      writer.WriteBits(0, 2);
     90    }
     91  }
     92  for (uint32_t k = 0; k < max_num_sublayer_minus1; k++) {
     93    if (sub_layer_profile_present_flags[k]) {  //
     94      // sub_layer profile_space/tier_flag/profile_idc. ignored. u(8)
     95      writer.WriteBits(0, 8);
     96      // profile_compatability_flag:  u(32)
     97      writer.WriteBits(0, 32);
     98      // sub_layer progressive_source_flag/interlaced_source_flag/
     99      // non_packed_constraint_flag/frame_only_constraint_flag: u(4)
    100      writer.WriteBits(0, 4);
    101      // following 43-bits are profile_idc specific. We simply read/skip it.
    102      // u(43)
    103      writer.WriteBits(0, 43);
    104      // 1-bit profile_idc specific inbld flag.  We simply read/skip it. u(1)
    105      writer.WriteBits(0, 1);
    106    }
    107    if (sub_layer_level_present_flags[k]) {
    108      // sub_layer_level_idc: u(8)
    109      writer.WriteBits(0, 8);
    110    }
    111  }
    112 
    113  // seq_parameter_set_id
    114  writer.WriteExponentialGolomb(id);
    115  // chroma_format_idc
    116  writer.WriteExponentialGolomb(2);
    117  if (width % 8 != 0 || height % 8 != 0) {
    118    int width_delta = 8 - width % 8;
    119    int height_delta = 8 - height % 8;
    120    if (width_delta != 8) {
    121      // pic_width_in_luma_samples
    122      writer.WriteExponentialGolomb(width + width_delta);
    123    } else {
    124      writer.WriteExponentialGolomb(width);
    125    }
    126    if (height_delta != 8) {
    127      // pic_height_in_luma_samples
    128      writer.WriteExponentialGolomb(height + height_delta);
    129    } else {
    130      writer.WriteExponentialGolomb(height);
    131    }
    132    // conformance_window_flag
    133    writer.WriteBits(1, 1);
    134    // conf_win_left_offset
    135    writer.WriteExponentialGolomb((width % 8) / 2);
    136    // conf_win_right_offset
    137    writer.WriteExponentialGolomb(0);
    138    // conf_win_top_offset
    139    writer.WriteExponentialGolomb(height_delta);
    140    // conf_win_bottom_offset
    141    writer.WriteExponentialGolomb(0);
    142  } else {
    143    // pic_width_in_luma_samples
    144    writer.WriteExponentialGolomb(width);
    145    // pic_height_in_luma_samples
    146    writer.WriteExponentialGolomb(height);
    147    // conformance_window_flag
    148    writer.WriteBits(0, 1);
    149  }
    150  // bit_depth_luma_minus8
    151  writer.WriteExponentialGolomb(0);
    152  // bit_depth_chroma_minus8
    153  writer.WriteExponentialGolomb(0);
    154  // log2_max_pic_order_cnt_lsb_minus4
    155  writer.WriteExponentialGolomb(4);
    156  // sps_sub_layer_ordering_info_present_flag
    157  writer.WriteBits(sub_layer_ordering_info_present_flag, 1);
    158  for (uint32_t i = (sub_layer_ordering_info_present_flag != 0)
    159                        ? 0
    160                        : max_num_sublayer_minus1;
    161       i <= max_num_sublayer_minus1; i++) {
    162    // sps_max_dec_pic_buffering_minus1: ue(v)
    163    writer.WriteExponentialGolomb(4);
    164    // sps_max_num_reorder_pics: ue(v)
    165    writer.WriteExponentialGolomb(3);
    166    // sps_max_latency_increase_plus1: ue(v)
    167    writer.WriteExponentialGolomb(0);
    168  }
    169  // log2_min_luma_coding_block_size_minus3
    170  writer.WriteExponentialGolomb(0);
    171  // log2_diff_max_min_luma_coding_block_size
    172  writer.WriteExponentialGolomb(3);
    173  // log2_min_luma_transform_block_size_minus2
    174  writer.WriteExponentialGolomb(0);
    175  // log2_diff_max_min_luma_transform_block_size
    176  writer.WriteExponentialGolomb(3);
    177  // max_transform_hierarchy_depth_inter
    178  writer.WriteExponentialGolomb(0);
    179  // max_transform_hierarchy_depth_intra
    180  writer.WriteExponentialGolomb(0);
    181  // scaling_list_enabled_flag
    182  writer.WriteBits(0, 1);
    183  // apm_enabled_flag
    184  writer.WriteBits(0, 1);
    185  // sample_adaptive_offset_enabled_flag
    186  writer.WriteBits(1, 1);
    187  // pcm_enabled_flag
    188  writer.WriteBits(0, 1);
    189  // num_short_term_ref_pic_sets
    190  writer.WriteExponentialGolomb(11);
    191  // short_term_ref_pic_set[0]
    192  // num_negative_pics
    193  writer.WriteExponentialGolomb(4);
    194  // num_positive_pics
    195  writer.WriteExponentialGolomb(0);
    196  // delta_poc_s0_minus1
    197  writer.WriteExponentialGolomb(7);
    198  // used_by_curr_pic_s0_flag
    199  writer.WriteBits(1, 1);
    200  for (int i = 0; i < 2; i++) {
    201    // delta_poc_s0_minus1
    202    writer.WriteExponentialGolomb(1);
    203    // used_by_curr_pic_s0_flag
    204    writer.WriteBits(1, 1);
    205  }
    206  // delta_poc_s0_minus1
    207  writer.WriteExponentialGolomb(3);
    208  // used_by_curr_pic_s0_flag
    209  writer.WriteBits(1, 1);
    210  // short_term_ref_pic_set[1]
    211  // inter_ref_pic_set_prediction_flag
    212  writer.WriteBits(1, 1);
    213  // delta_rps_sign
    214  writer.WriteBits(0, 1);
    215  // abs_delta_rps_minus1
    216  writer.WriteExponentialGolomb(3);
    217  for (int i = 0; i < 2; i++) {
    218    // used_by_curr_pic_flag
    219    writer.WriteBits(1, 1);
    220  }
    221  for (int i = 0; i < 2; i++) {
    222    // used_by_curr_pic_flag
    223    writer.WriteBits(0, 1);
    224    // use_delta_flag
    225    writer.WriteBits(0, 1);
    226  }
    227  // used_by_curr_pic_flag
    228  writer.WriteBits(1, 1);
    229  // short_term_ref_pic_set[2]
    230  // inter_ref_pic_set_prediction_flag
    231  writer.WriteBits(1, 1);
    232  // delta_rps_sign
    233  writer.WriteBits(0, 1);
    234  // abs_delta_rps_minus1
    235  writer.WriteExponentialGolomb(1);
    236  for (int i = 0; i < 4; i++) {
    237    // used_by_curr_pic_flag
    238    writer.WriteBits(1, 1);
    239  }
    240  // short_term_ref_pic_set[3]
    241  // inter_ref_pic_set_prediction_flag
    242  writer.WriteBits(1, 1);
    243  // delta_rps_sign
    244  writer.WriteBits(0, 1);
    245  // abs_delta_rps_minus1
    246  writer.WriteExponentialGolomb(0);
    247  // used_by_curr_pic_flag
    248  writer.WriteBits(1, 1);
    249  // used_by_curr_pic_flag
    250  writer.WriteBits(0, 1);
    251  // use_delta_flag
    252  writer.WriteBits(0, 1);
    253  for (int i = 0; i < 3; i++) {
    254    // used_by_curr_pic_flag
    255    writer.WriteBits(1, 1);
    256  }
    257  // short_term_ref_pic_set[4]
    258  // inter_ref_pic_set_prediction_flag
    259  writer.WriteBits(1, 1);
    260  // delta_rps_sign
    261  writer.WriteBits(1, 1);
    262  // abs_delta_rps_minus1
    263  writer.WriteExponentialGolomb(1);
    264  for (int i = 0; i < 4; i++) {
    265    // used_by_curr_pic_flag
    266    writer.WriteBits(1, 1);
    267  }
    268  // used_by_curr_pic_flag
    269  writer.WriteBits(0, 1);
    270  // use_delta_flag
    271  writer.WriteBits(0, 1);
    272  // short_term_ref_pic_set[5]
    273  // inter_ref_pic_set_prediction_flag
    274  writer.WriteBits(1, 1);
    275  // delta_rps_sign
    276  writer.WriteBits(1, 1);
    277  // abs_delta_rps_minus1
    278  writer.WriteExponentialGolomb(2);
    279  for (int i = 0; i < 4; i++) {
    280    // used_by_curr_pic_flag
    281    writer.WriteBits(1, 1);
    282  }
    283  // used_by_curr_pic_flag
    284  writer.WriteBits(0, 1);
    285  // use_delta_flag
    286  writer.WriteBits(0, 1);
    287  // short_term_ref_pic_set[6]
    288  // inter_ref_pic_set_prediction_flag
    289  writer.WriteBits(1, 1);
    290  // delta_rps_sign
    291  writer.WriteBits(0, 1);
    292  // abs_delta_rps_minus1
    293  writer.WriteExponentialGolomb(0);
    294  // used_by_curr_pic_flag
    295  writer.WriteBits(1, 1);
    296  // used_by_curr_pic_flag
    297  writer.WriteBits(0, 1);
    298  // use_delta_flag
    299  writer.WriteBits(0, 1);
    300  for (int i = 0; i < 3; i++) {
    301    // used_by_curr_pic_flag
    302    writer.WriteBits(1, 1);
    303  }
    304  // short_term_ref_pic_set[7]
    305  // inter_ref_pic_set_prediction_flag
    306  writer.WriteBits(1, 1);
    307  // delta_rps_sign
    308  writer.WriteBits(1, 1);
    309  // abs_delta_rps_minus1
    310  writer.WriteExponentialGolomb(1);
    311  for (int i = 0; i < 4; i++) {
    312    // used_by_curr_pic_flag
    313    writer.WriteBits(1, 1);
    314  }
    315  // used_by_curr_pic_flag
    316  writer.WriteBits(0, 1);
    317  // use_delta_flag
    318  writer.WriteBits(0, 1);
    319  // short_term_ref_pic_set[8]
    320  // inter_ref_pic_set_prediction_flag
    321  writer.WriteBits(0, 1);
    322  // num_negative_pics
    323  writer.WriteExponentialGolomb(1);
    324  // num_positive_pics
    325  writer.WriteExponentialGolomb(0);
    326  // delta_poc_s0_minus1
    327  writer.WriteExponentialGolomb(7);
    328  // used_by_curr_pic_s0_flag
    329  writer.WriteBits(1, 1);
    330  // short_term_ref_pic_set[9]
    331  // inter_ref_pic_set_prediction_flag
    332  writer.WriteBits(1, 1);
    333  // delta_rps_sign
    334  writer.WriteBits(0, 1);
    335  // abs_delta_rps_minus1
    336  writer.WriteExponentialGolomb(3);
    337  for (int i = 0; i < 2; i++) {
    338    // used_by_curr_pic_flag
    339    writer.WriteBits(1, 1);
    340  }
    341  // short_term_ref_pic_set[10]
    342  // inter_ref_pic_set_prediction_flag
    343  writer.WriteBits(1, 1);
    344  // delta_rps_sign
    345  writer.WriteBits(0, 1);
    346  // abs_delta_rps_minus1
    347  writer.WriteExponentialGolomb(1);
    348  for (int i = 0; i < 3; i++) {
    349    // used_by_curr_pic_flag
    350    writer.WriteBits(1, 1);
    351  }
    352  // long_term_ref_pics_present_flag
    353  writer.WriteBits(long_term_ref_pics_present_flag, 1);
    354  if (long_term_ref_pics_present_flag) {
    355    // num_long_term_ref_pics_sps
    356    writer.WriteExponentialGolomb(1);
    357    // lt_ref_pic_poc_lsb_sps
    358    writer.WriteExponentialGolomb(1);
    359    // used_by_curr_pic_lt_sps_flag
    360    writer.WriteBits(1, 8);
    361  }
    362  // sps_temproal_mvp_enabled_flag
    363  writer.WriteBits(1, 1);
    364 
    365  // Get the number of bytes written (including the last partial byte).
    366  size_t byte_count, bit_offset;
    367  writer.GetCurrentOffset(&byte_count, &bit_offset);
    368  if (bit_offset > 0) {
    369    byte_count++;
    370  }
    371 
    372  out_buffer->Clear();
    373  H265::WriteRbsp(MakeArrayView(rbsp, byte_count), out_buffer);
    374 }
    375 
    376 class H265SpsParserTest : public ::testing::Test {
    377 public:
    378  H265SpsParserTest() {}
    379  ~H265SpsParserTest() override {}
    380 };
    381 
    382 TEST_F(H265SpsParserTest, TestSampleSPSHdLandscape) {
    383  // SPS for a 1280x720 camera capture from ffmpeg on linux. Contains
    384  // emulation bytes but no cropping. This buffer is generated
    385  // with following command:
    386  // 1) ffmpeg -i /dev/video0 -r 30 -c:v libx265 -s 1280x720 camera.h265
    387  //
    388  // 2) Open camera.h265 and find the SPS, generally everything between the
    389  // second and third start codes (0 0 0 1 or 0 0 1). The first two bytes should
    390  // be 0x42 and 0x01, which should be stripped out before being passed to the
    391  // parser.
    392  const uint8_t buffer[] = {0x01, 0x04, 0x08, 0x00, 0x00, 0x03, 0x00, 0x9d,
    393                            0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x5d, 0xb0,
    394                            0x02, 0x80, 0x80, 0x2d, 0x16, 0x59, 0x59, 0xa4,
    395                            0x93, 0x2b, 0x80, 0x40, 0x00, 0x00, 0x03, 0x00,
    396                            0x40, 0x00, 0x00, 0x07, 0x82};
    397  std::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
    398  ASSERT_TRUE(sps.has_value());
    399  EXPECT_EQ(1280u, sps->width);
    400  EXPECT_EQ(720u, sps->height);
    401 }
    402 
    403 TEST_F(H265SpsParserTest, TestSampleSPSVerticalCropLandscape) {
    404  // SPS for a 640x260 camera captureH265SpsParser::ParseSps(buffer.data(),
    405  // buffer.size()) from ffmpeg on Linux,. Contains emulation bytes and vertical
    406  // cropping (crop from 640x264). The buffer is generated
    407  // with following command:
    408  // 1) Generate a video, from the camera:
    409  // ffmpeg -i /dev/video0 -r 30 -c:v libx265 -s 640x264 camera.h265
    410  //
    411  // 2) Crop the video to expected size(for example, 640x260 which will crop
    412  // from 640x264):
    413  // ffmpeg -i camera.h265 -filter:v crop=640:260:200:200 -c:v libx265
    414  // cropped.h265
    415  //
    416  // 3) Open cropped.h265 and find the SPS, generally everything between the
    417  // second and third start codes (0 0 0 1 or 0 0 1). The first two bytes should
    418  // be 0x42 and 0x01, which should be stripped out before being passed to the
    419  // parser.
    420  const uint8_t buffer[] = {0x01, 0x04, 0x08, 0x00, 0x00, 0x03, 0x00, 0x9d,
    421                            0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x3f, 0xb0,
    422                            0x05, 0x02, 0x01, 0x09, 0xf2, 0xe5, 0x95, 0x9a,
    423                            0x49, 0x32, 0xb8, 0x04, 0x00, 0x00, 0x03, 0x00,
    424                            0x04, 0x00, 0x00, 0x03, 0x00, 0x78, 0x20};
    425  std::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
    426  ASSERT_TRUE(sps.has_value());
    427  EXPECT_EQ(640u, sps->width);
    428  EXPECT_EQ(260u, sps->height);
    429 }
    430 
    431 TEST_F(H265SpsParserTest, TestSampleSPSHorizontalAndVerticalCrop) {
    432  // SPS for a 260x260 camera capture from ffmpeg on Linux. Contains emulation
    433  // bytes. Horizontal and veritcal crop (Crop from 264x264). The buffer is
    434  // generated with following command:
    435  // 1) Generate a video, from the camera:
    436  // ffmpeg -i /dev/video0 -r 30 -c:v libx265 -s 264x264 camera.h265
    437  //
    438  // 2) Crop the video to expected size(for example, 260x260 which will crop
    439  // from 264x264):
    440  // ffmpeg -i camera.h265 -filter:v crop=260:260:200:200 -c:v libx265
    441  // cropped.h265
    442  //
    443  // 3) Open cropped.h265 and find the SPS, generally everything between the
    444  // second and third start codes (0 0 0 1 or 0 0 1). The first two bytes should
    445  // be 0x42 and 0x01, which should be stripped out before being passed to the
    446  // parser.
    447  const uint8_t buffer[] = {0x01, 0x04, 0x08, 0x00, 0x00, 0x03, 0x00, 0x9d,
    448                            0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x3c, 0xb0,
    449                            0x08, 0x48, 0x04, 0x27, 0x72, 0xe5, 0x95, 0x9a,
    450                            0x49, 0x32, 0xb8, 0x04, 0x00, 0x00, 0x03, 0x00,
    451                            0x04, 0x00, 0x00, 0x03, 0x00, 0x78, 0x20};
    452  std::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
    453  ASSERT_TRUE(sps.has_value());
    454  EXPECT_EQ(260u, sps->width);
    455  EXPECT_EQ(260u, sps->height);
    456 }
    457 
    458 TEST_F(H265SpsParserTest, TestSyntheticSPSQvgaLandscape) {
    459  Buffer buffer;
    460  WriteSps(320u, 180u, 1, 0, 1, 0, &buffer);
    461  std::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
    462  ASSERT_TRUE(sps.has_value());
    463  EXPECT_EQ(320u, sps->width);
    464  EXPECT_EQ(180u, sps->height);
    465  EXPECT_EQ(1u, sps->sps_id);
    466 }
    467 
    468 TEST_F(H265SpsParserTest, TestSyntheticSPSWeirdResolution) {
    469  Buffer buffer;
    470  WriteSps(156u, 122u, 2, 0, 1, 0, &buffer);
    471  std::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
    472  ASSERT_TRUE(sps.has_value());
    473  EXPECT_EQ(156u, sps->width);
    474  EXPECT_EQ(122u, sps->height);
    475  EXPECT_EQ(2u, sps->sps_id);
    476 }
    477 
    478 TEST_F(H265SpsParserTest, TestLog2MaxSubLayersMinus1) {
    479  Buffer buffer;
    480  WriteSps(320u, 180u, 1, 0, 1, 0, &buffer);
    481  std::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
    482  ASSERT_TRUE(sps.has_value());
    483  EXPECT_EQ(320u, sps->width);
    484  EXPECT_EQ(180u, sps->height);
    485  EXPECT_EQ(1u, sps->sps_id);
    486  EXPECT_EQ(0u, sps->sps_max_sub_layers_minus1);
    487 
    488  WriteSps(320u, 180u, 1, 6, 1, 0, &buffer);
    489  std::optional<H265SpsParser::SpsState> sps1 = H265SpsParser::ParseSps(buffer);
    490  ASSERT_TRUE(sps1.has_value());
    491  EXPECT_EQ(320u, sps1->width);
    492  EXPECT_EQ(180u, sps1->height);
    493  EXPECT_EQ(1u, sps1->sps_id);
    494  EXPECT_EQ(6u, sps1->sps_max_sub_layers_minus1);
    495 
    496  WriteSps(320u, 180u, 1, 7, 1, 0, &buffer);
    497  std::optional<H265SpsParser::SpsState> result =
    498      H265SpsParser::ParseSps(buffer);
    499  EXPECT_FALSE(result.has_value());
    500 }
    501 
    502 TEST_F(H265SpsParserTest, TestSubLayerOrderingInfoPresentFlag) {
    503  Buffer buffer;
    504  WriteSps(320u, 180u, 1, 6, 1, 0, &buffer);
    505  std::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
    506  ASSERT_TRUE(sps.has_value());
    507  EXPECT_EQ(320u, sps->width);
    508  EXPECT_EQ(180u, sps->height);
    509  EXPECT_EQ(1u, sps->sps_id);
    510  EXPECT_EQ(6u, sps->sps_max_sub_layers_minus1);
    511 
    512  WriteSps(320u, 180u, 1, 6, 1, 0, &buffer);
    513  std::optional<H265SpsParser::SpsState> sps1 = H265SpsParser::ParseSps(buffer);
    514  ASSERT_TRUE(sps1.has_value());
    515  EXPECT_EQ(320u, sps1->width);
    516  EXPECT_EQ(180u, sps1->height);
    517  EXPECT_EQ(1u, sps1->sps_id);
    518  EXPECT_EQ(6u, sps1->sps_max_sub_layers_minus1);
    519 }
    520 
    521 TEST_F(H265SpsParserTest, TestLongTermRefPicsPresentFlag) {
    522  Buffer buffer;
    523  WriteSps(320u, 180u, 1, 0, 1, 0, &buffer);
    524  std::optional<H265SpsParser::SpsState> sps = H265SpsParser::ParseSps(buffer);
    525  ASSERT_TRUE(sps.has_value());
    526  EXPECT_EQ(320u, sps->width);
    527  EXPECT_EQ(180u, sps->height);
    528  EXPECT_EQ(1u, sps->sps_id);
    529  EXPECT_EQ(0u, sps->long_term_ref_pics_present_flag);
    530 
    531  WriteSps(320u, 180u, 1, 6, 1, 1, &buffer);
    532  std::optional<H265SpsParser::SpsState> sps1 = H265SpsParser::ParseSps(buffer);
    533  ASSERT_TRUE(sps1.has_value());
    534  EXPECT_EQ(320u, sps1->width);
    535  EXPECT_EQ(180u, sps1->height);
    536  EXPECT_EQ(1u, sps1->sps_id);
    537  EXPECT_EQ(1u, sps1->long_term_ref_pics_present_flag);
    538 }
    539 
    540 }  // namespace webrtc