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