| // 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 "media/filters/blocking_url_protocol.h" |
| |
| #include "base/bind.h" |
| #include "media/base/data_source.h" |
| #include "media/ffmpeg/ffmpeg_common.h" |
| |
| namespace media { |
| |
| BlockingUrlProtocol::BlockingUrlProtocol( |
| const scoped_refptr<DataSource>& data_source, |
| const base::Closure& error_cb) |
| : data_source_(data_source), |
| error_cb_(error_cb), |
| aborted_(true, false), // We never want to reset |aborted_|. |
| read_complete_(false, false), |
| last_read_bytes_(0), |
| read_position_(0) { |
| } |
| |
| BlockingUrlProtocol::~BlockingUrlProtocol() {} |
| |
| void BlockingUrlProtocol::Abort() { |
| aborted_.Signal(); |
| } |
| |
| int BlockingUrlProtocol::Read(int size, uint8* 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 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); |
| } |
| |
| read_position_ += last_read_bytes_; |
| return last_read_bytes_; |
| } |
| |
| bool BlockingUrlProtocol::GetPosition(int64* position_out) { |
| *position_out = read_position_; |
| return true; |
| } |
| |
| bool BlockingUrlProtocol::SetPosition(int64 position) { |
| int64 file_size; |
| if ((data_source_->GetSize(&file_size) && position >= file_size) || |
| position < 0) { |
| return false; |
| } |
| |
| read_position_ = position; |
| return true; |
| } |
| |
| bool BlockingUrlProtocol::GetSize(int64* 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 |