blob: ca3ed1de2a6e278f6f6731376e3eaac5b7a6f94d [file] [log] [blame]
// Copyright (c) 2009 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 "base/string_util.h"
#include "media/base/filters.h"
#include "media/filters/ffmpeg_common.h"
#include "media/filters/ffmpeg_glue.h"
namespace {
// FFmpeg protocol interface.
int OpenContext(URLContext* h, const char* filename, int flags) {
scoped_refptr<media::DataSource> data_source;
media::FFmpegGlue::get()->GetDataSource(filename, &data_source);
if (!data_source)
return AVERROR_IO;
data_source->AddRef();
h->priv_data = data_source;
h->flags = URL_RDONLY;
h->is_streamed = !data_source->IsSeekable();
return 0;
}
int ReadContext(URLContext* h, unsigned char* buf, int size) {
media::DataSource* data_source =
reinterpret_cast<media::DataSource*>(h->priv_data);
int result = data_source->Read(buf, size);
if (result < 0)
result = AVERROR_IO;
return result;
}
int WriteContext(URLContext* h, unsigned char* buf, int size) {
// We don't support writing.
return AVERROR_IO;
}
offset_t SeekContext(URLContext* h, offset_t offset, int whence) {
media::DataSource* data_source =
reinterpret_cast<media::DataSource*>(h->priv_data);
offset_t new_offset = AVERROR_IO;
switch (whence) {
case SEEK_SET:
if (data_source->SetPosition(offset))
data_source->GetPosition(&new_offset);
break;
case SEEK_CUR:
int64 pos;
if (!data_source->GetPosition(&pos))
break;
if (data_source->SetPosition(pos + offset))
data_source->GetPosition(&new_offset);
break;
case SEEK_END:
int64 size;
if (!data_source->GetSize(&size))
break;
if (data_source->SetPosition(size + offset))
data_source->GetPosition(&new_offset);
break;
case AVSEEK_SIZE:
data_source->GetSize(&new_offset);
break;
default:
NOTREACHED();
}
if (new_offset < 0)
new_offset = AVERROR_IO;
return new_offset;
}
int CloseContext(URLContext* h) {
media::DataSource* data_source =
reinterpret_cast<media::DataSource*>(h->priv_data);
data_source->Release();
h->priv_data = NULL;
return 0;
}
} // namespace
//------------------------------------------------------------------------------
namespace media {
// Use the HTTP protocol to avoid any file path separator issues.
static const char kProtocol[] = "http";
// Fill out our FFmpeg protocol definition.
static URLProtocol kFFmpegProtocol = {
kProtocol,
&OpenContext,
&ReadContext,
&WriteContext,
&SeekContext,
&CloseContext,
};
FFmpegGlue::FFmpegGlue() {
// Register our protocol glue code with FFmpeg.
avcodec_init();
av_register_protocol(&kFFmpegProtocol);
// Now register the rest of FFmpeg.
av_register_all();
}
FFmpegGlue::~FFmpegGlue() {
}
std::string FFmpegGlue::AddDataSource(DataSource* data_source) {
AutoLock auto_lock(lock_);
std::string key = GetDataSourceKey(data_source);
if (data_sources_.find(key) == data_sources_.end()) {
data_sources_[key] = data_source;
}
return key;
}
void FFmpegGlue::RemoveDataSource(DataSource* data_source) {
AutoLock auto_lock(lock_);
for (DataSourceMap::iterator cur, iter = data_sources_.begin();
iter != data_sources_.end();) {
cur = iter;
iter++;
if (cur->second == data_source)
data_sources_.erase(cur);
}
}
void FFmpegGlue::GetDataSource(const std::string& key,
scoped_refptr<DataSource>* data_source) {
AutoLock auto_lock(lock_);
DataSourceMap::iterator iter = data_sources_.find(key);
if (iter == data_sources_.end()) {
*data_source = NULL;
return;
}
*data_source = iter->second;
}
std::string FFmpegGlue::GetDataSourceKey(DataSource* data_source) {
// Use the DataSource's memory address to generate the unique string. This
// also has the nice property that adding the same DataSource reference will
// not generate duplicate entries.
return StringPrintf("%s://0x%lx", kProtocol, static_cast<void*>(data_source));
}
} // namespace media