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 es_queue_->Push(buf, size);
69 return ParseInternal();
72 void EsParserH26x::Flush() {
73 DVLOG(1) <<
"EsParserH26x::Flush";
80 if (type_ == Nalu::kH264) {
81 const uint8_t aud[] = {0x00, 0x00, 0x01, 0x09, 0x00, 0x00, 0x01, 0x09};
82 es_queue_->Push(aud,
sizeof(aud));
84 DCHECK_EQ(Nalu::kH265, type_);
85 const uint8_t aud[] = {0x00, 0x00, 0x01, 0x46, 0x01,
86 0x00, 0x00, 0x01, 0x46, 0x01};
87 es_queue_->Push(aud,
sizeof(aud));
90 CHECK(ParseInternal());
92 if (pending_sample_) {
94 DCHECK(pending_sample_duration_);
95 pending_sample_->set_duration(pending_sample_duration_);
96 emit_sample_cb_.Run(pid(), pending_sample_);
97 pending_sample_ = std::shared_ptr<MediaSample>();
101 void EsParserH26x::Reset() {
102 es_queue_.reset(
new media::OffsetByteQueue());
103 current_search_position_ = 0;
104 current_access_unit_position_ = 0;
105 current_video_slice_info_.valid =
false;
106 next_access_unit_position_set_ =
false;
107 next_access_unit_position_ = 0;
108 current_nalu_info_.reset();
109 timing_desc_list_.clear();
110 pending_sample_ = std::shared_ptr<MediaSample>();
111 pending_sample_duration_ = 0;
112 waiting_for_key_frame_ =
true;
115 bool EsParserH26x::SearchForNalu(uint64_t* position, Nalu* nalu) {
118 es_queue_->PeekAt(current_search_position_, &es, &es_size);
121 uint64_t start_code_offset;
122 uint8_t start_code_size;
123 const bool start_code_found = NaluReader::FindStartCode(
124 es, es_size, &start_code_offset, &start_code_size);
126 if (!start_code_found) {
128 if (es_size > kStartCodeSize)
129 current_search_position_ += es_size - kStartCodeSize;
134 const uint8_t* next_nalu_ptr = es + start_code_offset + start_code_size;
136 const int64_t next_nalu_size = es_size - start_code_offset - start_code_size;
138 (type_ == Nalu::kH264 ? kH264NaluHeaderSize : kH265NaluHeaderSize)) {
144 current_search_position_ += start_code_offset + start_code_size;
148 if (!next_nalu_info_)
149 next_nalu_info_.reset(
new NaluInfo);
150 if (!next_nalu_info_->nalu.Initialize(type_, next_nalu_ptr, next_nalu_size)) {
152 return SearchForNalu(position, nalu);
154 next_nalu_info_->position = current_search_position_ - start_code_size;
155 next_nalu_info_->start_code_size = start_code_size;
157 const bool current_nalu_set = current_nalu_info_ ? true :
false;
158 if (current_nalu_info_) {
160 *position = current_nalu_info_->position;
162 const uint8_t* current_nalu_ptr =
164 (current_nalu_info_->position + current_nalu_info_->start_code_size) -
165 current_search_position_;
166 const uint64_t current_nalu_size = next_nalu_info_->position -
167 current_nalu_info_->position -
168 current_nalu_info_->start_code_size;
169 CHECK(nalu->Initialize(type_, current_nalu_ptr, current_nalu_size));
171 current_nalu_info_.swap(next_nalu_info_);
172 return current_nalu_set ? true : SearchForNalu(position, nalu);
175 bool EsParserH26x::ParseInternal() {
178 VideoSliceInfo video_slice_info;
179 while (SearchForNalu(&position, &nalu)) {
189 if (nalu.can_start_access_unit()) {
190 if (!next_access_unit_position_set_) {
191 next_access_unit_position_set_ =
true;
192 next_access_unit_position_ = position;
194 RCHECK(ProcessNalu(nalu, &video_slice_info));
195 if (nalu.is_vcl() && !video_slice_info.valid) {
198 DCHECK(!current_video_slice_info_.valid);
199 next_access_unit_position_set_ =
false;
202 }
else if (nalu.is_vcl()) {
205 next_access_unit_position_set_ =
false;
213 return EmitCurrentAccessUnit();
217 if (!video_slice_info.valid)
222 bool is_first_vcl_nalu =
true;
223 if (type_ == Nalu::kH264) {
224 if (current_video_slice_info_.valid) {
228 video_slice_info.frame_num != current_video_slice_info_.frame_num ||
229 video_slice_info.pps_id != current_video_slice_info_.pps_id;
232 if (!is_first_vcl_nalu) {
235 next_access_unit_position_set_ =
false;
239 DCHECK(next_access_unit_position_set_);
240 RCHECK(EmitCurrentAccessUnit());
243 es_queue_->Trim(next_access_unit_position_);
245 current_access_unit_position_ = next_access_unit_position_;
246 current_video_slice_info_ = video_slice_info;
247 next_access_unit_position_set_ =
false;
252 bool EsParserH26x::EmitCurrentAccessUnit() {
253 if (current_video_slice_info_.valid) {
254 if (current_video_slice_info_.is_key_frame)
255 waiting_for_key_frame_ =
false;
256 if (!waiting_for_key_frame_) {
258 EmitFrame(current_access_unit_position_,
259 next_access_unit_position_ - current_access_unit_position_,
260 current_video_slice_info_.is_key_frame,
261 current_video_slice_info_.pps_id));
263 current_video_slice_info_.valid =
false;
268 bool EsParserH26x::EmitFrame(int64_t access_unit_pos,
269 int access_unit_size,
273 TimingDesc current_timing_desc = {kNoTimestamp, kNoTimestamp};
274 while (!timing_desc_list_.empty() &&
275 timing_desc_list_.front().first <= access_unit_pos) {
276 current_timing_desc = timing_desc_list_.front().second;
277 timing_desc_list_.pop_front();
279 if (current_timing_desc.pts == kNoTimestamp)
283 DVLOG(LOG_LEVEL_ES) <<
"Emit frame: stream_pos=" << access_unit_pos
284 <<
" size=" << access_unit_size;
287 es_queue_->PeekAt(access_unit_pos, &es, &es_size);
290 std::vector<uint8_t> converted_frame;
291 if (!stream_converter_->ConvertByteStreamToNalUnitStream(
292 es, access_unit_size, &converted_frame)) {
293 DLOG(ERROR) <<
"Failure to convert video frame to unit stream format.";
298 RCHECK(UpdateVideoDecoderConfig(pps_id));
303 converted_frame.data(), converted_frame.size(), is_key_frame);
304 media_sample->set_dts(current_timing_desc.dts);
305 media_sample->set_pts(current_timing_desc.pts);
306 if (pending_sample_) {
307 DCHECK_GT(media_sample->dts(), pending_sample_->dts());
308 pending_sample_duration_ = media_sample->dts() - pending_sample_->dts();
309 pending_sample_->set_duration(pending_sample_duration_);
310 emit_sample_cb_.Run(pid(), pending_sample_);
312 pending_sample_ = media_sample;
All the methods that are virtual are virtual for mocking.