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