Merge "MediaCodec refactoring part 2-a: introduce callback"
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index 27bb8db..12bbfd1 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -59,6 +59,114 @@
     oldhandler(signum);
 }
 
+namespace {
+
+enum {
+    kWhatFillThisBuffer      = 'fill',
+    kWhatDrainThisBuffer     = 'drai',
+    kWhatEOS                 = 'eos ',
+    kWhatStopCompleted       = 'scom',
+    kWhatReleaseCompleted    = 'rcom',
+    kWhatFlushCompleted      = 'fcom',
+    kWhatError               = 'erro',
+};
+
+class Sf2Callback : public CodecBase::Callback {
+public:
+    explicit Sf2Callback(const sp<AMessage> &notify);
+    ~Sf2Callback();
+
+    virtual void fillThisBuffer(IOMX::buffer_id bufferId, const sp<MediaCodecBuffer> &buffer,
+            const sp<AMessage> &reply) override;
+    virtual void drainThisBuffer(IOMX::buffer_id bufferId, const sp<MediaCodecBuffer> &buffer,
+            int32_t flags, const sp<AMessage> &reply) override;
+    virtual void onEos(status_t err) override;
+    virtual void onStopCompleted() override;
+    virtual void onReleaseCompleted() override;
+    virtual void onFlushCompleted() override;
+    virtual void onError(status_t err, enum ActionCode actionCode) override;
+    // Events below are not handled; thus ignore.
+    virtual void onComponentAllocated(const char *) override {}
+    virtual void onComponentConfigured(const sp<AMessage> &, const sp<AMessage> &) override {}
+    virtual void onInputSurfaceCreated(
+            const sp<AMessage> &,
+            const sp<AMessage> &,
+            const sp<BufferProducerWrapper> &) override {}
+    virtual void onInputSurfaceCreationFailed(status_t) override {}
+    virtual void onInputSurfaceAccepted(const sp<AMessage> &, const sp<AMessage> &) override {}
+    virtual void onInputSurfaceDeclined(status_t) override {}
+    virtual void onSignaledInputEOS(status_t) override {}
+    virtual void onBuffersAllocated(int32_t, const sp<CodecBase::PortDescription> &) override {}
+    virtual void onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &) override {}
+private:
+    const sp<AMessage> mNotify;
+};
+
+Sf2Callback::Sf2Callback(const sp<AMessage> &notify) : mNotify(notify) {}
+
+Sf2Callback::~Sf2Callback() {}
+
+void Sf2Callback::fillThisBuffer(
+        IOMX::buffer_id bufferId,
+        const sp<MediaCodecBuffer> &buffer,
+        const sp<AMessage> &reply) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatFillThisBuffer);
+    notify->setInt32("buffer-id", bufferId);
+    notify->setObject("buffer", buffer);
+    notify->setMessage("reply", reply);
+    notify->post();
+}
+
+void Sf2Callback::drainThisBuffer(
+        IOMX::buffer_id bufferId,
+        const sp<MediaCodecBuffer> &buffer,
+        int32_t flags,
+        const sp<AMessage> &reply) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatDrainThisBuffer);
+    notify->setInt32("buffer-id", bufferId);
+    notify->setObject("buffer", buffer);
+    notify->setInt32("flags", flags);
+    notify->setMessage("reply", reply);
+    notify->post();
+}
+
+void Sf2Callback::onEos(status_t err) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatEOS);
+    notify->setInt32("err", err);
+    notify->post();
+}
+
+void Sf2Callback::onStopCompleted() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatStopCompleted);
+    notify->post();
+}
+
+void Sf2Callback::onReleaseCompleted() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatReleaseCompleted);
+    notify->post();
+}
+
+void Sf2Callback::onFlushCompleted() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatFlushCompleted);
+    notify->post();
+}
+
+void Sf2Callback::onError(status_t err, enum ActionCode actionCode) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatError);
+    notify->setInt32("err", err);
+    notify->setInt32("actionCode", actionCode);
+    notify->post();
+}
+
+}  // namespace
+
 struct Controller : public AHandler {
     Controller(const char *uri, bool decodeAudio,
                const sp<Surface> &surface, bool renderToSurface)
@@ -148,8 +256,8 @@
 
                 mDecodeLooper->registerHandler(mCodec);
 
-                mCodec->setNotificationMessage(
-                        new AMessage(kWhatCodecNotify, this));
+                mCodec->setCallback(
+                        std::make_shared<Sf2Callback>(new AMessage(kWhatCodecNotify, this)));
 
                 sp<AMessage> format = makeFormat(mSource->getFormat());
 
@@ -210,28 +318,28 @@
                 int32_t what;
                 CHECK(msg->findInt32("what", &what));
 
-                if (what == CodecBase::kWhatFillThisBuffer) {
+                if (what == kWhatFillThisBuffer) {
                     onFillThisBuffer(msg);
-                } else if (what == CodecBase::kWhatDrainThisBuffer) {
+                } else if (what == kWhatDrainThisBuffer) {
                     if ((mNumOutputBuffersReceived++ % 16) == 0) {
                         printf(".");
                         fflush(stdout);
                     }
 
                     onDrainThisBuffer(msg);
-                } else if (what == CodecBase::kWhatEOS
-                        || what == CodecBase::kWhatError) {
-                    printf((what == CodecBase::kWhatEOS) ? "$\n" : "E\n");
+                } else if (what == kWhatEOS
+                        || what == kWhatError) {
+                    printf((what == kWhatEOS) ? "$\n" : "E\n");
 
                     printStatistics();
                     (new AMessage(kWhatStop, this))->post();
-                } else if (what == CodecBase::kWhatFlushCompleted) {
+                } else if (what == kWhatFlushCompleted) {
                     mSeekState = SEEK_FLUSH_COMPLETED;
                     mCodec->signalResume();
 
                     (new AMessage(kWhatSeek, this))->post(5000000ll);
-                } else if (what == CodecBase::kWhatStopCompleted ||
-                        what == CodecBase::kWhatReleaseCompleted) {
+                } else if (what == kWhatStopCompleted ||
+                        what == kWhatReleaseCompleted) {
                     mDecodeLooper->unregisterHandler(mCodec->id());
 
                     if (mDecodeLooper != looper()) {
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index 39a9089..25b8bf8 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -18,12 +18,15 @@
 
 #define CODEC_BASE_H_
 
+#include <memory>
+
 #include <stdint.h>
 
 #define STRINGIFY_ENUMS
 
 #include <media/IOMX.h>
 #include <media/MediaCodecInfo.h>
+#include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/foundation/AHandler.h>
 #include <media/stagefright/foundation/ColorUtils.h>
 #include <media/hardware/HardwareAPI.h>
@@ -34,33 +37,159 @@
 
 namespace android {
 
+class BufferProducerWrapper;
 class MediaCodecBuffer;
 struct PersistentSurface;
+struct RenderedFrameInfo;
 class Surface;
 
 struct CodecBase : public AHandler, /* static */ ColorUtils {
-    enum {
-        kWhatFillThisBuffer      = 'fill',
-        kWhatDrainThisBuffer     = 'drai',
-        kWhatEOS                 = 'eos ',
-        kWhatStopCompleted       = 'scom',
-        kWhatReleaseCompleted    = 'rcom',
-        kWhatFlushCompleted      = 'fcom',
-        kWhatError               = 'erro',
-        kWhatComponentAllocated  = 'cAll',
-        kWhatComponentConfigured = 'cCon',
-        kWhatInputSurfaceCreated = 'isfc',
-        kWhatInputSurfaceAccepted = 'isfa',
-        kWhatSignaledInputEOS    = 'seos',
-        kWhatBuffersAllocated    = 'allc',
-        kWhatOutputFramesRendered = 'outR',
+    struct PortDescription;
+
+    /**
+     * This interface defines events firing from CodecBase back to MediaCodec.
+     * All methods must not block.
+     */
+    class Callback {
+    public:
+        virtual ~Callback() = default;
+
+        /**
+         * Request MediaCodec to fill the specified input buffer.
+         *
+         * @param bufferId  ID of the buffer, assigned by underlying component.
+         * @param buffer    a buffer to be filled.
+         * @param reply     a message to post once MediaCodec has filled the
+         *                  buffer.
+         */
+        virtual void fillThisBuffer(
+                IOMX::buffer_id bufferId,
+                const sp<MediaCodecBuffer> &buffer,
+                const sp<AMessage> &reply) = 0;
+        /**
+         * Request MediaCodec to drain the specified output buffer.
+         *
+         * @param bufferId  ID of the buffer, assigned by underlying component.
+         * @param buffer    a buffer to be filled.
+         * @param flags     flags associated with this buffer (e.g. EOS).
+         * @param reply     a message to post once MediaCodec has filled the
+         *                  buffer.
+         */
+        virtual void drainThisBuffer(
+                IOMX::buffer_id bufferId,
+                const sp<MediaCodecBuffer> &buffer,
+                int32_t flags,
+                const sp<AMessage> &reply) = 0;
+        /**
+         * Notify MediaCodec for seeing an output EOS.
+         *
+         * @param err the underlying cause of the EOS. If the value is neither
+         *            OK nor ERROR_END_OF_STREAM, the EOS is declared
+         *            prematurely for that error.
+         */
+        virtual void onEos(status_t err) = 0;
+        /**
+         * Notify MediaCodec that stop operation is complete.
+         */
+        virtual void onStopCompleted() = 0;
+        /**
+         * Notify MediaCodec that release operation is complete.
+         */
+        virtual void onReleaseCompleted() = 0;
+        /**
+         * Notify MediaCodec that flush operation is complete.
+         */
+        virtual void onFlushCompleted() = 0;
+        /**
+         * Notify MediaCodec that an error is occurred.
+         *
+         * @param err         an error code for the occurred error.
+         * @param actionCode  an action code for severity of the error.
+         */
+        virtual void onError(status_t err, enum ActionCode actionCode) = 0;
+        /**
+         * Notify MediaCodec that the underlying component is allocated.
+         *
+         * @param componentName the unique name of the component specified in
+         *                      MediaCodecList.
+         */
+        virtual void onComponentAllocated(const char *componentName) = 0;
+        /**
+         * Notify MediaCodec that the underlying component is configured.
+         *
+         * @param inputFormat   an input format at configure time.
+         * @param outputFormat  an output format at configure time.
+         */
+        virtual void onComponentConfigured(
+                const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) = 0;
+        /**
+         * Notify MediaCodec that the input surface is created.
+         *
+         * @param inputFormat   an input format at surface creation. Formats
+         *                      could change from the previous state as a result
+         *                      of creating a surface.
+         * @param outputFormat  an output format at surface creation.
+         * @param inputSurface  the created surface.
+         */
+        virtual void onInputSurfaceCreated(
+                const sp<AMessage> &inputFormat,
+                const sp<AMessage> &outputFormat,
+                const sp<BufferProducerWrapper> &inputSurface) = 0;
+        /**
+         * Notify MediaCodec that the input surface creation is failed.
+         *
+         * @param err an error code of the cause.
+         */
+        virtual void onInputSurfaceCreationFailed(status_t err) = 0;
+        /**
+         * Notify MediaCodec that the component accepted the provided input
+         * surface.
+         *
+         * @param inputFormat   an input format at surface assignment. Formats
+         *                      could change from the previous state as a result
+         *                      of assigning a surface.
+         * @param outputFormat  an output format at surface assignment.
+         */
+        virtual void onInputSurfaceAccepted(
+                const sp<AMessage> &inputFormat,
+                const sp<AMessage> &outputFormat) = 0;
+        /**
+         * Notify MediaCodec that the component declined the provided input
+         * surface.
+         *
+         * @param err an error code of the cause.
+         */
+        virtual void onInputSurfaceDeclined(status_t err) = 0;
+        /**
+         * Noitfy MediaCodec that the requested input EOS is sent to the input
+         * surface.
+         *
+         * @param err an error code returned from the surface. If there is no
+         *            input surface, the value is INVALID_OPERATION.
+         */
+        virtual void onSignaledInputEOS(status_t err) = 0;
+        /**
+         * Notify MediaCodec with the allocated buffers.
+         *
+         * @param portIndex zero for input port, one for output port.
+         * @param portDesc  a PortDescription object containing allocated
+         *                  buffers.
+         */
+        virtual void onBuffersAllocated(int32_t portIndex, const sp<PortDescription> &portDesc) = 0;
+        /**
+         * Notify MediaCodec that output frames are rendered with information on
+         * those frames.
+         *
+         * @param done  a list of rendered frames.
+         */
+        virtual void onOutputFramesRendered(const std::list<RenderedFrameInfo> &done) = 0;
     };
 
     enum {
         kMaxCodecBufferSize = 8192 * 4096 * 4, // 8K RGBA
     };
 
-    virtual void setNotificationMessage(const sp<AMessage> &msg) = 0;
+    void setCallback(std::shared_ptr<Callback> &&callback);
 
     virtual void initiateAllocateComponent(const sp<AMessage> &msg) = 0;
     virtual void initiateConfigureComponent(const sp<AMessage> &msg) = 0;
@@ -107,6 +236,8 @@
     CodecBase();
     virtual ~CodecBase();
 
+    std::shared_ptr<Callback> mCallback;
+
 private:
     DISALLOW_EVIL_CONSTRUCTORS(CodecBase);
 };
diff --git a/include/media/stagefright/FrameRenderTracker.h b/include/media/stagefright/FrameRenderTracker.h
index 8396657..6c572b8 100644
--- a/include/media/stagefright/FrameRenderTracker.h
+++ b/include/media/stagefright/FrameRenderTracker.h
@@ -32,58 +32,61 @@
 class Fence;
 class GraphicBuffer;
 
+// Tracks the render information about a frame. Frames go through several states while
+// the render information is tracked:
+//
+// 1. queued frame: mMediaTime and mGraphicBuffer are set for the frame. mFence is the
+// queue fence (read fence). mIndex is negative, and mRenderTimeNs is invalid.
+// Key characteristics: mFence is not NULL and mIndex is negative.
+//
+// 2. dequeued frame: mFence is updated with the dequeue fence (write fence). mIndex is set.
+// Key characteristics: mFence is not NULL and mIndex is non-negative. mRenderTime is still
+// invalid.
+//
+// 3. rendered frame or frame: mFence is cleared, mRenderTimeNs is set.
+// Key characteristics: mFence is NULL.
+//
+struct RenderedFrameInfo {
+    // set by client during onFrameQueued or onFrameRendered
+    int64_t getMediaTimeUs() const  { return mMediaTimeUs; }
+
+    // -1 if frame is not yet rendered
+    nsecs_t getRenderTimeNs() const { return mRenderTimeNs; }
+
+    // set by client during updateRenderInfoForDequeuedBuffer; -1 otherwise
+    ssize_t getIndex() const        { return mIndex; }
+
+    // creates information for a queued frame
+    RenderedFrameInfo(int64_t mediaTimeUs, const sp<GraphicBuffer> &graphicBuffer,
+            const sp<Fence> &fence)
+        : mMediaTimeUs(mediaTimeUs),
+          mRenderTimeNs(-1),
+          mIndex(-1),
+          mGraphicBuffer(graphicBuffer),
+          mFence(fence) {
+    }
+
+    // creates information for a frame rendered on a tunneled surface
+    RenderedFrameInfo(int64_t mediaTimeUs, nsecs_t renderTimeNs)
+        : mMediaTimeUs(mediaTimeUs),
+          mRenderTimeNs(renderTimeNs),
+          mIndex(-1),
+          mGraphicBuffer(NULL),
+          mFence(NULL) {
+    }
+
+private:
+    int64_t mMediaTimeUs;
+    nsecs_t mRenderTimeNs;
+    ssize_t mIndex;         // to be used by client
+    sp<GraphicBuffer> mGraphicBuffer;
+    sp<Fence> mFence;
+
+    friend class FrameRenderTracker;
+};
+
 struct FrameRenderTracker {
-    // Tracks the render information about a frame. Frames go through several states while
-    // the render information is tracked:
-    //
-    // 1. queued frame: mMediaTime and mGraphicBuffer are set for the frame. mFence is the
-    // queue fence (read fence). mIndex is negative, and mRenderTimeNs is invalid.
-    // Key characteristics: mFence is not NULL and mIndex is negative.
-    //
-    // 2. dequeued frame: mFence is updated with the dequeue fence (write fence). mIndex is set.
-    // Key characteristics: mFence is not NULL and mIndex is non-negative. mRenderTime is still
-    // invalid.
-    //
-    // 3. rendered frame or frame: mFence is cleared, mRenderTimeNs is set.
-    // Key characteristics: mFence is NULL.
-    //
-    struct Info {
-        // set by client during onFrameQueued or onFrameRendered
-        int64_t getMediaTimeUs() const  { return mMediaTimeUs; }
-
-        // -1 if frame is not yet rendered
-        nsecs_t getRenderTimeNs() const { return mRenderTimeNs; }
-
-        // set by client during updateRenderInfoForDequeuedBuffer; -1 otherwise
-        ssize_t getIndex() const        { return mIndex; }
-
-        // creates information for a queued frame
-        Info(int64_t mediaTimeUs, const sp<GraphicBuffer> &graphicBuffer, const sp<Fence> &fence)
-            : mMediaTimeUs(mediaTimeUs),
-              mRenderTimeNs(-1),
-              mIndex(-1),
-              mGraphicBuffer(graphicBuffer),
-              mFence(fence) {
-        }
-
-        // creates information for a frame rendered on a tunneled surface
-        Info(int64_t mediaTimeUs, nsecs_t renderTimeNs)
-            : mMediaTimeUs(mediaTimeUs),
-              mRenderTimeNs(renderTimeNs),
-              mIndex(-1),
-              mGraphicBuffer(NULL),
-              mFence(NULL) {
-        }
-
-    private:
-        int64_t mMediaTimeUs;
-        nsecs_t mRenderTimeNs;
-        ssize_t mIndex;         // to be used by client
-        sp<GraphicBuffer> mGraphicBuffer;
-        sp<Fence> mFence;
-
-        friend class FrameRenderTracker;
-    };
+    typedef RenderedFrameInfo Info;
 
     FrameRenderTracker();
 
diff --git a/include/media/stagefright/MediaFilter.h b/include/media/stagefright/MediaFilter.h
index 0e39431..a0e580b 100644
--- a/include/media/stagefright/MediaFilter.h
+++ b/include/media/stagefright/MediaFilter.h
@@ -28,8 +28,6 @@
 struct MediaFilter : public CodecBase {
     MediaFilter();
 
-    virtual void setNotificationMessage(const sp<AMessage> &msg);
-
     virtual void initiateAllocateComponent(const sp<AMessage> &msg);
     virtual void initiateConfigureComponent(const sp<AMessage> &msg);
     virtual void initiateCreateInputSurface();
@@ -120,7 +118,6 @@
     int32_t mColorFormatIn, mColorFormatOut;
     size_t mMaxInputSize, mMaxOutputSize;
     int32_t mGeneration;
-    sp<AMessage> mNotify;
     sp<AMessage> mInputFormat;
     sp<AMessage> mOutputFormat;
 
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 4a02289..a0c8ace 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -934,20 +934,12 @@
         return err;
     }
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatBuffersAllocated);
-
-    notify->setInt32("portIndex", portIndex);
-
     sp<PortDescription> desc = new PortDescription;
-
     for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
         const BufferInfo &info = mBuffers[portIndex][i];
         desc->addBuffer(info.mBufferID, info.mData);
     }
-
-    notify->setObject("portDesc", desc);
-    notify->post();
+    mCallback->onBuffersAllocated(portIndex, desc);
 
     return OK;
 }
@@ -1309,8 +1301,6 @@
 }
 
 void ACodec::notifyOfRenderedFrames(bool dropIncomplete, FrameRenderTracker::Info *until) {
-    sp<AMessage> msg = mNotify->dup();
-    msg->setInt32("what", CodecBase::kWhatOutputFramesRendered);
     std::list<FrameRenderTracker::Info> done =
         mRenderTracker.checkFencesAndGetRenderedFrames(until, dropIncomplete);
 
@@ -1326,9 +1316,7 @@
         }
     }
 
-    if (MediaCodec::CreateFramesRenderedMessage(done, msg)) {
-        msg->post();
-    }
+    mCallback->onOutputFramesRendered(done);
 }
 
 ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {
@@ -5118,8 +5106,6 @@
 }
 
 void ACodec::signalError(OMX_ERRORTYPE error, status_t internalError) {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatError);
     ALOGE("signalError(omxError %#x, internalError %d)", error, internalError);
 
     if (internalError == UNKNOWN_ERROR) { // find better error code
@@ -5132,10 +5118,7 @@
     }
 
     mFatalError = true;
-
-    notify->setInt32("err", internalError);
-    notify->setInt32("actionCode", ACTION_CODE_FATAL); // could translate from OMX error.
-    notify->post();
+    mCallback->onError(internalError, ACTION_CODE_FATAL);
 }
 
 status_t ACodec::requestIDRFrame() {
@@ -5262,9 +5245,7 @@
             status_t err = mCodec->mOMXNode->freeNode();
             ALOGE_IF("[%s] failed to release codec instance: err=%d",
                        mCodec->mComponentName.c_str(), err);
-            sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", CodecBase::kWhatReleaseCompleted);
-            notify->post();
+            mCodec->mCallback->onReleaseCompleted();
             break;
         }
 
@@ -5488,21 +5469,11 @@
 
     CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
 
-    sp<AMessage> notify = mCodec->mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatFillThisBuffer);
-    notify->setInt32("buffer-id", info->mBufferID);
-
     info->mData->setFormat(mCodec->mInputFormat);
-    notify->setObject("buffer", info->mData);
-    info->mData.clear();
-
     sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, mCodec);
     reply->setInt32("buffer-id", info->mBufferID);
-
-    notify->setMessage("reply", reply);
-
-    notify->post();
-
+    mCodec->mCallback->fillThisBuffer(info->mBufferID, info->mData, reply);
+    info->mData.clear();
     info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
 }
 
@@ -5852,8 +5823,7 @@
                 break;
             }
 
-            sp<AMessage> reply =
-                new AMessage(kWhatOutputBufferDrained, mCodec);
+            sp<AMessage> reply = new AMessage(kWhatOutputBufferDrained, mCodec);
             sp<MediaCodecBuffer> buffer = info->mData;
 
             if (mCodec->mOutputFormat != mCodec->mLastOutputFormat && rangeLength > 0) {
@@ -5909,29 +5879,18 @@
             }
             buffer->meta()->setInt64("timeUs", timeUs);
 
-            sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", CodecBase::kWhatDrainThisBuffer);
-            notify->setInt32("buffer-id", info->mBufferID);
-            notify->setObject("buffer", buffer);
             info->mData.clear();
-            notify->setInt32("flags", flags);
 
             reply->setInt32("buffer-id", info->mBufferID);
 
-            notify->setMessage("reply", reply);
-
-            notify->post();
+            mCodec->mCallback->drainThisBuffer(info->mBufferID, buffer, flags, reply);
 
             info->mStatus = BufferInfo::OWNED_BY_DOWNSTREAM;
 
             if (flags & OMX_BUFFERFLAG_EOS) {
                 ALOGV("[%s] saw output EOS", mCodec->mComponentName.c_str());
 
-                sp<AMessage> notify = mCodec->mNotify->dup();
-                notify->setInt32("what", CodecBase::kWhatEOS);
-                notify->setInt32("err", mCodec->mInputEOSResult);
-                notify->post();
-
+                mCodec->mCallback->onEos(mCodec->mInputEOSResult);
                 mCodec->mPortEOS[kPortIndexOutput] = true;
             }
             break;
@@ -6150,22 +6109,18 @@
                         "keepComponentAllocated", &keepComponentAllocated));
             ALOGW_IF(keepComponentAllocated,
                      "cannot keep component allocated on shutdown in Uninitialized state");
-
-            sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", keepComponentAllocated ?
-                    CodecBase::kWhatStopCompleted : CodecBase::kWhatReleaseCompleted);
-            notify->post();
-
+            if (keepComponentAllocated) {
+                mCodec->mCallback->onStopCompleted();
+            } else {
+                mCodec->mCallback->onReleaseCompleted();
+            }
             handled = true;
             break;
         }
 
         case ACodec::kWhatFlush:
         {
-            sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", CodecBase::kWhatFlushCompleted);
-            notify->post();
-
+            mCodec->mCallback->onFlushCompleted();
             handled = true;
             break;
         }
@@ -6293,14 +6248,7 @@
     omxNode->setQuirks(quirks);
     mCodec->mOMX = omx;
     mCodec->mOMXNode = omxNode;
-
-    {
-        sp<AMessage> notify = mCodec->mNotify->dup();
-        notify->setInt32("what", CodecBase::kWhatComponentAllocated);
-        notify->setString("componentName", mCodec->mComponentName.c_str());
-        notify->post();
-    }
-
+    mCodec->mCallback->onComponentAllocated(mCodec->mComponentName.c_str());
     mCodec->changeState(mCodec->mLoadedState);
 
     return true;
@@ -6349,10 +6297,11 @@
     }
 
     if (mCodec->mExplicitShutdown) {
-        sp<AMessage> notify = mCodec->mNotify->dup();
-        notify->setInt32("what", keepComponentAllocated ?
-                CodecBase::kWhatStopCompleted : CodecBase::kWhatReleaseCompleted);
-        notify->post();
+        if (keepComponentAllocated) {
+            mCodec->mCallback->onStopCompleted();
+        } else {
+            mCodec->mCallback->onReleaseCompleted();
+        }
         mCodec->mExplicitShutdown = false;
     }
 }
@@ -6404,10 +6353,7 @@
 
         case ACodec::kWhatFlush:
         {
-            sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", CodecBase::kWhatFlushCompleted);
-            notify->post();
-
+            mCodec->mCallback->onFlushCompleted();
             handled = true;
             break;
         }
@@ -6440,13 +6386,7 @@
         return false;
     }
 
-    {
-        sp<AMessage> notify = mCodec->mNotify->dup();
-        notify->setInt32("what", CodecBase::kWhatComponentConfigured);
-        notify->setMessage("input-format", mCodec->mInputFormat);
-        notify->setMessage("output-format", mCodec->mOutputFormat);
-        notify->post();
-    }
+    mCodec->mCallback->onComponentConfigured(mCodec->mInputFormat, mCodec->mOutputFormat);
 
     return true;
 }
@@ -6568,9 +6508,6 @@
         const sp<AMessage> & /* msg */) {
     ALOGV("onCreateInputSurface");
 
-    sp<AMessage> notify = mCodec->mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatInputSurfaceCreated);
-
     sp<IGraphicBufferProducer> bufferProducer;
     status_t err = mCodec->mOMX->createInputSurface(
             &bufferProducer, &mCodec->mGraphicBufferSource);
@@ -6580,10 +6517,9 @@
     }
 
     if (err == OK) {
-        notify->setMessage("input-format", mCodec->mInputFormat);
-        notify->setMessage("output-format", mCodec->mOutputFormat);
-
-        notify->setObject("input-surface",
+        mCodec->mCallback->onInputSurfaceCreated(
+                mCodec->mInputFormat,
+                mCodec->mOutputFormat,
                 new BufferProducerWrapper(bufferProducer));
     } else {
         // Can't use mCodec->signalError() here -- MediaCodec won't forward
@@ -6591,18 +6527,13 @@
         // send a kWhatInputSurfaceCreated with an error value instead.
         ALOGE("[%s] onCreateInputSurface returning error %d",
                 mCodec->mComponentName.c_str(), err);
-        notify->setInt32("err", err);
+        mCodec->mCallback->onInputSurfaceCreationFailed(err);
     }
-    notify->post();
 }
 
-void ACodec::LoadedState::onSetInputSurface(
-        const sp<AMessage> &msg) {
+void ACodec::LoadedState::onSetInputSurface(const sp<AMessage> &msg) {
     ALOGV("onSetInputSurface");
 
-    sp<AMessage> notify = mCodec->mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatInputSurfaceAccepted);
-
     sp<RefBase> obj;
     CHECK(msg->findObject("input-surface", &obj));
     sp<PersistentSurface> surface = static_cast<PersistentSurface *>(obj.get());
@@ -6611,17 +6542,16 @@
     status_t err = setupInputSurface();
 
     if (err == OK) {
-        notify->setMessage("input-format", mCodec->mInputFormat);
-        notify->setMessage("output-format", mCodec->mOutputFormat);
+        mCodec->mCallback->onInputSurfaceAccepted(
+                mCodec->mInputFormat, mCodec->mOutputFormat);
     } else {
         // Can't use mCodec->signalError() here -- MediaCodec won't forward
         // the error through because it's in the "configured" state.  We
         // send a kWhatInputSurfaceAccepted with an error value instead.
         ALOGE("[%s] onSetInputSurface returning error %d",
                 mCodec->mComponentName.c_str(), err);
-        notify->setInt32("err", err);
+        mCodec->mCallback->onInputSurfaceDeclined(err);
     }
-    notify->post();
 }
 
 void ACodec::LoadedState::onStart() {
@@ -6699,9 +6629,7 @@
         case kWhatFlush:
         {
             // We haven't even started yet, so we're flushed alright...
-            sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", CodecBase::kWhatFlushCompleted);
-            notify->post();
+            mCodec->mCallback->onFlushCompleted();
             return true;
         }
 
@@ -6771,10 +6699,7 @@
         case kWhatFlush:
         {
             // We haven't even started yet, so we're flushed alright...
-            sp<AMessage> notify = mCodec->mNotify->dup();
-            notify->setInt32("what", CodecBase::kWhatFlushCompleted);
-            notify->post();
-
+            mCodec->mCallback->onFlushCompleted();
             return true;
         }
 
@@ -7149,17 +7074,11 @@
 }
 
 void ACodec::onSignalEndOfInputStream() {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatSignaledInputEOS);
-
     status_t err = INVALID_OPERATION;
     if (mGraphicBufferSource != NULL) {
         err = statusFromBinderStatus(mGraphicBufferSource->signalEndOfInputStream());
     }
-    if (err != OK) {
-        notify->setInt32("err", err);
-    }
-    notify->post();
+    mCallback->onSignaledInputEOS(err);
 }
 
 bool ACodec::ExecutingState::onOMXFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) {
@@ -7636,9 +7555,7 @@
 
         mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC));
 
-        sp<AMessage> notify = mCodec->mNotify->dup();
-        notify->setInt32("what", CodecBase::kWhatFlushCompleted);
-        notify->post();
+        mCodec->mCallback->onFlushCompleted();
 
         mCodec->mPortEOS[kPortIndexInput] =
             mCodec->mPortEOS[kPortIndexOutput] = false;
diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp
index f729d4d..3eca52a 100644
--- a/media/libstagefright/CodecBase.cpp
+++ b/media/libstagefright/CodecBase.cpp
@@ -35,4 +35,8 @@
 CodecBase::PortDescription::~PortDescription() {
 }
 
+void CodecBase::setCallback(std::shared_ptr<Callback> &&callback) {
+    mCallback = callback;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 7c725ae..f29f786 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -67,6 +67,8 @@
 static const int kMaxRetry = 2;
 static const int kMaxReclaimWaitTimeInUs = 500000;  // 0.5s
 
+////////////////////////////////////////////////////////////////////////////////
+
 struct ResourceManagerClient : public BnResourceManagerClient {
     explicit ResourceManagerClient(MediaCodec* codec) : mMediaCodec(codec) {}
 
@@ -171,6 +173,206 @@
     return mService->reclaimResource(mPid, resources);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+enum {
+    kWhatFillThisBuffer      = 'fill',
+    kWhatDrainThisBuffer     = 'drai',
+    kWhatEOS                 = 'eos ',
+    kWhatStopCompleted       = 'scom',
+    kWhatReleaseCompleted    = 'rcom',
+    kWhatFlushCompleted      = 'fcom',
+    kWhatError               = 'erro',
+    kWhatComponentAllocated  = 'cAll',
+    kWhatComponentConfigured = 'cCon',
+    kWhatInputSurfaceCreated = 'isfc',
+    kWhatInputSurfaceAccepted = 'isfa',
+    kWhatSignaledInputEOS    = 'seos',
+    kWhatBuffersAllocated    = 'allc',
+    kWhatOutputFramesRendered = 'outR',
+};
+
+class MediaCodecCallback : public CodecBase::Callback {
+public:
+    explicit MediaCodecCallback(const sp<AMessage> &notify);
+    virtual ~MediaCodecCallback();
+
+    virtual void fillThisBuffer(IOMX::buffer_id bufferId, const sp<MediaCodecBuffer> &buffer,
+            const sp<AMessage> &reply) override;
+    virtual void drainThisBuffer(IOMX::buffer_id bufferId, const sp<MediaCodecBuffer> &buffer,
+            int32_t flags, const sp<AMessage> &reply) override;
+    virtual void onEos(status_t err) override;
+    virtual void onStopCompleted() override;
+    virtual void onReleaseCompleted() override;
+    virtual void onFlushCompleted() override;
+    virtual void onError(status_t err, enum ActionCode actionCode) override;
+    virtual void onComponentAllocated(const char *componentName) override;
+    virtual void onComponentConfigured(
+            const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) override;
+    virtual void onInputSurfaceCreated(
+            const sp<AMessage> &inputFormat,
+            const sp<AMessage> &outputFormat,
+            const sp<BufferProducerWrapper> &inputSurface) override;
+    virtual void onInputSurfaceCreationFailed(status_t err) override;
+    virtual void onInputSurfaceAccepted(
+            const sp<AMessage> &inputFormat,
+            const sp<AMessage> &outputFormat) override;
+    virtual void onInputSurfaceDeclined(status_t err) override;
+    virtual void onSignaledInputEOS(status_t err) override;
+    virtual void onBuffersAllocated(
+            int32_t portIndex, const sp<CodecBase::PortDescription> &portDesc) override;
+    virtual void onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) override;
+private:
+    const sp<AMessage> mNotify;
+};
+
+MediaCodecCallback::MediaCodecCallback(const sp<AMessage> &notify) : mNotify(notify) {}
+
+MediaCodecCallback::~MediaCodecCallback() {}
+
+void MediaCodecCallback::fillThisBuffer(
+        IOMX::buffer_id bufferId,
+        const sp<MediaCodecBuffer> &buffer,
+        const sp<AMessage> &reply) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatFillThisBuffer);
+    notify->setInt32("buffer-id", bufferId);
+    notify->setObject("buffer", buffer);
+    notify->setMessage("reply", reply);
+    notify->post();
+}
+
+void MediaCodecCallback::drainThisBuffer(
+        IOMX::buffer_id bufferId,
+        const sp<MediaCodecBuffer> &buffer,
+        int32_t flags,
+        const sp<AMessage> &reply) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatDrainThisBuffer);
+    notify->setInt32("buffer-id", bufferId);
+    notify->setObject("buffer", buffer);
+    notify->setInt32("flags", flags);
+    notify->setMessage("reply", reply);
+    notify->post();
+}
+
+void MediaCodecCallback::onEos(status_t err) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatEOS);
+    notify->setInt32("err", err);
+    notify->post();
+}
+
+void MediaCodecCallback::onStopCompleted() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatStopCompleted);
+    notify->post();
+}
+
+void MediaCodecCallback::onReleaseCompleted() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatReleaseCompleted);
+    notify->post();
+}
+
+void MediaCodecCallback::onFlushCompleted() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatFlushCompleted);
+    notify->post();
+}
+
+void MediaCodecCallback::onError(status_t err, enum ActionCode actionCode) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatError);
+    notify->setInt32("err", err);
+    notify->setInt32("actionCode", actionCode);
+    notify->post();
+}
+
+void MediaCodecCallback::onComponentAllocated(const char *componentName) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatComponentAllocated);
+    notify->setString("componentName", componentName);
+    notify->post();
+}
+
+void MediaCodecCallback::onComponentConfigured(
+        const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatComponentConfigured);
+    notify->setMessage("input-format", inputFormat);
+    notify->setMessage("output-format", outputFormat);
+    notify->post();
+}
+
+void MediaCodecCallback::onInputSurfaceCreated(
+        const sp<AMessage> &inputFormat,
+        const sp<AMessage> &outputFormat,
+        const sp<BufferProducerWrapper> &inputSurface) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatInputSurfaceCreated);
+    notify->setMessage("input-format", inputFormat);
+    notify->setMessage("output-format", outputFormat);
+    notify->setObject("input-surface", inputSurface);
+    notify->post();
+}
+
+void MediaCodecCallback::onInputSurfaceCreationFailed(status_t err) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatInputSurfaceCreated);
+    notify->setInt32("err", err);
+    notify->post();
+}
+
+void MediaCodecCallback::onInputSurfaceAccepted(
+        const sp<AMessage> &inputFormat,
+        const sp<AMessage> &outputFormat) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatInputSurfaceAccepted);
+    notify->setMessage("input-format", inputFormat);
+    notify->setMessage("output-format", outputFormat);
+    notify->post();
+}
+
+void MediaCodecCallback::onInputSurfaceDeclined(status_t err) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatInputSurfaceAccepted);
+    notify->setInt32("err", err);
+    notify->post();
+}
+
+void MediaCodecCallback::onSignaledInputEOS(status_t err) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatSignaledInputEOS);
+    if (err != OK) {
+        notify->setInt32("err", err);
+    }
+    notify->post();
+}
+
+void MediaCodecCallback::onBuffersAllocated(
+        int32_t portIndex, const sp<CodecBase::PortDescription> &portDesc) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatBuffersAllocated);
+    notify->setInt32("portIndex", portIndex);
+    notify->setObject("portDesc", portDesc);
+    notify->post();
+}
+
+void MediaCodecCallback::onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatOutputFramesRendered);
+    if (MediaCodec::CreateFramesRenderedMessage(done, notify)) {
+        notify->post();
+    }
+}
+
+}  // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+
 // static
 sp<MediaCodec> MediaCodec::CreateByType(
         const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err, pid_t pid,
@@ -370,7 +572,8 @@
 
     mLooper->registerHandler(this);
 
-    mCodec->setNotificationMessage(new AMessage(kWhatCodecNotify, this));
+    mCodec->setCallback(
+            std::make_shared<MediaCodecCallback>(new AMessage(kWhatCodecNotify, this)));
 
     sp<AMessage> msg = new AMessage(kWhatInit, this);
     msg->setString("name", name);
@@ -1056,7 +1259,7 @@
             CHECK(msg->findInt32("what", &what));
 
             switch (what) {
-                case CodecBase::kWhatError:
+                case kWhatError:
                 {
                     int32_t err, actionCode;
                     CHECK(msg->findInt32("err", &err));
@@ -1191,7 +1394,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatComponentAllocated:
+                case kWhatComponentAllocated:
                 {
                     CHECK_EQ(mState, INITIALIZING);
                     setState(INITIALIZED);
@@ -1223,7 +1426,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatComponentConfigured:
+                case kWhatComponentConfigured:
                 {
                     if (mState == UNINITIALIZED || mState == INITIALIZED) {
                         // In case a kWhatError message came in and replied with error,
@@ -1252,7 +1455,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatInputSurfaceCreated:
+                case kWhatInputSurfaceCreated:
                 {
                     // response to initiateCreateInputSurface()
                     status_t err = NO_ERROR;
@@ -1276,7 +1479,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatInputSurfaceAccepted:
+                case kWhatInputSurfaceAccepted:
                 {
                     // response to initiateSetInputSurface()
                     status_t err = NO_ERROR;
@@ -1292,7 +1495,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatSignaledInputEOS:
+                case kWhatSignaledInputEOS:
                 {
                     // response to signalEndOfInputStream()
                     sp<AMessage> response = new AMessage;
@@ -1305,7 +1508,7 @@
                 }
 
 
-                case CodecBase::kWhatBuffersAllocated:
+                case kWhatBuffersAllocated:
                 {
                     Mutex::Autolock al(mBufferLock);
                     int32_t portIndex;
@@ -1376,7 +1579,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatOutputFramesRendered:
+                case kWhatOutputFramesRendered:
                 {
                     // ignore these in all states except running, and check that we have a
                     // notification set
@@ -1388,7 +1591,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatFillThisBuffer:
+                case kWhatFillThisBuffer:
                 {
                     /* size_t index = */updateBuffers(kPortIndexInput, msg);
 
@@ -1446,7 +1649,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatDrainThisBuffer:
+                case kWhatDrainThisBuffer:
                 {
                     /* size_t index = */updateBuffers(kPortIndexOutput, msg);
 
@@ -1543,14 +1746,14 @@
                     break;
                 }
 
-                case CodecBase::kWhatEOS:
+                case kWhatEOS:
                 {
                     // We already notify the client of this by using the
                     // corresponding flag in "onOutputBufferReady".
                     break;
                 }
 
-                case CodecBase::kWhatStopCompleted:
+                case kWhatStopCompleted:
                 {
                     if (mState != STOPPING) {
                         ALOGW("Received kWhatStopCompleted in state %d", mState);
@@ -1561,7 +1764,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatReleaseCompleted:
+                case kWhatReleaseCompleted:
                 {
                     if (mState != RELEASING) {
                         ALOGW("Received kWhatReleaseCompleted in state %d", mState);
@@ -1578,7 +1781,7 @@
                     break;
                 }
 
-                case CodecBase::kWhatFlushCompleted:
+                case kWhatFlushCompleted:
                 {
                     if (mState != FLUSHING) {
                         ALOGW("received FlushCompleted message in state %d",
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
index 877aead..7290193 100644
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -60,10 +60,6 @@
 
 //////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////
 
-void MediaFilter::setNotificationMessage(const sp<AMessage> &msg) {
-    mNotify = msg;
-}
-
 void MediaFilter::initiateAllocateComponent(const sp<AMessage> &msg) {
     msg->setWhat(kWhatAllocateComponent);
     msg->setTarget(this);
@@ -223,10 +219,7 @@
 }
 
 void MediaFilter::signalError(status_t error) {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatError);
-    notify->setInt32("err", error);
-    notify->post();
+    mCallback->onError(error, ACTION_CODE_FATAL);
 }
 
 status_t MediaFilter::allocateBuffersOnPort(OMX_U32 portIndex) {
@@ -266,11 +259,6 @@
         }
     }
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatBuffersAllocated);
-
-    notify->setInt32("portIndex", portIndex);
-
     sp<PortDescription> desc = new PortDescription;
 
     for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
@@ -278,9 +266,7 @@
 
         desc->addBuffer(info.mBufferID, info.mData);
     }
-
-    notify->setObject("portDesc", desc);
-    notify->post();
+    mCallback->onBuffersAllocated(portIndex, desc);
 
     return OK;
 }
@@ -314,20 +300,14 @@
 
     info->mGeneration = mGeneration;
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatFillThisBuffer);
-    notify->setInt32("buffer-id", info->mBufferID);
-
     info->mData->meta()->clear();
-    notify->setObject("buffer", info->mData);
 
     sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, this);
     reply->setInt32("buffer-id", info->mBufferID);
 
-    notify->setMessage("reply", reply);
-
     info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
-    notify->post();
+
+    mCallback->fillThisBuffer(info->mBufferID, info->mData, reply);
 }
 
 void MediaFilter::postDrainThisBuffer(BufferInfo *info) {
@@ -335,27 +315,17 @@
 
     info->mGeneration = mGeneration;
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatDrainThisBuffer);
-    notify->setInt32("buffer-id", info->mBufferID);
-    notify->setInt32("flags", info->mOutputFlags);
-    notify->setObject("buffer", info->mData);
-
     sp<AMessage> reply = new AMessage(kWhatOutputBufferDrained, this);
     reply->setInt32("buffer-id", info->mBufferID);
 
-    notify->setMessage("reply", reply);
-
-    notify->post();
+    mCallback->drainThisBuffer(
+            info->mBufferID, info->mData, info->mOutputFlags, reply);
 
     info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
 }
 
 void MediaFilter::postEOS() {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatEOS);
-    notify->setInt32("err", ERROR_END_OF_STREAM);
-    notify->post();
+    mCallback->onEos(ERROR_END_OF_STREAM);
 
     ALOGV("Sent kWhatEOS.");
 }
@@ -445,11 +415,8 @@
         return;
     }
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatComponentAllocated);
     // HACK - need "OMX.google" to use MediaCodec's software renderer
-    notify->setString("componentName", "OMX.google.MediaFilter");
-    notify->post();
+    mCallback->onComponentAllocated("OMX.google.MediaFilter");
     mState = INITIALIZED;
     ALOGV("Handled kWhatAllocateComponent.");
 }
@@ -526,12 +493,7 @@
     mOutputFormat->setInt32("width", mWidth);
     mOutputFormat->setInt32("height", mHeight);
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatComponentConfigured);
-    notify->setString("componentName", "MediaFilter");
-    notify->setMessage("input-format", mInputFormat);
-    notify->setMessage("output-format", mOutputFormat);
-    notify->post();
+    mCallback->onComponentConfigured(mInputFormat, mOutputFormat);
     mState = CONFIGURED;
     ALOGV("Handled kWhatConfigureComponent.");
 }
@@ -675,10 +637,11 @@
         mState = INITIALIZED;
     }
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", keepComponentAllocated ?
-            CodecBase::kWhatStopCompleted : CodecBase::kWhatReleaseCompleted);
-    notify->post();
+    if (keepComponentAllocated) {
+        mCallback->onStopCompleted();
+    } else {
+        mCallback->onReleaseCompleted();
+    }
 }
 
 void MediaFilter::onFlush() {
@@ -700,9 +663,7 @@
     mPortEOS[kPortIndexOutput] = false;
     mInputEOSResult = OK;
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatFlushCompleted);
-    notify->post();
+    mCallback->onFlushCompleted();
     ALOGV("Posted kWhatFlushCompleted");
 
     // MediaCodec returns all input buffers after flush, so in
@@ -734,13 +695,10 @@
         return;
     }
 
-    sp<AMessage> reply = mNotify->dup();
-    reply->setInt32("what", CodecBase::kWhatInputSurfaceCreated);
-    reply->setObject(
-            "input-surface",
+    mCallback->onInputSurfaceCreated(
+            nullptr, nullptr,
             new BufferProducerWrapper(
                     mGraphicBufferListener->getIGraphicBufferProducer()));
-    reply->post();
 }
 
 void MediaFilter::onInputFrameAvailable() {
@@ -802,9 +760,7 @@
     }
 
     mPortEOS[kPortIndexOutput] = true;
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", CodecBase::kWhatSignaledInputEOS);
-    notify->post();
+    mCallback->onSignaledInputEOS(OK);
 
     ALOGV("Output stream saw EOS.");
 }