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/avc_decoder_configuration.h"
16 #include "packager/media/filters/h264_byte_to_unit_stream_converter.h"
17 #include "packager/media/filters/h264_parser.h"
18 #include "packager/media/formats/mp2t/mp2t_common.h"
20 namespace edash_packager {
28 const int kMinAUDSize = 4;
32 EsParserH264::EsParserH264(uint32_t pid,
33 const NewStreamInfoCB& new_stream_info_cb,
34 const EmitSampleCB& emit_sample_cb)
36 new_stream_info_cb_(new_stream_info_cb),
37 emit_sample_cb_(emit_sample_cb),
38 es_queue_(new media::OffsetByteQueue()),
39 h264_parser_(new H264Parser()),
40 current_access_unit_pos_(0),
41 next_access_unit_pos_(0),
42 stream_converter_(new H264ByteToUnitStreamConverter),
43 decoder_config_check_pending_(false),
44 pending_sample_duration_(0),
45 waiting_for_key_frame_(true) {
48 EsParserH264::~EsParserH264() {
51 bool EsParserH264::Parse(
const uint8_t* buf,
64 DVLOG_IF(1, pts == kNoTimestamp) <<
"Each video PES should have a PTS";
65 if (pts != kNoTimestamp) {
66 TimingDesc timing_desc;
67 timing_desc.pts = pts;
68 timing_desc.dts = (dts != kNoTimestamp) ? dts : pts;
71 timing_desc_list_.push_back(
72 std::pair<int64_t, TimingDesc>(es_queue_->tail(), timing_desc));
76 es_queue_->Push(buf, size);
77 return ParseInternal();
80 void EsParserH264::Flush() {
81 DVLOG(1) <<
"EsParserH264::Flush";
83 if (FindAUD(¤t_access_unit_pos_)) {
86 uint8_t aud[] = {0x00, 0x00, 0x01, 0x09};
87 es_queue_->Push(aud,
sizeof(aud));
91 if (pending_sample_) {
93 DCHECK(pending_sample_duration_);
94 pending_sample_->set_duration(pending_sample_duration_);
95 emit_sample_cb_.Run(pid(), pending_sample_);
96 pending_sample_ = scoped_refptr<MediaSample>();
100 void EsParserH264::Reset() {
101 DVLOG(1) <<
"EsParserH264::Reset";
102 es_queue_.reset(
new media::OffsetByteQueue());
103 h264_parser_.reset(
new H264Parser());
104 current_access_unit_pos_ = 0;
105 next_access_unit_pos_ = 0;
106 timing_desc_list_.clear();
107 last_video_decoder_config_ = scoped_refptr<StreamInfo>();
108 decoder_config_check_pending_ =
false;
109 pending_sample_ = scoped_refptr<MediaSample>();
110 pending_sample_duration_ = 0;
111 waiting_for_key_frame_ =
true;
114 bool EsParserH264::FindAUD(int64_t* stream_pos) {
118 es_queue_->PeekAt(*stream_pos, &es, &size);
121 off_t start_code_offset;
122 off_t start_code_size;
123 bool start_code_found = H264Parser::FindStartCode(
124 es, size, &start_code_offset, &start_code_size);
125 *stream_pos += start_code_offset;
128 if (!start_code_found || start_code_offset + start_code_size >= size)
135 if (es[start_code_offset + start_code_size] == H264NALU::kAUD)
140 *stream_pos += start_code_size;
146 bool EsParserH264::ParseInternal() {
147 DCHECK_LE(es_queue_->head(), current_access_unit_pos_);
148 DCHECK_LE(current_access_unit_pos_, next_access_unit_pos_);
149 DCHECK_LE(next_access_unit_pos_, es_queue_->tail());
156 bool aud_found = FindAUD(¤t_access_unit_pos_);
157 es_queue_->Trim(current_access_unit_pos_);
158 if (next_access_unit_pos_ < current_access_unit_pos_)
159 next_access_unit_pos_ = current_access_unit_pos_;
166 if (next_access_unit_pos_ < current_access_unit_pos_ + kMinAUDSize) {
167 next_access_unit_pos_ = current_access_unit_pos_ + kMinAUDSize;
168 DCHECK_LE(next_access_unit_pos_, es_queue_->tail());
170 if (!FindAUD(&next_access_unit_pos_))
174 bool is_key_frame =
false;
175 int pps_id_for_access_unit = -1;
179 es_queue_->PeekAt(current_access_unit_pos_, &es, &size);
180 int access_unit_size = base::checked_cast<int, int64_t>(
181 next_access_unit_pos_ - current_access_unit_pos_);
182 DCHECK_LE(access_unit_size, size);
183 h264_parser_->SetStream(es, access_unit_size);
188 switch (h264_parser_->AdvanceToNextNALU(&nalu)) {
189 case H264Parser::kOk:
191 case H264Parser::kInvalidStream:
192 case H264Parser::kUnsupportedStream:
194 case H264Parser::kEOStream:
201 switch (nalu.nal_unit_type) {
202 case H264NALU::kAUD: {
203 DVLOG(LOG_LEVEL_ES) <<
"NALU: AUD";
206 case H264NALU::kSPS: {
207 DVLOG(LOG_LEVEL_ES) <<
"NALU: SPS";
209 if (h264_parser_->ParseSPS(&sps_id) != H264Parser::kOk)
211 decoder_config_check_pending_ =
true;
214 case H264NALU::kPPS: {
215 DVLOG(LOG_LEVEL_ES) <<
"NALU: PPS";
217 if (h264_parser_->ParsePPS(&pps_id) != H264Parser::kOk) {
219 if (last_video_decoder_config_)
222 decoder_config_check_pending_ =
true;
226 case H264NALU::kIDRSlice:
227 case H264NALU::kNonIDRSlice: {
228 is_key_frame = (nalu.nal_unit_type == H264NALU::kIDRSlice);
229 DVLOG(LOG_LEVEL_ES) <<
"NALU: slice IDR=" << is_key_frame;
230 H264SliceHeader shdr;
231 if (h264_parser_->ParseSliceHeader(nalu, &shdr) != H264Parser::kOk) {
234 if (last_video_decoder_config_)
237 pps_id_for_access_unit = shdr.pic_parameter_set_id;
242 DVLOG(LOG_LEVEL_ES) <<
"NALU: " << nalu.nal_unit_type;
247 if (waiting_for_key_frame_) {
248 waiting_for_key_frame_ = !is_key_frame;
250 if (!waiting_for_key_frame_) {
252 RCHECK(EmitFrame(current_access_unit_pos_, access_unit_size,
253 is_key_frame, pps_id_for_access_unit));
255 current_access_unit_pos_ = next_access_unit_pos_;
256 es_queue_->Trim(current_access_unit_pos_);
261 bool EsParserH264::EmitFrame(int64_t access_unit_pos,
262 int access_unit_size,
266 TimingDesc current_timing_desc = {kNoTimestamp, kNoTimestamp};
267 while (!timing_desc_list_.empty() &&
268 timing_desc_list_.front().first <= access_unit_pos) {
269 current_timing_desc = timing_desc_list_.front().second;
270 timing_desc_list_.pop_front();
272 if (current_timing_desc.pts == kNoTimestamp)
276 DVLOG(LOG_LEVEL_ES) <<
"Emit frame: stream_pos=" << current_access_unit_pos_
277 <<
" size=" << access_unit_size;
280 es_queue_->PeekAt(current_access_unit_pos_, &es, &es_size);
281 CHECK_GE(es_size, access_unit_size);
284 std::vector<uint8_t> converted_frame;
285 if (!stream_converter_->ConvertByteStreamToNalUnitStream(
286 es, access_unit_size, &converted_frame)) {
287 DLOG(ERROR) <<
"Failure to convert video frame to unit stream format.";
291 if (decoder_config_check_pending_) {
293 const H264PPS* pps = h264_parser_->GetPPS(pps_id);
300 if (last_video_decoder_config_)
303 const H264SPS* sps = h264_parser_->GetSPS(pps->seq_parameter_set_id);
306 RCHECK(UpdateVideoDecoderConfig(sps));
307 decoder_config_check_pending_ =
false;
314 converted_frame.data(), converted_frame.size(), is_key_frame);
315 media_sample->set_dts(current_timing_desc.dts);
316 media_sample->set_pts(current_timing_desc.pts);
317 if (pending_sample_) {
318 DCHECK_GT(media_sample->dts(), pending_sample_->dts());
319 pending_sample_duration_ = media_sample->dts() - pending_sample_->dts();
320 pending_sample_->set_duration(pending_sample_duration_);
321 emit_sample_cb_.Run(pid(), pending_sample_);
323 pending_sample_ = media_sample;
328 bool EsParserH264::UpdateVideoDecoderConfig(
const H264SPS* sps) {
329 std::vector<uint8_t> decoder_config_record;
330 if (!stream_converter_->GetAVCDecoderConfigurationRecord(
331 &decoder_config_record)) {
332 DLOG(ERROR) <<
"Failure to construct an AVCDecoderConfigurationRecord";
336 if (last_video_decoder_config_) {
337 if (last_video_decoder_config_->extra_data() != decoder_config_record) {
343 LOG(WARNING) <<
"H.264 decoder configuration has changed.";
344 last_video_decoder_config_->set_extra_data(decoder_config_record);
349 uint32_t coded_width = 0;
350 uint32_t coded_height = 0;
351 uint32_t pixel_width = 0;
352 uint32_t pixel_height = 0;
353 if (!ExtractResolutionFromSps(*sps, &coded_width, &coded_height, &pixel_width,
355 LOG(ERROR) <<
"Failed to parse SPS.";
359 last_video_decoder_config_ = scoped_refptr<StreamInfo>(
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_);