| // Copyright 2016 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "media/base/decoder_buffer_cache.h" |
| |
| namespace media { |
| |
| DecoderBufferCache::DecoderBufferCache() |
| : audio_buffer_index_(0), video_buffer_index_(0) {} |
| |
| void DecoderBufferCache::AddBuffer(DemuxerStream::Type type, |
| const scoped_refptr<DecoderBuffer>& buffer) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| if (type == DemuxerStream::AUDIO) { |
| audio_buffers_.push_back(buffer); |
| if (buffer->IsKeyframe()) { |
| audio_key_frame_timestamps_.push_back(buffer->GetTimestamp()); |
| } |
| } else { |
| DCHECK_EQ(type, DemuxerStream::VIDEO); |
| video_buffers_.push_back(buffer); |
| if (buffer->IsKeyframe()) { |
| video_key_frame_timestamps_.push_back(buffer->GetTimestamp()); |
| } |
| } |
| } |
| |
| void DecoderBufferCache::ClearSegmentsBeforeMediaTime( |
| base::TimeDelta media_time) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| ClearSegmentsBeforeMediaTime(media_time, &audio_buffers_, |
| &audio_key_frame_timestamps_); |
| ClearSegmentsBeforeMediaTime(media_time, &video_buffers_, |
| &video_key_frame_timestamps_); |
| } |
| |
| void DecoderBufferCache::ClearAll() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| audio_buffers_.clear(); |
| audio_key_frame_timestamps_.clear(); |
| video_buffers_.clear(); |
| video_key_frame_timestamps_.clear(); |
| } |
| |
| void DecoderBufferCache::StartResuming() { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| audio_buffer_index_ = 0; |
| video_buffer_index_ = 0; |
| } |
| |
| scoped_refptr<DecoderBuffer> DecoderBufferCache::GetBuffer( |
| DemuxerStream::Type type) const { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| if (type == DemuxerStream::AUDIO) { |
| if (audio_buffer_index_ < audio_buffers_.size()) { |
| return audio_buffers_[audio_buffer_index_]; |
| } |
| return NULL; |
| } |
| |
| DCHECK_EQ(type, DemuxerStream::VIDEO); |
| if (video_buffer_index_ < video_buffers_.size()) { |
| return video_buffers_[video_buffer_index_]; |
| } |
| return NULL; |
| } |
| |
| void DecoderBufferCache::AdvanceToNextBuffer(DemuxerStream::Type type) { |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| |
| if (type == DemuxerStream::AUDIO) { |
| ++audio_buffer_index_; |
| } else { |
| DCHECK_EQ(type, DemuxerStream::VIDEO); |
| ++video_buffer_index_; |
| } |
| } |
| |
| // static |
| void DecoderBufferCache::ClearSegmentsBeforeMediaTime( |
| base::TimeDelta media_time, |
| Buffers* buffers, |
| KeyFrameTimestamps* key_frame_timestamps) { |
| // Use K to denote a key frame and N for non-key frame. If the cache contains |
| // K N N N N N N N N K N N N N N N N N K N N N N N N N N |
| // | |
| // media_time |
| // Then we should remove everything before the key frame before the |
| // |media_time| and turn the cache into: |
| // K N N N N N N N N K N N N N N N N N |
| // | |
| // media_time |
| // So we need at least two keyframes before we can remove any frames. |
| while (key_frame_timestamps->size() > 1 && |
| key_frame_timestamps->at(1) <= media_time) { |
| key_frame_timestamps->erase(key_frame_timestamps->begin()); |
| } |
| if (key_frame_timestamps->empty()) { |
| return; |
| } |
| while (scoped_refptr<DecoderBuffer> buffer = buffers->front()) { |
| if (buffer->IsKeyframe() && |
| buffer->GetTimestamp() == key_frame_timestamps->front()) { |
| break; |
| } |
| buffers->pop_front(); |
| } |
| } |
| |
| } // namespace media |