7 #include "packager/media/codecs/nalu_reader.h"
11 #include "packager/base/logging.h"
12 #include "packager/media/base/buffer_reader.h"
13 #include "packager/media/codecs/h264_parser.h"
19 inline bool IsStartCode(
const uint8_t* data) {
20 return data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01;
24 Nalu::Nalu() =
default;
26 bool Nalu::Initialize(CodecType type,
29 if (type == Nalu::kH264) {
30 return InitializeFromH264(data, size);
32 DCHECK_EQ(Nalu::kH265, type);
33 return InitializeFromH265(data, size);
38 bool Nalu::InitializeFromH264(
const uint8_t* data, uint64_t size) {
42 const uint8_t header = data[0];
43 if ((header & 0x80) != 0) {
44 LOG(WARNING) <<
"forbidden_zero_bit shall be equal to 0 (header 0x"
45 << std::hex << static_cast<int>(header) <<
").";
51 payload_size_ = size - header_size_;
52 ref_idc_ = (header >> 5) & 0x3;
53 type_ = header & 0x1F;
56 if (type_ == Nalu::H264_Unspecified || type_ == Nalu::H264_Reserved17 ||
57 type_ == Nalu::H264_Reserved18 || type_ >= Nalu::H264_Reserved22) {
58 LOG(WARNING) <<
"Unspecified or reserved nal_unit_type " << type_
59 <<
" (header 0x" << std::hex << static_cast<int>(header)
62 }
else if (type_ == Nalu::H264_IDRSlice || type_ == Nalu::H264_SPS ||
63 type_ == Nalu::H264_SPSExtension ||
64 type_ == Nalu::H264_SubsetSPS || type_ == Nalu::H264_PPS) {
66 LOG(WARNING) <<
"nal_ref_idc shall not be equal to 0 for nalu type "
67 << type_ <<
" (header 0x" << std::hex
68 <<
static_cast<int>(header) <<
").";
71 }
else if (type_ == Nalu::H264_SEIMessage ||
72 (type_ >= Nalu::H264_AUD && type_ <= Nalu::H264_FillerData)) {
74 LOG(WARNING) <<
"nal_ref_idc shall be equal to 0 for nalu type " << type_
75 <<
" (header 0x" << std::hex << static_cast<int>(header)
81 is_aud_ = type_ == H264_AUD;
82 is_vcl_ = (type_ >= Nalu::H264_NonIDRSlice && type_ <= Nalu::H264_IDRSlice);
84 (type_ == Nalu::H264_NonIDRSlice || type_ == Nalu::H264_IDRSlice);
85 can_start_access_unit_ =
86 (is_vcl_ || type_ == Nalu::H264_AUD || type_ == Nalu::H264_SPS ||
87 type_ == Nalu::H264_PPS || type_ == Nalu::H264_SEIMessage ||
88 (type_ >= Nalu::H264_PrefixNALUnit && type_ <= Nalu::H264_Reserved18));
93 bool Nalu::InitializeFromH265(
const uint8_t* data, uint64_t size) {
97 const uint16_t header = (data[0] << 8) | data[1];
98 if ((header & 0x8000) != 0) {
99 LOG(WARNING) <<
"forbidden_zero_bit shall be equal to 0 (header 0x"
100 << std::hex << header <<
").";
106 payload_size_ = size - header_size_;
108 type_ = (header >> 9) & 0x3F;
109 nuh_layer_id_ = (header >> 3) & 0x3F;
110 const int nuh_temporal_id_plus1 = header & 0x7;
111 if (nuh_temporal_id_plus1 == 0) {
112 LOG(WARNING) <<
"nul_temporal_id_plus1 shall not be equal to 0 (header 0x"
113 << std::hex << header <<
").";
116 nuh_temporal_id_ = nuh_temporal_id_plus1 - 1;
118 if (type_ == Nalu::H265_EOB && nuh_layer_id_ != 0) {
119 LOG(WARNING) <<
"nuh_layer_id shall be equal to 0 for nalu type " << type_
120 <<
" (header 0x" << std::hex << header <<
").";
125 if ((type_ >= Nalu::H265_RSV_VCL_N10 && type_ <= Nalu::H265_RSV_VCL_R15) ||
126 (type_ >= Nalu::H265_RSV_IRAP_VCL22 && type_ < Nalu::H265_RSV_VCL31) ||
127 (type_ >= Nalu::H265_RSV_NVCL41)) {
128 LOG(WARNING) <<
"Unspecified or reserved nal_unit_type " << type_
129 <<
" (header 0x" << std::hex << header <<
").";
131 }
else if ((type_ >= Nalu::H265_BLA_W_LP &&
132 type_ <= Nalu::H265_RSV_IRAP_VCL23) ||
133 type_ == Nalu::H265_VPS || type_ == Nalu::H265_SPS ||
134 type_ == Nalu::H265_EOS || type_ == Nalu::H265_EOB) {
135 if (nuh_temporal_id_ != 0) {
136 LOG(WARNING) <<
"TemporalId shall be equal to 0 for nalu type " << type_
137 <<
" (header 0x" << std::hex << header <<
").";
140 }
else if (type_ == Nalu::H265_TSA_N || type_ == Nalu::H265_TSA_R ||
141 (nuh_layer_id_ == 0 &&
142 (type_ == Nalu::H265_STSA_N || type_ == Nalu::H265_STSA_R))) {
143 if (nuh_temporal_id_ == 0) {
144 LOG(WARNING) <<
"TemporalId shall not be equal to 0 for nalu type "
145 << type_ <<
" (header 0x" << std::hex << header <<
").";
150 is_aud_ = type_ == H265_AUD;
151 is_vcl_ = type_ >= Nalu::H265_TRAIL_N && type_ <= Nalu::H265_CRA_NUT;
152 is_video_slice_ = is_vcl_;
153 can_start_access_unit_ =
154 nuh_layer_id_ == 0 &&
155 (is_vcl_ || type_ == Nalu::H265_AUD || type_ == Nalu::H265_VPS ||
156 type_ == Nalu::H265_SPS || type_ == Nalu::H265_PPS ||
157 type_ == Nalu::H265_PREFIX_SEI ||
158 (type_ >= Nalu::H265_RSV_NVCL41 && type_ <= Nalu::H265_RSV_NVCL44) ||
159 (type_ >= Nalu::H265_UNSPEC48 && type_ <= Nalu::H265_UNSPEC55));
164 uint8_t nal_length_size,
165 const uint8_t* stream,
166 uint64_t stream_size)
168 stream_size_(stream_size),
170 nalu_length_size_(nal_length_size),
171 format_(nal_length_size == 0 ? kAnnexbByteStreamFormat
172 : kNalUnitStreamFormat) {
175 NaluReader::~NaluReader() {}
178 if (stream_size_ <= 0)
179 return NaluReader::kEOStream;
181 uint8_t nalu_length_size_or_start_code_size;
182 uint64_t nalu_length;
183 if (format_ == kAnnexbByteStreamFormat) {
185 uint64_t nalu_length_with_header;
186 if (!LocateNaluByStartCode(&nalu_length_with_header,
187 &nalu_length_size_or_start_code_size)) {
188 LOG(ERROR) <<
"Could not find next NALU, bytes left in stream: "
193 return NaluReader::kInvalidStream;
195 nalu_length = nalu_length_with_header - nalu_length_size_or_start_code_size;
199 return NaluReader::kInvalidStream;
200 nalu_length_size_or_start_code_size = nalu_length_size_;
202 if (nalu_length + nalu_length_size_ > stream_size_) {
203 LOG(ERROR) <<
"NALU length exceeds stream size: "
204 << stream_size_ <<
" < " << nalu_length;
205 return NaluReader::kInvalidStream;
207 if (nalu_length == 0) {
208 LOG(ERROR) <<
"NALU size 0";
209 return NaluReader::kInvalidStream;
213 const uint8_t* nalu_data = stream_ + nalu_length_size_or_start_code_size;
214 if (!nalu->Initialize(nalu_type_, nalu_data, nalu_length))
215 return NaluReader::kInvalidStream;
219 stream_ += nalu_length_size_or_start_code_size + nalu_length;
220 stream_size_ -= nalu_length_size_or_start_code_size + nalu_length;
222 DVLOG(4) <<
"NALU type: " <<
static_cast<int>(nalu->
type())
223 <<
" at: " << reinterpret_cast<const void*>(nalu->
data())
226 return NaluReader::kOk;
230 if (stream_size_ >= 3) {
231 if (IsStartCode(stream_))
234 if (stream_size_ >= 4) {
235 if (stream_[0] == 0x00 && IsStartCode(stream_ + 1))
242 bool NaluReader::FindStartCode(
const uint8_t* data,
245 uint8_t* start_code_size) {
246 uint64_t bytes_left = data_size;
248 while (bytes_left >= 3) {
249 if (IsStartCode(data)) {
251 *offset = data_size - bytes_left;
252 *start_code_size = 3;
256 if (*offset > 0 && *(data - 1) == 0x00) {
258 ++(*start_code_size);
270 *offset = data_size - bytes_left;
271 *start_code_size = 0;
275 bool NaluReader::LocateNaluByStartCode(uint64_t* nalu_size,
276 uint8_t* start_code_size) {
278 uint64_t nalu_start_off = 0;
279 uint8_t annexb_start_code_size = 0;
280 if (!FindStartCode(stream_, stream_size_,
281 &nalu_start_off, &annexb_start_code_size)) {
282 DVLOG(4) <<
"Could not find start code, end of stream?";
287 stream_ += nalu_start_off;
288 stream_size_ -= nalu_start_off;
290 const uint8_t* nalu_data = stream_ + annexb_start_code_size;
291 uint64_t max_nalu_data_size = stream_size_ - annexb_start_code_size;
292 if (max_nalu_data_size <= 0) {
293 DVLOG(3) <<
"End of stream";
303 uint64_t nalu_size_without_start_code = 0;
304 uint8_t next_start_code_size = 0;
306 if (!FindStartCode(nalu_data, max_nalu_data_size,
307 &nalu_size_without_start_code, &next_start_code_size)) {
308 nalu_data += max_nalu_data_size;
312 nalu_data += nalu_size_without_start_code + next_start_code_size;
313 max_nalu_data_size -= nalu_size_without_start_code + next_start_code_size;
317 if (nalu.Initialize(nalu_type_, nalu_data, max_nalu_data_size)) {
318 nalu_data -= next_start_code_size;
321 LOG(WARNING) <<
"Seeing invalid NAL unit. Emulation prevention may not "
322 "have been applied properly. Assuming it is part of the "
323 "previous NAL unit.";
325 *nalu_size = nalu_data - stream_;
326 *start_code_size = annexb_start_code_size;