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