Shaka Packager SDK
es_parser_h265.cc
1 // Copyright 2016 Google LLC. 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 <cstdint>
10 
11 #include <absl/log/log.h>
12 
13 #include <packager/macros/logging.h>
14 #include <packager/media/base/media_sample.h>
15 #include <packager/media/base/offset_byte_queue.h>
16 #include <packager/media/base/timestamp.h>
17 #include <packager/media/base/video_stream_info.h>
18 #include <packager/media/codecs/h265_byte_to_unit_stream_converter.h>
19 #include <packager/media/codecs/h265_parser.h>
20 #include <packager/media/codecs/hevc_decoder_configuration_record.h>
21 #include <packager/media/formats/mp2t/mp2t_common.h>
22 
23 namespace shaka {
24 namespace media {
25 namespace mp2t {
26 
27 EsParserH265::EsParserH265(uint32_t pid,
28  const NewStreamInfoCB& new_stream_info_cb,
29  const EmitSampleCB& emit_sample_cb)
30  : EsParserH26x(Nalu::kH265,
31  std::unique_ptr<H26xByteToUnitStreamConverter>(
32  new H265ByteToUnitStreamConverter()),
33  pid,
34  emit_sample_cb),
35  new_stream_info_cb_(new_stream_info_cb),
36  decoder_config_check_pending_(false),
37  h265_parser_(new H265Parser()) {}
38 
39 EsParserH265::~EsParserH265() {}
40 
41 void EsParserH265::Reset() {
42  DVLOG(1) << "EsParserH265::Reset";
43  h265_parser_.reset(new H265Parser());
44  last_video_decoder_config_ = std::shared_ptr<VideoStreamInfo>();
45  decoder_config_check_pending_ = false;
46  EsParserH26x::Reset();
47 }
48 
49 bool EsParserH265::ProcessNalu(const Nalu& nalu,
50  VideoSliceInfo* video_slice_info) {
51  video_slice_info->valid = false;
52  switch (nalu.type()) {
53  case Nalu::H265_AUD: {
54  DVLOG(LOG_LEVEL_ES) << "Nalu: AUD";
55  break;
56  }
57  case Nalu::H265_SPS: {
58  DVLOG(LOG_LEVEL_ES) << "Nalu: SPS";
59  int sps_id;
60  auto status = h265_parser_->ParseSps(nalu, &sps_id);
61  if (status == H265Parser::kOk)
62  decoder_config_check_pending_ = true;
63  else if (status == H265Parser::kUnsupportedStream)
64  // Indicate the stream can't be parsed.
65  new_stream_info_cb_(nullptr);
66  else
67  return false;
68  break;
69  }
70  case Nalu::H265_PPS: {
71  DVLOG(LOG_LEVEL_ES) << "Nalu: PPS";
72  int pps_id;
73  auto status = h265_parser_->ParsePps(nalu, &pps_id);
74  if (status == H265Parser::kOk) {
75  decoder_config_check_pending_ = true;
76  } else if (status == H265Parser::kUnsupportedStream) {
77  // Indicate the stream can't be parsed.
78  new_stream_info_cb_(nullptr);
79  } else {
80  // Allow PPS parsing to fail if waiting for SPS.
81  if (last_video_decoder_config_)
82  return false;
83  }
84  break;
85  }
86  default: {
87  if (nalu.is_vcl() && nalu.nuh_layer_id() == 0) {
88  const bool is_key_frame = nalu.type() == Nalu::H265_IDR_W_RADL ||
89  nalu.type() == Nalu::H265_IDR_N_LP;
90  DVLOG(LOG_LEVEL_ES) << "Nalu: slice KeyFrame=" << is_key_frame;
91  H265SliceHeader shdr;
92  auto status = h265_parser_->ParseSliceHeader(nalu, &shdr);
93  if (status == H265Parser::kOk) {
94  video_slice_info->valid = true;
95  video_slice_info->is_key_frame = is_key_frame;
96  video_slice_info->frame_num = 0; // frame_num is only for H264.
97  video_slice_info->pps_id = shdr.pic_parameter_set_id;
98  } else if (status == H265Parser::kUnsupportedStream) {
99  // Indicate the stream can't be parsed.
100  new_stream_info_cb_(nullptr);
101  } else {
102  // Only accept an invalid SPS/PPS at the beginning when the stream
103  // does not necessarily start with an SPS/PPS/IDR.
104  if (last_video_decoder_config_)
105  return false;
106  }
107  } else {
108  DVLOG(LOG_LEVEL_ES) << "Nalu: " << nalu.type();
109  }
110  }
111  }
112 
113  return true;
114 }
115 
116 bool EsParserH265::UpdateVideoDecoderConfig(int pps_id) {
117  // Update the video decoder configuration if needed.
118  if (!decoder_config_check_pending_)
119  return true;
120 
121  const H265Pps* pps = h265_parser_->GetPps(pps_id);
122  const H265Sps* sps;
123  if (!pps) {
124  // Only accept an invalid PPS at the beginning when the stream
125  // does not necessarily start with an SPS/PPS/IDR.
126  // In this case, the initial frames are conveyed to the upper layer with
127  // an invalid VideoDecoderConfig and it's up to the upper layer
128  // to process this kind of frame accordingly.
129  return last_video_decoder_config_ == nullptr;
130  } else {
131  sps = h265_parser_->GetSps(pps->seq_parameter_set_id);
132  if (!sps)
133  return false;
134  decoder_config_check_pending_ = false;
135  }
136 
137  std::vector<uint8_t> decoder_config_record;
138  HEVCDecoderConfigurationRecord decoder_config;
139  if (!stream_converter()->GetDecoderConfigurationRecord(
140  &decoder_config_record) ||
141  !decoder_config.Parse(decoder_config_record)) {
142  DLOG(ERROR) << "Failure to construct an HEVCDecoderConfigurationRecord";
143  return false;
144  }
145 
146  if (last_video_decoder_config_) {
147  if (last_video_decoder_config_->codec_config() != decoder_config_record) {
148  // Video configuration has changed. Issue warning.
149  // TODO(tinskip): Check the nature of the configuration change. Only
150  // minor configuration changes (such as frame ordering) can be handled
151  // gracefully by decoders without notification. Major changes (such as
152  // video resolution changes) should be treated as errors.
153  LOG(WARNING) << "H.265 decoder configuration has changed.";
154  last_video_decoder_config_->set_codec_config(decoder_config_record);
155  }
156  return true;
157  }
158 
159  uint32_t coded_width = 0;
160  uint32_t coded_height = 0;
161  uint32_t pixel_width = 0;
162  uint32_t pixel_height = 0;
163  if (!ExtractResolutionFromSps(*sps, &coded_width, &coded_height, &pixel_width,
164  &pixel_height)) {
165  LOG(ERROR) << "Failed to parse SPS.";
166  return false;
167  }
168 
169  const uint8_t nalu_length_size =
170  H26xByteToUnitStreamConverter::kUnitStreamNaluLengthSize;
171  const H26xStreamFormat stream_format = stream_converter()->stream_format();
172  const FourCC codec_fourcc =
173  stream_format == H26xStreamFormat::kNalUnitStreamWithParameterSetNalus
174  ? FOURCC_hev1
175  : FOURCC_hvc1;
176  last_video_decoder_config_ = std::make_shared<VideoStreamInfo>(
177  pid(), kMpeg2Timescale, kInfiniteDuration, kCodecH265, stream_format,
178  decoder_config.GetCodecString(codec_fourcc), decoder_config_record.data(),
179  decoder_config_record.size(), coded_width, coded_height, pixel_width,
180  pixel_height, sps->vui_parameters.color_primaries,
181  sps->vui_parameters.matrix_coefficients,
182  sps->vui_parameters.transfer_characteristics, 0, nalu_length_size,
183  std::string(), false);
184 
185  // Video config notification.
186  new_stream_info_cb_(last_video_decoder_config_);
187 
188  return true;
189 }
190 
191 int64_t EsParserH265::CalculateSampleDuration(int pps_id) {
192  auto pps = h265_parser_->GetPps(pps_id);
193  if (pps) {
194  auto sps_id = pps->seq_parameter_set_id;
195  auto sps = h265_parser_->GetSps(sps_id);
196  if (sps && sps->vui_parameters_present &&
197  sps->vui_parameters.vui_timing_info_present_flag) {
198  return static_cast<int64_t>(kMpeg2Timescale) *
199  sps->vui_parameters.vui_num_units_in_tick * 2 /
200  sps->vui_parameters.vui_time_scale;
201  }
202  }
203  LOG(WARNING) << "[MPEG-2 TS] PID " << pid()
204  << " Cannot calculate frame rate from SPS.";
205  // Returns arbitrary safe duration
206  return 0.001 * kMpeg2Timescale; // 1ms.
207 }
208 
209 } // namespace mp2t
210 } // namespace media
211 } // namespace shaka
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66