| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cobalt/media/filters/blocking_url_protocol.h" |
| |
| #include "base/basictypes.h" |
| #include "base/bind.h" |
| #include "cobalt/media/base/data_source.h" |
| #include "cobalt/media/ffmpeg/ffmpeg_common.h" |
| #include "starboard/types.h" |
| |
| namespace cobalt { |
| namespace media { |
| |
| BlockingUrlProtocol::BlockingUrlProtocol(DataSource* data_source, |
| const base::Closure& error_cb) |
| : data_source_(data_source), |
| error_cb_(error_cb), |
| aborted_(base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED), // We never |
| // want to |
| // reset |
| // |aborted_|. |
| read_complete_(base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| base::WaitableEvent::InitialState::NOT_SIGNALED), |
| last_read_bytes_(0), |
| read_position_(0) {} |
| |
| BlockingUrlProtocol::~BlockingUrlProtocol() {} |
| |
| void BlockingUrlProtocol::Abort() { aborted_.Signal(); } |
| |
| int BlockingUrlProtocol::Read(int size, uint8_t* data) { |
| // Read errors are unrecoverable. |
| if (aborted_.IsSignaled()) return AVERROR(EIO); |
| |
| // Even though FFmpeg defines AVERROR_EOF, it's not to be used with I/O |
| // routines. Instead return 0 for any read at or past EOF. |
| int64_t file_size; |
| if (data_source_->GetSize(&file_size) && read_position_ >= file_size) |
| return 0; |
| |
| // Blocking read from data source until either: |
| // 1) |last_read_bytes_| is set and |read_complete_| is signalled |
| // 2) |aborted_| is signalled |
| data_source_->Read(read_position_, size, data, |
| base::Bind(&BlockingUrlProtocol::SignalReadCompleted, |
| base::Unretained(this))); |
| |
| base::WaitableEvent* events[] = {&aborted_, &read_complete_}; |
| size_t index = base::WaitableEvent::WaitMany(events, arraysize(events)); |
| |
| if (events[index] == &aborted_) return AVERROR(EIO); |
| |
| if (last_read_bytes_ == DataSource::kReadError) { |
| aborted_.Signal(); |
| error_cb_.Run(); |
| return AVERROR(EIO); |
| } |
| |
| if (last_read_bytes_ == DataSource::kAborted) return AVERROR(EIO); |
| |
| read_position_ += last_read_bytes_; |
| return last_read_bytes_; |
| } |
| |
| bool BlockingUrlProtocol::GetPosition(int64_t* position_out) { |
| *position_out = read_position_; |
| return true; |
| } |
| |
| bool BlockingUrlProtocol::SetPosition(int64_t position) { |
| int64_t file_size; |
| if ((data_source_->GetSize(&file_size) && position > file_size) || |
| position < 0) { |
| return false; |
| } |
| |
| read_position_ = position; |
| return true; |
| } |
| |
| bool BlockingUrlProtocol::GetSize(int64_t* size_out) { |
| return data_source_->GetSize(size_out); |
| } |
| |
| bool BlockingUrlProtocol::IsStreaming() { return data_source_->IsStreaming(); } |
| |
| void BlockingUrlProtocol::SignalReadCompleted(int size) { |
| last_read_bytes_ = size; |
| read_complete_.Signal(); |
| } |
| |
| } // namespace media |
| } // namespace cobalt |