| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/filters/chunk_demuxer.h" | 5 #include "media/filters/chunk_demuxer.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "media/base/audio_decoder_config.h" | 10 #include "media/base/audio_decoder_config.h" |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 | 126 |
| 127 void StartWaitingForSeek(); | 127 void StartWaitingForSeek(); |
| 128 void Seek(base::TimeDelta time); | 128 void Seek(base::TimeDelta time); |
| 129 bool IsSeekPending() const; | 129 bool IsSeekPending() const; |
| 130 | 130 |
| 131 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, | 131 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, |
| 132 // which handle ordering and overlap resolution. | 132 // which handle ordering and overlap resolution. |
| 133 // Returns true if buffers were successfully added. | 133 // Returns true if buffers were successfully added. |
| 134 bool Append(const StreamParser::BufferQueue& buffers); | 134 bool Append(const StreamParser::BufferQueue& buffers); |
| 135 | 135 |
| 136 // Returns a list of the buffered time ranges. |
| 137 SourceBufferStream::TimespanList GetBufferedTime() const; |
| 138 |
| 136 // Called when mid-stream config updates occur. | 139 // Called when mid-stream config updates occur. |
| 137 // Returns true if the new config is accepted. | 140 // Returns true if the new config is accepted. |
| 138 // Returns false if the new config should trigger an error. | 141 // Returns false if the new config should trigger an error. |
| 139 bool UpdateAudioConfig(const AudioDecoderConfig& config); | 142 bool UpdateAudioConfig(const AudioDecoderConfig& config); |
| 140 bool UpdateVideoConfig(const VideoDecoderConfig& config); | 143 bool UpdateVideoConfig(const VideoDecoderConfig& config); |
| 141 | 144 |
| 142 void EndOfStream(); | 145 void EndOfStream(); |
| 143 bool CanEndOfStream() const; | 146 bool CanEndOfStream() const; |
| 144 void Shutdown(); | 147 void Shutdown(); |
| 145 | 148 |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 } | 242 } |
| 240 CreateReadDoneClosures_Locked(&closures); | 243 CreateReadDoneClosures_Locked(&closures); |
| 241 } | 244 } |
| 242 | 245 |
| 243 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it) | 246 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it) |
| 244 it->Run(); | 247 it->Run(); |
| 245 | 248 |
| 246 return true; | 249 return true; |
| 247 } | 250 } |
| 248 | 251 |
| 252 SourceBufferStream::TimespanList ChunkDemuxerStream::GetBufferedTime() const { |
| 253 base::AutoLock auto_lock(lock_); |
| 254 return stream_->GetBufferedTime(); |
| 255 } |
| 256 |
| 249 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) { | 257 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) { |
| 250 DCHECK(config.IsValidConfig()); | 258 DCHECK(config.IsValidConfig()); |
| 251 DCHECK_EQ(type_, AUDIO); | 259 DCHECK_EQ(type_, AUDIO); |
| 252 | 260 |
| 253 const AudioDecoderConfig& current_config = | 261 const AudioDecoderConfig& current_config = |
| 254 stream_->GetCurrentAudioDecoderConfig(); | 262 stream_->GetCurrentAudioDecoderConfig(); |
| 255 | 263 |
| 256 bool success = (current_config.codec() == config.codec()) && | 264 bool success = (current_config.codec() == config.codec()) && |
| 257 (current_config.bits_per_channel() == config.bits_per_channel()) && | 265 (current_config.bits_per_channel() == config.bits_per_channel()) && |
| 258 (current_config.channel_layout() == config.channel_layout()) && | 266 (current_config.channel_layout() == config.channel_layout()) && |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 audio_->Shutdown(); | 581 audio_->Shutdown(); |
| 574 | 582 |
| 575 if (source_id_video_ == id && video_) | 583 if (source_id_video_ == id && video_) |
| 576 video_->Shutdown(); | 584 video_->Shutdown(); |
| 577 } | 585 } |
| 578 | 586 |
| 579 bool ChunkDemuxer::GetBufferedRanges(const std::string& id, | 587 bool ChunkDemuxer::GetBufferedRanges(const std::string& id, |
| 580 Ranges* ranges_out) const { | 588 Ranges* ranges_out) const { |
| 581 DCHECK(!id.empty()); | 589 DCHECK(!id.empty()); |
| 582 DCHECK_GT(stream_parser_map_.count(id), 0u); | 590 DCHECK_GT(stream_parser_map_.count(id), 0u); |
| 591 DCHECK(id == source_id_audio_ || id == source_id_video_); |
| 583 DCHECK(ranges_out); | 592 DCHECK(ranges_out); |
| 584 | 593 |
| 585 base::AutoLock auto_lock(lock_); | 594 base::AutoLock auto_lock(lock_); |
| 586 | 595 |
| 587 // TODO(annacc): Calculate buffered ranges (http://crbug.com/129852 ). | 596 if (id == source_id_audio_ && id != source_id_video_) { |
| 588 return false; | 597 // Only include ranges that have been buffered in |audio_| |
| 598 return CopyIntoRanges(audio_->GetBufferedTime(), ranges_out); |
| 599 } |
| 600 |
| 601 if (id != source_id_audio_ && id == source_id_video_) { |
| 602 // Only include ranges that have been buffered in |video_| |
| 603 return CopyIntoRanges(video_->GetBufferedTime(), ranges_out); |
| 604 } |
| 605 |
| 606 // Include ranges that have been buffered in both |audio_| and |video_|. |
| 607 SourceBufferStream::TimespanList audio_ranges = audio_->GetBufferedTime(); |
| 608 SourceBufferStream::TimespanList video_ranges = video_->GetBufferedTime(); |
| 609 SourceBufferStream::TimespanList::const_iterator video_ranges_itr = |
| 610 video_ranges.begin(); |
| 611 SourceBufferStream::TimespanList::const_iterator audio_ranges_itr = |
| 612 audio_ranges.begin(); |
| 613 bool success = false; |
| 614 |
| 615 while (audio_ranges_itr != audio_ranges.end() && |
| 616 video_ranges_itr != video_ranges.end()) { |
| 617 // If this is the last range and EndOfStream() was called (i.e. all data |
| 618 // has been appended), choose the max end point of the ranges. |
| 619 bool last_range_after_ended = |
| 620 state_ == ENDED && |
| 621 (audio_ranges_itr + 1) == audio_ranges.end() && |
| 622 (video_ranges_itr + 1) == video_ranges.end(); |
| 623 |
| 624 // Audio range start time is within the video range. |
| 625 if ((*audio_ranges_itr).first >= (*video_ranges_itr).first && |
| 626 (*audio_ranges_itr).first <= (*video_ranges_itr).second) { |
| 627 AddIntersectionRange(*audio_ranges_itr, *video_ranges_itr, |
| 628 last_range_after_ended, ranges_out); |
| 629 audio_ranges_itr++; |
| 630 success = true; |
| 631 continue; |
| 632 } |
| 633 |
| 634 // Video range start time is within the audio range. |
| 635 if ((*video_ranges_itr).first >= (*audio_ranges_itr).first && |
| 636 (*video_ranges_itr).first <= (*audio_ranges_itr).second) { |
| 637 AddIntersectionRange(*video_ranges_itr, *audio_ranges_itr, |
| 638 last_range_after_ended, ranges_out); |
| 639 video_ranges_itr++; |
| 640 success = true; |
| 641 continue; |
| 642 } |
| 643 |
| 644 // No overlap was found. Increment the earliest one and keep looking. |
| 645 if ((*audio_ranges_itr).first < (*video_ranges_itr).first) |
| 646 audio_ranges_itr++; |
| 647 else |
| 648 video_ranges_itr++; |
| 649 } |
| 650 |
| 651 return success; |
| 652 } |
| 653 |
| 654 bool ChunkDemuxer::CopyIntoRanges( |
| 655 const SourceBufferStream::TimespanList& timespans, |
| 656 Ranges* ranges_out) const { |
| 657 for (SourceBufferStream::TimespanList::const_iterator itr = timespans.begin(); |
| 658 itr != timespans.end(); ++itr) { |
| 659 ranges_out->push_back(*itr); |
| 660 } |
| 661 return !timespans.empty(); |
| 662 } |
| 663 |
| 664 void ChunkDemuxer::AddIntersectionRange( |
| 665 SourceBufferStream::Timespan timespan_a, |
| 666 SourceBufferStream::Timespan timespan_b, |
| 667 bool last_range_after_ended, |
| 668 Ranges* ranges_out) const { |
| 669 base::TimeDelta start = timespan_a.first; |
| 670 |
| 671 // If this is the last range after EndOfStream() was called, choose the later |
| 672 // end point of the ranges, otherwise choose the earlier. |
| 673 base::TimeDelta end; |
| 674 if (last_range_after_ended) |
| 675 end = std::max(timespan_a.second, timespan_b.second); |
| 676 else |
| 677 end = std::min(timespan_a.second, timespan_b.second); |
| 678 |
| 679 ranges_out->push_back(std::make_pair(start, end)); |
| 589 } | 680 } |
| 590 | 681 |
| 591 bool ChunkDemuxer::AppendData(const std::string& id, | 682 bool ChunkDemuxer::AppendData(const std::string& id, |
| 592 const uint8* data, | 683 const uint8* data, |
| 593 size_t length) { | 684 size_t length) { |
| 594 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; | 685 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; |
| 595 | 686 |
| 596 DCHECK(!id.empty()); | 687 DCHECK(!id.empty()); |
| 597 DCHECK(data); | 688 DCHECK(data); |
| 598 DCHECK_GT(length, 0u); | 689 DCHECK_GT(length, 0u); |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 885 return true; | 976 return true; |
| 886 } | 977 } |
| 887 | 978 |
| 888 bool ChunkDemuxer::OnKeyNeeded(scoped_array<uint8> init_data, | 979 bool ChunkDemuxer::OnKeyNeeded(scoped_array<uint8> init_data, |
| 889 int init_data_size) { | 980 int init_data_size) { |
| 890 client_->KeyNeeded(init_data.Pass(), init_data_size); | 981 client_->KeyNeeded(init_data.Pass(), init_data_size); |
| 891 return true; | 982 return true; |
| 892 } | 983 } |
| 893 | 984 |
| 894 } // namespace media | 985 } // namespace media |
| OLD | NEW |