5 #include "packager/media/formats/mp2t/es_parser_h26x.h"
9 #include "packager/base/logging.h"
10 #include "packager/base/numerics/safe_conversions.h"
11 #include "packager/media/base/media_sample.h"
12 #include "packager/media/base/offset_byte_queue.h"
13 #include "packager/media/base/timestamp.h"
14 #include "packager/media/base/video_stream_info.h"
15 #include "packager/media/codecs/h26x_byte_to_unit_stream_converter.h"
16 #include "packager/media/formats/mp2t/mp2t_common.h"
24 const int kStartCodeSize = 3;
25 const int kH264NaluHeaderSize = 1;
26 const int kH265NaluHeaderSize = 2;
30 EsParserH26x::EsParserH26x(
32 std::unique_ptr<H26xByteToUnitStreamConverter> stream_converter,
34 const EmitSampleCB& emit_sample_cb)
36 emit_sample_cb_(emit_sample_cb),
38 es_queue_(new media::OffsetByteQueue()),
39 stream_converter_(std::move(stream_converter)) {}
41 EsParserH26x::~EsParserH26x() {}
43 bool EsParserH26x::Parse(
const uint8_t* buf,
56 DVLOG_IF(1, pts == kNoTimestamp) <<
"Each video PES should have a PTS";
57 if (pts != kNoTimestamp) {
58 TimingDesc timing_desc;
59 timing_desc.pts = pts;
60 timing_desc.dts = (dts != kNoTimestamp) ? dts : pts;
63 timing_desc_list_.push_back(
64 std::pair<int64_t, TimingDesc>(es_queue_->tail(), timing_desc));
68 const size_t kWarningSize =
70 LOG_IF(WARNING, timing_desc_list_.size() >= kWarningSize)
71 <<
"Unusually large number of cached timestamps ("
72 << timing_desc_list_.size() <<
").";
76 es_queue_->Push(buf, size);
77 return ParseInternal();
80 bool EsParserH26x::Flush() {
81 DVLOG(1) <<
"EsParserH26x::Flush";
88 if (type_ == Nalu::kH264) {
89 const uint8_t aud[] = {0x00, 0x00, 0x01, 0x09, 0x00, 0x00, 0x01, 0x09};
90 es_queue_->Push(aud,
sizeof(aud));
92 DCHECK_EQ(Nalu::kH265, type_);
93 const uint8_t aud[] = {0x00, 0x00, 0x01, 0x46, 0x01,
94 0x00, 0x00, 0x01, 0x46, 0x01};
95 es_queue_->Push(aud,
sizeof(aud));
98 RCHECK(ParseInternal());
100 if (pending_sample_) {
102 DCHECK(pending_sample_duration_);
103 pending_sample_->set_duration(pending_sample_duration_);
104 emit_sample_cb_.Run(std::move(pending_sample_));
109 void EsParserH26x::Reset() {
110 es_queue_.reset(
new media::OffsetByteQueue());
111 current_search_position_ = 0;
112 current_access_unit_position_ = 0;
113 current_video_slice_info_.valid =
false;
114 next_access_unit_position_set_ =
false;
115 next_access_unit_position_ = 0;
116 current_nalu_info_.reset();
117 timing_desc_list_.clear();
118 pending_sample_ = std::shared_ptr<MediaSample>();
119 pending_sample_duration_ = 0;
120 waiting_for_key_frame_ =
true;
123 bool EsParserH26x::SearchForNalu(uint64_t* position, Nalu* nalu) {
126 es_queue_->PeekAt(current_search_position_, &es, &es_size);
129 uint64_t start_code_offset;
130 uint8_t start_code_size;
131 const bool start_code_found = NaluReader::FindStartCode(
132 es, es_size, &start_code_offset, &start_code_size);
134 if (!start_code_found) {
136 if (es_size > kStartCodeSize)
137 current_search_position_ += es_size - kStartCodeSize;
142 const uint8_t* next_nalu_ptr = es + start_code_offset + start_code_size;
144 const int64_t next_nalu_size = es_size - start_code_offset - start_code_size;
146 (type_ == Nalu::kH264 ? kH264NaluHeaderSize : kH265NaluHeaderSize)) {
152 current_search_position_ += start_code_offset + start_code_size;
156 if (!next_nalu_info_)
157 next_nalu_info_.reset(
new NaluInfo);
158 if (!next_nalu_info_->nalu.Initialize(type_, next_nalu_ptr, next_nalu_size)) {
160 return SearchForNalu(position, nalu);
162 next_nalu_info_->position = current_search_position_ - start_code_size;
163 next_nalu_info_->start_code_size = start_code_size;
165 const bool current_nalu_set = current_nalu_info_ ? true :
false;
166 if (current_nalu_info_) {
168 *position = current_nalu_info_->position;
170 const uint8_t* current_nalu_ptr =
172 (current_nalu_info_->position + current_nalu_info_->start_code_size) -
173 current_search_position_;
174 const uint64_t current_nalu_size = next_nalu_info_->position -
175 current_nalu_info_->position -
176 current_nalu_info_->start_code_size;
177 CHECK(nalu->Initialize(type_, current_nalu_ptr, current_nalu_size));
179 current_nalu_info_.swap(next_nalu_info_);
180 return current_nalu_set ? true : SearchForNalu(position, nalu);
183 bool EsParserH26x::ParseInternal() {
186 VideoSliceInfo video_slice_info;
187 while (SearchForNalu(&position, &nalu)) {
197 if (nalu.can_start_access_unit()) {
198 if (!next_access_unit_position_set_) {
199 next_access_unit_position_set_ =
true;
200 next_access_unit_position_ = position;
202 RCHECK(ProcessNalu(nalu, &video_slice_info));
203 if (nalu.is_vcl() && !video_slice_info.valid) {
206 DCHECK(!current_video_slice_info_.valid);
207 next_access_unit_position_set_ =
false;
210 }
else if (nalu.is_vcl()) {
213 next_access_unit_position_set_ =
false;
221 RCHECK(EmitCurrentAccessUnit());
227 if (!video_slice_info.valid)
232 bool is_first_vcl_nalu =
true;
233 if (type_ == Nalu::kH264) {
234 if (current_video_slice_info_.valid) {
238 video_slice_info.frame_num != current_video_slice_info_.frame_num ||
239 video_slice_info.pps_id != current_video_slice_info_.pps_id;
242 if (!is_first_vcl_nalu) {
245 next_access_unit_position_set_ =
false;
249 DCHECK(next_access_unit_position_set_);
250 RCHECK(EmitCurrentAccessUnit());
253 es_queue_->Trim(next_access_unit_position_);
255 current_access_unit_position_ = next_access_unit_position_;
256 current_video_slice_info_ = video_slice_info;
257 next_access_unit_position_set_ =
false;
262 bool EsParserH26x::EmitCurrentAccessUnit() {
263 if (current_video_slice_info_.valid) {
264 if (current_video_slice_info_.is_key_frame)
265 waiting_for_key_frame_ =
false;
266 if (!waiting_for_key_frame_) {
268 EmitFrame(current_access_unit_position_,
269 next_access_unit_position_ - current_access_unit_position_,
270 current_video_slice_info_.is_key_frame,
271 current_video_slice_info_.pps_id));
273 current_video_slice_info_.valid =
false;
278 bool EsParserH26x::EmitFrame(int64_t access_unit_pos,
279 int access_unit_size,
283 TimingDesc current_timing_desc = {kNoTimestamp, kNoTimestamp};
284 while (!timing_desc_list_.empty() &&
285 timing_desc_list_.front().first <= access_unit_pos) {
286 current_timing_desc = timing_desc_list_.front().second;
287 timing_desc_list_.pop_front();
289 if (current_timing_desc.pts == kNoTimestamp)
293 DVLOG(LOG_LEVEL_ES) <<
"Emit frame: stream_pos=" << access_unit_pos
294 <<
" size=" << access_unit_size <<
" pts "
295 << current_timing_desc.pts <<
" timing_desc_list size "
296 << timing_desc_list_.size();
299 es_queue_->PeekAt(access_unit_pos, &es, &es_size);
302 std::vector<uint8_t> converted_frame;
303 if (!stream_converter_->ConvertByteStreamToNalUnitStream(
304 es, access_unit_size, &converted_frame)) {
305 DLOG(ERROR) <<
"Failure to convert video frame to unit stream format.";
310 RCHECK(UpdateVideoDecoderConfig(pps_id));
314 std::shared_ptr<MediaSample> media_sample = MediaSample::CopyFrom(
315 converted_frame.data(), converted_frame.size(), is_key_frame);
316 media_sample->set_dts(current_timing_desc.dts);
317 media_sample->set_pts(current_timing_desc.pts);
318 if (pending_sample_) {
319 if (media_sample->dts() <= pending_sample_->dts()) {
320 LOG(WARNING) <<
"[MPEG-2 TS] PID " << pid() <<
" dts "
321 << media_sample->dts()
322 <<
" less than or equal to previous dts "
323 << pending_sample_->dts();
326 const int64_t kArbitrarySmallDuration = 0.001 * kMpeg2Timescale;
327 pending_sample_->set_duration(kArbitrarySmallDuration);
329 uint64_t sample_duration = media_sample->dts() - pending_sample_->dts();
330 pending_sample_->set_duration(sample_duration);
332 const int kArbitraryGapScale = 10;
333 if (sample_duration > kArbitraryGapScale * pending_sample_duration_) {
334 LOG(WARNING) <<
"[MPEG-2 TS] PID " << pid() <<
" Possible GAP at dts "
335 << pending_sample_->dts() <<
" with next sample at dts "
336 << media_sample->dts() <<
" (difference "
337 << sample_duration <<
")";
340 pending_sample_duration_ = sample_duration;
342 emit_sample_cb_.Run(std::move(pending_sample_));
344 pending_sample_ = media_sample;
All the methods that are virtual are virtual for mocking.