blob: 00e65f1fdd77b844a41056c39873a3e571e47bcd [file] [log] [blame]
/*
* Copyright 2012 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "media/base/shell_data_source_reader.h"
#include <limits.h> // for ULLONG_MAX
namespace media {
const int ShellDataSourceReader::kReadError = DataSource::kReadError;
ShellDataSourceReader::ShellDataSourceReader()
: data_source_(NULL),
blocking_read_event_(false, false),
file_size_(-1),
read_has_failed_(false),
last_bytes_read_(0) {}
ShellDataSourceReader::~ShellDataSourceReader() {}
void ShellDataSourceReader::SetDataSource(DataSource* data_source) {
DCHECK(data_source);
data_source_ = data_source;
}
// currently only single-threaded reads supported
int ShellDataSourceReader::BlockingRead(int64 position, int size, uint8* data) {
// read failures are unrecoverable, all subsequent reads will also fail
if (read_has_failed_) {
return kReadError;
}
// check bounds of read at or past EOF
if (file_size_ >= 0 && position >= file_size_) {
return 0;
}
int total_bytes_read = 0;
while (size > 0 && !read_has_failed_) {
{
base::AutoLock auto_lock(lock_);
if (!data_source_) {
break;
}
data_source_->Read(
position, size, data,
base::Bind(&ShellDataSourceReader::BlockingReadCompleted, this));
}
// wait for callback on read completion
blocking_read_event_.Wait();
if (last_bytes_read_ == DataSource::kReadError) {
// make all future reads fail
read_has_failed_ = true;
return kReadError;
}
DCHECK_LE(last_bytes_read_, size);
if (last_bytes_read_ > size) {
// make all future reads fail
read_has_failed_ = true;
return kReadError;
}
// Avoid entering an endless loop here.
if (last_bytes_read_ == 0)
break;
total_bytes_read += last_bytes_read_;
position += last_bytes_read_;
size -= last_bytes_read_;
data += last_bytes_read_;
}
if (read_has_failed_) {
return kReadError;
}
return total_bytes_read;
}
void ShellDataSourceReader::Stop(const base::Closure& callback) {
if (data_source_) {
// stop the data source, it can call the callback
data_source_->Stop();
base::AutoLock auto_lock(lock_);
data_source_ = NULL;
}
callback.Run();
}
void ShellDataSourceReader::BlockingReadCompleted(int bytes_read) {
last_bytes_read_ = bytes_read;
// wake up blocked thread
blocking_read_event_.Signal();
}
int64 ShellDataSourceReader::FileSize() {
if (file_size_ == -1) {
base::AutoLock auto_lock(lock_);
if (data_source_ && !data_source_->GetSize(&file_size_)) {
file_size_ = -1;
}
}
return file_size_;
}
} // namespace media