OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/formats/mp2t/mp2t_stream_parser.h" | 5 #include "media/formats/mp2t/mp2t_stream_parser.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
150 } | 150 } |
151 | 151 |
152 Mp2tStreamParser::BufferQueueWithConfig::~BufferQueueWithConfig() { | 152 Mp2tStreamParser::BufferQueueWithConfig::~BufferQueueWithConfig() { |
153 } | 153 } |
154 | 154 |
155 Mp2tStreamParser::Mp2tStreamParser(bool sbr_in_mimetype) | 155 Mp2tStreamParser::Mp2tStreamParser(bool sbr_in_mimetype) |
156 : sbr_in_mimetype_(sbr_in_mimetype), | 156 : sbr_in_mimetype_(sbr_in_mimetype), |
157 selected_audio_pid_(-1), | 157 selected_audio_pid_(-1), |
158 selected_video_pid_(-1), | 158 selected_video_pid_(-1), |
159 is_initialized_(false), | 159 is_initialized_(false), |
160 segment_started_(false), | 160 segment_started_(false) { |
161 first_video_frame_in_segment_(true) { | |
162 } | 161 } |
163 | 162 |
164 Mp2tStreamParser::~Mp2tStreamParser() { | 163 Mp2tStreamParser::~Mp2tStreamParser() { |
165 STLDeleteValues(&pids_); | 164 STLDeleteValues(&pids_); |
166 } | 165 } |
167 | 166 |
168 void Mp2tStreamParser::Init( | 167 void Mp2tStreamParser::Init( |
169 const InitCB& init_cb, | 168 const InitCB& init_cb, |
170 const NewConfigCB& config_cb, | 169 const NewConfigCB& config_cb, |
171 const NewBuffersCB& new_buffers_cb, | 170 const NewBuffersCB& new_buffers_cb, |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
203 delete pid_state; | 202 delete pid_state; |
204 } | 203 } |
205 pids_.clear(); | 204 pids_.clear(); |
206 EmitRemainingBuffers(); | 205 EmitRemainingBuffers(); |
207 buffer_queue_chain_.clear(); | 206 buffer_queue_chain_.clear(); |
208 | 207 |
209 // End of the segment. | 208 // End of the segment. |
210 // Note: does not need to invoke |end_of_segment_cb_| since flushing the | 209 // Note: does not need to invoke |end_of_segment_cb_| since flushing the |
211 // stream parser already involves the end of the current segment. | 210 // stream parser already involves the end of the current segment. |
212 segment_started_ = false; | 211 segment_started_ = false; |
213 first_video_frame_in_segment_ = true; | |
214 discarded_frames_dts_.clear(); | |
215 | 212 |
216 // Remove any bytes left in the TS buffer. | 213 // Remove any bytes left in the TS buffer. |
217 // (i.e. any partial TS packet => less than 188 bytes). | 214 // (i.e. any partial TS packet => less than 188 bytes). |
218 ts_byte_queue_.Reset(); | 215 ts_byte_queue_.Reset(); |
219 | 216 |
220 // Reset the selected PIDs. | 217 // Reset the selected PIDs. |
221 selected_audio_pid_ = -1; | 218 selected_audio_pid_ = -1; |
222 selected_video_pid_ = -1; | 219 selected_video_pid_ = -1; |
223 } | 220 } |
224 | 221 |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
498 scoped_refptr<StreamParserBuffer> stream_parser_buffer) { | 495 scoped_refptr<StreamParserBuffer> stream_parser_buffer) { |
499 DCHECK_EQ(pes_pid, selected_audio_pid_); | 496 DCHECK_EQ(pes_pid, selected_audio_pid_); |
500 | 497 |
501 DVLOG(LOG_LEVEL_ES) | 498 DVLOG(LOG_LEVEL_ES) |
502 << "OnEmitAudioBuffer: " | 499 << "OnEmitAudioBuffer: " |
503 << " size=" | 500 << " size=" |
504 << stream_parser_buffer->data_size() | 501 << stream_parser_buffer->data_size() |
505 << " dts=" | 502 << " dts=" |
506 << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds() | 503 << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds() |
507 << " pts=" | 504 << " pts=" |
508 << stream_parser_buffer->timestamp().InMilliseconds(); | 505 << stream_parser_buffer->timestamp().InMilliseconds() |
506 << " dur=" | |
507 << stream_parser_buffer->duration().InMilliseconds(); | |
509 stream_parser_buffer->set_timestamp( | 508 stream_parser_buffer->set_timestamp( |
510 stream_parser_buffer->timestamp() - time_offset_); | 509 stream_parser_buffer->timestamp() - time_offset_); |
511 stream_parser_buffer->SetDecodeTimestamp( | 510 stream_parser_buffer->SetDecodeTimestamp( |
512 stream_parser_buffer->GetDecodeTimestamp() - time_offset_); | 511 stream_parser_buffer->GetDecodeTimestamp() - time_offset_); |
513 | 512 |
514 // Ignore the incoming buffer if it is not associated with any config. | 513 // Ignore the incoming buffer if it is not associated with any config. |
515 if (buffer_queue_chain_.empty()) { | 514 if (buffer_queue_chain_.empty()) { |
516 DVLOG(1) << "Ignoring audio buffer with no corresponding audio config"; | 515 DVLOG(1) << "Ignoring audio buffer with no corresponding audio config"; |
wolenetz
2014/07/10 17:57:23
If there has been no init segment prior to media s
damienv1
2014/07/10 18:34:51
True. With the updated code, there should always b
| |
517 return; | 516 return; |
518 } | 517 } |
519 | 518 |
520 buffer_queue_chain_.back().audio_queue.push_back(stream_parser_buffer); | 519 buffer_queue_chain_.back().audio_queue.push_back(stream_parser_buffer); |
521 } | 520 } |
522 | 521 |
523 void Mp2tStreamParser::OnEmitVideoBuffer( | 522 void Mp2tStreamParser::OnEmitVideoBuffer( |
524 int pes_pid, | 523 int pes_pid, |
525 scoped_refptr<StreamParserBuffer> stream_parser_buffer) { | 524 scoped_refptr<StreamParserBuffer> stream_parser_buffer) { |
526 DCHECK_EQ(pes_pid, selected_video_pid_); | 525 DCHECK_EQ(pes_pid, selected_video_pid_); |
527 | 526 |
528 DVLOG(LOG_LEVEL_ES) | 527 DVLOG(LOG_LEVEL_ES) |
529 << "OnEmitVideoBuffer" | 528 << "OnEmitVideoBuffer" |
530 << " size=" | 529 << " size=" |
531 << stream_parser_buffer->data_size() | 530 << stream_parser_buffer->data_size() |
532 << " dts=" | 531 << " dts=" |
533 << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds() | 532 << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds() |
534 << " pts=" | 533 << " pts=" |
535 << stream_parser_buffer->timestamp().InMilliseconds() | 534 << stream_parser_buffer->timestamp().InMilliseconds() |
535 << " dur=" | |
536 << stream_parser_buffer->duration().InMilliseconds() | |
536 << " IsKeyframe=" | 537 << " IsKeyframe=" |
537 << stream_parser_buffer->IsKeyframe(); | 538 << stream_parser_buffer->IsKeyframe(); |
538 stream_parser_buffer->set_timestamp( | 539 stream_parser_buffer->set_timestamp( |
539 stream_parser_buffer->timestamp() - time_offset_); | 540 stream_parser_buffer->timestamp() - time_offset_); |
540 stream_parser_buffer->SetDecodeTimestamp( | 541 stream_parser_buffer->SetDecodeTimestamp( |
541 stream_parser_buffer->GetDecodeTimestamp() - time_offset_); | 542 stream_parser_buffer->GetDecodeTimestamp() - time_offset_); |
542 | 543 |
543 // Discard the incoming buffer: | 544 // Ignore the incoming buffer if it is not associated with any config. |
544 // - if it is not associated with any config, | 545 if (buffer_queue_chain_.empty()) { |
545 // - or if only non-key frames have been added to a new segment. | 546 DVLOG(1) << "Ignoring video buffer with no corresponding video config"; |
wolenetz
2014/07/10 17:57:23
If there has been no init segment prior to media s
damienv1
2014/07/10 18:34:52
ditto.
| |
546 if (buffer_queue_chain_.empty() || | |
547 (first_video_frame_in_segment_ && !stream_parser_buffer->IsKeyframe())) { | |
548 DVLOG(1) << "Discard video buffer:" | |
549 << " keyframe=" << stream_parser_buffer->IsKeyframe() | |
550 << " dts=" | |
551 << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds(); | |
552 if (discarded_frames_dts_.empty() || | |
553 discarded_frames_min_pts_ > stream_parser_buffer->timestamp()) { | |
554 discarded_frames_min_pts_ = stream_parser_buffer->timestamp(); | |
555 } | |
556 discarded_frames_dts_.push_back( | |
557 stream_parser_buffer->GetDecodeTimestamp()); | |
558 return; | 547 return; |
559 } | 548 } |
560 | 549 |
561 // Fill the gap created by frames that have been discarded. | |
562 if (!discarded_frames_dts_.empty()) | |
563 FillVideoGap(stream_parser_buffer); | |
564 | |
565 first_video_frame_in_segment_ = false; | |
566 buffer_queue_chain_.back().video_queue.push_back(stream_parser_buffer); | 550 buffer_queue_chain_.back().video_queue.push_back(stream_parser_buffer); |
567 } | 551 } |
568 | 552 |
569 bool Mp2tStreamParser::EmitRemainingBuffers() { | 553 bool Mp2tStreamParser::EmitRemainingBuffers() { |
570 DVLOG(LOG_LEVEL_ES) << "Mp2tStreamParser::EmitRemainingBuffers"; | 554 DVLOG(LOG_LEVEL_ES) << "Mp2tStreamParser::EmitRemainingBuffers"; |
571 | 555 |
572 // No buffer should be sent until fully initialized. | 556 // No buffer should be sent until fully initialized. |
573 if (!is_initialized_) | 557 if (!is_initialized_) |
574 return true; | 558 return true; |
575 | 559 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
623 | 607 |
624 // Push an empty queue with the last audio/video config | 608 // Push an empty queue with the last audio/video config |
625 // so that buffers with the same config can be added later on. | 609 // so that buffers with the same config can be added later on. |
626 BufferQueueWithConfig queue_with_config( | 610 BufferQueueWithConfig queue_with_config( |
627 true, last_audio_config, last_video_config); | 611 true, last_audio_config, last_video_config); |
628 buffer_queue_chain_.push_back(queue_with_config); | 612 buffer_queue_chain_.push_back(queue_with_config); |
629 | 613 |
630 return true; | 614 return true; |
631 } | 615 } |
632 | 616 |
633 void Mp2tStreamParser::FillVideoGap( | |
634 const scoped_refptr<StreamParserBuffer>& stream_parser_buffer) { | |
635 DCHECK(!buffer_queue_chain_.empty()); | |
636 DCHECK(!discarded_frames_dts_.empty()); | |
637 DCHECK(stream_parser_buffer->IsKeyframe()); | |
638 | |
639 // PTS is interpolated between the min PTS of discarded frames | |
640 // and the PTS of the first valid buffer. | |
641 base::TimeDelta pts = discarded_frames_min_pts_; | |
642 base::TimeDelta pts_delta = | |
643 (stream_parser_buffer->timestamp() - pts) / discarded_frames_dts_.size(); | |
644 | |
645 while (!discarded_frames_dts_.empty()) { | |
646 scoped_refptr<StreamParserBuffer> frame = | |
647 StreamParserBuffer::CopyFrom( | |
648 stream_parser_buffer->data(), | |
649 stream_parser_buffer->data_size(), | |
650 stream_parser_buffer->IsKeyframe(), | |
651 stream_parser_buffer->type(), | |
652 stream_parser_buffer->track_id()); | |
653 frame->SetDecodeTimestamp(discarded_frames_dts_.front()); | |
654 frame->set_timestamp(pts); | |
655 buffer_queue_chain_.back().video_queue.push_back(frame); | |
656 pts += pts_delta; | |
657 discarded_frames_dts_.pop_front(); | |
658 } | |
659 } | |
660 | |
661 } // namespace mp2t | 617 } // namespace mp2t |
662 } // namespace media | 618 } // namespace media |
OLD | NEW |