5 #include "packager/media/formats/mp2t/es_parser_h264.h"
9 #include "packager/base/logging.h"
10 #include "packager/base/numerics/safe_conversions.h"
11 #include "packager/media/base/media_sample.h"
12 #include "packager/media/base/offset_byte_queue.h"
13 #include "packager/media/base/timestamp.h"
14 #include "packager/media/base/video_stream_info.h"
15 #include "packager/media/filters/h264_byte_to_unit_stream_converter.h"
16 #include "packager/media/filters/h264_parser.h"
17 #include "packager/media/formats/mp2t/mp2t_common.h"
19 namespace edash_packager {
27 const int kMinAUDSize = 4;
31 EsParserH264::EsParserH264(uint32_t pid,
32 const NewStreamInfoCB& new_stream_info_cb,
33 const EmitSampleCB& emit_sample_cb)
35 new_stream_info_cb_(new_stream_info_cb),
36 emit_sample_cb_(emit_sample_cb),
37 es_queue_(new media::OffsetByteQueue()),
38 h264_parser_(new H264Parser()),
39 current_access_unit_pos_(0),
40 next_access_unit_pos_(0),
41 stream_converter_(new H264ByteToUnitStreamConverter),
42 decoder_config_check_pending_(false),
43 pending_sample_duration_(0),
44 waiting_for_key_frame_(true) {
47 EsParserH264::~EsParserH264() {
50 bool EsParserH264::Parse(
const uint8_t* buf,
63 DVLOG_IF(1, pts == kNoTimestamp) <<
"Each video PES should have a PTS";
64 if (pts != kNoTimestamp) {
65 TimingDesc timing_desc;
66 timing_desc.pts = pts;
67 timing_desc.dts = (dts != kNoTimestamp) ? dts : pts;
70 timing_desc_list_.push_back(
71 std::pair<int64_t, TimingDesc>(es_queue_->tail(), timing_desc));
75 es_queue_->Push(buf, size);
76 return ParseInternal();
79 void EsParserH264::Flush() {
80 DVLOG(1) <<
"EsParserH264::Flush";
82 if (FindAUD(¤t_access_unit_pos_)) {
85 uint8_t aud[] = {0x00, 0x00, 0x01, 0x09};
86 es_queue_->Push(aud,
sizeof(aud));
90 if (pending_sample_) {
92 DCHECK(pending_sample_duration_);
93 pending_sample_->set_duration(pending_sample_duration_);
94 emit_sample_cb_.Run(pid(), pending_sample_);
95 pending_sample_ = scoped_refptr<MediaSample>();
99 void EsParserH264::Reset() {
100 DVLOG(1) <<
"EsParserH264::Reset";
101 es_queue_.reset(
new media::OffsetByteQueue());
102 h264_parser_.reset(
new H264Parser());
103 current_access_unit_pos_ = 0;
104 next_access_unit_pos_ = 0;
105 timing_desc_list_.clear();
106 last_video_decoder_config_ = scoped_refptr<StreamInfo>();
107 decoder_config_check_pending_ =
false;
108 pending_sample_ = scoped_refptr<MediaSample>();
109 pending_sample_duration_ = 0;
110 waiting_for_key_frame_ =
true;
113 bool EsParserH264::FindAUD(int64_t* stream_pos) {
117 es_queue_->PeekAt(*stream_pos, &es, &size);
120 off_t start_code_offset;
121 off_t start_code_size;
122 bool start_code_found = H264Parser::FindStartCode(
123 es, size, &start_code_offset, &start_code_size);
124 *stream_pos += start_code_offset;
127 if (!start_code_found || start_code_offset + start_code_size >= size)
134 if (es[start_code_offset + start_code_size] == H264NALU::kAUD)
139 *stream_pos += start_code_size;
145 bool EsParserH264::ParseInternal() {
146 DCHECK_LE(es_queue_->head(), current_access_unit_pos_);
147 DCHECK_LE(current_access_unit_pos_, next_access_unit_pos_);
148 DCHECK_LE(next_access_unit_pos_, es_queue_->tail());
155 bool aud_found = FindAUD(¤t_access_unit_pos_);
156 es_queue_->Trim(current_access_unit_pos_);
157 if (next_access_unit_pos_ < current_access_unit_pos_)
158 next_access_unit_pos_ = current_access_unit_pos_;
165 if (next_access_unit_pos_ < current_access_unit_pos_ + kMinAUDSize) {
166 next_access_unit_pos_ = current_access_unit_pos_ + kMinAUDSize;
167 DCHECK_LE(next_access_unit_pos_, es_queue_->tail());
169 if (!FindAUD(&next_access_unit_pos_))
173 bool is_key_frame =
false;
174 int pps_id_for_access_unit = -1;
178 es_queue_->PeekAt(current_access_unit_pos_, &es, &size);
179 int access_unit_size = base::checked_cast<int, int64_t>(
180 next_access_unit_pos_ - current_access_unit_pos_);
181 DCHECK_LE(access_unit_size, size);
182 h264_parser_->SetStream(es, access_unit_size);
187 switch (h264_parser_->AdvanceToNextNALU(&nalu)) {
188 case H264Parser::kOk:
190 case H264Parser::kInvalidStream:
191 case H264Parser::kUnsupportedStream:
193 case H264Parser::kEOStream:
200 switch (nalu.nal_unit_type) {
201 case H264NALU::kAUD: {
202 DVLOG(LOG_LEVEL_ES) <<
"NALU: AUD";
205 case H264NALU::kSPS: {
206 DVLOG(LOG_LEVEL_ES) <<
"NALU: SPS";
208 if (h264_parser_->ParseSPS(&sps_id) != H264Parser::kOk)
210 decoder_config_check_pending_ =
true;
213 case H264NALU::kPPS: {
214 DVLOG(LOG_LEVEL_ES) <<
"NALU: PPS";
216 if (h264_parser_->ParsePPS(&pps_id) != H264Parser::kOk) {
218 if (last_video_decoder_config_)
221 decoder_config_check_pending_ =
true;
225 case H264NALU::kIDRSlice:
226 case H264NALU::kNonIDRSlice: {
227 is_key_frame = (nalu.nal_unit_type == H264NALU::kIDRSlice);
228 DVLOG(LOG_LEVEL_ES) <<
"NALU: slice IDR=" << is_key_frame;
229 H264SliceHeader shdr;
230 if (h264_parser_->ParseSliceHeader(nalu, &shdr) != H264Parser::kOk) {
233 if (last_video_decoder_config_)
236 pps_id_for_access_unit = shdr.pic_parameter_set_id;
241 DVLOG(LOG_LEVEL_ES) <<
"NALU: " << nalu.nal_unit_type;
246 if (waiting_for_key_frame_) {
247 waiting_for_key_frame_ = !is_key_frame;
249 if (!waiting_for_key_frame_) {
251 RCHECK(EmitFrame(current_access_unit_pos_, access_unit_size,
252 is_key_frame, pps_id_for_access_unit));
254 current_access_unit_pos_ = next_access_unit_pos_;
255 es_queue_->Trim(current_access_unit_pos_);
260 bool EsParserH264::EmitFrame(int64_t access_unit_pos,
261 int access_unit_size,
265 TimingDesc current_timing_desc = {kNoTimestamp, kNoTimestamp};
266 while (!timing_desc_list_.empty() &&
267 timing_desc_list_.front().first <= access_unit_pos) {
268 current_timing_desc = timing_desc_list_.front().second;
269 timing_desc_list_.pop_front();
271 if (current_timing_desc.pts == kNoTimestamp)
275 DVLOG(LOG_LEVEL_ES) <<
"Emit frame: stream_pos=" << current_access_unit_pos_
276 <<
" size=" << access_unit_size;
279 es_queue_->PeekAt(current_access_unit_pos_, &es, &es_size);
280 CHECK_GE(es_size, access_unit_size);
283 std::vector<uint8_t> converted_frame;
284 if (!stream_converter_->ConvertByteStreamToNalUnitStream(
285 es, access_unit_size, &converted_frame)) {
286 DLOG(ERROR) <<
"Failure to convert video frame to unit stream format.";
290 if (decoder_config_check_pending_) {
292 const H264PPS* pps = h264_parser_->GetPPS(pps_id);
299 if (last_video_decoder_config_)
302 const H264SPS* sps = h264_parser_->GetSPS(pps->seq_parameter_set_id);
305 RCHECK(UpdateVideoDecoderConfig(sps));
306 decoder_config_check_pending_ =
false;
313 converted_frame.data(), converted_frame.size(), is_key_frame);
314 media_sample->set_dts(current_timing_desc.dts);
315 media_sample->set_pts(current_timing_desc.pts);
316 if (pending_sample_) {
317 DCHECK_GT(media_sample->dts(), pending_sample_->dts());
318 pending_sample_duration_ = media_sample->dts() - pending_sample_->dts();
319 pending_sample_->set_duration(pending_sample_duration_);
320 emit_sample_cb_.Run(pid(), pending_sample_);
322 pending_sample_ = media_sample;
327 bool EsParserH264::UpdateVideoDecoderConfig(
const H264SPS* sps) {
328 std::vector<uint8_t> decoder_config_record;
329 if (!stream_converter_->GetAVCDecoderConfigurationRecord(
330 &decoder_config_record)) {
331 DLOG(ERROR) <<
"Failure to construct an AVCDecoderConfigurationRecord";
335 if (last_video_decoder_config_) {
336 if (last_video_decoder_config_->extra_data() != decoder_config_record) {
342 LOG(WARNING) <<
"H.264 decoder configuration has changed.";
343 last_video_decoder_config_->set_extra_data(decoder_config_record);
348 uint32_t coded_width = 0;
349 uint32_t coded_height = 0;
350 uint32_t pixel_width = 0;
351 uint32_t pixel_height = 0;
352 if (!ExtractResolutionFromSps(*sps, &coded_width, &coded_height, &pixel_width,
354 LOG(ERROR) <<
"Failed to parse SPS.";
358 last_video_decoder_config_ = scoped_refptr<StreamInfo>(
365 decoder_config_record[1],
366 decoder_config_record[2],
367 decoder_config_record[3]),
374 H264ByteToUnitStreamConverter::kUnitStreamNaluLengthSize,
375 decoder_config_record.data(),
376 decoder_config_record.size(),
378 DVLOG(1) <<
"Profile IDC: " << sps->profile_idc;
379 DVLOG(1) <<
"Level IDC: " << sps->level_idc;
380 DVLOG(1) <<
"log2_max_frame_num_minus4: " << sps->log2_max_frame_num_minus4;
383 new_stream_info_cb_.Run(last_video_decoder_config_);