1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "media/filters/blocking_url_protocol.h" 6 7 #include "base/bind.h" 8 #include "media/base/data_source.h" 9 #include "media/ffmpeg/ffmpeg_common.h" 10 11 namespace media { 12 13 BlockingUrlProtocol::BlockingUrlProtocol( 14 DataSource* data_source, 15 const base::Closure& error_cb) 16 : data_source_(data_source), 17 error_cb_(error_cb), 18 aborted_(true, false), // We never want to reset |aborted_|. 19 read_complete_(false, false), 20 last_read_bytes_(0), 21 read_position_(0) { 22 } 23 24 BlockingUrlProtocol::~BlockingUrlProtocol() {} 25 26 void BlockingUrlProtocol::Abort() { 27 aborted_.Signal(); 28 } 29 30 int BlockingUrlProtocol::Read(int size, uint8* data) { 31 // Read errors are unrecoverable. 32 if (aborted_.IsSignaled()) 33 return AVERROR(EIO); 34 35 // Even though FFmpeg defines AVERROR_EOF, it's not to be used with I/O 36 // routines. Instead return 0 for any read at or past EOF. 37 int64 file_size; 38 if (data_source_->GetSize(&file_size) && read_position_ >= file_size) 39 return 0; 40 41 // Blocking read from data source until either: 42 // 1) |last_read_bytes_| is set and |read_complete_| is signalled 43 // 2) |aborted_| is signalled 44 data_source_->Read(read_position_, size, data, base::Bind( 45 &BlockingUrlProtocol::SignalReadCompleted, base::Unretained(this))); 46 47 base::WaitableEvent* events[] = { &aborted_, &read_complete_ }; 48 size_t index = base::WaitableEvent::WaitMany(events, arraysize(events)); 49 50 if (events[index] == &aborted_) 51 return AVERROR(EIO); 52 53 if (last_read_bytes_ == DataSource::kReadError) { 54 aborted_.Signal(); 55 error_cb_.Run(); 56 return AVERROR(EIO); 57 } 58 59 read_position_ += last_read_bytes_; 60 return last_read_bytes_; 61 } 62 63 bool BlockingUrlProtocol::GetPosition(int64* position_out) { 64 *position_out = read_position_; 65 return true; 66 } 67 68 bool BlockingUrlProtocol::SetPosition(int64 position) { 69 int64 file_size; 70 if ((data_source_->GetSize(&file_size) && position > file_size) || 71 position < 0) { 72 return false; 73 } 74 75 read_position_ = position; 76 return true; 77 } 78 79 bool BlockingUrlProtocol::GetSize(int64* size_out) { 80 return data_source_->GetSize(size_out); 81 } 82 83 bool BlockingUrlProtocol::IsStreaming() { 84 return data_source_->IsStreaming(); 85 } 86 87 void BlockingUrlProtocol::SignalReadCompleted(int size) { 88 last_read_bytes_ = size; 89 read_complete_.Signal(); 90 } 91 92 } // namespace media 93