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