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