diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-27 23:13:56 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-27 23:13:56 +0000 |
commit | e2026714d2735956dcd079100bc4039de33b9bdd (patch) | |
tree | fec01da639c32fe5988699280a0b9b50ff8f30b2 /media | |
parent | 63c339b3d57a95d3caf47558cae6cef1ef23b676 (diff) | |
download | chromium_src-e2026714d2735956dcd079100bc4039de33b9bdd.zip chromium_src-e2026714d2735956dcd079100bc4039de33b9bdd.tar.gz chromium_src-e2026714d2735956dcd079100bc4039de33b9bdd.tar.bz2 |
Implements video decoder filter for OpenMAX
OpenMAX needs to stay in a separate filter. This greatly reduces the
communications between different layers.
Review URL: http://codereview.chromium.org/2168003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@48446 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/filters/omx_video_decoder.cc | 111 | ||||
-rw-r--r-- | media/filters/omx_video_decoder.h | 42 | ||||
-rw-r--r-- | media/filters/video_decode_engine.h | 6 |
3 files changed, 141 insertions, 18 deletions
diff --git a/media/filters/omx_video_decoder.cc b/media/filters/omx_video_decoder.cc index 8f9a992..f3fd0c2 100644 --- a/media/filters/omx_video_decoder.cc +++ b/media/filters/omx_video_decoder.cc @@ -6,7 +6,10 @@ #include "base/callback.h" #include "base/waitable_event.h" +#include "media/base/factory.h" +#include "media/base/filter_host.h" #include "media/ffmpeg/ffmpeg_common.h" +#include "media/filters/ffmpeg_interfaces.h" #include "media/filters/omx_video_decode_engine.h" namespace media { @@ -37,26 +40,35 @@ bool OmxVideoDecoder::IsMediaFormatSupported(const MediaFormat& format) { } OmxVideoDecoder::OmxVideoDecoder(OmxVideoDecodeEngine* engine) - : VideoDecoderImpl(engine), - omx_engine_(engine) { + : omx_engine_(engine) { #if defined(ENABLE_EGLIMAGE) supports_egl_image_ = true; #else supports_egl_image_ = false; #endif + DCHECK(omx_engine_.get()); } OmxVideoDecoder::~OmxVideoDecoder() { + // TODO(hclam): Make sure OmxVideoDecodeEngine is stopped. } -void OmxVideoDecoder::DoInitialize(DemuxerStream* demuxer_stream, - bool* success, - Task* done_cb) { - if (supports_egl_image_) - media_format_.SetAsString(MediaFormat::kMimeType, - mime_type::kUncompressedVideoEglImage); +void OmxVideoDecoder::Initialize(DemuxerStream* stream, + FilterCallback* callback) { + message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(this, + &OmxVideoDecoder::DoInitialize, + stream, + callback)); +} - VideoDecoderImpl::DoInitialize(demuxer_stream, success, done_cb); +void OmxVideoDecoder::FillThisBuffer(scoped_refptr<VideoFrame> frame) { + DCHECK(omx_engine_.get()); + message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(omx_engine_.get(), + &OmxVideoDecodeEngine::FillThisBuffer, frame)); } void OmxVideoDecoder::Stop() { @@ -66,4 +78,85 @@ void OmxVideoDecoder::Stop() { event.Wait(); } +void OmxVideoDecoder::DoInitialize(DemuxerStream* demuxer_stream, + FilterCallback* callback) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + + // Sets the output format. + if (supports_egl_image_) { + media_format_.SetAsString(MediaFormat::kMimeType, + mime_type::kUncompressedVideoEglImage); + } + + // Savs the demuxer stream. + demuxer_stream_ = demuxer_stream; + + // Get the AVStream by querying for the provider interface. + AVStreamProvider* av_stream_provider; + if (!demuxer_stream->QueryInterface(&av_stream_provider)) + return; + AVStream* av_stream = av_stream_provider->GetAVStream(); + + // Initialize the decode engine. + omx_engine_->Initialize( + message_loop(), + av_stream, + NewCallback(this, &OmxVideoDecoder::EmptyBufferCallback), + NewCallback(this, &OmxVideoDecoder::FillBufferCallback), + NewRunnableMethod(this, &OmxVideoDecoder::InitCompleteTask, callback)); +} + +void OmxVideoDecoder::FillBufferCallback(scoped_refptr<VideoFrame> frame) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + + // Invoke the FillBufferDoneCallback with the frame. + DCHECK(fill_buffer_done_callback()); + fill_buffer_done_callback()->Run(frame); +} + +void OmxVideoDecoder::EmptyBufferCallback(scoped_refptr<Buffer> buffer) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + + // Issue more demux. + demuxer_stream_->Read(NewCallback(this, &OmxVideoDecoder::DemuxCompleteTask)); +} + +void OmxVideoDecoder::InitCompleteTask(FilterCallback* callback) { + DCHECK_EQ(message_loop(), MessageLoop::current()); + + // Check the status of the decode engine. + if (omx_engine_->state() == VideoDecodeEngine::kError) + host()->SetError(PIPELINE_ERROR_DECODE); + else + InitialDemux(); + + callback->Run(); + delete callback; +} + +void OmxVideoDecoder::DemuxCompleteTask(Buffer* buffer) { + // We simply delicate the buffer to the right message loop. + scoped_refptr<Buffer> ref_buffer = buffer; + DCHECK(omx_engine_.get()); + message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(omx_engine_.get(), + &OmxVideoDecodeEngine::EmptyThisBuffer, ref_buffer)); +} + +void OmxVideoDecoder::InitialDemux() { + DCHECK_EQ(message_loop(), MessageLoop::current()); + + // This is the right time to issue read to the demuxer. The first thing we + // need to do here is to determine how many we should read from the + // demuxer. + // TODO(hclam): Query this number from |omx_engine_|. + const int kDemuxPackets = 2; + DCHECK(demuxer_stream_); + for (int i = 0; i < kDemuxPackets; ++i) { + demuxer_stream_->Read( + NewCallback(this, &OmxVideoDecoder::DemuxCompleteTask)); + } +} + } // namespace media diff --git a/media/filters/omx_video_decoder.h b/media/filters/omx_video_decoder.h index 22aa56a..c406095 100644 --- a/media/filters/omx_video_decoder.h +++ b/media/filters/omx_video_decoder.h @@ -5,33 +5,59 @@ #ifndef MEDIA_FILTERS_OMX_VIDEO_DECODER_H_ #define MEDIA_FILTERS_OMX_VIDEO_DECODER_H_ -#include "media/filters/video_decoder_impl.h" +#include <queue> + +#include "media/base/filters.h" +#include "media/base/media_format.h" class MessageLoop; namespace media { +class Buffer; class FilterFactory; -class MediaFormat; class OmxVideoDecodeEngine; +class VideoFrame; -class OmxVideoDecoder : public VideoDecoderImpl { +class OmxVideoDecoder : public VideoDecoder { public: + typedef Callback1<VideoFrame*>::Type ReadCallback; + static FilterFactory* CreateFactory(); static bool IsMediaFormatSupported(const MediaFormat& media_format); OmxVideoDecoder(OmxVideoDecodeEngine* engine); virtual ~OmxVideoDecoder(); + virtual void Initialize(DemuxerStream* stream, FilterCallback* callback); virtual void Stop(); - - protected: - void DoInitialize(DemuxerStream* demuxer_stream, bool* success, - Task* done_cb); + virtual void FillThisBuffer(scoped_refptr<VideoFrame> frame); + virtual const MediaFormat& media_format() { return media_format_; } private: + virtual void DoInitialize(DemuxerStream* stream, FilterCallback* callback); + + // Called after the decode engine has successfully decoded something. + void FillBufferCallback(scoped_refptr<VideoFrame> frame); + + // Called after the decode engine has consumed an input buffer. + void EmptyBufferCallback(scoped_refptr<Buffer> buffer); + + void InitCompleteTask(FilterCallback* callback); + // TODO(hclam): This is very ugly that we keep reference instead of + // scoped_refptr. + void DemuxCompleteTask(Buffer* buffer); + + // Calls |omx_engine_|'s EmptyThisBuffer() method on the right thread. + void EmptyBufferTask(scoped_refptr<Buffer> buffer); + + // Helper method to do the initial demuxing. + void InitialDemux(); + + DemuxerStream* demuxer_stream_; bool supports_egl_image_; - OmxVideoDecodeEngine* omx_engine_; + scoped_refptr<OmxVideoDecodeEngine> omx_engine_; + MediaFormat media_format_; DISALLOW_COPY_AND_ASSIGN(OmxVideoDecoder); }; diff --git a/media/filters/video_decode_engine.h b/media/filters/video_decode_engine.h index 2cc767a..f0ff923 100644 --- a/media/filters/video_decode_engine.h +++ b/media/filters/video_decode_engine.h @@ -32,7 +32,12 @@ class VideoDecodeEngine { VideoDecodeEngine() {} virtual ~VideoDecodeEngine() {} + // This calback is called by the decode engine to notify that the decode + // engine has consumed an input bufer in response to a EmptyThisBuffer() call. typedef Callback1<scoped_refptr<Buffer> >::Type EmptyThisBufferCallback; + + // This callback is called by the decode engine to notify that a video + // frame is ready to be consumed in reaponse to a FillThisBuffer() call. typedef Callback1<scoped_refptr<VideoFrame> >::Type FillThisBufferCallback; // Initialized the engine. On successful Initialization, state() should @@ -55,7 +60,6 @@ class VideoDecodeEngine { // 2. Output buffers are provided from outside the engine, and feed into // engine through |FillThisBuffer|. Output buffers are returned to outside // by |FillThisBufferCallback|. - virtual void EmptyThisBuffer(scoped_refptr<Buffer> buffer) = 0; virtual void FillThisBuffer(scoped_refptr<VideoFrame> frame) { NOTREACHED(); |