212 lines
7.6 KiB
C++
212 lines
7.6 KiB
C++
// Copyright 2016 Google LLC. All rights reserved.
|
|
//
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file or at
|
|
// https://developers.google.com/open-source/licenses/bsd
|
|
|
|
#include <packager/media/codecs/h265_parser.h>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <packager/media/codecs/nalu_reader.h>
|
|
|
|
namespace shaka {
|
|
namespace media {
|
|
namespace H265 {
|
|
|
|
namespace {
|
|
|
|
// Data taken from bear-640x360-hevc.mp4 and bear-640x360-hevc-hdr10.mp4.
|
|
const uint8_t kSpsData[] = {
|
|
0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x3f, 0xa0, 0x05, 0x02, 0x01, 0x69, 0x65, 0x95, 0xe4, 0x93,
|
|
0x2b, 0xc0, 0x40, 0x40, 0x00, 0x00, 0xfa, 0x40, 0x00, 0x1d, 0x4c, 0x02};
|
|
const uint8_t kSpsDataWithTransferCharacteristics[] = {
|
|
0x42, 0x01, 0x01, 0x02, 0x20, 0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 0x00,
|
|
0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0xA0, 0x03, 0xC0, 0x80, 0x10, 0xE4,
|
|
0xD9, 0x65, 0x66, 0x92, 0x4C, 0xAF, 0x01, 0x6A, 0x12, 0x20, 0x13, 0x6C,
|
|
0x20, 0x00, 0x00, 0x7D, 0x20, 0x00, 0x0B, 0xB8, 0x0C, 0x25, 0x9A, 0x4B,
|
|
0xC0, 0x01, 0xE8, 0x48, 0x00, 0x3D, 0x09, 0x10};
|
|
const uint8_t kPpsData[] = {0x44, 0x01, 0xc1, 0x73, 0xd1, 0x89};
|
|
const uint8_t kSliceData[] = {
|
|
// Incomplete segment data.
|
|
0x26, 0x01, 0xaf, 0x08, 0x4c, 0x2e, 0xa6, 0x56, 0xd9, 0xaf, 0x50, 0xeb,
|
|
0x94, 0x9a, 0xae, 0x89, 0x29, 0x0e, 0x42, 0x9f, 0xb9, 0x5e, 0x85, 0xd5};
|
|
const uint8_t kSliceData2[] = {0x02, 0x01, 0xd0, 0x29, 0xc9, 0xfd, 0x63, 0x22,
|
|
0x52, 0x04, 0x06, 0x13, 0x3d, 0xc6, 0xf0, 0xb9,
|
|
0x55, 0x98, 0xa0, 0x16, 0x57, 0xf6, 0xb8, 0x25};
|
|
|
|
} // namespace
|
|
|
|
TEST(H265ParserTest, ParseSliceHeader) {
|
|
// Parse the SPS and PPS first so the data is available.
|
|
int id;
|
|
Nalu nalu;
|
|
H265Parser parser;
|
|
ASSERT_TRUE(nalu.Initialize(Nalu::kH265, kSpsData, std::size(kSpsData)));
|
|
ASSERT_EQ(H265Parser::kOk, parser.ParseSps(nalu, &id));
|
|
ASSERT_TRUE(nalu.Initialize(Nalu::kH265, kPpsData, std::size(kPpsData)));
|
|
ASSERT_EQ(H265Parser::kOk, parser.ParsePps(nalu, &id));
|
|
|
|
// Parse the slice header.
|
|
ASSERT_TRUE(nalu.Initialize(Nalu::kH265, kSliceData, std::size(kSliceData)));
|
|
ASSERT_EQ(Nalu::H265_IDR_W_RADL, nalu.type());
|
|
|
|
H265SliceHeader header;
|
|
ASSERT_EQ(H265Parser::kOk, parser.ParseSliceHeader(nalu, &header));
|
|
|
|
EXPECT_TRUE(header.first_slice_segment_in_pic_flag);
|
|
EXPECT_EQ(0, header.pic_parameter_set_id);
|
|
EXPECT_FALSE(header.dependent_slice_segment_flag);
|
|
EXPECT_EQ(2, header.slice_type);
|
|
EXPECT_EQ(8, header.slice_qp_delta);
|
|
EXPECT_FALSE(header.cu_chroma_qp_offset_enabled_flag);
|
|
EXPECT_EQ(5, header.num_entry_point_offsets);
|
|
EXPECT_EQ(88u, header.header_bit_size);
|
|
}
|
|
|
|
TEST(H265ParserTest, ParseSliceHeader_NonIDR) {
|
|
// Parse the SPS and PPS first so the data is available.
|
|
int id;
|
|
Nalu nalu;
|
|
H265Parser parser;
|
|
ASSERT_TRUE(nalu.Initialize(Nalu::kH265, kSpsData, std::size(kSpsData)));
|
|
ASSERT_EQ(H265Parser::kOk, parser.ParseSps(nalu, &id));
|
|
ASSERT_TRUE(nalu.Initialize(Nalu::kH265, kPpsData, std::size(kPpsData)));
|
|
ASSERT_EQ(H265Parser::kOk, parser.ParsePps(nalu, &id));
|
|
|
|
// Parse the slice header.
|
|
ASSERT_TRUE(
|
|
nalu.Initialize(Nalu::kH265, kSliceData2, std::size(kSliceData2)));
|
|
ASSERT_EQ(1 /* TRAIL_R */, nalu.type());
|
|
|
|
H265SliceHeader header;
|
|
ASSERT_EQ(H265Parser::kOk, parser.ParseSliceHeader(nalu, &header));
|
|
|
|
EXPECT_TRUE(header.first_slice_segment_in_pic_flag);
|
|
EXPECT_EQ(0, header.pic_parameter_set_id);
|
|
EXPECT_FALSE(header.dependent_slice_segment_flag);
|
|
EXPECT_EQ(1, header.slice_type);
|
|
EXPECT_EQ(5, header.num_entry_point_offsets);
|
|
EXPECT_EQ(128u, header.header_bit_size);
|
|
}
|
|
|
|
TEST(H265ParserTest, ParseSps) {
|
|
Nalu nalu;
|
|
ASSERT_TRUE(nalu.Initialize(Nalu::kH265, kSpsData, std::size(kSpsData)));
|
|
ASSERT_EQ(Nalu::H265_SPS, nalu.type());
|
|
|
|
int id = 12;
|
|
H265Parser parser;
|
|
ASSERT_EQ(H265Parser::kOk, parser.ParseSps(nalu, &id));
|
|
ASSERT_EQ(0, id);
|
|
|
|
const H265Sps* sps = parser.GetSps(id);
|
|
ASSERT_TRUE(sps);
|
|
|
|
EXPECT_EQ(0, sps->video_parameter_set_id);
|
|
EXPECT_EQ(0, sps->max_sub_layers_minus1);
|
|
EXPECT_EQ(0, sps->seq_parameter_set_id);
|
|
EXPECT_EQ(1, sps->chroma_format_idc);
|
|
EXPECT_EQ(360, sps->pic_height_in_luma_samples);
|
|
EXPECT_EQ(4, sps->log2_max_pic_order_cnt_lsb_minus4);
|
|
EXPECT_EQ(3, sps->log2_diff_max_min_luma_transform_block_size);
|
|
EXPECT_EQ(0, sps->max_transform_hierarchy_depth_intra);
|
|
EXPECT_EQ(0, sps->vui_parameters.transfer_characteristics);
|
|
}
|
|
|
|
TEST(H265ParserTest, ParseSpsWithTransferCharacteristics) {
|
|
Nalu nalu;
|
|
ASSERT_TRUE(nalu.Initialize(Nalu::kH265, kSpsDataWithTransferCharacteristics,
|
|
std::size(kSpsDataWithTransferCharacteristics)));
|
|
ASSERT_EQ(Nalu::H265_SPS, nalu.type());
|
|
|
|
int id = 12;
|
|
H265Parser parser;
|
|
ASSERT_EQ(H265Parser::kOk, parser.ParseSps(nalu, &id));
|
|
ASSERT_EQ(0, id);
|
|
|
|
const H265Sps* sps = parser.GetSps(id);
|
|
ASSERT_TRUE(sps);
|
|
|
|
EXPECT_EQ(0, sps->video_parameter_set_id);
|
|
EXPECT_EQ(0, sps->max_sub_layers_minus1);
|
|
EXPECT_EQ(0, sps->seq_parameter_set_id);
|
|
EXPECT_EQ(1, sps->chroma_format_idc);
|
|
EXPECT_EQ(1080, sps->pic_height_in_luma_samples);
|
|
EXPECT_EQ(4, sps->log2_max_pic_order_cnt_lsb_minus4);
|
|
EXPECT_EQ(3, sps->log2_diff_max_min_luma_transform_block_size);
|
|
EXPECT_EQ(0, sps->max_transform_hierarchy_depth_intra);
|
|
EXPECT_EQ(16, sps->vui_parameters.transfer_characteristics);
|
|
}
|
|
|
|
TEST(H265ParserTest, ParsePps) {
|
|
Nalu nalu;
|
|
ASSERT_TRUE(nalu.Initialize(Nalu::kH265, kPpsData, std::size(kPpsData)));
|
|
ASSERT_EQ(Nalu::H265_PPS, nalu.type());
|
|
|
|
int id = 12;
|
|
H265Parser parser;
|
|
ASSERT_EQ(H265Parser::kOk, parser.ParsePps(nalu, &id));
|
|
ASSERT_EQ(0, id);
|
|
|
|
const H265Pps* pps = parser.GetPps(id);
|
|
ASSERT_TRUE(pps);
|
|
|
|
EXPECT_EQ(0, pps->num_extra_slice_header_bits);
|
|
EXPECT_TRUE(pps->weighted_pred_flag);
|
|
EXPECT_FALSE(pps->scaling_list_data_present_flag);
|
|
EXPECT_EQ(0, pps->log2_parallel_merge_level_minus2);
|
|
}
|
|
|
|
TEST(H265ParserTest, ExtractResolutionFromSpsData) {
|
|
H265Parser parser;
|
|
int sps_id = 0;
|
|
Nalu nalu;
|
|
ASSERT_TRUE(nalu.Initialize(Nalu::kH265, kSpsData, std::size(kSpsData)));
|
|
ASSERT_EQ(H265Parser::kOk, parser.ParseSps(nalu, &sps_id));
|
|
|
|
uint32_t coded_width = 0;
|
|
uint32_t coded_height = 0;
|
|
uint32_t pixel_width = 0;
|
|
uint32_t pixel_height = 0;
|
|
ASSERT_TRUE(ExtractResolutionFromSps(*parser.GetSps(sps_id), &coded_width,
|
|
&coded_height, &pixel_width,
|
|
&pixel_height));
|
|
EXPECT_EQ(640u, coded_width);
|
|
EXPECT_EQ(360u, coded_height);
|
|
EXPECT_EQ(1u, pixel_width);
|
|
EXPECT_EQ(1u, pixel_height);
|
|
}
|
|
|
|
TEST(H265ParserTest, ExtractResolutionFromSpsDataWithCrop) {
|
|
const uint8_t kSpsCropData[] = {
|
|
0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x90, 0x00,
|
|
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x3c, 0xa0, 0x0f, 0x08, 0x0f,
|
|
0x16, 0x59, 0x99, 0xa4, 0x93, 0x2b, 0xff, 0xc0, 0xd5, 0xc0, 0xd6,
|
|
0x40, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x06, 0x02,
|
|
};
|
|
H265Parser parser;
|
|
int sps_id = 0;
|
|
Nalu nalu;
|
|
ASSERT_TRUE(
|
|
nalu.Initialize(Nalu::kH265, kSpsCropData, std::size(kSpsCropData)));
|
|
ASSERT_EQ(H265Parser::kOk, parser.ParseSps(nalu, &sps_id));
|
|
|
|
uint32_t coded_width = 0;
|
|
uint32_t coded_height = 0;
|
|
uint32_t pixel_width = 0;
|
|
uint32_t pixel_height = 0;
|
|
ASSERT_TRUE(ExtractResolutionFromSps(*parser.GetSps(sps_id), &coded_width,
|
|
&coded_height, &pixel_width,
|
|
&pixel_height));
|
|
EXPECT_EQ(480u, coded_width);
|
|
EXPECT_EQ(240u, coded_height);
|
|
EXPECT_EQ(855u, pixel_width);
|
|
EXPECT_EQ(857u, pixel_height);
|
|
}
|
|
|
|
} // namespace H265
|
|
} // namespace media
|
|
} // namespace shaka
|