Index: media/filters/ffmpeg_glue.cc |
diff --git a/media/filters/ffmpeg_glue.cc b/media/filters/ffmpeg_glue.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0d3957b527b5211c22e27cb1757189b1df970083 |
--- /dev/null |
+++ b/media/filters/ffmpeg_glue.cc |
@@ -0,0 +1,162 @@ |
+// 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; |
+ // TODO(scherkus): data source should be able to tell us if we're streaming. |
+ h->is_streamed = FALSE; |
+ 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(); |
+ register_protocol(&kFFmpegProtocol); |
+ |
+ // Now register the rest of FFmpeg. |
+ av_register_all(); |
+} |
+ |
+FFmpegGlue::~FFmpegGlue() { |
+ DataSourceMap::iterator iter = data_sources_.begin(); |
+ while (iter != data_sources_.end()) { |
+ DataSource* data_source = iter->second; |
+ iter = data_sources_.erase(iter); |
+ } |
+} |
+ |
+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_); |
+ DataSourceMap::iterator iter = data_sources_.begin(); |
+ while (iter != data_sources_.end()) { |
+ if (iter->second == data_source) { |
+ iter = data_sources_.erase(iter); |
+ } else { |
+ ++iter; |
+ } |
+ } |
+} |
+ |
+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 |