7 #include "packager/media/filters/nalu_reader.h"
11 #include "packager/base/logging.h"
12 #include "packager/media/base/buffer_reader.h"
13 #include "packager/media/filters/h264_parser.h"
15 namespace edash_packager {
19 inline bool IsStartCode(
const uint8_t* data) {
20 return data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01;
32 is_video_slice_(false) {}
35 bool Nalu::InitializeFromH264(
const uint8_t* data, uint64_t size) {
39 const uint8_t header = data[0];
40 if ((header & 0x80) != 0) {
41 LOG(WARNING) <<
"forbidden_zero_bit shall be equal to 0 (header 0x"
42 << std::hex << static_cast<int>(header) <<
").";
48 payload_size_ = size - header_size_;
49 ref_idc_ = (header >> 5) & 0x3;
50 type_ = header & 0x1F;
53 if (type_ == Nalu::H264_Unspecified || type_ == Nalu::H264_Reserved17 ||
54 type_ == Nalu::H264_Reserved18 || type_ >= Nalu::H264_Reserved22) {
55 LOG(WARNING) <<
"Unspecified or reserved nal_unit_type " << type_
56 <<
" (header 0x" << std::hex << static_cast<int>(header)
59 }
else if (type_ == Nalu::H264_IDRSlice || type_ == Nalu::H264_SPS ||
60 type_ == Nalu::H264_SPSExtension || type_ == Nalu::H264_SubsetSPS ||
61 type_ == Nalu::H264_PPS) {
63 LOG(WARNING) <<
"nal_ref_idc shall not be equal to 0 for nalu type "
64 << type_ <<
" (header 0x" << std::hex
65 <<
static_cast<int>(header) <<
").";
68 }
else if (type_ == Nalu::H264_SEIMessage ||
69 (type_ >= Nalu::H264_AUD && type_ <= Nalu::H264_FillerData)) {
71 LOG(WARNING) <<
"nal_ref_idc shall be equal to 0 for nalu type " << type_
72 <<
" (header 0x" << std::hex << static_cast<int>(header)
78 is_video_slice_ = (type_ >= Nalu::H264_NonIDRSlice &&
79 type_ <= Nalu::H264_IDRSlice);
84 bool Nalu::InitializeFromH265(
const uint8_t* data, uint64_t size) {
88 const uint16_t header = (data[0] << 8) | data[1];
89 if ((header & 0x8000) != 0) {
90 LOG(WARNING) <<
"forbidden_zero_bit shall be equal to 0 (header 0x"
91 << std::hex << header <<
").";
97 payload_size_ = size - header_size_;
99 type_ = (header >> 9) & 0x3F;
100 nuh_layer_id_ = (header >> 3) & 0x3F;
101 const int nuh_temporal_id_plus1 = header & 0x7;
102 if (nuh_temporal_id_plus1 == 0) {
103 LOG(WARNING) <<
"nul_temporal_id_plus1 shall not be equal to 0 (header 0x"
104 << std::hex << header <<
").";
107 nuh_temporal_id_ = nuh_temporal_id_plus1 - 1;
109 if (type_ == Nalu::H265_EOB && nuh_layer_id_ != 0) {
110 LOG(WARNING) <<
"nuh_layer_id shall be equal to 0 for nalu type " << type_
111 <<
" (header 0x" << std::hex << header <<
").";
116 if ((type_ >= Nalu::H265_RSV_VCL_N10 && type_ <= Nalu::H265_RSV_VCL_R15) ||
117 (type_ >= Nalu::H265_RSV_IRAP_VCL22 && type_ < Nalu::H265_RSV_VCL31) ||
118 (type_ >= Nalu::H265_RSV_NVCL41)) {
119 LOG(WARNING) <<
"Unspecified or reserved nal_unit_type " << type_
120 <<
" (header 0x" << std::hex << header <<
").";
122 }
else if ((type_ >= Nalu::H265_BLA_W_LP &&
123 type_ <= Nalu::H265_RSV_IRAP_VCL23) ||
124 type_ == Nalu::H265_VPS || type_ == Nalu::H265_SPS ||
125 type_ == Nalu::H265_EOS || type_ == Nalu::H265_EOB) {
126 if (nuh_temporal_id_ != 0) {
127 LOG(WARNING) <<
"TemporalId shall be equal to 0 for nalu type " << type_
128 <<
" (header 0x" << std::hex << header <<
").";
131 }
else if (type_ == Nalu::H265_TSA_N || type_ == Nalu::H265_TSA_R ||
132 (nuh_layer_id_ == 0 &&
133 (type_ == Nalu::H265_STSA_N || type_ == Nalu::H265_STSA_R))) {
134 if (nuh_temporal_id_ == 0) {
135 LOG(WARNING) <<
"TemporalId shall not be equal to 0 for nalu type "
136 << type_ <<
" (header 0x" << std::hex << header <<
").";
141 is_video_slice_ = type_ >= Nalu::H265_TRAIL_N && type_ <= Nalu::H265_CRA_NUT;
146 uint8_t nal_length_size,
147 const uint8_t* stream,
148 uint64_t stream_size)
150 stream_size_(stream_size),
152 nalu_length_size_(nal_length_size),
153 format_(nal_length_size == 0 ? kAnnexbByteStreamFormat
154 : kNalUnitStreamFormat) {
157 NaluReader::~NaluReader() {}
160 if (stream_size_ <= 0)
161 return NaluReader::kEOStream;
163 uint8_t nalu_length_size_or_start_code_size;
164 uint64_t nalu_length;
165 if (format_ == kAnnexbByteStreamFormat) {
167 uint64_t nalu_length_with_header;
168 if (!LocateNaluByStartCode(&nalu_length_with_header,
169 &nalu_length_size_or_start_code_size)) {
170 LOG(ERROR) <<
"Could not find next NALU, bytes left in stream: "
175 return NaluReader::kInvalidStream;
177 nalu_length = nalu_length_with_header - nalu_length_size_or_start_code_size;
181 return NaluReader::kInvalidStream;
182 nalu_length_size_or_start_code_size = nalu_length_size_;
184 if (nalu_length + nalu_length_size_ > stream_size_) {
185 LOG(ERROR) <<
"NALU length exceeds stream size: "
186 << stream_size_ <<
" < " << nalu_length;
187 return NaluReader::kInvalidStream;
189 if (nalu_length == 0) {
190 LOG(ERROR) <<
"NALU size 0";
191 return NaluReader::kInvalidStream;
195 const uint8_t* nalu_data = stream_ + nalu_length_size_or_start_code_size;
196 if (nalu_type_ == kH264) {
197 if (!nalu->InitializeFromH264(nalu_data, nalu_length))
198 return NaluReader::kInvalidStream;
200 DCHECK_EQ(kH265, nalu_type_);
201 if (!nalu->InitializeFromH265(nalu_data, nalu_length))
202 return NaluReader::kInvalidStream;
207 stream_ += nalu_length_size_or_start_code_size + nalu_length;
208 stream_size_ -= nalu_length_size_or_start_code_size + nalu_length;
210 DVLOG(4) <<
"NALU type: " <<
static_cast<int>(nalu->type())
211 <<
" at: " << reinterpret_cast<const void*>(nalu->data())
212 <<
" data size: " << nalu->payload_size();
214 return NaluReader::kOk;
218 if (stream_size_ >= 3) {
219 if (IsStartCode(stream_))
222 if (stream_size_ >= 4) {
223 if (stream_[0] == 0x00 && IsStartCode(stream_ + 1))
230 bool NaluReader::FindStartCode(
const uint8_t* data,
233 uint8_t* start_code_size) {
234 uint64_t bytes_left = data_size;
236 while (bytes_left >= 3) {
237 if (IsStartCode(data)) {
239 *offset = data_size - bytes_left;
240 *start_code_size = 3;
244 if (*offset > 0 && *(data - 1) == 0x00) {
246 ++(*start_code_size);
258 *offset = data_size - bytes_left;
259 *start_code_size = 0;
263 bool NaluReader::LocateNaluByStartCode(uint64_t* nalu_size,
264 uint8_t* start_code_size) {
266 uint64_t nalu_start_off = 0;
267 uint8_t annexb_start_code_size = 0;
268 if (!FindStartCode(stream_, stream_size_,
269 &nalu_start_off, &annexb_start_code_size)) {
270 DVLOG(4) <<
"Could not find start code, end of stream?";
275 stream_ += nalu_start_off;
276 stream_size_ -= nalu_start_off;
278 const uint8_t* nalu_data = stream_ + annexb_start_code_size;
279 uint64_t max_nalu_data_size = stream_size_ - annexb_start_code_size;
280 if (max_nalu_data_size <= 0) {
281 DVLOG(3) <<
"End of stream";
291 uint64_t nalu_size_without_start_code = 0;
292 uint8_t next_start_code_size = 0;
294 if (!FindStartCode(nalu_data, max_nalu_data_size,
295 &nalu_size_without_start_code, &next_start_code_size)) {
296 nalu_data += max_nalu_data_size;
300 nalu_data += nalu_size_without_start_code + next_start_code_size;
301 max_nalu_data_size -= nalu_size_without_start_code + next_start_code_size;
305 if (nalu_type_ == kH264
306 ? nalu.InitializeFromH264(nalu_data, max_nalu_data_size)
307 : nalu.InitializeFromH265(nalu_data, max_nalu_data_size)) {
308 nalu_data -= next_start_code_size;
311 LOG(WARNING) <<
"Seeing invalid NAL unit. Emulation prevention may not "
312 "have been applied properly. Assuming it is part of the "
313 "previous NAL unit.";
315 *nalu_size = nalu_data - stream_;
316 *start_code_size = annexb_start_code_size;