Shaka Packager SDK
Loading...
Searching...
No Matches
hevc_decoder_configuration_record.cc
1// Copyright 2015 Google LLC. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file or at
5// https://developers.google.com/open-source/licenses/bsd
6
7#include <packager/media/codecs/hevc_decoder_configuration_record.h>
8
9#include <cstddef>
10#include <cstdint>
11#include <iterator>
12#include <string>
13#include <vector>
14
15#include <absl/log/check.h>
16#include <absl/log/log.h>
17#include <absl/strings/escaping.h>
18#include <absl/strings/str_format.h>
19#include <absl/strings/str_join.h>
20
21#include <packager/media/base/buffer_reader.h>
22#include <packager/media/base/fourccs.h>
23#include <packager/media/base/rcheck.h>
24#include <packager/media/codecs/h265_parser.h>
25#include <packager/utils/bytes_to_string_view.h>
26
27namespace shaka {
28namespace media {
29
30namespace {
31
32// ISO/IEC 14496-15:2014 Annex E.
33std::string GeneralProfileSpaceAsString(uint8_t general_profile_space) {
34 switch (general_profile_space) {
35 case 0:
36 return "";
37 case 1:
38 return "A";
39 case 2:
40 return "B";
41 case 3:
42 return "C";
43 default:
44 LOG(WARNING) << "Unexpected general_profile_space "
45 << general_profile_space;
46 return "";
47 }
48}
49
50std::string TrimLeadingZeros(const std::string& str) {
51 DCHECK_GT(str.size(), 0u);
52 for (size_t i = 0; i < str.size(); ++i) {
53 if (str[i] == '0')
54 continue;
55 return str.substr(i);
56 }
57 return "0";
58}
59
60// Encode the 32 bits input, but in reverse bit order, i.e. bit [31] as the most
61// significant bit, followed by, bit [30], and down to bit [0] as the least
62// significant bit, where bits [i] for i in the range of 0 to 31, inclusive, are
63// specified in ISO/IEC 23008‐2, encoded in hexadecimal (leading zeroes may be
64// omitted).
65std::string ReverseBitsAndHexEncode(uint32_t x) {
66 x = ((x & 0x55555555) << 1) | ((x & 0xAAAAAAAA) >> 1);
67 x = ((x & 0x33333333) << 2) | ((x & 0xCCCCCCCC) >> 2);
68 x = ((x & 0x0F0F0F0F) << 4) | ((x & 0xF0F0F0F0) >> 4);
69 const uint8_t bytes[] = {static_cast<uint8_t>(x & 0xFF),
70 static_cast<uint8_t>((x >> 8) & 0xFF),
71 static_cast<uint8_t>((x >> 16) & 0xFF),
72 static_cast<uint8_t>((x >> 24) & 0xFF)};
73 return TrimLeadingZeros(absl::BytesToHexString(
74 byte_array_to_string_view(bytes, std::size(bytes))));
75}
76
77} // namespace
78
79HEVCDecoderConfigurationRecord::HEVCDecoderConfigurationRecord() = default;
80
81HEVCDecoderConfigurationRecord::~HEVCDecoderConfigurationRecord() = default;
82
83bool HEVCDecoderConfigurationRecord::ParseInternal() {
84 BufferReader reader(data(), data_size());
85
86 uint8_t profile_indication = 0;
87 uint8_t length_size_minus_one = 0;
88 uint8_t num_of_arrays = 0;
89 if (!layered_) {
90 RCHECK(reader.Read1(&version_) && version_ == 1 &&
91 reader.Read1(&profile_indication) &&
92 reader.Read4(&general_profile_compatibility_flags_) &&
93 reader.ReadToVector(&general_constraint_indicator_flags_, 6) &&
94 reader.Read1(&general_level_idc_) &&
95 reader.SkipBytes(8) && // Skip uninterested fields.
96 reader.Read1(&length_size_minus_one) &&
97 reader.Read1(&num_of_arrays));
98
99 general_profile_space_ = profile_indication >> 6;
100 RCHECK(general_profile_space_ <= 3u);
101 general_tier_flag_ = ((profile_indication >> 5) & 1) == 1;
102 general_profile_idc_ = profile_indication & 0x1f;
103 } else {
104 RCHECK(reader.Read1(&version_) && version_ == 1 &&
105 reader.SkipBytes(3) && // Skip uninterested fields.
106 reader.Read1(&length_size_minus_one) &&
107 reader.Read1(&num_of_arrays));
108 }
109 if ((length_size_minus_one & 0x3) == 2) {
110 LOG(ERROR) << "Invalid NALU length size.";
111 return false;
112 }
113 set_nalu_length_size((length_size_minus_one & 0x3) + 1);
114
115 if (parser_ == nullptr) {
116 if (internal_parser_used_ == true)
117 parser_ = &internal_parser_;
118 else {
119 LOG(ERROR) << "Internal parser is not used, but parser_ is not set!";
120 return false;
121 }
122 }
123
124 for (int i = 0; i < num_of_arrays; i++) {
125 uint8_t nal_unit_type;
126 uint16_t num_nalus;
127 RCHECK(reader.Read1(&nal_unit_type));
128 nal_unit_type &= 0x3f;
129 RCHECK(reader.Read2(&num_nalus));
130 for (int j = 0; j < num_nalus; j++) {
131 uint16_t nalu_length;
132 RCHECK(reader.Read2(&nalu_length));
133 uint64_t nalu_offset = reader.pos();
134 RCHECK(reader.SkipBytes(nalu_length));
135
136 Nalu nalu;
137 RCHECK(nalu.Initialize(Nalu::kH265, data() + nalu_offset, nalu_length));
138 RCHECK(nalu.type() == nal_unit_type);
139 AddNalu(nalu);
140
141 if (nalu.type() == Nalu::H265_VPS) {
142 int vps_id = 0;
143 RCHECK(parser_->ParseVps(nalu, &vps_id) == H265Parser::kOk);
144 } else if (nalu.type() == Nalu::H265_SPS) {
145 int sps_id = 0;
146 RCHECK(parser_->ParseSps(nalu, &sps_id) == H265Parser::kOk);
147 const H265Sps* sps = parser_->GetSps(sps_id);
148 if (!layered_) {
150 sps->vui_parameters.transfer_characteristics);
151 set_color_primaries(sps->vui_parameters.color_primaries);
152 set_matrix_coefficients(sps->vui_parameters.matrix_coefficients);
153 } else {
154 // Get profile/tier/level info from the SPS/VPS.
155 const int* general_profile_tier_level_data =
156 sps->general_profile_tier_level_data;
157 general_profile_space_ =
158 (general_profile_tier_level_data[0] & 0xFF) >> 6;
159 RCHECK(general_profile_space_ <= 3u);
160 general_tier_flag_ =
161 ((general_profile_tier_level_data[0] & 0x3F) >> 5) == 1;
162 general_profile_idc_ = general_profile_tier_level_data[0] & 0x1F;
163 general_profile_compatibility_flags_ =
164 ((general_profile_tier_level_data[1] & 0xFF) << 24) |
165 ((general_profile_tier_level_data[2] & 0xFF) << 16) |
166 ((general_profile_tier_level_data[3] & 0xFF) << 8) |
167 (general_profile_tier_level_data[4] & 0xFF);
168 general_constraint_indicator_flags_.resize(6);
169 for (int k = 0; k < 6; ++k) {
170 general_constraint_indicator_flags_[i] =
171 general_profile_tier_level_data[5 + i] & 0xFF;
172 }
173 general_level_idc_ = general_profile_tier_level_data[11] & 0xFF;
174 }
175 }
176 }
177 }
178
179 // TODO(kqyang): Parse SPS to get resolutions.
180 return true;
181}
182
184 FourCC codec_fourcc) const {
185 // ISO/IEC 14496-15:2014 Annex E.
186 std::vector<std::string> fields;
187 fields.push_back(FourCCToString(codec_fourcc));
188 fields.push_back(GeneralProfileSpaceAsString(general_profile_space_) +
189 absl::StrFormat("%d", general_profile_idc_));
190 fields.push_back(
191 ReverseBitsAndHexEncode(general_profile_compatibility_flags_));
192 fields.push_back((general_tier_flag_ ? "H" : "L") +
193 absl::StrFormat("%d", general_level_idc_));
194
195 // Remove trailing bytes that are zero.
196 std::vector<uint8_t> constraints = general_constraint_indicator_flags_;
197 size_t size = constraints.size();
198 for (; size > 0; --size) {
199 if (constraints[size - 1] != 0)
200 break;
201 }
202 constraints.resize(size);
203 for (uint8_t constraint : constraints)
204 fields.push_back(TrimLeadingZeros(
205 absl::BytesToHexString(byte_array_to_string_view(&constraint, 1))));
206
207 return absl::StrJoin(fields, ".");
208}
209
210bool HEVCDecoderConfigurationRecord::ParseLHEVCConfig(
211 const std::vector<uint8_t>& data) {
212 layered_ = true;
213 return Parse(data.data(), data.size());
214}
215
216} // namespace media
217} // namespace shaka
void set_matrix_coefficients(uint8_t matrix_coefficients)
Sets the matrix coeffs.
void AddNalu(const Nalu &nalu)
Adds the given Nalu to the configuration.
void set_color_primaries(uint8_t color_primaries)
Sets the colour primaries.
void set_transfer_characteristics(uint8_t transfer_characteristics)
Sets the transfer characteristics.
bool Parse(const std::vector< uint8_t > &data)
void set_nalu_length_size(uint8_t nalu_length_size)
Sets the size of the NAL unit length field.
Result ParseSps(const Nalu &nalu, int *sps_id)
Result ParseVps(const Nalu &nalu, int *vps_id)
const H265Sps * GetSps(int sps_id)
All the methods that are virtual are virtual for mocking.
std::string_view byte_array_to_string_view(const uint8_t *bytes, size_t bytes_size)
Convert byte array to string_view.