DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerator
es_parser_h264.cc
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "packager/media/formats/mp2t/es_parser_h264.h"
6 
7 #include <stdint.h>
8 
9 #include "packager/base/logging.h"
10 #include "packager/media/base/media_sample.h"
11 #include "packager/media/base/timestamp.h"
12 #include "packager/media/base/video_stream_info.h"
13 #include "packager/media/filters/avc_decoder_configuration.h"
14 #include "packager/media/filters/h264_byte_to_unit_stream_converter.h"
15 #include "packager/media/filters/h264_parser.h"
16 #include "packager/media/formats/mp2t/mp2t_common.h"
17 
18 namespace edash_packager {
19 namespace media {
20 namespace mp2t {
21 
22 EsParserH264::EsParserH264(uint32_t pid,
23  const NewStreamInfoCB& new_stream_info_cb,
24  const EmitSampleCB& emit_sample_cb)
25  : EsParserH26x(Nalu::kH264, pid, emit_sample_cb),
26  new_stream_info_cb_(new_stream_info_cb),
27  decoder_config_check_pending_(false),
28  h264_parser_(new H264Parser()) {}
29 
30 EsParserH264::~EsParserH264() {}
31 
32 void EsParserH264::Reset() {
33  DVLOG(1) << "EsParserH264::Reset";
34  h264_parser_.reset(new H264Parser());
35  last_video_decoder_config_ = scoped_refptr<StreamInfo>();
36  decoder_config_check_pending_ = false;
37  EsParserH26x::Reset();
38 }
39 
40 bool EsParserH264::ProcessNalu(const Nalu& nalu,
41  bool* is_key_frame,
42  int* pps_id_for_access_unit) {
43  switch (nalu.type()) {
44  case Nalu::H264_AUD: {
45  DVLOG(LOG_LEVEL_ES) << "Nalu: AUD";
46  break;
47  }
48  case Nalu::H264_SPS: {
49  DVLOG(LOG_LEVEL_ES) << "Nalu: SPS";
50  int sps_id;
51  if (h264_parser_->ParseSps(nalu, &sps_id) != H264Parser::kOk)
52  return false;
53  decoder_config_check_pending_ = true;
54  break;
55  }
56  case Nalu::H264_PPS: {
57  DVLOG(LOG_LEVEL_ES) << "Nalu: PPS";
58  int pps_id;
59  if (h264_parser_->ParsePps(nalu, &pps_id) != H264Parser::kOk) {
60  // Allow PPS parsing to fail if waiting for SPS.
61  if (last_video_decoder_config_)
62  return false;
63  } else {
64  decoder_config_check_pending_ = true;
65  }
66  break;
67  }
68  case Nalu::H264_IDRSlice:
69  case Nalu::H264_NonIDRSlice: {
70  *is_key_frame = (nalu.type() == Nalu::H264_IDRSlice);
71  DVLOG(LOG_LEVEL_ES) << "Nalu: slice IDR=" << is_key_frame;
72  H264SliceHeader shdr;
73  if (h264_parser_->ParseSliceHeader(nalu, &shdr) != H264Parser::kOk) {
74  // Only accept an invalid SPS/PPS at the beginning when the stream
75  // does not necessarily start with an SPS/PPS/IDR.
76  if (last_video_decoder_config_)
77  return false;
78  } else {
79  *pps_id_for_access_unit = shdr.pic_parameter_set_id;
80  }
81  break;
82  }
83  default: {
84  DVLOG(LOG_LEVEL_ES) << "Nalu: " << nalu.type();
85  }
86  }
87 
88  return true;
89 }
90 
91 bool EsParserH264::UpdateVideoDecoderConfig(int pps_id) {
92  // Update the video decoder configuration if needed.
93  if (!decoder_config_check_pending_)
94  return true;
95 
96  const H264Pps* pps = h264_parser_->GetPps(pps_id);
97  const H264Sps* sps;
98  if (!pps) {
99  // Only accept an invalid PPS at the beginning when the stream
100  // does not necessarily start with an SPS/PPS/IDR.
101  // In this case, the initial frames are conveyed to the upper layer with
102  // an invalid VideoDecoderConfig and it's up to the upper layer
103  // to process this kind of frame accordingly.
104  return last_video_decoder_config_ == nullptr;
105  } else {
106  sps = h264_parser_->GetSps(pps->seq_parameter_set_id);
107  if (!sps)
108  return false;
109  decoder_config_check_pending_ = false;
110  }
111 
112  std::vector<uint8_t> decoder_config_record;
113  if (!stream_converter()->GetDecoderConfigurationRecord(
114  &decoder_config_record)) {
115  DLOG(ERROR) << "Failure to construct an AVCDecoderConfigurationRecord";
116  return false;
117  }
118 
119  if (last_video_decoder_config_) {
120  if (last_video_decoder_config_->extra_data() != decoder_config_record) {
121  // Video configuration has changed. Issue warning.
122  // TODO(tinskip): Check the nature of the configuration change. Only
123  // minor configuration changes (such as frame ordering) can be handled
124  // gracefully by decoders without notification. Major changes (such as
125  // video resolution changes) should be treated as errors.
126  LOG(WARNING) << "H.264 decoder configuration has changed.";
127  last_video_decoder_config_->set_extra_data(decoder_config_record);
128  }
129  return true;
130  }
131 
132  uint32_t coded_width = 0;
133  uint32_t coded_height = 0;
134  uint32_t pixel_width = 0;
135  uint32_t pixel_height = 0;
136  if (!ExtractResolutionFromSps(*sps, &coded_width, &coded_height, &pixel_width,
137  &pixel_height)) {
138  LOG(ERROR) << "Failed to parse SPS.";
139  return false;
140  }
141 
142  last_video_decoder_config_ = scoped_refptr<StreamInfo>(
143  new VideoStreamInfo(
144  pid(),
145  kMpeg2Timescale,
146  kInfiniteDuration,
147  kCodecH264,
148  AVCDecoderConfiguration::GetCodecString(decoder_config_record[1],
149  decoder_config_record[2],
150  decoder_config_record[3]),
151  std::string(),
152  coded_width,
153  coded_height,
154  pixel_width,
155  pixel_height,
156  0,
157  H264ByteToUnitStreamConverter::kUnitStreamNaluLengthSize,
158  decoder_config_record.data(),
159  decoder_config_record.size(),
160  false));
161  DVLOG(1) << "Profile IDC: " << sps->profile_idc;
162  DVLOG(1) << "Level IDC: " << sps->level_idc;
163  DVLOG(1) << "log2_max_frame_num_minus4: " << sps->log2_max_frame_num_minus4;
164 
165  // Video config notification.
166  new_stream_info_cb_.Run(last_video_decoder_config_);
167 
168  return true;
169 }
170 
171 } // namespace mp2t
172 } // namespace media
173 } // namespace edash_packager