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
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
23namespace shaka {
24namespace media {
25namespace mp2t {
26
27EsParserH265::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
39EsParserH265::~EsParserH265() {}
40
41void 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
49bool 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
116bool 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
191int64_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.