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
11namespace media {
12
13BlockingUrlProtocol::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
24BlockingUrlProtocol::~BlockingUrlProtocol() {}
25
26void BlockingUrlProtocol::Abort() {
27  aborted_.Signal();
28}
29
30int 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
63bool BlockingUrlProtocol::GetPosition(int64* position_out) {
64  *position_out = read_position_;
65  return true;
66}
67
68bool 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
79bool BlockingUrlProtocol::GetSize(int64* size_out) {
80  return data_source_->GetSize(size_out);
81}
82
83bool BlockingUrlProtocol::IsStreaming() {
84  return data_source_->IsStreaming();
85}
86
87void BlockingUrlProtocol::SignalReadCompleted(int size) {
88  last_read_bytes_ = size;
89  read_complete_.Signal();
90}
91
92}  // namespace media
93