blob: fca08be27ec4b79f4b764634de954f1b072b501a [file] [log] [blame]
// Copyright 2017 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 "starboard/shared/win32/video_decoder_thread.h"
#include <deque>
namespace starboard {
namespace shared {
namespace win32 {
namespace {
const size_t kMaxSize = 16;
size_t WriteAsMuchAsPossible(
std::deque<scoped_refptr<InputBuffer> >* data_queue,
AbstractWin32VideoDecoder* video_decoder,
bool* is_end_of_stream_reached) {
const size_t original_size = data_queue->size();
while (!data_queue->empty()) {
scoped_refptr<InputBuffer> buff = data_queue->front();
data_queue->pop_front();
if (buff) {
const bool write_ok = video_decoder->TryWrite(buff);
if (!write_ok) {
data_queue->push_front(buff);
break;
}
} else {
video_decoder->WriteEndOfStream();
*is_end_of_stream_reached = true;
}
}
return original_size - data_queue->size();
}
} // namespace.
VideoDecoderThread::VideoDecoderThread(AbstractWin32VideoDecoder* decoder_impl,
VideoDecodedCallback* callback)
: SimpleThread("VideoDecoderThread"),
win32_video_decoder_(decoder_impl),
callback_(callback) {
Start();
}
VideoDecoderThread::~VideoDecoderThread() {
Join();
SB_DCHECK(join_called());
}
bool VideoDecoderThread::QueueInput(const scoped_refptr<InputBuffer>& buffer) {
{
::starboard::ScopedLock lock(input_buffer_queue_mutex_);
input_buffer_queue_.push_back(buffer);
}
// increment() returns the prev value.
size_t proc_size = processing_elements_.increment() + 1;
semaphore_.Put();
return proc_size < kMaxSize;
}
void VideoDecoderThread::QueueEndOfStream() {
scoped_refptr<InputBuffer> empty;
QueueInput(empty);
}
void VideoDecoderThread::TransferPendingInputTo(
std::deque<scoped_refptr<InputBuffer> >* output) {
// Transfer input buffer to local thread.
::starboard::ScopedLock lock(input_buffer_queue_mutex_);
while (!input_buffer_queue_.empty()) {
output->push_back(input_buffer_queue_.front());
input_buffer_queue_.pop_front();
}
}
void VideoDecoderThread::Run() {
std::deque<scoped_refptr<InputBuffer> > local_queue;
while (!join_called()) {
if (local_queue.empty()) {
TransferPendingInputTo(&local_queue);
}
bool work_done = false;
bool is_end_of_stream = false;
const size_t number_written =
WriteAsMuchAsPossible(&local_queue, win32_video_decoder_,
&is_end_of_stream);
if (number_written > 0) {
processing_elements_.fetch_sub(static_cast<int32_t>(number_written));
work_done = true;
callback_->OnVideoDecoded(NULL);
}
bool too_many_outstanding_frames;
while (VideoFramePtr decoded_datum = win32_video_decoder_->ProcessAndRead(
&too_many_outstanding_frames)) {
if (decoded_datum.get()) {
callback_->OnVideoDecoded(decoded_datum);
}
work_done = true;
}
if (is_end_of_stream) {
callback_->OnVideoDecoded(VideoFrame::CreateEOSFrame());
work_done = true;
}
if (too_many_outstanding_frames) {
SbThreadSleep(10 * kSbTimeMillisecond);
}
if (!work_done) {
semaphore_.TakeWait(kSbTimeMillisecond);
}
}
}
} // namespace win32
} // namespace shared
} // namespace starboard