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