Home | History | Annotate | Download | only in filters
      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