Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(638)

Unified Diff: media/filters/decoder_base.h

Issue 465044: Refactor FFmpegVideoDecoder to try and generalize code common to all video decoders. (Closed)
Patch Set: Fix SCOPED_TRACE since VS faults on %zd. Created 11 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/ffmpeg/ffmpeg_util.cc ('k') | media/filters/ffmpeg_audio_decoder.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/decoder_base.h
diff --git a/media/filters/decoder_base.h b/media/filters/decoder_base.h
index a2289581508887dee0bbf30b18ebd3a0cf22a976..cc403bcd11eb91b36fccb9159396e4ad83a076ad 100644
--- a/media/filters/decoder_base.h
+++ b/media/filters/decoder_base.h
@@ -14,6 +14,7 @@
#include "base/task.h"
#include "base/thread.h"
#include "media/base/buffers.h"
+#include "media/base/callback.h"
#include "media/base/filters.h"
#include "media/base/filter_host.h"
@@ -55,17 +56,6 @@ class DecoderBase : public Decoder {
NewRunnableMethod(this, &DecoderBase::ReadTask, read_callback));
}
- void OnReadComplete(Buffer* buffer) {
- // Little bit of magic here to get NewRunnableMethod() to generate a Task
- // that holds onto a reference via scoped_refptr<>.
- //
- // TODO(scherkus): change the callback format to pass a scoped_refptr<> or
- // better yet see if we can get away with not using reference counting.
- scoped_refptr<Buffer> buffer_ref = buffer;
- this->message_loop()->PostTask(FROM_HERE,
- NewRunnableMethod(this, &DecoderBase::ReadCompleteTask, buffer_ref));
- }
-
protected:
DecoderBase()
: pending_reads_(0),
@@ -89,6 +79,12 @@ class DecoderBase : public Decoder {
}
}
+ // TODO(ajwong): All these "Task*" used as completion callbacks should be
+ // FilterCallbacks. However, since NewCallback() cannot prebind parameters,
+ // we use NewRunnableMethod() instead which causes an unfortunate refcount.
+ // We should move stoyan's Mutant code into base/task.h and turn these
+ // back into FilterCallbacks.
+
// Method that must be implemented by the derived class. Called from within
// the DecoderBase::Initialize() method before any reads are submitted to
// the demuxer stream. Returns true if successful, otherwise false indicates
@@ -96,32 +92,46 @@ class DecoderBase : public Decoder {
// InitializationComplete() method. If this method returns true, then the
// base class will call the host to complete initialization. During this
// call, the derived class must fill in the media_format_ member.
- virtual bool OnInitialize(DemuxerStream* demuxer_stream) = 0;
+ virtual void DoInitialize(DemuxerStream* demuxer_stream, bool* success,
+ Task* done_cb) = 0;
// Method that may be implemented by the derived class if desired. It will
// be called from within the MediaFilter::Stop() method prior to stopping the
// base class.
- virtual void OnStop() {}
+ //
+ // TODO(ajwong): Make this asynchronous.
+ virtual void DoStop() {}
// Derived class can implement this method and perform seeking logic prior
// to the base class.
- virtual void OnSeek(base::TimeDelta time) {}
+ virtual void DoSeek(base::TimeDelta time, Task* done_cb) = 0;
// Method that must be implemented by the derived class. If the decode
// operation produces one or more outputs, the derived class should call
// the EnequeueResult() method from within this method.
- virtual void OnDecode(Buffer* input) = 0;
+ virtual void DoDecode(Buffer* input, Task* done_cb) = 0;
MediaFormat media_format_;
private:
bool IsStopped() { return state_ == kStopped; }
+ void OnReadComplete(Buffer* buffer) {
+ // Little bit of magic here to get NewRunnableMethod() to generate a Task
+ // that holds onto a reference via scoped_refptr<>.
+ //
+ // TODO(scherkus): change the callback format to pass a scoped_refptr<> or
+ // better yet see if we can get away with not using reference counting.
+ scoped_refptr<Buffer> buffer_ref = buffer;
+ this->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &DecoderBase::ReadCompleteTask, buffer_ref));
+ }
+
void StopTask() {
DCHECK_EQ(MessageLoop::current(), this->message_loop());
// Delegate to the subclass first.
- OnStop();
+ DoStop();
// Throw away all buffers in all queues.
result_queue_.clear();
@@ -133,7 +143,6 @@ class DecoderBase : public Decoder {
DCHECK_EQ(MessageLoop::current(), this->message_loop());
DCHECK_EQ(0u, pending_reads_) << "Pending reads should have completed";
DCHECK(read_queue_.empty()) << "Read requests should be empty";
- scoped_ptr<FilterCallback> c(callback);
// Delegate to the subclass first.
//
@@ -142,8 +151,11 @@ class DecoderBase : public Decoder {
// either flush their buffers here or wait for IsDiscontinuous(). I'm
// inclined to say that they should still wait for IsDiscontinuous() so they
// don't have duplicated logic for Seek() and actual discontinuous frames.
- OnSeek(time);
+ DoSeek(time,
+ NewRunnableMethod(this, &DecoderBase::OnSeekComplete, callback));
+ }
+ void OnSeekComplete(FilterCallback* callback) {
// Flush our decoded results. We'll set a boolean that we can DCHECK to
// verify our assertion that the first buffer received after a Seek() should
// always be discontinuous.
@@ -158,20 +170,30 @@ class DecoderBase : public Decoder {
DCHECK_EQ(MessageLoop::current(), this->message_loop());
CHECK(kUninitialized == state_);
CHECK(!demuxer_stream_);
- scoped_ptr<FilterCallback> c(callback);
demuxer_stream_ = demuxer_stream;
+ bool* success = new bool;
+ DoInitialize(demuxer_stream,
+ success,
+ NewRunnableMethod(this, &DecoderBase::OnInitializeComplete,
+ success, callback));
+ }
+
+ void OnInitializeComplete(bool* success, FilterCallback* done_cb) {
+ // Note: The done_runner must be declared *last* to ensure proper
+ // destruction order.
+ scoped_ptr<bool> success_deleter(success);
+ AutoCallbackRunner done_runner(done_cb);
+
+ DCHECK_EQ(MessageLoop::current(), this->message_loop());
// Delegate to subclass first.
- if (!OnInitialize(demuxer_stream_)) {
+ if (!*success) {
this->host()->SetError(PIPELINE_ERROR_DECODE);
- callback->Run();
- return;
+ } else {
+ // TODO(scherkus): subclass shouldn't mutate superclass media format.
+ DCHECK(!media_format_.empty()) << "Subclass did not set media_format_";
+ state_ = kInitialized;
}
-
- // TODO(scherkus): subclass shouldn't mutate superclass media format.
- DCHECK(!media_format_.empty()) << "Subclass did not set media_format_";
- state_ = kInitialized;
- callback->Run();
}
void ReadTask(ReadCallback* read_callback) {
@@ -210,8 +232,10 @@ class DecoderBase : public Decoder {
}
// Decode the frame right away.
- OnDecode(buffer);
+ DoDecode(buffer, NewRunnableMethod(this, &DecoderBase::OnDecodeComplete));
+ }
+ void OnDecodeComplete() {
// Attempt to fulfill a pending read callback and schedule additional reads
// if necessary.
FulfillPendingRead();
« no previous file with comments | « media/ffmpeg/ffmpeg_util.cc ('k') | media/filters/ffmpeg_audio_decoder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698