Chromium Code Reviews| 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/webm/webm_cluster_parser.h" | 5 #include "media/formats/webm/webm_cluster_parser.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/sys_byteorder.h" | 10 #include "base/sys_byteorder.h" |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 37 block_data_size_(-1), | 37 block_data_size_(-1), |
| 38 block_duration_(-1), | 38 block_duration_(-1), |
| 39 block_add_id_(-1), | 39 block_add_id_(-1), |
| 40 block_additional_data_size_(-1), | 40 block_additional_data_size_(-1), |
| 41 discard_padding_(-1), | 41 discard_padding_(-1), |
| 42 cluster_timecode_(-1), | 42 cluster_timecode_(-1), |
| 43 cluster_start_time_(kNoTimestamp()), | 43 cluster_start_time_(kNoTimestamp()), |
| 44 cluster_ended_(false), | 44 cluster_ended_(false), |
| 45 audio_(audio_track_num, false, audio_default_duration, log_cb), | 45 audio_(audio_track_num, false, audio_default_duration, log_cb), |
| 46 video_(video_track_num, true, video_default_duration, log_cb), | 46 video_(video_track_num, true, video_default_duration, log_cb), |
| 47 ready_buffer_upper_bound_(kNoTimestamp()), | 47 ready_buffer_upper_bound_(kNoDecodeTimestamp()), |
| 48 log_cb_(log_cb) { | 48 log_cb_(log_cb) { |
| 49 for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin(); | 49 for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin(); |
| 50 it != text_tracks.end(); | 50 it != text_tracks.end(); |
| 51 ++it) { | 51 ++it) { |
| 52 text_track_map_.insert(std::make_pair( | 52 text_track_map_.insert(std::make_pair( |
| 53 it->first, Track(it->first, false, kNoTimestamp(), log_cb_))); | 53 it->first, Track(it->first, false, kNoTimestamp(), log_cb_))); |
| 54 } | 54 } |
| 55 } | 55 } |
| 56 | 56 |
| 57 WebMClusterParser::~WebMClusterParser() {} | 57 WebMClusterParser::~WebMClusterParser() {} |
| 58 | 58 |
| 59 void WebMClusterParser::Reset() { | 59 void WebMClusterParser::Reset() { |
| 60 last_block_timecode_ = -1; | 60 last_block_timecode_ = -1; |
| 61 cluster_timecode_ = -1; | 61 cluster_timecode_ = -1; |
| 62 cluster_start_time_ = kNoTimestamp(); | 62 cluster_start_time_ = kNoTimestamp(); |
| 63 cluster_ended_ = false; | 63 cluster_ended_ = false; |
| 64 parser_.Reset(); | 64 parser_.Reset(); |
| 65 audio_.Reset(); | 65 audio_.Reset(); |
| 66 video_.Reset(); | 66 video_.Reset(); |
| 67 ResetTextTracks(); | 67 ResetTextTracks(); |
| 68 ready_buffer_upper_bound_ = kNoTimestamp(); | 68 ready_buffer_upper_bound_ = kNoDecodeTimestamp(); |
| 69 } | 69 } |
| 70 | 70 |
| 71 int WebMClusterParser::Parse(const uint8* buf, int size) { | 71 int WebMClusterParser::Parse(const uint8* buf, int size) { |
| 72 audio_.ClearReadyBuffers(); | 72 audio_.ClearReadyBuffers(); |
| 73 video_.ClearReadyBuffers(); | 73 video_.ClearReadyBuffers(); |
| 74 ClearTextTrackReadyBuffers(); | 74 ClearTextTrackReadyBuffers(); |
| 75 ready_buffer_upper_bound_ = kNoTimestamp(); | 75 ready_buffer_upper_bound_ = kNoDecodeTimestamp(); |
| 76 | 76 |
| 77 int result = parser_.Parse(buf, size); | 77 int result = parser_.Parse(buf, size); |
| 78 | 78 |
| 79 if (result < 0) { | 79 if (result < 0) { |
| 80 cluster_ended_ = false; | 80 cluster_ended_ = false; |
| 81 return result; | 81 return result; |
| 82 } | 82 } |
| 83 | 83 |
| 84 cluster_ended_ = parser_.IsParsingComplete(); | 84 cluster_ended_ = parser_.IsParsingComplete(); |
| 85 if (cluster_ended_) { | 85 if (cluster_ended_) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 101 parser_.Reset(); | 101 parser_.Reset(); |
| 102 | 102 |
| 103 last_block_timecode_ = -1; | 103 last_block_timecode_ = -1; |
| 104 cluster_timecode_ = -1; | 104 cluster_timecode_ = -1; |
| 105 } | 105 } |
| 106 | 106 |
| 107 return result; | 107 return result; |
| 108 } | 108 } |
| 109 | 109 |
| 110 const WebMClusterParser::BufferQueue& WebMClusterParser::GetAudioBuffers() { | 110 const WebMClusterParser::BufferQueue& WebMClusterParser::GetAudioBuffers() { |
| 111 if (ready_buffer_upper_bound_ == kNoTimestamp()) | 111 if (ready_buffer_upper_bound_ == kNoDecodeTimestamp()) |
| 112 UpdateReadyBuffers(); | 112 UpdateReadyBuffers(); |
| 113 | 113 |
| 114 return audio_.ready_buffers(); | 114 return audio_.ready_buffers(); |
| 115 } | 115 } |
| 116 | 116 |
| 117 const WebMClusterParser::BufferQueue& WebMClusterParser::GetVideoBuffers() { | 117 const WebMClusterParser::BufferQueue& WebMClusterParser::GetVideoBuffers() { |
| 118 if (ready_buffer_upper_bound_ == kNoTimestamp()) | 118 if (ready_buffer_upper_bound_ == kNoDecodeTimestamp()) |
| 119 UpdateReadyBuffers(); | 119 UpdateReadyBuffers(); |
| 120 | 120 |
| 121 return video_.ready_buffers(); | 121 return video_.ready_buffers(); |
| 122 } | 122 } |
| 123 | 123 |
| 124 const WebMClusterParser::TextBufferQueueMap& | 124 const WebMClusterParser::TextBufferQueueMap& |
| 125 WebMClusterParser::GetTextBuffers() { | 125 WebMClusterParser::GetTextBuffers() { |
| 126 if (ready_buffer_upper_bound_ == kNoTimestamp()) | 126 if (ready_buffer_upper_bound_ == kNoDecodeTimestamp()) |
| 127 UpdateReadyBuffers(); | 127 UpdateReadyBuffers(); |
| 128 | 128 |
| 129 // Translate our |text_track_map_| into |text_buffers_map_|, inserting rows in | 129 // Translate our |text_track_map_| into |text_buffers_map_|, inserting rows in |
| 130 // the output only for non-empty ready_buffer() queues in |text_track_map_|. | 130 // the output only for non-empty ready_buffer() queues in |text_track_map_|. |
| 131 text_buffers_map_.clear(); | 131 text_buffers_map_.clear(); |
| 132 for (TextTrackMap::const_iterator itr = text_track_map_.begin(); | 132 for (TextTrackMap::const_iterator itr = text_track_map_.begin(); |
| 133 itr != text_track_map_.end(); | 133 itr != text_track_map_.end(); |
| 134 ++itr) { | 134 ++itr) { |
| 135 const BufferQueue& text_buffers = itr->second.ready_buffers(); | 135 const BufferQueue& text_buffers = itr->second.ready_buffers(); |
| 136 if (!text_buffers.empty()) | 136 if (!text_buffers.empty()) |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 432 is_video_(is_video), | 432 is_video_(is_video), |
| 433 default_duration_(default_duration), | 433 default_duration_(default_duration), |
| 434 estimated_next_frame_duration_(kNoTimestamp()), | 434 estimated_next_frame_duration_(kNoTimestamp()), |
| 435 log_cb_(log_cb) { | 435 log_cb_(log_cb) { |
| 436 DCHECK(default_duration_ == kNoTimestamp() || | 436 DCHECK(default_duration_ == kNoTimestamp() || |
| 437 default_duration_ > base::TimeDelta()); | 437 default_duration_ > base::TimeDelta()); |
| 438 } | 438 } |
| 439 | 439 |
| 440 WebMClusterParser::Track::~Track() {} | 440 WebMClusterParser::Track::~Track() {} |
| 441 | 441 |
| 442 base::TimeDelta WebMClusterParser::Track::GetReadyUpperBound() { | 442 DecodeTimestamp WebMClusterParser::Track::GetReadyUpperBound() { |
| 443 DCHECK(ready_buffers_.empty()); | 443 DCHECK(ready_buffers_.empty()); |
| 444 if (last_added_buffer_missing_duration_) | 444 if (last_added_buffer_missing_duration_) |
| 445 return last_added_buffer_missing_duration_->GetDecodeTimestamp(); | 445 return last_added_buffer_missing_duration_->GetDecodeTimestamp(); |
| 446 | 446 |
| 447 return kInfiniteDuration(); | 447 return DecodeTimestamp::FromPresentationTime(kInfiniteDuration()); |
|
wolenetz
2014/08/08 21:30:05
nit: We have an explicit kNoDecodeTimestamp(). Doe
acolwell GONE FROM CHROMIUM
2014/08/11 17:05:06
I don't think it is worth it since I'm pretty sure
wolenetz
2014/08/12 00:09:00
Acknowledged.
| |
| 448 } | 448 } |
| 449 | 449 |
| 450 void WebMClusterParser::Track::ExtractReadyBuffers( | 450 void WebMClusterParser::Track::ExtractReadyBuffers( |
| 451 const base::TimeDelta before_timestamp) { | 451 const DecodeTimestamp before_timestamp) { |
| 452 DCHECK(ready_buffers_.empty()); | 452 DCHECK(ready_buffers_.empty()); |
| 453 DCHECK(base::TimeDelta() <= before_timestamp); | 453 DCHECK(DecodeTimestamp() <= before_timestamp); |
| 454 DCHECK(kNoTimestamp() != before_timestamp); | 454 DCHECK(kNoDecodeTimestamp() != before_timestamp); |
| 455 | 455 |
| 456 if (buffers_.empty()) | 456 if (buffers_.empty()) |
| 457 return; | 457 return; |
| 458 | 458 |
| 459 if (buffers_.back()->GetDecodeTimestamp() < before_timestamp) { | 459 if (buffers_.back()->GetDecodeTimestamp() < before_timestamp) { |
| 460 // All of |buffers_| are ready. | 460 // All of |buffers_| are ready. |
| 461 ready_buffers_.swap(buffers_); | 461 ready_buffers_.swap(buffers_); |
| 462 DVLOG(3) << __FUNCTION__ << " : " << track_num_ << " All " | 462 DVLOG(3) << __FUNCTION__ << " : " << track_num_ << " All " |
| 463 << ready_buffers_.size() << " are ready: before upper bound ts " | 463 << ready_buffers_.size() << " are ready: before upper bound ts " |
| 464 << before_timestamp.InSecondsF(); | 464 << before_timestamp.InSecondsF(); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 572 return true; | 572 return true; |
| 573 } | 573 } |
| 574 | 574 |
| 575 bool WebMClusterParser::Track::QueueBuffer( | 575 bool WebMClusterParser::Track::QueueBuffer( |
| 576 const scoped_refptr<StreamParserBuffer>& buffer) { | 576 const scoped_refptr<StreamParserBuffer>& buffer) { |
| 577 DCHECK(!last_added_buffer_missing_duration_); | 577 DCHECK(!last_added_buffer_missing_duration_); |
| 578 | 578 |
| 579 // WebMClusterParser::OnBlock() gives MEDIA_LOG and parse error on decreasing | 579 // WebMClusterParser::OnBlock() gives MEDIA_LOG and parse error on decreasing |
| 580 // block timecode detection within a cluster. Therefore, we should not see | 580 // block timecode detection within a cluster. Therefore, we should not see |
| 581 // those here. | 581 // those here. |
| 582 base::TimeDelta previous_buffers_timestamp = buffers_.empty() ? | 582 DecodeTimestamp previous_buffers_timestamp = buffers_.empty() ? |
| 583 base::TimeDelta() : buffers_.back()->GetDecodeTimestamp(); | 583 DecodeTimestamp() : buffers_.back()->GetDecodeTimestamp(); |
| 584 CHECK(previous_buffers_timestamp <= buffer->GetDecodeTimestamp()); | 584 CHECK(previous_buffers_timestamp <= buffer->GetDecodeTimestamp()); |
| 585 | 585 |
| 586 base::TimeDelta duration = buffer->duration(); | 586 base::TimeDelta duration = buffer->duration(); |
| 587 if (duration < base::TimeDelta() || duration == kNoTimestamp()) { | 587 if (duration < base::TimeDelta() || duration == kNoTimestamp()) { |
| 588 MEDIA_LOG(log_cb_) << "Invalid buffer duration: " << duration.InSecondsF(); | 588 MEDIA_LOG(log_cb_) << "Invalid buffer duration: " << duration.InSecondsF(); |
| 589 return false; | 589 return false; |
| 590 } | 590 } |
| 591 | 591 |
| 592 // The estimated frame duration is the minimum non-zero duration since the | 592 // The estimated frame duration is the minimum non-zero duration since the |
| 593 // last initialization segment. The minimum is used to ensure frame durations | 593 // last initialization segment. The minimum is used to ensure frame durations |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 637 void WebMClusterParser::ResetTextTracks() { | 637 void WebMClusterParser::ResetTextTracks() { |
| 638 ClearTextTrackReadyBuffers(); | 638 ClearTextTrackReadyBuffers(); |
| 639 for (TextTrackMap::iterator it = text_track_map_.begin(); | 639 for (TextTrackMap::iterator it = text_track_map_.begin(); |
| 640 it != text_track_map_.end(); | 640 it != text_track_map_.end(); |
| 641 ++it) { | 641 ++it) { |
| 642 it->second.Reset(); | 642 it->second.Reset(); |
| 643 } | 643 } |
| 644 } | 644 } |
| 645 | 645 |
| 646 void WebMClusterParser::UpdateReadyBuffers() { | 646 void WebMClusterParser::UpdateReadyBuffers() { |
| 647 DCHECK(ready_buffer_upper_bound_ == kNoTimestamp()); | 647 DCHECK(ready_buffer_upper_bound_ == kNoDecodeTimestamp()); |
| 648 DCHECK(text_buffers_map_.empty()); | 648 DCHECK(text_buffers_map_.empty()); |
| 649 | 649 |
| 650 if (cluster_ended_) { | 650 if (cluster_ended_) { |
| 651 audio_.ApplyDurationEstimateIfNeeded(); | 651 audio_.ApplyDurationEstimateIfNeeded(); |
| 652 video_.ApplyDurationEstimateIfNeeded(); | 652 video_.ApplyDurationEstimateIfNeeded(); |
| 653 // Per OnBlock(), all text buffers should already have valid durations, so | 653 // Per OnBlock(), all text buffers should already have valid durations, so |
| 654 // there is no need to call ApplyDurationEstimateIfNeeded() on text tracks | 654 // there is no need to call ApplyDurationEstimateIfNeeded() on text tracks |
| 655 // here. | 655 // here. |
| 656 ready_buffer_upper_bound_ = kInfiniteDuration(); | 656 ready_buffer_upper_bound_ = |
| 657 DecodeTimestamp::FromPresentationTime(kInfiniteDuration()); | |
| 657 DCHECK(ready_buffer_upper_bound_ == audio_.GetReadyUpperBound()); | 658 DCHECK(ready_buffer_upper_bound_ == audio_.GetReadyUpperBound()); |
| 658 DCHECK(ready_buffer_upper_bound_ == video_.GetReadyUpperBound()); | 659 DCHECK(ready_buffer_upper_bound_ == video_.GetReadyUpperBound()); |
| 659 } else { | 660 } else { |
| 660 ready_buffer_upper_bound_ = std::min(audio_.GetReadyUpperBound(), | 661 ready_buffer_upper_bound_ = std::min(audio_.GetReadyUpperBound(), |
| 661 video_.GetReadyUpperBound()); | 662 video_.GetReadyUpperBound()); |
| 662 DCHECK(base::TimeDelta() <= ready_buffer_upper_bound_); | 663 DCHECK(DecodeTimestamp() <= ready_buffer_upper_bound_); |
| 663 DCHECK(kNoTimestamp() != ready_buffer_upper_bound_); | 664 DCHECK(kNoDecodeTimestamp() != ready_buffer_upper_bound_); |
| 664 } | 665 } |
| 665 | 666 |
| 666 // Prepare each track's ready buffers for retrieval. | 667 // Prepare each track's ready buffers for retrieval. |
| 667 audio_.ExtractReadyBuffers(ready_buffer_upper_bound_); | 668 audio_.ExtractReadyBuffers(ready_buffer_upper_bound_); |
| 668 video_.ExtractReadyBuffers(ready_buffer_upper_bound_); | 669 video_.ExtractReadyBuffers(ready_buffer_upper_bound_); |
| 669 for (TextTrackMap::iterator itr = text_track_map_.begin(); | 670 for (TextTrackMap::iterator itr = text_track_map_.begin(); |
| 670 itr != text_track_map_.end(); | 671 itr != text_track_map_.end(); |
| 671 ++itr) { | 672 ++itr) { |
| 672 itr->second.ExtractReadyBuffers(ready_buffer_upper_bound_); | 673 itr->second.ExtractReadyBuffers(ready_buffer_upper_bound_); |
| 673 } | 674 } |
| 674 } | 675 } |
| 675 | 676 |
| 676 WebMClusterParser::Track* | 677 WebMClusterParser::Track* |
| 677 WebMClusterParser::FindTextTrack(int track_num) { | 678 WebMClusterParser::FindTextTrack(int track_num) { |
| 678 const TextTrackMap::iterator it = text_track_map_.find(track_num); | 679 const TextTrackMap::iterator it = text_track_map_.find(track_num); |
| 679 | 680 |
| 680 if (it == text_track_map_.end()) | 681 if (it == text_track_map_.end()) |
| 681 return NULL; | 682 return NULL; |
| 682 | 683 |
| 683 return &it->second; | 684 return &it->second; |
| 684 } | 685 } |
| 685 | 686 |
| 686 } // namespace media | 687 } // namespace media |
| OLD | NEW |