diff options
author | ralphl@chromium.org <ralphl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-26 04:20:48 +0000 |
---|---|---|
committer | ralphl@chromium.org <ralphl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-26 04:20:48 +0000 |
commit | 636cf88fc365a7c62cc3318f149b3919d148f5d0 (patch) | |
tree | 520002c5b36dfbffac1229bddf04b0721981a5f8 /media | |
parent | d815db156387600cdad5466be6b172421df420d8 (diff) | |
download | chromium_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.h | 24 | ||||
-rw-r--r-- | media/base/mock_media_filters.h | 81 | ||||
-rw-r--r-- | media/base/pipeline_impl.cc | 2 | ||||
-rw-r--r-- | media/filters/decoder_base.h | 2 | ||||
-rw-r--r-- | media/filters/ffmpeg_common.cc | 7 | ||||
-rw-r--r-- | media/filters/ffmpeg_common.h | 12 | ||||
-rw-r--r-- | media/filters/ffmpeg_demuxer.cc | 45 | ||||
-rw-r--r-- | media/filters/ffmpeg_demuxer.h | 16 | ||||
-rw-r--r-- | media/filters/ffmpeg_demuxer_unittest.cc | 14 |
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; |