summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorralphl@chromium.org <ralphl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-26 04:20:48 +0000
committerralphl@chromium.org <ralphl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-26 04:20:48 +0000
commit636cf88fc365a7c62cc3318f149b3919d148f5d0 (patch)
tree520002c5b36dfbffac1229bddf04b0721981a5f8 /media
parentd815db156387600cdad5466be6b172421df420d8 (diff)
downloadchromium_src-636cf88fc365a7c62cc3318f149b3919d148f5d0.zip
chromium_src-636cf88fc365a7c62cc3318f149b3919d148f5d0.tar.gz
chromium_src-636cf88fc365a7c62cc3318f149b3919d148f5d0.tar.bz2
Ability for demuxer clients to get to FFmpeg's AVStream object exposed as an extended interface through DemuxerStream object.
DemuxerStream now derives from base::RefCountedThreadSafe. Review URL: http://codereview.chromium.org/42521 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12537 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/base/filters.h24
-rw-r--r--media/base/mock_media_filters.h81
-rw-r--r--media/base/pipeline_impl.cc2
-rw-r--r--media/filters/decoder_base.h2
-rw-r--r--media/filters/ffmpeg_common.cc7
-rw-r--r--media/filters/ffmpeg_common.h12
-rw-r--r--media/filters/ffmpeg_demuxer.cc45
-rw-r--r--media/filters/ffmpeg_demuxer.h16
-rw-r--r--media/filters/ffmpeg_demuxer_unittest.cc14
9 files changed, 136 insertions, 67 deletions
diff --git a/media/base/filters.h b/media/base/filters.h
index 3776c72..7ceb9e8 100644
--- a/media/base/filters.h
+++ b/media/base/filters.h
@@ -147,11 +147,11 @@ class Demuxer : public MediaFilter {
virtual size_t GetNumberOfStreams() = 0;
// Returns the stream for the given index, NULL otherwise
- virtual DemuxerStream* GetStream(int stream_id) = 0;
+ virtual scoped_refptr<DemuxerStream> GetStream(int stream_id) = 0;
};
-class DemuxerStream {
+class DemuxerStream : public base::RefCountedThreadSafe<DemuxerStream> {
public:
// Returns the MediaFormat for this filter.
virtual const MediaFormat* GetMediaFormat() = 0;
@@ -159,7 +159,27 @@ class DemuxerStream {
// Schedules a read and takes ownership of the given buffer.
virtual void Read(Assignable<Buffer>* buffer) = 0;
+ // Given a class that supports the |Interface| and a related static method
+ // interface_id(), which returns a const char*, this method returns true if
+ // the class returns an interface pointer and assigns the pointer to
+ // |interface_out|. Otherwise this method returns false.
+ template <class Interface>
+ bool QueryInterface(scoped_refptr<Interface>* interface_out) {
+ void* i = QueryInterface(Interface::interface_id());
+ *interface_out = reinterpret_cast<Interface*>(i);
+ return (NULL != i);
+ };
+
protected:
+ // Optional method that is implemented by filters that support extended
+ // interfaces. The filter should return a pointer to the interface
+ // associated with the |interface_id| string if they support it, otherwise
+ // return NULL to indicate the interface is unknown. The derived filter
+ // should NOT AddRef() the interface. The DemuxerStream::QueryInterface()
+ // public template function will assign the interface to a scoped_refptr<>.
+ virtual void* QueryInterface(const char* interface_id) { return NULL; }
+
+ friend class base::RefCountedThreadSafe<DemuxerStream>;
virtual ~DemuxerStream() {}
};
diff --git a/media/base/mock_media_filters.h b/media/base/mock_media_filters.h
index 5a3c6bf..4f12c00 100644
--- a/media/base/mock_media_filters.h
+++ b/media/base/mock_media_filters.h
@@ -195,6 +195,39 @@ class MockDataSource : public DataSource {
//------------------------------------------------------------------------------
+class MockDemuxerStream : public DemuxerStream {
+ public:
+ MockDemuxerStream(const MockFilterConfig* config, bool is_audio) {
+ if (is_audio) {
+ media_format_.SetAsString(MediaFormat::kMimeType,
+ config->compressed_audio_mime_type);
+ } else {
+ media_format_.SetAsString(MediaFormat::kMimeType,
+ config->compressed_video_mime_type);
+ media_format_.SetAsInteger(MediaFormat::kWidth, config->video_width);
+ media_format_.SetAsInteger(MediaFormat::kHeight, config->video_height);
+ }
+ }
+
+ // Implementation of DemuxerStream.
+ virtual const MediaFormat* GetMediaFormat() {
+ return &media_format_;
+ }
+
+ virtual void Read(Assignable<Buffer>* buffer) {
+ NOTREACHED(); // TODO(ralphl): fix me!!
+ }
+
+ private:
+ virtual ~MockDemuxerStream() {}
+
+ MediaFormat media_format_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockDemuxerStream);
+};
+
+//------------------------------------------------------------------------------
+
class MockDemuxer : public Demuxer {
public:
static FilterFactory* CreateFactory(const MockFilterConfig* config) {
@@ -204,8 +237,8 @@ class MockDemuxer : public Demuxer {
explicit MockDemuxer(const MockFilterConfig* config)
: config_(config),
- mock_audio_stream_(config, true),
- mock_video_stream_(config, false) {
+ mock_audio_stream_(new MockDemuxerStream(config, true)),
+ mock_video_stream_(new MockDemuxerStream(config, false)) {
}
// Implementation of MediaFilter.
@@ -228,18 +261,18 @@ class MockDemuxer : public Demuxer {
return num_streams;
}
- virtual DemuxerStream* GetStream(int stream_id) {
+ virtual scoped_refptr<DemuxerStream> GetStream(int stream_id) {
switch (stream_id) {
case 0:
if (config_->has_audio) {
- return &mock_audio_stream_;
+ return mock_audio_stream_;
} else if (config_->has_video) {
- return &mock_video_stream_;
+ return mock_video_stream_;
}
break;
case 1:
if (config_->has_audio && config_->has_video) {
- return &mock_video_stream_;
+ return mock_video_stream_;
}
break;
}
@@ -250,41 +283,9 @@ class MockDemuxer : public Demuxer {
private:
virtual ~MockDemuxer() {}
- // Internal class implements DemuxerStream interface.
- class MockDemuxerStream : public DemuxerStream {
- public:
- MockDemuxerStream(const MockFilterConfig* config, bool is_audio) {
- if (is_audio) {
- media_format_.SetAsString(MediaFormat::kMimeType,
- config->compressed_audio_mime_type);
- } else {
- media_format_.SetAsString(MediaFormat::kMimeType,
- config->compressed_video_mime_type);
- media_format_.SetAsInteger(MediaFormat::kWidth, config->video_width);
- media_format_.SetAsInteger(MediaFormat::kHeight, config->video_height);
- }
- }
-
- virtual ~MockDemuxerStream() {}
-
- // Implementation of DemuxerStream.
- virtual const MediaFormat* GetMediaFormat() {
- return &media_format_;
- }
-
- virtual void Read(Assignable<Buffer>* buffer) {
- NOTREACHED(); // TODO(ralphl): fix me!!
- }
-
- private:
- MediaFormat media_format_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDemuxerStream);
- };
-
const MockFilterConfig* config_;
- MockDemuxerStream mock_audio_stream_;
- MockDemuxerStream mock_video_stream_;
+ scoped_refptr<DemuxerStream> mock_audio_stream_;
+ scoped_refptr<DemuxerStream> mock_video_stream_;
DISALLOW_COPY_AND_ASSIGN(MockDemuxer);
};
diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc
index 67f4b9c..3e3a40d 100644
--- a/media/base/pipeline_impl.cc
+++ b/media/base/pipeline_impl.cc
@@ -418,7 +418,7 @@ void PipelineThread::Render(FilterFactory* filter_factory, Demuxer* demuxer) {
const std::string major_mime_type = Decoder::major_mime_type();
const int num_outputs = demuxer->GetNumberOfStreams();
for (int i = 0; i < num_outputs; ++i) {
- DemuxerStream* demuxer_stream = demuxer->GetStream(i);
+ scoped_refptr<DemuxerStream> demuxer_stream = demuxer->GetStream(i);
const MediaFormat* stream_format = demuxer_stream->GetMediaFormat();
std::string value;
if (stream_format->GetAsString(MediaFormat::kMimeType, &value) &&
diff --git a/media/filters/decoder_base.h b/media/filters/decoder_base.h
index 8a2ef60..685495d 100644
--- a/media/filters/decoder_base.h
+++ b/media/filters/decoder_base.h
@@ -258,7 +258,7 @@ class DecoderBase : public Decoder {
bool running_;
// Pointer to the demuxer stream that will feed us compressed buffers.
- DemuxerStream* demuxer_stream_;
+ scoped_refptr<DemuxerStream> demuxer_stream_;
// If this pointer is NULL then there is no thread dedicated to this decoder
// and decodes will happen on the pipeline thread.
diff --git a/media/filters/ffmpeg_common.cc b/media/filters/ffmpeg_common.cc
index 80ace45..875d968 100644
--- a/media/filters/ffmpeg_common.cc
+++ b/media/filters/ffmpeg_common.cc
@@ -15,4 +15,11 @@ const char kFFmpegVideo[] = "video/x-ffmpeg";
} // namespace mime_type
+
+namespace interface_id {
+
+const char kFFmpegDemuxerStream[] = "FFmpegDemuxerStream";
+
+} // namespace interface_id
+
} // namespace media
diff --git a/media/filters/ffmpeg_common.h b/media/filters/ffmpeg_common.h
index baddbb1..6a5f0e9 100644
--- a/media/filters/ffmpeg_common.h
+++ b/media/filters/ffmpeg_common.h
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#ifndef MEDIA_FILTERS_FFMPEG_COMMON_H_
+#define MEDIA_FILTERS_FFMPEG_COMMON_H_
+
// Used for FFmpeg error codes.
#include <cerrno>
@@ -30,4 +33,13 @@ extern const char kFFmpegVideo[];
} // namespace mime_type
+namespace interface_id {
+
+extern const char kFFmpegDemuxerStream[];
+
+} // namespace interface_id
+
+
} // namespace media
+
+#endif // MEDIA_FILTERS_FFMPEG_COMMON_H_
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index 472ec5bd..5fce5a4 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -49,39 +49,40 @@ class AVPacketBuffer : public Buffer {
// FFmpegDemuxerStream
//
FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer,
- const AVStream& stream)
- : demuxer_(demuxer) {
+ AVStream* stream)
+ : demuxer_(demuxer),
+ av_stream_(stream) {
DCHECK(demuxer_);
// Determine our media format.
- switch (stream.codec->codec_type) {
+ switch (stream->codec->codec_type) {
case CODEC_TYPE_AUDIO:
media_format_.SetAsString(MediaFormat::kMimeType,
mime_type::kFFmpegAudio);
media_format_.SetAsInteger(MediaFormat::kChannels,
- stream.codec->channels);
+ stream->codec->channels);
media_format_.SetAsInteger(MediaFormat::kSampleRate,
- stream.codec->sample_rate);
+ stream->codec->sample_rate);
break;
case CODEC_TYPE_VIDEO:
media_format_.SetAsString(MediaFormat::kMimeType,
mime_type::kFFmpegVideo);
media_format_.SetAsInteger(MediaFormat::kHeight,
- stream.codec->height);
+ stream->codec->height);
media_format_.SetAsInteger(MediaFormat::kWidth,
- stream.codec->width);
+ stream->codec->width);
break;
default:
NOTREACHED();
break;
}
- int codec_id = static_cast<int>(stream.codec->codec_id);
+ int codec_id = static_cast<int>(stream->codec->codec_id);
media_format_.SetAsInteger(kFFmpegCodecID, codec_id);
// Calculate the time base and duration in microseconds.
- int64 time_base_us = static_cast<int64>(av_q2d(stream.time_base) *
+ int64 time_base_us = static_cast<int64>(av_q2d(stream->time_base) *
base::Time::kMicrosecondsPerSecond);
- int64 duration_us = static_cast<int64>(time_base_us * stream.duration);
+ int64 duration_us = static_cast<int64>(time_base_us * stream->duration);
time_base_ = base::TimeDelta::FromMicroseconds(time_base_us);
duration_ = base::TimeDelta::FromMicroseconds(duration_us);
}
@@ -91,6 +92,20 @@ FFmpegDemuxerStream::~FFmpegDemuxerStream() {
// should get released.
}
+// static
+const char* FFmpegDemuxerStream::interface_id() {
+ return interface_id::kFFmpegDemuxerStream;
+}
+
+void* FFmpegDemuxerStream::QueryInterface(const char* id) {
+ DCHECK(id);
+ FFmpegDemuxerStream* interface_ptr = NULL;
+ if (0 == strcmp(id, interface_id())) {
+ interface_ptr = this;
+ }
+ return interface_ptr;
+}
+
bool FFmpegDemuxerStream::HasPendingReads() {
AutoLock auto_lock(lock_);
return !output_queue_.empty();
@@ -158,10 +173,6 @@ FFmpegDemuxer::~FFmpegDemuxer() {
if (format_context_) {
av_free(format_context_);
}
- while (!streams_.empty()) {
- delete streams_.back();
- streams_.pop_back();
- }
}
void FFmpegDemuxer::ScheduleDemux() {
@@ -215,7 +226,7 @@ bool FFmpegDemuxer::Initialize(DataSource* data_source) {
if (codec_type == CODEC_TYPE_AUDIO || codec_type == CODEC_TYPE_VIDEO) {
AVStream* stream = format_context_->streams[i];
FFmpegDemuxerStream* demuxer_stream
- = new FFmpegDemuxerStream(this, *stream);
+ = new FFmpegDemuxerStream(this, stream);
DCHECK(demuxer_stream);
streams_.push_back(demuxer_stream);
max_duration = std::max(max_duration, demuxer_stream->duration());
@@ -237,10 +248,10 @@ size_t FFmpegDemuxer::GetNumberOfStreams() {
return streams_.size();
}
-DemuxerStream* FFmpegDemuxer::GetStream(int stream) {
+scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(int stream) {
DCHECK(stream >= 0);
DCHECK(stream < static_cast<int>(streams_.size()));
- return streams_[stream];
+ return streams_[stream].get();
}
void FFmpegDemuxer::Demux() {
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h
index 895dd65..317969d 100644
--- a/media/filters/ffmpeg_demuxer.h
+++ b/media/filters/ffmpeg_demuxer.h
@@ -43,7 +43,7 @@ class FFmpegDemuxerStream : public DemuxerStream {
public:
// Maintains a reference to |demuxer| and initializes itself using information
// inside |stream|.
- FFmpegDemuxerStream(FFmpegDemuxer* demuxer, const AVStream& stream);
+ FFmpegDemuxerStream(FFmpegDemuxer* demuxer, AVStream* stream);
virtual ~FFmpegDemuxerStream();
@@ -60,11 +60,21 @@ class FFmpegDemuxerStream : public DemuxerStream {
virtual const MediaFormat* GetMediaFormat();
virtual void Read(Assignable<Buffer>* buffer);
+ AVStream* av_stream() {
+ return av_stream_;
+ }
+
+ static const char* interface_id();
+
+ protected:
+ virtual void* QueryInterface(const char* interface_id);
+
private:
// Returns true if there are still pending reads.
bool FulfillPendingReads();
FFmpegDemuxer* demuxer_;
+ AVStream* av_stream_;
MediaFormat media_format_;
base::TimeDelta time_base_;
base::TimeDelta duration_;
@@ -95,7 +105,7 @@ class FFmpegDemuxer : public Demuxer {
// Demuxer implementation.
virtual bool Initialize(DataSource* data_source);
virtual size_t GetNumberOfStreams();
- virtual DemuxerStream* GetStream(int stream_id);
+ virtual scoped_refptr<DemuxerStream> GetStream(int stream_id);
private:
// Only allow a factory to create this class.
@@ -116,7 +126,7 @@ class FFmpegDemuxer : public Demuxer {
AVFormatContext* format_context_;
// Vector of streams.
- typedef std::vector<FFmpegDemuxerStream*> StreamVector;
+ typedef std::vector< scoped_refptr<FFmpegDemuxerStream> > StreamVector;
StreamVector streams_;
DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxer);
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index 2c4ecbe..b37196d 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -241,7 +241,7 @@ TEST(FFmpegDemuxerTest, InitializeStreams) {
EXPECT_EQ(2, demuxer->GetNumberOfStreams());
// First stream should be video.
- DemuxerStream* stream = demuxer->GetStream(0);
+ scoped_refptr<DemuxerStream> stream = demuxer->GetStream(0);
ASSERT_TRUE(stream);
const MediaFormat* stream_format = stream->GetMediaFormat();
std::string mime_type;
@@ -311,11 +311,19 @@ TEST(FFmpegDemuxerTest, Read) {
EXPECT_EQ(2, demuxer->GetNumberOfStreams());
// Get our streams.
- DemuxerStream* audio_stream = demuxer->GetStream(kAudio);
- DemuxerStream* video_stream = demuxer->GetStream(kVideo);
+ scoped_refptr<DemuxerStream> audio_stream = demuxer->GetStream(kAudio);
+ scoped_refptr<DemuxerStream> video_stream = demuxer->GetStream(kVideo);
ASSERT_TRUE(audio_stream);
ASSERT_TRUE(video_stream);
+ // Both streams should support FFmpegDemuxerStream interface.
+ scoped_refptr<FFmpegDemuxerStream> ffmpeg_demuxer_stream;
+ EXPECT_TRUE(audio_stream->QueryInterface(&ffmpeg_demuxer_stream));
+ EXPECT_TRUE(ffmpeg_demuxer_stream);
+ ffmpeg_demuxer_stream = NULL;
+ EXPECT_TRUE(video_stream->QueryInterface(&ffmpeg_demuxer_stream));
+ EXPECT_TRUE(ffmpeg_demuxer_stream);
+
// Prepare our test audio packet.
g_packet.stream_index = kAudio;
g_packet.data = audio_data;