blob: 865216f21a1013f0b7a8718e7ce73d818eedb5de [file] [log] [blame]
// Copyright 2016 The Cobalt Authors. 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 "cobalt/media/base/decoder_buffer_cache.h"
namespace cobalt {
namespace media {
DecoderBufferCache::DecoderBufferCache()
: audio_buffer_index_(0), video_buffer_index_(0) {}
void DecoderBufferCache::AddBuffer(DemuxerStream::Type type,
const scoped_refptr<DecoderBuffer>& buffer) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (type == DemuxerStream::AUDIO) {
audio_buffers_.push_back(buffer);
if (!buffer->end_of_stream() && buffer->is_key_frame()) {
audio_key_frame_timestamps_.push_back(buffer->timestamp());
}
} else {
DCHECK_EQ(type, DemuxerStream::VIDEO);
video_buffers_.push_back(buffer);
if (!buffer->end_of_stream() && buffer->is_key_frame()) {
video_key_frame_timestamps_.push_back(buffer->timestamp());
}
}
}
void DecoderBufferCache::ClearSegmentsBeforeMediaTime(
base::TimeDelta media_time) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
audio_buffer_index_ -= ClearSegmentsBeforeMediaTime(
media_time, &audio_buffers_, &audio_key_frame_timestamps_);
video_buffer_index_ -= ClearSegmentsBeforeMediaTime(
media_time, &video_buffers_, &video_key_frame_timestamps_);
}
void DecoderBufferCache::ClearAll() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
audio_buffers_.clear();
audio_key_frame_timestamps_.clear();
video_buffers_.clear();
video_key_frame_timestamps_.clear();
audio_buffer_index_ = 0;
video_buffer_index_ = 0;
}
void DecoderBufferCache::StartResuming() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
audio_buffer_index_ = 0;
video_buffer_index_ = 0;
}
scoped_refptr<DecoderBuffer> DecoderBufferCache::GetBuffer(
DemuxerStream::Type type) const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
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_CALLED_ON_VALID_THREAD(thread_checker_);
if (type == DemuxerStream::AUDIO) {
++audio_buffer_index_;
} else {
DCHECK_EQ(type, DemuxerStream::VIDEO);
++video_buffer_index_;
}
}
// static
size_t 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 0;
}
size_t buffers_removed = 0;
while (scoped_refptr<DecoderBuffer> buffer = buffers->front()) {
if (buffer->is_key_frame() &&
buffer->timestamp() == key_frame_timestamps->front()) {
break;
}
buffers->pop_front();
++buffers_removed;
}
return buffers_removed;
}
} // namespace media
} // namespace cobalt