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 uint64_t start_code_offset;
122 uint8_t start_code_size;
123 bool start_code_found = NaluReader::FindStartCode(
124 es, size, &start_code_offset, &start_code_size);
125 *stream_pos += start_code_offset;
128 if (!start_code_found ||
129 start_code_offset + start_code_size >= static_cast<uint64_t>(size)) {
137 if (es[start_code_offset + start_code_size] == Nalu::H264_AUD)
142 *stream_pos += start_code_size;
148 bool EsParserH264::ParseInternal() {
149 DCHECK_LE(es_queue_->head(), current_access_unit_pos_);
150 DCHECK_LE(current_access_unit_pos_, next_access_unit_pos_);
151 DCHECK_LE(next_access_unit_pos_, es_queue_->tail());
158 bool aud_found = FindAUD(¤t_access_unit_pos_);
159 es_queue_->Trim(current_access_unit_pos_);
160 if (next_access_unit_pos_ < current_access_unit_pos_)
161 next_access_unit_pos_ = current_access_unit_pos_;
168 if (next_access_unit_pos_ < current_access_unit_pos_ + kMinAUDSize) {
169 next_access_unit_pos_ = current_access_unit_pos_ + kMinAUDSize;
170 DCHECK_LE(next_access_unit_pos_, es_queue_->tail());
172 if (!FindAUD(&next_access_unit_pos_))
176 bool is_key_frame =
false;
177 int pps_id_for_access_unit = -1;
181 es_queue_->PeekAt(current_access_unit_pos_, &es, &size);
182 int access_unit_size = base::checked_cast<int, int64_t>(
183 next_access_unit_pos_ - current_access_unit_pos_);
184 DCHECK_LE(access_unit_size, size);
185 NaluReader reader(Nalu::kH264, kIsAnnexbByteStream, es, access_unit_size);
190 switch (reader.Advance(&nalu)) {
191 case NaluReader::kOk:
193 case NaluReader::kEOStream:
202 switch (nalu.type()) {
203 case Nalu::H264_AUD: {
204 DVLOG(LOG_LEVEL_ES) <<
"Nalu: AUD";
207 case Nalu::H264_SPS: {
208 DVLOG(LOG_LEVEL_ES) <<
"Nalu: SPS";
210 if (h264_parser_->ParseSps(nalu, &sps_id) != H264Parser::kOk)
212 decoder_config_check_pending_ =
true;
215 case Nalu::H264_PPS: {
216 DVLOG(LOG_LEVEL_ES) <<
"Nalu: PPS";
218 if (h264_parser_->ParsePps(nalu, &pps_id) != H264Parser::kOk) {
220 if (last_video_decoder_config_)
223 decoder_config_check_pending_ =
true;
227 case Nalu::H264_IDRSlice:
228 case Nalu::H264_NonIDRSlice: {
229 is_key_frame = (nalu.type() == Nalu::H264_IDRSlice);
230 DVLOG(LOG_LEVEL_ES) <<
"Nalu: slice IDR=" << is_key_frame;
231 H264SliceHeader shdr;
232 if (h264_parser_->ParseSliceHeader(nalu, &shdr) != H264Parser::kOk) {
235 if (last_video_decoder_config_)
238 pps_id_for_access_unit = shdr.pic_parameter_set_id;
243 DVLOG(LOG_LEVEL_ES) <<
"Nalu: " << nalu.type();
248 if (waiting_for_key_frame_) {
249 waiting_for_key_frame_ = !is_key_frame;
251 if (!waiting_for_key_frame_) {
253 RCHECK(EmitFrame(current_access_unit_pos_, access_unit_size,
254 is_key_frame, pps_id_for_access_unit));
256 current_access_unit_pos_ = next_access_unit_pos_;
257 es_queue_->Trim(current_access_unit_pos_);
262 bool EsParserH264::EmitFrame(int64_t access_unit_pos,
263 int access_unit_size,
267 TimingDesc current_timing_desc = {kNoTimestamp, kNoTimestamp};
268 while (!timing_desc_list_.empty() &&
269 timing_desc_list_.front().first <= access_unit_pos) {
270 current_timing_desc = timing_desc_list_.front().second;
271 timing_desc_list_.pop_front();
273 if (current_timing_desc.pts == kNoTimestamp)
277 DVLOG(LOG_LEVEL_ES) <<
"Emit frame: stream_pos=" << current_access_unit_pos_
278 <<
" size=" << access_unit_size;
281 es_queue_->PeekAt(current_access_unit_pos_, &es, &es_size);
282 CHECK_GE(es_size, access_unit_size);
285 std::vector<uint8_t> converted_frame;
286 if (!stream_converter_->ConvertByteStreamToNalUnitStream(
287 es, access_unit_size, &converted_frame)) {
288 DLOG(ERROR) <<
"Failure to convert video frame to unit stream format.";
292 if (decoder_config_check_pending_) {
294 const H264Pps* pps = h264_parser_->GetPps(pps_id);
301 if (last_video_decoder_config_)
304 const H264Sps* sps = h264_parser_->GetSps(pps->seq_parameter_set_id);
307 RCHECK(UpdateVideoDecoderConfig(sps));
308 decoder_config_check_pending_ =
false;
315 converted_frame.data(), converted_frame.size(), is_key_frame);
316 media_sample->set_dts(current_timing_desc.dts);
317 media_sample->set_pts(current_timing_desc.pts);
318 if (pending_sample_) {
319 DCHECK_GT(media_sample->dts(), pending_sample_->dts());
320 pending_sample_duration_ = media_sample->dts() - pending_sample_->dts();
321 pending_sample_->set_duration(pending_sample_duration_);
322 emit_sample_cb_.Run(pid(), pending_sample_);
324 pending_sample_ = media_sample;
329 bool EsParserH264::UpdateVideoDecoderConfig(
const H264Sps* sps) {
330 std::vector<uint8_t> decoder_config_record;
331 if (!stream_converter_->GetDecoderConfigurationRecord(
332 &decoder_config_record)) {
333 DLOG(ERROR) <<
"Failure to construct an AVCDecoderConfigurationRecord";
337 if (last_video_decoder_config_) {
338 if (last_video_decoder_config_->extra_data() != decoder_config_record) {
344 LOG(WARNING) <<
"H.264 decoder configuration has changed.";
345 last_video_decoder_config_->set_extra_data(decoder_config_record);
350 uint32_t coded_width = 0;
351 uint32_t coded_height = 0;
352 uint32_t pixel_width = 0;
353 uint32_t pixel_height = 0;
354 if (!ExtractResolutionFromSps(*sps, &coded_width, &coded_height, &pixel_width,
356 LOG(ERROR) <<
"Failed to parse SPS.";
360 last_video_decoder_config_ = scoped_refptr<StreamInfo>(
367 decoder_config_record[2],
368 decoder_config_record[3]),
375 H264ByteToUnitStreamConverter::kUnitStreamNaluLengthSize,
376 decoder_config_record.data(),
377 decoder_config_record.size(),
379 DVLOG(1) <<
"Profile IDC: " << sps->profile_idc;
380 DVLOG(1) <<
"Level IDC: " << sps->level_idc;
381 DVLOG(1) <<
"log2_max_frame_num_minus4: " << sps->log2_max_frame_num_minus4;
384 new_stream_info_cb_.Run(last_video_decoder_config_);