stagefright: abstract GraphicBufferSource to interfaces

Create two interfaces from GraphicBufferSource:

a) IGraphicBufferSource for client (ACodec) to configure the graphic
buffer source. IOMX no longer routes these messages and OMX internal
options are removed.

b) IOMXBufferSource for IOMX to send OMX specific callbacks.

Added an |origTimestamp| argument to emptyGraphicBuffer, and restore
the original PTS inside OMX to avoid going back to GraphicBufferSource
to patch the output PTS. In the longer term, we should consider moving
the max PTS gap entirely into OMX (probably as an extension index).

Define newly introduced interfaces using AIDL to facilitate code
development.

bug: 31399200

Change-Id: Ibaf6ca1a0737ba6ba9f83bedc3b06ef358db36cb
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index f971ee2..c0c48c1 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -34,11 +34,10 @@
 
 namespace android {
 
+class IGraphicBufferSource;
 class IMemory;
 class IOMXObserver;
-class IOMXRenderer;
 class NativeHandle;
-class Surface;
 struct omx_message;
 
 class IOMX : public IInterface {
@@ -129,6 +128,7 @@
     virtual status_t createInputSurface(
             node_id node, OMX_U32 port_index, android_dataspace dataSpace,
             sp<IGraphicBufferProducer> *bufferProducer,
+            sp<IGraphicBufferSource> *bufferSource,
             MetadataBufferType *type = NULL) = 0;
 
     virtual status_t createPersistentInputSurface(
@@ -140,10 +140,9 @@
     virtual status_t setInputSurface(
             node_id node, OMX_U32 port_index,
             const sp<IGraphicBufferConsumer> &bufferConsumer,
+            sp<IGraphicBufferSource> *bufferSource,
             MetadataBufferType *type) = 0;
 
-    virtual status_t signalEndOfInputStream(node_id node) = 0;
-
     // Allocate an opaque buffer as a native handle. If component supports returning native
     // handles, those are returned in *native_handle. Otherwise, the allocated buffer is
     // returned in *buffer_data. This clearly only makes sense if the caller lives in the
@@ -180,34 +179,23 @@
             OMX_U32 range_offset, OMX_U32 range_length,
             OMX_U32 flags, OMX_TICKS timestamp, int fenceFd = -1) = 0;
 
+    // Calls OMX_EmptyBuffer on buffer (after updating buffer header with metadata of
+    // |graphicBuffer|, |flags| and |timestamp|). Passes |fenceFd| to component if it
+    // supports fences. Otherwise, it waits on |fenceFd| before calling OMX_EmptyBuffer.
+    // Takes ownership of |fenceFd| even if this call fails. If |origTimestamp| >= 0,
+    // timestamp on the filled buffer corresponding to this frame will be modified to
+    // |origTimestamp| after it's filled.
     virtual status_t emptyGraphicBuffer(
             node_id node,
             buffer_id buffer,
-            const sp<GraphicBuffer> &graphicBuffer,
-            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) = 0;
+            const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
+            OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd) = 0;
 
     virtual status_t getExtensionIndex(
             node_id node,
             const char *parameter_name,
             OMX_INDEXTYPE *index) = 0;
 
-    enum InternalOptionType {
-        INTERNAL_OPTION_SUSPEND,  // data is a bool
-        INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY,  // data is an int64_t
-        INTERNAL_OPTION_MAX_TIMESTAMP_GAP, // data is int64_t
-        INTERNAL_OPTION_MAX_FPS, // data is float
-        INTERNAL_OPTION_START_TIME, // data is an int64_t
-        INTERNAL_OPTION_TIME_LAPSE, // data is an int64_t[2]
-        INTERNAL_OPTION_COLOR_ASPECTS, // data is ColorAspects
-        INTERNAL_OPTION_TIME_OFFSET, // data is an int64_t
-    };
-    virtual status_t setInternalOption(
-            node_id node,
-            OMX_U32 port_index,
-            InternalOptionType type,
-            const void *data,
-            size_t size) = 0;
-
     virtual status_t dispatchMessage(const omx_message &msg) = 0;
 };
 
diff --git a/include/media/OMXFenceParcelable.h b/include/media/OMXFenceParcelable.h
new file mode 100644
index 0000000..c9da301
--- /dev/null
+++ b/include/media/OMXFenceParcelable.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _OMX_FENCE_PARCELABLE_
+#define _OMX_FENCE_PARCELABLE_
+
+#include <binder/Parcel.h>
+
+namespace android {
+
+struct OMXFenceParcelable : public Parcelable {
+    OMXFenceParcelable() : mFenceFd(-1) {}
+    OMXFenceParcelable(int fenceFd) : mFenceFd(fenceFd) {}
+
+    int get() const { return mFenceFd; }
+
+    status_t readFromParcel(const Parcel* parcel) override;
+    status_t writeToParcel(Parcel* parcel) const override;
+
+private:
+    // Disable copy ctor and operator=
+    OMXFenceParcelable(const OMXFenceParcelable &);
+    OMXFenceParcelable &operator=(const OMXFenceParcelable &);
+
+    int mFenceFd;
+};
+
+inline status_t OMXFenceParcelable::readFromParcel(const Parcel* parcel) {
+    int32_t haveFence;
+    status_t err = parcel->readInt32(&haveFence);
+    if (err == OK && haveFence) {
+        int fd = ::dup(parcel->readFileDescriptor());
+        if (fd < 0) {
+            return fd;
+        }
+        mFenceFd = fd;
+    }
+    return err;
+}
+
+inline status_t OMXFenceParcelable::writeToParcel(Parcel* parcel) const {
+    status_t err = parcel->writeInt32(mFenceFd >= 0);
+    if (err == OK && mFenceFd >= 0) {
+        err = parcel->writeFileDescriptor(mFenceFd, true /* takeOwnership */);
+    }
+    return err;
+}
+
+} // namespace android
+
+#endif // _OMX_FENCE_PARCELABLE_
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 5a0913e..faf62ad 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -290,13 +290,12 @@
     size_t mNumUndequeuedBuffers;
     sp<DataConverter> mConverter[2];
 
+    sp<IGraphicBufferSource> mGraphicBufferSource;
     int64_t mRepeatFrameDelayUs;
     int64_t mMaxPtsGapUs;
     float mMaxFps;
-
     int64_t mTimePerFrameUs;
     int64_t mTimePerCaptureUs;
-
     bool mCreateInputBuffersSuspended;
 
     bool mTunneled;
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 0c4c547..59cb28c 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -2,7 +2,14 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_AIDL_INCLUDES := \
+    frameworks/av/media/libmedia/aidl
+
 LOCAL_SRC_FILES:= \
+    aidl/android/IGraphicBufferSource.aidl \
+    aidl/android/IOMXBufferSource.aidl
+
+LOCAL_SRC_FILES += \
     AudioTrack.cpp \
     AudioTrackShared.cpp \
     IAudioFlinger.cpp \
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 0dedad4..5e6ac36 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -27,6 +27,8 @@
 #include <media/openmax/OMX_IndexExt.h>
 #include <utils/NativeHandle.h>
 
+#include <android/IGraphicBufferSource.h>
+
 namespace android {
 
 enum {
@@ -47,7 +49,6 @@
     CREATE_INPUT_SURFACE,
     CREATE_PERSISTENT_INPUT_SURFACE,
     SET_INPUT_SURFACE,
-    SIGNAL_END_OF_INPUT_STREAM,
     STORE_META_DATA_IN_BUFFERS,
     PREPARE_FOR_ADAPTIVE_PLAYBACK,
     ALLOC_SECURE_BUFFER,
@@ -59,7 +60,6 @@
     GET_EXTENSION_INDEX,
     OBSERVER_ON_MSG,
     GET_GRAPHIC_BUFFER_USAGE,
-    SET_INTERNAL_OPTION,
     UPDATE_GRAPHIC_BUFFER_IN_META,
     CONFIGURE_VIDEO_TUNNEL_MODE,
     UPDATE_NATIVE_HANDLE_IN_META,
@@ -337,7 +337,9 @@
 
     virtual status_t createInputSurface(
             node_id node, OMX_U32 port_index, android_dataspace dataSpace,
-            sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
+            sp<IGraphicBufferProducer> *bufferProducer,
+            sp<IGraphicBufferSource> *bufferSource,
+            MetadataBufferType *type) {
         Parcel data, reply;
         status_t err;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
@@ -363,6 +365,8 @@
 
         *bufferProducer = IGraphicBufferProducer::asInterface(
                 reply.readStrongBinder());
+        *bufferSource = IGraphicBufferSource::asInterface(
+                reply.readStrongBinder());
 
         return err;
     }
@@ -394,7 +398,9 @@
 
     virtual status_t setInputSurface(
             node_id node, OMX_U32 port_index,
-            const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) {
+            const sp<IGraphicBufferConsumer> &bufferConsumer,
+            sp<IGraphicBufferSource> *bufferSource,
+            MetadataBufferType *type) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
         status_t err;
@@ -415,21 +421,15 @@
             *type = (MetadataBufferType)negotiatedType;
         }
 
-        return reply.readInt32();
-    }
-
-    virtual status_t signalEndOfInputStream(node_id node) {
-        Parcel data, reply;
-        status_t err;
-        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeInt32((int32_t)node);
-        err = remote()->transact(SIGNAL_END_OF_INPUT_STREAM, data, &reply);
+        err = reply.readInt32();
         if (err != OK) {
-            ALOGW("binder transaction failed: %d", err);
             return err;
         }
 
-        return reply.readInt32();
+        *bufferSource = IGraphicBufferSource::asInterface(
+                reply.readStrongBinder());
+
+        return err;
     }
 
     virtual status_t storeMetaDataInBuffers(
@@ -590,8 +590,8 @@
     virtual status_t emptyGraphicBuffer(
             node_id node,
             buffer_id buffer,
-            const sp<GraphicBuffer> &graphicBuffer,
-            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
+            const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
+            OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
         data.writeInt32((int32_t)node);
@@ -599,6 +599,7 @@
         data.write(*graphicBuffer);
         data.writeInt32(flags);
         data.writeInt64(timestamp);
+        data.writeInt64(origTimestamp);
         data.writeInt32(fenceFd >= 0);
         if (fenceFd >= 0) {
             data.writeFileDescriptor(fenceFd, true /* takeOwnership */);
@@ -629,24 +630,6 @@
         return err;
     }
 
-    virtual status_t setInternalOption(
-            node_id node,
-            OMX_U32 port_index,
-            InternalOptionType type,
-            const void *optionData,
-            size_t size) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
-        data.writeInt32((int32_t)node);
-        data.writeInt32(port_index);
-        data.writeInt64(size);
-        data.write(optionData, size);
-        data.writeInt32(type);
-        remote()->transact(SET_INTERNAL_OPTION, data, &reply);
-
-        return reply.readInt32();
-    }
-
     virtual status_t dispatchMessage(const omx_message &msg) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
@@ -767,7 +750,6 @@
         case SET_PARAMETER:
         case GET_CONFIG:
         case SET_CONFIG:
-        case SET_INTERNAL_OPTION:
         {
             CHECK_OMX_INTERFACE(IOMX, data, reply);
 
@@ -781,8 +763,7 @@
             size_t pageSize = 0;
             size_t allocSize = 0;
             bool isUsageBits = (index == (OMX_INDEXTYPE) OMX_IndexParamConsumerUsageBits);
-            if ((isUsageBits && size < 4) ||
-                    (!isUsageBits && code != SET_INTERNAL_OPTION && size < 8)) {
+            if ((isUsageBits && size < 4) || (!isUsageBits && size < 8)) {
                 // we expect the structure to contain at least the size and
                 // version, 8 bytes total
                 ALOGE("b/27207275 (%zu) (%d/%d)", size, int(index), int(code));
@@ -804,8 +785,7 @@
                     } else {
                         err = NOT_ENOUGH_DATA;
                         OMX_U32 declaredSize = *(OMX_U32*)params;
-                        if (code != SET_INTERNAL_OPTION &&
-                                index != (OMX_INDEXTYPE) OMX_IndexParamConsumerUsageBits &&
+                        if (index != (OMX_INDEXTYPE) OMX_IndexParamConsumerUsageBits &&
                                 declaredSize > size) {
                             // the buffer says it's bigger than it actually is
                             ALOGE("b/27207275 (%u/%zu)", declaredSize, size);
@@ -831,15 +811,6 @@
                                     case SET_CONFIG:
                                         err = setConfig(node, index, params, size);
                                         break;
-                                    case SET_INTERNAL_OPTION:
-                                    {
-                                        InternalOptionType type =
-                                            (InternalOptionType)data.readInt32();
-
-                                        err = setInternalOption(node, index, type, params, size);
-                                        break;
-                                    }
-
                                     default:
                                         TRESPASS();
                                 }
@@ -1002,8 +973,10 @@
             android_dataspace dataSpace = (android_dataspace)data.readInt32();
 
             sp<IGraphicBufferProducer> bufferProducer;
+            sp<IGraphicBufferSource> bufferSource;
             MetadataBufferType type = kMetadataBufferTypeInvalid;
-            status_t err = createInputSurface(node, port_index, dataSpace, &bufferProducer, &type);
+            status_t err = createInputSurface(
+                    node, port_index, dataSpace, &bufferProducer, &bufferSource, &type);
 
             if ((err != OK) && (type == kMetadataBufferTypeInvalid)) {
                 android_errorWriteLog(0x534e4554, "26324358");
@@ -1014,6 +987,7 @@
 
             if (err == OK) {
                 reply->writeStrongBinder(IInterface::asBinder(bufferProducer));
+                reply->writeStrongBinder(IInterface::asBinder(bufferSource));
             }
 
             return NO_ERROR;
@@ -1048,13 +1022,14 @@
             sp<IGraphicBufferConsumer> bufferConsumer =
                     interface_cast<IGraphicBufferConsumer>(data.readStrongBinder());
 
+            sp<IGraphicBufferSource> bufferSource;
             MetadataBufferType type = kMetadataBufferTypeInvalid;
 
             status_t err = INVALID_OPERATION;
             if (bufferConsumer == NULL) {
                 ALOGE("b/26392700");
             } else {
-                err = setInputSurface(node, port_index, bufferConsumer, &type);
+                err = setInputSurface(node, port_index, bufferConsumer, &bufferSource, &type);
 
                 if ((err != OK) && (type == kMetadataBufferTypeInvalid)) {
                    android_errorWriteLog(0x534e4554, "26324358");
@@ -1063,18 +1038,9 @@
 
             reply->writeInt32(type);
             reply->writeInt32(err);
-            return NO_ERROR;
-        }
-
-        case SIGNAL_END_OF_INPUT_STREAM:
-        {
-            CHECK_OMX_INTERFACE(IOMX, data, reply);
-
-            node_id node = (node_id)data.readInt32();
-
-            status_t err = signalEndOfInputStream(node);
-            reply->writeInt32(err);
-
+            if (err == OK) {
+                reply->writeStrongBinder(IInterface::asBinder(bufferSource));
+            }
             return NO_ERROR;
         }
 
@@ -1246,10 +1212,12 @@
             data.read(*graphicBuffer);
             OMX_U32 flags = data.readInt32();
             OMX_TICKS timestamp = data.readInt64();
+            OMX_TICKS origTimestamp = data.readInt64();
             bool haveFence = data.readInt32();
             int fenceFd = haveFence ? ::dup(data.readFileDescriptor()) : -1;
             reply->writeInt32(emptyGraphicBuffer(
-                    node, buffer, graphicBuffer, flags, timestamp, fenceFd));
+                    node, buffer, graphicBuffer, flags,
+                    timestamp, origTimestamp, fenceFd));
 
             return NO_ERROR;
         }
diff --git a/media/libmedia/aidl/android/IGraphicBufferSource.aidl b/media/libmedia/aidl/android/IGraphicBufferSource.aidl
new file mode 100644
index 0000000..adbb75f
--- /dev/null
+++ b/media/libmedia/aidl/android/IGraphicBufferSource.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android;
+
+/**
+ * Binder interface for controlling a graphic buffer source.
+ *
+ * @hide
+ */
+interface IGraphicBufferSource {
+    void setSuspend(boolean suspend);
+    void setRepeatPreviousFrameDelayUs(long repeatAfterUs);
+    void setMaxTimestampGapUs(long maxGapUs);
+    void setMaxFps(float maxFps);
+    void setTimeLapseConfig(long timePerFrameUs, long timePerCaptureUs);
+    void setStartTimeUs(long startTimeUs);
+    void setColorAspects(int aspects);
+    void setTimeOffsetUs(long timeOffsetsUs);
+    void signalEndOfInputStream();
+}
\ No newline at end of file
diff --git a/media/libmedia/aidl/android/IOMXBufferSource.aidl b/media/libmedia/aidl/android/IOMXBufferSource.aidl
new file mode 100644
index 0000000..a5bf448
--- /dev/null
+++ b/media/libmedia/aidl/android/IOMXBufferSource.aidl
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android;
+
+import android.OMXFenceParcelable;
+
+/**
+ * Binder interface for a buffer source to be used together with an OMX encoder
+ *
+ * @hide
+ */
+interface IOMXBufferSource {
+    /**
+     * This is called when OMX transitions to OMX_StateExecuting, which means
+     * we can start handing it buffers.  If we already have buffers of data
+     * sitting in the BufferQueue, this will send them to the codec.
+     */
+    void onOmxExecuting();
+
+    /**
+     * This is called when OMX transitions to OMX_StateIdle, indicating that
+     * the codec is meant to return all buffers back to the client for them
+     * to be freed. Do NOT submit any more buffers to the component.
+     */
+    void onOmxIdle();
+
+    /**
+     * This is called when OMX transitions to OMX_StateLoaded, indicating that
+     * we are shutting down.
+     */
+    void onOmxLoaded();
+
+    /**
+     * A "codec buffer", i.e. a buffer that can be used to pass data into
+     * the encoder, has been allocated.
+     */
+    void onInputBufferAdded(int bufferID);
+
+    /**
+     * Called from OnEmptyBufferDone. If we have a BQ buffer available,
+     * fill it with a new frame of data; otherwise, just mark it as available.
+     *
+     * fenceParcel contains the fence's fd that the callee should wait on before
+     * using the buffer (or pass on to the user of the buffer, if the user supports
+     * fences). Callee takes ownership of the fence fd even if it fails.
+     */
+    void onInputBufferEmptied(int bufferID, in OMXFenceParcelable fenceParcel);
+}
\ No newline at end of file
diff --git a/media/libmedia/aidl/android/OMXFenceParcelable.aidl b/media/libmedia/aidl/android/OMXFenceParcelable.aidl
new file mode 100644
index 0000000..6d517e8
--- /dev/null
+++ b/media/libmedia/aidl/android/OMXFenceParcelable.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android;
+
+/** @hide */
+parcelable OMXFenceParcelable cpp_header "media/OMXFenceParcelable.h";
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index a6e8de3..62ebb3f 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -55,8 +55,12 @@
 #include "include/DataConverter.h"
 #include "omx/OMXUtils.h"
 
+#include <android/IGraphicBufferSource.h>
+
 namespace android {
 
+using binder::Status;
+
 enum {
     kMaxIndicesToCheck = 32, // used when enumerating supported formats and profiles
 };
@@ -90,6 +94,21 @@
     }
 }
 
+static inline status_t statusFromBinderStatus(const Status &status) {
+    if (status.isOk()) {
+        return OK;
+    }
+    status_t err;
+    if ((err = status.serviceSpecificErrorCode()) != OK) {
+        return err;
+    }
+    if ((err = status.transactionError()) != OK) {
+        return err;
+    }
+    // Other exception
+    return UNKNOWN_ERROR;
+}
+
 // checks and converts status_t to a non-side-effect status_t
 static inline status_t makeNoSideEffectStatus(status_t err) {
     switch (err) {
@@ -5372,6 +5391,7 @@
         {
             // This will result in kFlagSawMediaServerDie handling in MediaCodec.
             ALOGE("OMX/mediaserver died, signalling error!");
+            mCodec->mGraphicBufferSource.clear();
             mCodec->signalError(OMX_ErrorResourcesLost, DEAD_OBJECT);
             break;
         }
@@ -6445,6 +6465,7 @@
     mCodec->mInputFormat.clear();
     mCodec->mOutputFormat.clear();
     mCodec->mBaseOutputFormat.clear();
+    mCodec->mGraphicBufferSource.clear();
 
     if (mCodec->mShutdownInProgress) {
         bool keepComponentAllocated = mCodec->mKeepComponentAllocated;
@@ -6572,87 +6593,61 @@
     status_t err = OK;
 
     if (mCodec->mRepeatFrameDelayUs > 0ll) {
-        err = mCodec->mOMX->setInternalOption(
-                mCodec->mNode,
-                kPortIndexInput,
-                IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY,
-                &mCodec->mRepeatFrameDelayUs,
-                sizeof(mCodec->mRepeatFrameDelayUs));
+        err = statusFromBinderStatus(
+                mCodec->mGraphicBufferSource->setRepeatPreviousFrameDelayUs(
+                        mCodec->mRepeatFrameDelayUs));
 
         if (err != OK) {
             ALOGE("[%s] Unable to configure option to repeat previous "
                   "frames (err %d)",
-                  mCodec->mComponentName.c_str(),
-                  err);
+                  mCodec->mComponentName.c_str(), err);
             return err;
         }
     }
 
     if (mCodec->mMaxPtsGapUs > 0ll) {
-        err = mCodec->mOMX->setInternalOption(
-                mCodec->mNode,
-                kPortIndexInput,
-                IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP,
-                &mCodec->mMaxPtsGapUs,
-                sizeof(mCodec->mMaxPtsGapUs));
+        err = statusFromBinderStatus(
+                mCodec->mGraphicBufferSource->setMaxTimestampGapUs(
+                        mCodec->mMaxPtsGapUs));
 
         if (err != OK) {
             ALOGE("[%s] Unable to configure max timestamp gap (err %d)",
-                    mCodec->mComponentName.c_str(),
-                    err);
+                    mCodec->mComponentName.c_str(), err);
             return err;
         }
     }
 
     if (mCodec->mMaxFps > 0) {
-        err = mCodec->mOMX->setInternalOption(
-                mCodec->mNode,
-                kPortIndexInput,
-                IOMX::INTERNAL_OPTION_MAX_FPS,
-                &mCodec->mMaxFps,
-                sizeof(mCodec->mMaxFps));
+        err = statusFromBinderStatus(
+                mCodec->mGraphicBufferSource->setMaxFps(mCodec->mMaxFps));
 
         if (err != OK) {
             ALOGE("[%s] Unable to configure max fps (err %d)",
-                    mCodec->mComponentName.c_str(),
-                    err);
+                    mCodec->mComponentName.c_str(), err);
             return err;
         }
     }
 
     if (mCodec->mTimePerCaptureUs > 0ll
             && mCodec->mTimePerFrameUs > 0ll) {
-        int64_t timeLapse[2];
-        timeLapse[0] = mCodec->mTimePerFrameUs;
-        timeLapse[1] = mCodec->mTimePerCaptureUs;
-        err = mCodec->mOMX->setInternalOption(
-                mCodec->mNode,
-                kPortIndexInput,
-                IOMX::INTERNAL_OPTION_TIME_LAPSE,
-                &timeLapse[0],
-                sizeof(timeLapse));
+        err = statusFromBinderStatus(
+                mCodec->mGraphicBufferSource->setTimeLapseConfig(
+                        mCodec->mTimePerFrameUs, mCodec->mTimePerCaptureUs));
 
         if (err != OK) {
             ALOGE("[%s] Unable to configure time lapse (err %d)",
-                    mCodec->mComponentName.c_str(),
-                    err);
+                    mCodec->mComponentName.c_str(), err);
             return err;
         }
     }
 
     if (mCodec->mCreateInputBuffersSuspended) {
-        bool suspend = true;
-        err = mCodec->mOMX->setInternalOption(
-                mCodec->mNode,
-                kPortIndexInput,
-                IOMX::INTERNAL_OPTION_SUSPEND,
-                &suspend,
-                sizeof(suspend));
+        err = statusFromBinderStatus(
+                mCodec->mGraphicBufferSource->setSuspend(true));
 
         if (err != OK) {
             ALOGE("[%s] Unable to configure option to suspend (err %d)",
-                  mCodec->mComponentName.c_str(),
-                  err);
+                  mCodec->mComponentName.c_str(), err);
             return err;
         }
     }
@@ -6667,9 +6662,14 @@
 
     sp<ABuffer> colorAspectsBuffer;
     if (mCodec->mInputFormat->findBuffer("android._color-aspects", &colorAspectsBuffer)) {
-        err = mCodec->mOMX->setInternalOption(
-                mCodec->mNode, kPortIndexInput, IOMX::INTERNAL_OPTION_COLOR_ASPECTS,
-                colorAspectsBuffer->base(), colorAspectsBuffer->capacity());
+        if (colorAspectsBuffer->size() != sizeof(ColorAspects)) {
+            return INVALID_OPERATION;
+        }
+
+        err = statusFromBinderStatus(
+                mCodec->mGraphicBufferSource->setColorAspects(ColorUtils::packToU32(
+                        *(ColorAspects *)colorAspectsBuffer->base())));
+
         if (err != OK) {
             ALOGE("[%s] Unable to configure color aspects (err %d)",
                   mCodec->mComponentName.c_str(), err);
@@ -6696,7 +6696,8 @@
     if (err == OK) {
         mCodec->mInputMetadataType = kMetadataBufferTypeANWBuffer;
         err = mCodec->mOMX->createInputSurface(
-                mCodec->mNode, kPortIndexInput, dataSpace, &bufferProducer,
+                mCodec->mNode, kPortIndexInput, dataSpace,
+                &bufferProducer, &mCodec->mGraphicBufferSource,
                 &mCodec->mInputMetadataType);
         // framework uses ANW buffers internally instead of gralloc handles
         if (mCodec->mInputMetadataType == kMetadataBufferTypeGrallocSource) {
@@ -6742,7 +6743,9 @@
     if (err == OK) {
         mCodec->mInputMetadataType = kMetadataBufferTypeANWBuffer;
         err = mCodec->mOMX->setInputSurface(
-                mCodec->mNode, kPortIndexInput, surface->getBufferConsumer(),
+                mCodec->mNode, kPortIndexInput,
+                surface->getBufferConsumer(),
+                &mCodec->mGraphicBufferSource,
                 &mCodec->mInputMetadataType);
         // framework uses ANW buffers internally instead of gralloc handles
         if (mCodec->mInputMetadataType == kMetadataBufferTypeGrallocSource) {
@@ -7205,12 +7208,14 @@
 
     int64_t timeOffsetUs;
     if (params->findInt64("time-offset-us", &timeOffsetUs)) {
-        status_t err = mOMX->setInternalOption(
-            mNode,
-            kPortIndexInput,
-            IOMX::INTERNAL_OPTION_TIME_OFFSET,
-            &timeOffsetUs,
-            sizeof(timeOffsetUs));
+        if (mGraphicBufferSource == NULL) {
+            ALOGE("[%s] Invalid to set input buffer time offset without surface",
+                    mComponentName.c_str());
+            return INVALID_OPERATION;
+        }
+
+        status_t err = statusFromBinderStatus(
+                mGraphicBufferSource->setTimeOffsetUs(timeOffsetUs));
 
         if (err != OK) {
             ALOGE("[%s] Unable to set input buffer time offset (err %d)",
@@ -7222,13 +7227,14 @@
 
     int64_t skipFramesBeforeUs;
     if (params->findInt64("skip-frames-before", &skipFramesBeforeUs)) {
-        status_t err =
-            mOMX->setInternalOption(
-                     mNode,
-                     kPortIndexInput,
-                     IOMX::INTERNAL_OPTION_START_TIME,
-                     &skipFramesBeforeUs,
-                     sizeof(skipFramesBeforeUs));
+        if (mGraphicBufferSource == NULL) {
+            ALOGE("[%s] Invalid to set start time without surface",
+                    mComponentName.c_str());
+            return INVALID_OPERATION;
+        }
+
+        status_t err = statusFromBinderStatus(
+                mGraphicBufferSource->setStartTimeUs(skipFramesBeforeUs));
 
         if (err != OK) {
             ALOGE("Failed to set parameter 'skip-frames-before' (err %d)", err);
@@ -7238,15 +7244,14 @@
 
     int32_t dropInputFrames;
     if (params->findInt32("drop-input-frames", &dropInputFrames)) {
-        bool suspend = dropInputFrames != 0;
+        if (mGraphicBufferSource == NULL) {
+            ALOGE("[%s] Invalid to set suspend without surface",
+                    mComponentName.c_str());
+            return INVALID_OPERATION;
+        }
 
-        status_t err =
-            mOMX->setInternalOption(
-                     mNode,
-                     kPortIndexInput,
-                     IOMX::INTERNAL_OPTION_SUSPEND,
-                     &suspend,
-                     sizeof(suspend));
+        status_t err = statusFromBinderStatus(
+                mGraphicBufferSource->setSuspend(dropInputFrames != 0));
 
         if (err != OK) {
             ALOGE("Failed to set parameter 'drop-input-frames' (err %d)", err);
@@ -7296,7 +7301,10 @@
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", CodecBase::kWhatSignaledInputEOS);
 
-    status_t err = mOMX->signalEndOfInputStream(mNode);
+    status_t err = INVALID_OPERATION;
+    if (mGraphicBufferSource != NULL) {
+        err = statusFromBinderStatus(mGraphicBufferSource->signalEndOfInputStream());
+    }
     if (err != OK) {
         notify->setInt32("err", err);
     }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b088775..f6763a0 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2123,7 +2123,7 @@
             sp<AReplyToken> replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
-            if (!isExecuting()) {
+            if (!isExecuting() || !mHaveInputSurface) {
                 PostReplyWithError(replyID, INVALID_OPERATION);
                 break;
             } else if (mFlags & kFlagStickyError) {
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 0dd7a9a..30b078f 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -1017,7 +1017,7 @@
         CHECK(msg->findInt64("time-offset-us", &mInputBufferTimeOffsetUs));
 
         // Propagate the timestamp offset to GraphicBufferSource.
-        if (mIsVideo) {
+        if (mFlags & FLAG_USE_SURFACE_INPUT) {
             sp<AMessage> params = new AMessage;
             params->setInt64("time-offset-us", mInputBufferTimeOffsetUs);
             err = mEncoder->setParameters(params);
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 16fbcd6..05ad2e8 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -117,7 +117,9 @@
 
     virtual status_t createInputSurface(
             node_id node, OMX_U32 port_index, android_dataspace dataSpace,
-            sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type);
+            sp<IGraphicBufferProducer> *bufferProducer,
+            sp<IGraphicBufferSource> *bufferSource,
+            MetadataBufferType *type);
 
     virtual status_t createPersistentInputSurface(
             sp<IGraphicBufferProducer> *bufferProducer,
@@ -125,9 +127,9 @@
 
     virtual status_t setInputSurface(
             node_id node, OMX_U32 port_index,
-            const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type);
-
-    virtual status_t signalEndOfInputStream(node_id node);
+            const sp<IGraphicBufferConsumer> &bufferConsumer,
+            sp<IGraphicBufferSource> *bufferSource,
+            MetadataBufferType *type);
 
     virtual status_t allocateSecureBuffer(
             node_id node, OMX_U32 port_index, size_t size,
@@ -151,21 +153,14 @@
     virtual status_t emptyGraphicBuffer(
             node_id node,
             buffer_id buffer,
-            const sp<GraphicBuffer> &graphicBuffer,
-            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
+            const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
+            OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd);
 
     virtual status_t getExtensionIndex(
             node_id node,
             const char *parameter_name,
             OMX_INDEXTYPE *index);
 
-    virtual status_t setInternalOption(
-            node_id node,
-            OMX_U32 port_index,
-            InternalOptionType type,
-            const void *data,
-            size_t size);
-
     virtual status_t dispatchMessage(const omx_message &msg);
 
 private:
@@ -420,9 +415,11 @@
 
 status_t MuxOMX::createInputSurface(
         node_id node, OMX_U32 port_index, android_dataspace dataSpace,
-        sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
+        sp<IGraphicBufferProducer> *bufferProducer,
+        sp<IGraphicBufferSource> *bufferSource,
+        MetadataBufferType *type) {
     status_t err = getOMX(node)->createInputSurface(
-            node, port_index, dataSpace, bufferProducer, type);
+            node, port_index, dataSpace, bufferProducer, bufferSource, type);
     return err;
 }
 
@@ -444,12 +441,10 @@
 
 status_t MuxOMX::setInputSurface(
         node_id node, OMX_U32 port_index,
-        const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) {
-    return getOMX(node)->setInputSurface(node, port_index, bufferConsumer, type);
-}
-
-status_t MuxOMX::signalEndOfInputStream(node_id node) {
-    return getOMX(node)->signalEndOfInputStream(node);
+        const sp<IGraphicBufferConsumer> &bufferConsumer,
+        sp<IGraphicBufferSource> *bufferSource,
+        MetadataBufferType *type) {
+    return getOMX(node)->setInputSurface(node, port_index, bufferConsumer, bufferSource, type);
 }
 
 status_t MuxOMX::allocateSecureBuffer(
@@ -487,10 +482,10 @@
 status_t MuxOMX::emptyGraphicBuffer(
         node_id node,
         buffer_id buffer,
-        const sp<GraphicBuffer> &graphicBuffer,
-        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
+        const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
+        OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd) {
     return getOMX(node)->emptyGraphicBuffer(
-            node, buffer, graphicBuffer, flags, timestamp, fenceFd);
+            node, buffer, graphicBuffer, flags, timestamp, origTimestamp, fenceFd);
 }
 
 status_t MuxOMX::getExtensionIndex(
@@ -500,15 +495,6 @@
     return getOMX(node)->getExtensionIndex(node, parameter_name, index);
 }
 
-status_t MuxOMX::setInternalOption(
-        node_id node,
-        OMX_U32 port_index,
-        InternalOptionType type,
-        const void *data,
-        size_t size) {
-    return getOMX(node)->setInternalOption(node, port_index, type, data, size);
-}
-
 status_t MuxOMX::dispatchMessage(const omx_message &msg) {
     return getOMX(msg.node)->dispatchMessage(msg);
 }
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index f7b6ab6..3af59ae 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -100,6 +100,7 @@
     virtual status_t createInputSurface(
             node_id node, OMX_U32 port_index, android_dataspace dataSpace,
             sp<IGraphicBufferProducer> *bufferProducer,
+            sp<IGraphicBufferSource> *bufferSource,
             MetadataBufferType *type);
 
     virtual status_t createPersistentInputSurface(
@@ -109,10 +110,9 @@
     virtual status_t setInputSurface(
             node_id node, OMX_U32 port_index,
             const sp<IGraphicBufferConsumer> &bufferConsumer,
+            sp<IGraphicBufferSource> *bufferSource,
             MetadataBufferType *type);
 
-    virtual status_t signalEndOfInputStream(node_id node);
-
     virtual status_t allocateSecureBuffer(
             node_id node, OMX_U32 port_index, size_t size,
             buffer_id *buffer, void **buffer_data, sp<NativeHandle> *native_handle);
@@ -135,21 +135,14 @@
     virtual status_t emptyGraphicBuffer(
             node_id node,
             buffer_id buffer,
-            const sp<GraphicBuffer> &graphicBuffer,
-            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
+            const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
+            OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd);
 
     virtual status_t getExtensionIndex(
             node_id node,
             const char *parameter_name,
             OMX_INDEXTYPE *index);
 
-    virtual status_t setInternalOption(
-            node_id node,
-            OMX_U32 port_index,
-            InternalOptionType type,
-            const void *data,
-            size_t size);
-
     virtual status_t dispatchMessage(const omx_message &msg);
 
     virtual void binderDied(const wp<IBinder> &the_late_who);
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index 3753cb0..e4f204e 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -25,10 +25,10 @@
 #include <utils/threads.h>
 
 namespace android {
-
+class IGraphicBufferSource;
+class IOMXBufferSource;
 class IOMXObserver;
 struct OMXMaster;
-class GraphicBufferSource;
 
 struct OMXNodeInstance {
     OMXNodeInstance(
@@ -87,6 +87,7 @@
     status_t createInputSurface(
             OMX_U32 portIndex, android_dataspace dataSpace,
             sp<IGraphicBufferProducer> *bufferProducer,
+            sp<IGraphicBufferSource> *bufferSource,
             MetadataBufferType *type);
 
     static status_t createPersistentInputSurface(
@@ -94,11 +95,11 @@
             sp<IGraphicBufferConsumer> *bufferConsumer);
 
     status_t setInputSurface(
-            OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &bufferConsumer,
+            OMX_U32 portIndex,
+            const sp<IGraphicBufferConsumer> &bufferConsumer,
+            sp<IGraphicBufferSource> *bufferSource,
             MetadataBufferType *type);
 
-    status_t signalEndOfInputStream();
-
     status_t allocateSecureBuffer(
             OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
             void **buffer_data, sp<NativeHandle> *native_handle);
@@ -117,18 +118,13 @@
             OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
 
     status_t emptyGraphicBuffer(
-            OMX::buffer_id buffer, const sp<GraphicBuffer> &graphicBuffer,
-            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd);
+            OMX::buffer_id buffer,
+            const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
+            OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd);
 
     status_t getExtensionIndex(
             const char *parameterName, OMX_INDEXTYPE *index);
 
-    status_t setInternalOption(
-            OMX_U32 portIndex,
-            IOMX::InternalOptionType type,
-            const void *data,
-            size_t size);
-
     bool isSecure() const {
         return mIsSecure;
     }
@@ -154,11 +150,11 @@
     SortedVector<OMX_INDEXTYPE> mProhibitedExtensions;
     bool mIsSecure;
 
-    // Lock only covers mGraphicBufferSource.  We can't always use mLock
-    // because of rare instances where we'd end up locking it recursively.
-    Mutex mGraphicBufferSourceLock;
-    // Access this through getGraphicBufferSource().
-    sp<GraphicBufferSource> mGraphicBufferSource;
+    // Lock only covers mOMXBufferSource and mOMXOutputListener.  We can't always
+    // use mLock because of rare instances where we'd end up locking it recursively.
+    Mutex mOMXBufferSourceLock;
+    // Access these through getBufferSource().
+    sp<IOMXBufferSource> mOMXBufferSource;
 
     struct ActiveBuffer {
         OMX_U32 mPortIndex;
@@ -180,6 +176,10 @@
     };
     SecureBufferType mSecureBufferType[2];
 
+    KeyedVector<int64_t, int64_t> mOriginalTimeUs;
+    bool mShouldRestorePts;
+    bool mRestorePtsFailed;
+
     // For debug support
     char *mName;
     int DEBUG;
@@ -253,10 +253,16 @@
             OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header, bool updateCodecBuffer);
 
     status_t createGraphicBufferSource(
-            OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &consumer /* nullable */,
+            OMX_U32 portIndex, android_dataspace dataSpace,
+            const sp<IGraphicBufferConsumer> &bufferConsumer,
+            sp<IGraphicBufferProducer> *bufferProducer,
+            sp<IGraphicBufferSource> *bufferSource,
             MetadataBufferType *type);
-    sp<GraphicBufferSource> getGraphicBufferSource();
-    void setGraphicBufferSource(const sp<GraphicBufferSource> &bufferSource);
+    sp<IOMXBufferSource> getBufferSource();
+    void setBufferSource(const sp<IOMXBufferSource> &bufferSource);
+    // Called when omx_message::FILL_BUFFER_DONE is received. (Currently the
+    // buffer source will fix timestamp in the header if needed.)
+    void codecBufferFilled(omx_message &msg);
 
     // Handles |msg|, and may modify it. Returns true iff completely handled it and
     // |msg| does not need to be sent to the event listener.
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 8557a28..334c5d3 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -23,7 +23,6 @@
 #define STRINGIFY_ENUMS // for asString in HardwareAPI.h/VideoAPI.h
 
 #include "GraphicBufferSource.h"
-#include "OMXUtils.h"
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/ColorUtils.h>
@@ -213,7 +212,7 @@
     }
 }
 
-void GraphicBufferSource::omxExecuting() {
+Status GraphicBufferSource::onOmxExecuting() {
     Mutex::Autolock autoLock(mMutex);
     ALOGV("--> executing; avail=%zu, codec vec size=%zd",
             mNumFramesAvailable, mCodecBuffers.size());
@@ -262,9 +261,11 @@
             msg->post(mRepeatAfterUs);
         }
     }
+
+    return Status::ok();
 }
 
-void GraphicBufferSource::omxIdle() {
+Status GraphicBufferSource::onOmxIdle() {
     ALOGV("omxIdle");
 
     Mutex::Autolock autoLock(mMutex);
@@ -274,9 +275,10 @@
         // not loaded->idle.
         mExecuting = false;
     }
+    return Status::ok();
 }
 
-void GraphicBufferSource::omxLoaded(){
+Status GraphicBufferSource::onOmxLoaded(){
     Mutex::Autolock autoLock(mMutex);
     if (!mExecuting) {
         // This can happen if something failed very early.
@@ -300,16 +302,17 @@
     //       are null; complain if not
 
     mExecuting = false;
+    return Status::ok();
 }
 
-void GraphicBufferSource::addCodecBuffer(IOMX::buffer_id bufferID) {
+Status GraphicBufferSource::onInputBufferAdded(int32_t bufferID) {
     Mutex::Autolock autoLock(mMutex);
 
     if (mExecuting) {
         // This should never happen -- buffers can only be allocated when
         // transitioning from "loaded" to "idle".
         ALOGE("addCodecBuffer: buffer added while executing");
-        return;
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
     }
 
     ALOGV("addCodecBuffer id=%u", bufferID);
@@ -317,15 +320,19 @@
     CodecBuffer codecBuffer;
     codecBuffer.mBufferID = bufferID;
     mCodecBuffers.add(codecBuffer);
+    return Status::ok();
 }
 
-void GraphicBufferSource::codecBufferEmptied(const omx_message &msg) {
-    IOMX::buffer_id bufferID = msg.u.buffer_data.buffer;
-    int fenceFd = msg.fenceFd;
+Status GraphicBufferSource::onInputBufferEmptied(
+        int32_t bufferID, const OMXFenceParcelable &fenceParcel) {
+    int fenceFd = fenceParcel.get();
 
     Mutex::Autolock autoLock(mMutex);
     if (!mExecuting) {
-        return;
+        if (fenceFd >= 0) {
+            ::close(fenceFd);
+        }
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
     }
 
     int cbi = findMatchingCodecBuffer_l(bufferID);
@@ -335,7 +342,7 @@
         if (fenceFd >= 0) {
             ::close(fenceFd);
         }
-        return;
+        return Status::fromServiceSpecificError(BAD_VALUE);
     }
 
     ALOGV("codecBufferEmptied id=%u", bufferID);
@@ -357,7 +364,7 @@
         if (fenceFd >= 0) {
             ::close(fenceFd);
         }
-        return;
+        return Status::fromServiceSpecificError(BAD_VALUE);
     }
 
     // Find matching entry in our cached copy of the BufferQueue slots.
@@ -409,77 +416,7 @@
         mRepeatBufferDeferred = false;
     }
 
-    return;
-}
-
-void GraphicBufferSource::codecBufferFilled(omx_message &msg) {
-    Mutex::Autolock autoLock(mMutex);
-
-    OMX_U32 &flags = msg.u.extended_buffer_data.flags;
-    OMX_TICKS &timestamp = msg.u.extended_buffer_data.timestamp;
-
-    if (mMaxTimestampGapUs > 0ll
-            && !(flags & OMX_BUFFERFLAG_CODECCONFIG)) {
-        ssize_t index = mOriginalTimeUs.indexOfKey(timestamp);
-        if (index >= 0) {
-            ALOGV("OUT timestamp: %lld -> %lld",
-                    static_cast<long long>(timestamp),
-                    static_cast<long long>(mOriginalTimeUs[index]));
-            timestamp = mOriginalTimeUs[index];
-            mOriginalTimeUs.removeItemsAt(index);
-        } else {
-            // giving up the effort as encoder doesn't appear to preserve pts
-            ALOGW("giving up limiting timestamp gap (pts = %lld)", timestamp);
-            mMaxTimestampGapUs = -1ll;
-        }
-        if (mOriginalTimeUs.size() > BufferQueue::NUM_BUFFER_SLOTS) {
-            // something terribly wrong must have happened, giving up...
-            ALOGE("mOriginalTimeUs has too many entries (%zu)",
-                    mOriginalTimeUs.size());
-            mMaxTimestampGapUs = -1ll;
-        }
-    }
-}
-
-void GraphicBufferSource::suspend(bool suspend) {
-    Mutex::Autolock autoLock(mMutex);
-
-    if (suspend) {
-        mSuspended = true;
-
-        while (mNumFramesAvailable > 0) {
-            BufferItem item;
-            status_t err = mConsumer->acquireBuffer(&item, 0);
-
-            if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
-                // shouldn't happen.
-                ALOGW("suspend: frame was not available");
-                break;
-            } else if (err != OK) {
-                ALOGW("suspend: acquireBuffer returned err=%d", err);
-                break;
-            }
-
-            ++mNumBufferAcquired;
-            --mNumFramesAvailable;
-
-            releaseBuffer(item.mSlot, item.mFrameNumber,
-                    item.mGraphicBuffer, item.mFence);
-        }
-        return;
-    }
-
-    mSuspended = false;
-
-    if (mExecuting && mNumFramesAvailable == 0 && mRepeatBufferDeferred) {
-        if (repeatLatestBuffer_l()) {
-            ALOGV("suspend/deferred repeatLatestBuffer_l SUCCESS");
-
-            mRepeatBufferDeferred = false;
-        } else {
-            ALOGV("suspend/deferred repeatLatestBuffer_l FAILURE");
-        }
-    }
+    return Status::ok();
 }
 
 void GraphicBufferSource::onDataSpaceChanged_l(
@@ -675,34 +612,10 @@
     }
 }
 
-status_t GraphicBufferSource::signalEndOfInputStream() {
-    Mutex::Autolock autoLock(mMutex);
-    ALOGV("signalEndOfInputStream: exec=%d avail=%zu eos=%d",
-            mExecuting, mNumFramesAvailable, mEndOfStream);
+bool GraphicBufferSource::getTimestamp(
+        const BufferItem &item, int64_t *origTimeUs, int64_t *codecTimeUs) {
+    *origTimeUs = -1ll;
 
-    if (mEndOfStream) {
-        ALOGE("EOS was already signaled");
-        return INVALID_OPERATION;
-    }
-
-    // Set the end-of-stream flag.  If no frames are pending from the
-    // BufferQueue, and a codec buffer is available, and we're executing,
-    // we initiate the EOS from here.  Otherwise, we'll let
-    // codecBufferEmptied() (or omxExecuting) do it.
-    //
-    // Note: if there are no pending frames and all codec buffers are
-    // available, we *must* submit the EOS from here or we'll just
-    // stall since no future events are expected.
-    mEndOfStream = true;
-
-    if (mExecuting && mNumFramesAvailable == 0) {
-        submitEndOfInputStream_l();
-    }
-
-    return OK;
-}
-
-int64_t GraphicBufferSource::getTimestamp(const BufferItem &item) {
     int64_t timeUs = item.mTimestamp / 1000;
     timeUs += mInputBufferTimeOffsetUs;
 
@@ -721,7 +634,7 @@
             if (nFrames <= 0) {
                 // skip this frame as it's too close to previous capture
                 ALOGV("skipping frame, timeUs %lld", static_cast<long long>(timeUs));
-                return -1;
+                return false;
             }
             mPrevCaptureUs = mPrevCaptureUs + nFrames * mTimePerCaptureUs;
             mPrevFrameUs += mTimePerFrameUs * nFrames;
@@ -732,14 +645,15 @@
                 static_cast<long long>(mPrevCaptureUs),
                 static_cast<long long>(mPrevFrameUs));
 
-        return mPrevFrameUs;
+        *codecTimeUs = mPrevFrameUs;
+        return true;
     } else {
         int64_t originalTimeUs = timeUs;
         if (originalTimeUs <= mPrevOriginalTimeUs) {
                 // Drop the frame if it's going backward in time. Bad timestamp
                 // could disrupt encoder's rate control completely.
             ALOGW("Dropping frame that's going backward in time");
-            return -1;
+            return false;
         }
 
         if (mMaxTimestampGapUs > 0ll) {
@@ -757,7 +671,7 @@
                 timeUs = (timestampGapUs < mMaxTimestampGapUs ?
                     timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
             }
-            mOriginalTimeUs.add(timeUs, originalTimeUs);
+            *origTimeUs = originalTimeUs;
             ALOGV("IN  timestamp: %lld -> %lld",
                 static_cast<long long>(originalTimeUs),
                 static_cast<long long>(timeUs));
@@ -767,14 +681,15 @@
         mPrevModifiedTimeUs = timeUs;
     }
 
-    return timeUs;
+    *codecTimeUs = timeUs;
+    return true;
 }
 
 status_t GraphicBufferSource::submitBuffer_l(const BufferItem &item, int cbi) {
     ALOGV("submitBuffer_l: slot=%d, cbi=%d", item.mSlot, cbi);
 
-    int64_t timeUs = getTimestamp(item);
-    if (timeUs < 0ll) {
+    int64_t origTimeUs, codecTimeUs;
+    if (!getTimestamp(item, &origTimeUs, &codecTimeUs)) {
         return UNKNOWN_ERROR;
     }
 
@@ -788,7 +703,8 @@
     int fenceID = item.mFence->isValid() ? item.mFence->dup() : -1;
 
     status_t err = mOMX->emptyGraphicBuffer(
-            mNodeID, bufferID, buffer, OMX_BUFFERFLAG_ENDOFFRAME, timeUs, fenceID);
+            mNodeID, bufferID, buffer, OMX_BUFFERFLAG_ENDOFFRAME,
+            codecTimeUs, origTimeUs, fenceID);
 
     if (err != OK) {
         ALOGW("WARNING: emptyGraphicBuffer failed: 0x%x", err);
@@ -823,7 +739,7 @@
     status_t err = mOMX->emptyGraphicBuffer(
             mNodeID, bufferID, NULL /* buffer */,
             OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS,
-            0 /* timestamp */, -1 /* fenceFd */);
+            0 /* timestamp */, -1ll /* origTimestamp */, -1 /* fenceFd */);
     if (err != OK) {
         ALOGW("emptyDirectBuffer EOS failed: 0x%x", err);
     } else {
@@ -963,88 +879,172 @@
     mLastDataSpace = dataSpace;
 }
 
-status_t GraphicBufferSource::setRepeatPreviousFrameDelayUs(
-        int64_t repeatAfterUs) {
+Status GraphicBufferSource::setSuspend(bool suspend) {
+    ALOGV("setSuspend=%d", suspend);
+
+    Mutex::Autolock autoLock(mMutex);
+
+    if (suspend) {
+        mSuspended = true;
+
+        while (mNumFramesAvailable > 0) {
+            BufferItem item;
+            status_t err = mConsumer->acquireBuffer(&item, 0);
+
+            if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+                // shouldn't happen.
+                ALOGW("suspend: frame was not available");
+                break;
+            } else if (err != OK) {
+                ALOGW("suspend: acquireBuffer returned err=%d", err);
+                break;
+            }
+
+            ++mNumBufferAcquired;
+            --mNumFramesAvailable;
+
+            releaseBuffer(item.mSlot, item.mFrameNumber,
+                    item.mGraphicBuffer, item.mFence);
+        }
+        return Status::ok();
+    }
+
+    mSuspended = false;
+
+    if (mExecuting && mNumFramesAvailable == 0 && mRepeatBufferDeferred) {
+        if (repeatLatestBuffer_l()) {
+            ALOGV("suspend/deferred repeatLatestBuffer_l SUCCESS");
+
+            mRepeatBufferDeferred = false;
+        } else {
+            ALOGV("suspend/deferred repeatLatestBuffer_l FAILURE");
+        }
+    }
+    return Status::ok();
+}
+
+Status GraphicBufferSource::setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) {
+    ALOGV("setRepeatPreviousFrameDelayUs: delayUs=%lld", (long long)repeatAfterUs);
+
     Mutex::Autolock autoLock(mMutex);
 
     if (mExecuting || repeatAfterUs <= 0ll) {
-        return INVALID_OPERATION;
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
     }
 
     mRepeatAfterUs = repeatAfterUs;
-
-    return OK;
+    return Status::ok();
 }
 
-status_t GraphicBufferSource::setMaxTimestampGapUs(int64_t maxGapUs) {
+Status GraphicBufferSource::setMaxTimestampGapUs(int64_t maxGapUs) {
+    ALOGV("setMaxTimestampGapUs: maxGapUs=%lld", (long long)maxGapUs);
+
     Mutex::Autolock autoLock(mMutex);
 
     if (mExecuting || maxGapUs <= 0ll) {
-        return INVALID_OPERATION;
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
     }
 
     mMaxTimestampGapUs = maxGapUs;
 
-    return OK;
+    return Status::ok();
 }
 
-status_t GraphicBufferSource::setInputBufferTimeOffset(int64_t timeOffsetUs) {
+Status GraphicBufferSource::setTimeOffsetUs(int64_t timeOffsetUs) {
     Mutex::Autolock autoLock(mMutex);
 
     // timeOffsetUs must be negative for adjustment.
     if (timeOffsetUs >= 0ll) {
-        return INVALID_OPERATION;
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
     }
 
     mInputBufferTimeOffsetUs = timeOffsetUs;
-    return OK;
+    return Status::ok();
 }
 
-status_t GraphicBufferSource::setMaxFps(float maxFps) {
+Status GraphicBufferSource::setMaxFps(float maxFps) {
+    ALOGV("setMaxFps: maxFps=%lld", (long long)maxFps);
+
     Mutex::Autolock autoLock(mMutex);
 
     if (mExecuting) {
-        return INVALID_OPERATION;
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
     }
 
     mFrameDropper = new FrameDropper();
     status_t err = mFrameDropper->setMaxFrameRate(maxFps);
     if (err != OK) {
         mFrameDropper.clear();
-        return err;
+        return Status::fromServiceSpecificError(err);
     }
 
-    return OK;
+    return Status::ok();
 }
 
-void GraphicBufferSource::setSkipFramesBeforeUs(int64_t skipFramesBeforeUs) {
+Status GraphicBufferSource::setStartTimeUs(int64_t skipFramesBeforeUs) {
+    ALOGV("setStartTimeUs: skipFramesBeforeUs=%lld", (long long)skipFramesBeforeUs);
+
     Mutex::Autolock autoLock(mMutex);
 
     mSkipFramesBeforeNs =
             (skipFramesBeforeUs > 0) ? (skipFramesBeforeUs * 1000) : -1ll;
+
+    return Status::ok();
 }
 
-status_t GraphicBufferSource::setTimeLapseConfig(const TimeLapseConfig &config) {
+Status GraphicBufferSource::setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) {
+    ALOGV("setTimeLapseConfig: timePerFrameUs=%lld, timePerCaptureUs=%lld",
+            (long long)timePerFrameUs, (long long)timePerCaptureUs);
+
     Mutex::Autolock autoLock(mMutex);
 
-    if (mExecuting || config.mTimePerFrameUs <= 0ll || config.mTimePerCaptureUs <= 0ll) {
-        return INVALID_OPERATION;
+    if (mExecuting || timePerFrameUs <= 0ll || timePerCaptureUs <= 0ll) {
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
     }
 
-    mTimePerFrameUs = config.mTimePerFrameUs;
-    mTimePerCaptureUs = config.mTimePerCaptureUs;
+    mTimePerFrameUs = timePerFrameUs;
+    mTimePerCaptureUs = timePerCaptureUs;
 
-    return OK;
+    return Status::ok();
 }
 
-void GraphicBufferSource::setColorAspects(const ColorAspects &aspects) {
+Status GraphicBufferSource::setColorAspects(int32_t aspectsPacked) {
     Mutex::Autolock autoLock(mMutex);
-    mColorAspects = aspects;
+    mColorAspects = ColorUtils::unpackToColorAspects(aspectsPacked);
     ALOGD("requesting color aspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s))",
-            aspects.mRange, asString(aspects.mRange),
-            aspects.mPrimaries, asString(aspects.mPrimaries),
-            aspects.mMatrixCoeffs, asString(aspects.mMatrixCoeffs),
-            aspects.mTransfer, asString(aspects.mTransfer));
+            mColorAspects.mRange, asString(mColorAspects.mRange),
+            mColorAspects.mPrimaries, asString(mColorAspects.mPrimaries),
+            mColorAspects.mMatrixCoeffs, asString(mColorAspects.mMatrixCoeffs),
+            mColorAspects.mTransfer, asString(mColorAspects.mTransfer));
+
+    return Status::ok();
+}
+
+Status GraphicBufferSource::signalEndOfInputStream() {
+    Mutex::Autolock autoLock(mMutex);
+    ALOGV("signalEndOfInputStream: exec=%d avail=%zu eos=%d",
+            mExecuting, mNumFramesAvailable, mEndOfStream);
+
+    if (mEndOfStream) {
+        ALOGE("EOS was already signaled");
+        return Status::fromStatusT(INVALID_OPERATION);
+    }
+
+    // Set the end-of-stream flag.  If no frames are pending from the
+    // BufferQueue, and a codec buffer is available, and we're executing,
+    // we initiate the EOS from here.  Otherwise, we'll let
+    // codecBufferEmptied() (or omxExecuting) do it.
+    //
+    // Note: if there are no pending frames and all codec buffers are
+    // available, we *must* submit the EOS from here or we'll just
+    // stall since no future events are expected.
+    mEndOfStream = true;
+
+    if (mExecuting && mNumFramesAvailable == 0) {
+        submitEndOfInputStream_l();
+    }
+
+    return Status::ok();
 }
 
 void GraphicBufferSource::onMessageReceived(const sp<AMessage> &msg) {
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 7ce9f98..16fefc4 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -22,15 +22,20 @@
 #include <gui/BufferQueue.h>
 #include <utils/RefBase.h>
 
-#include <OMX_Core.h>
 #include <VideoAPI.h>
-#include "../include/OMXNodeInstance.h"
+#include <media/IOMX.h>
+#include <media/OMXFenceParcelable.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AHandlerReflector.h>
 #include <media/stagefright/foundation/ALooper.h>
 
+#include <android/BnGraphicBufferSource.h>
+#include <android/BnOMXBufferSource.h>
+
 namespace android {
 
+using ::android::binder::Status;
+
 struct FrameDropper;
 
 /*
@@ -49,7 +54,9 @@
  * before the codec is in the "executing" state, so we need to queue
  * things up until we're ready to go.
  */
-class GraphicBufferSource : public BufferQueue::ConsumerListener {
+class GraphicBufferSource : public BnGraphicBufferSource,
+                            public BnOMXBufferSource,
+                            public BufferQueue::ConsumerListener {
 public:
     GraphicBufferSource(
             const sp<IOMX> &omx,
@@ -81,38 +88,35 @@
     // This is called when OMX transitions to OMX_StateExecuting, which means
     // we can start handing it buffers.  If we already have buffers of data
     // sitting in the BufferQueue, this will send them to the codec.
-    void omxExecuting();
+    Status onOmxExecuting() override;
 
     // This is called when OMX transitions to OMX_StateIdle, indicating that
     // the codec is meant to return all buffers back to the client for them
     // to be freed. Do NOT submit any more buffers to the component.
-    void omxIdle();
+    Status onOmxIdle() override;
 
     // This is called when OMX transitions to OMX_StateLoaded, indicating that
     // we are shutting down.
-    void omxLoaded();
+    Status onOmxLoaded() override;
 
     // A "codec buffer", i.e. a buffer that can be used to pass data into
     // the encoder, has been allocated.  (This call does not call back into
     // OMXNodeInstance.)
-    void addCodecBuffer(IOMX::buffer_id bufferID);
+    Status onInputBufferAdded(int32_t bufferID) override;
 
     // Called from OnEmptyBufferDone.  If we have a BQ buffer available,
     // fill it with a new frame of data; otherwise, just mark it as available.
-    void codecBufferEmptied(const omx_message &msg);
-
-    // Called when omx_message::FILL_BUFFER_DONE is received. (Currently the
-    // buffer source will fix timestamp in the header if needed.)
-    void codecBufferFilled(omx_message &msg);
+    Status onInputBufferEmptied(
+            int32_t bufferID, const OMXFenceParcelable& fenceParcel) override;
 
     // This is called after the last input frame has been submitted.  We
     // need to submit an empty buffer with the EOS flag set.  If we don't
     // have a codec buffer ready, we just set the mEndOfStream flag.
-    status_t signalEndOfInputStream();
+    Status signalEndOfInputStream() override;
 
     // If suspend is true, all incoming buffers (including those currently
     // in the BufferQueue) will be discarded until the suspension is lifted.
-    void suspend(bool suspend);
+    Status setSuspend(bool suspend) override;
 
     // Specifies the interval after which we requeue the buffer previously
     // queued to the encoder. This is useful in the case of surface flinger
@@ -121,7 +125,7 @@
     // the decoder on the remote end would be unable to decode the latest frame.
     // This API must be called before transitioning the encoder to "executing"
     // state and once this behaviour is specified it cannot be reset.
-    status_t setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs);
+    Status setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) override;
 
     // When set, the timestamp fed to the encoder will be modified such that
     // the gap between two adjacent frames is capped at maxGapUs. Timestamp
@@ -130,31 +134,26 @@
     // This is to solve a problem in certain real-time streaming case, where
     // encoder's rate control logic produces huge frames after a long period
     // of suspension on input.
-    status_t setMaxTimestampGapUs(int64_t maxGapUs);
+    Status setMaxTimestampGapUs(int64_t maxGapUs) override;
 
     // Sets the input buffer timestamp offset.
     // When set, the sample's timestamp will be adjusted with the timeOffsetUs.
-    status_t setInputBufferTimeOffset(int64_t timeOffsetUs);
+    Status setTimeOffsetUs(int64_t timeOffsetUs) override;
 
     // When set, the max frame rate fed to the encoder will be capped at maxFps.
-    status_t setMaxFps(float maxFps);
-
-    struct TimeLapseConfig {
-        int64_t mTimePerFrameUs;   // the time (us) between two frames for playback
-        int64_t mTimePerCaptureUs; // the time (us) between two frames for capture
-    };
+    Status setMaxFps(float maxFps) override;
 
     // Sets the time lapse (or slow motion) parameters.
     // When set, the sample's timestamp will be modified to playback framerate,
     // and capture timestamp will be modified to capture rate.
-    status_t setTimeLapseConfig(const TimeLapseConfig &config);
+    Status setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) override;
 
     // Sets the start time us (in system time), samples before which should
     // be dropped and not submitted to encoder
-    void setSkipFramesBeforeUs(int64_t startTimeUs);
+    Status setStartTimeUs(int64_t startTimeUs) override;
 
     // Sets the desired color aspects, e.g. to be used when producer does not specify a dataspace.
-    void setColorAspects(const ColorAspects &aspects);
+    Status setColorAspects(int32_t aspectsPacked) override;
 
 protected:
     // BufferQueue::ConsumerListener interface, called when a new frame of
@@ -163,17 +162,17 @@
     // into the codec buffer, and call Empty[This]Buffer.  If we're not yet
     // executing or there's no codec buffer available, we just increment
     // mNumFramesAvailable and return.
-    virtual void onFrameAvailable(const BufferItem& item);
+    void onFrameAvailable(const BufferItem& item) override;
 
     // BufferQueue::ConsumerListener interface, called when the client has
     // released one or more GraphicBuffers.  We clear out the appropriate
     // set of mBufferSlot entries.
-    virtual void onBuffersReleased();
+    void onBuffersReleased() override;
 
     // BufferQueue::ConsumerListener interface, called when the client has
     // changed the sideband stream. GraphicBufferSource doesn't handle sideband
     // streams so this is a no-op (and should never be called).
-    virtual void onSidebandStreamChanged();
+    void onSidebandStreamChanged() override;
 
 private:
     // PersistentProxyListener is similar to BufferQueue::ProxyConsumerListener
@@ -251,7 +250,7 @@
 
     void setLatestBuffer_l(const BufferItem &item, bool dropped);
     bool repeatLatestBuffer_l();
-    int64_t getTimestamp(const BufferItem &item);
+    bool getTimestamp(const BufferItem &item, int64_t *timeUs, int64_t *codecTimeUs);
 
     // called when the data space of the input buffer changes
     void onDataSpaceChanged_l(android_dataspace dataSpace, android_pixel_format pixelFormat);
@@ -312,7 +311,6 @@
         kRepeatLastFrameCount = 10,
     };
 
-    KeyedVector<int64_t, int64_t> mOriginalTimeUs;
     int64_t mMaxTimestampGapUs;
     int64_t mPrevOriginalTimeUs;
     int64_t mPrevModifiedTimeUs;
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 36bae4a..d867fe4 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -503,7 +503,9 @@
 
 status_t OMX::createInputSurface(
         node_id node, OMX_U32 port_index, android_dataspace dataSpace,
-        sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
+        sp<IGraphicBufferProducer> *bufferProducer,
+        sp<IGraphicBufferSource> *bufferSource,
+        MetadataBufferType *type) {
     OMXNodeInstance *instance = findInstance(node);
 
     if (instance == NULL) {
@@ -511,7 +513,7 @@
     }
 
     return instance->createInputSurface(
-            port_index, dataSpace, bufferProducer, type);
+            port_index, dataSpace, bufferProducer, bufferSource, type);
 }
 
 status_t OMX::createPersistentInputSurface(
@@ -523,25 +525,16 @@
 
 status_t OMX::setInputSurface(
         node_id node, OMX_U32 port_index,
-        const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) {
+        const sp<IGraphicBufferConsumer> &bufferConsumer,
+        sp<IGraphicBufferSource> *bufferSource,
+        MetadataBufferType *type) {
     OMXNodeInstance *instance = findInstance(node);
 
     if (instance == NULL) {
         return NAME_NOT_FOUND;
     }
 
-    return instance->setInputSurface(port_index, bufferConsumer, type);
-}
-
-
-status_t OMX::signalEndOfInputStream(node_id node) {
-    OMXNodeInstance *instance = findInstance(node);
-
-    if (instance == NULL) {
-        return NAME_NOT_FOUND;
-    }
-
-    return instance->signalEndOfInputStream();
+    return instance->setInputSurface(port_index, bufferConsumer, bufferSource, type);
 }
 
 status_t OMX::allocateSecureBuffer(
@@ -609,8 +602,8 @@
 status_t OMX::emptyGraphicBuffer(
         node_id node,
         buffer_id buffer,
-        const sp<GraphicBuffer> &graphicBuffer,
-        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
+        const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
+        OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd) {
     OMXNodeInstance *instance = findInstance(node);
 
     if (instance == NULL) {
@@ -618,7 +611,7 @@
     }
 
     return instance->emptyGraphicBuffer(
-            buffer, graphicBuffer, flags, timestamp, fenceFd);
+            buffer, graphicBuffer, flags, timestamp, origTimestamp, fenceFd);
 }
 
 status_t OMX::getExtensionIndex(
@@ -635,21 +628,6 @@
             parameter_name, index);
 }
 
-status_t OMX::setInternalOption(
-        node_id node,
-        OMX_U32 port_index,
-        InternalOptionType type,
-        const void *data,
-        size_t size) {
-    OMXNodeInstance *instance = findInstance(node);
-
-    if (instance == NULL) {
-        return NAME_NOT_FOUND;
-    }
-
-    return instance->setInternalOption(port_index, type, data, size);
-}
-
 status_t OMX::dispatchMessage(const omx_message &msg) {
     sp<OMX::CallbackDispatcher> dispatcher = findDispatcher(msg.node);
 
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 2e13398..997cc13 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -24,6 +24,8 @@
 #include "OMXMaster.h"
 #include "OMXUtils.h"
 #include "GraphicBufferSource.h"
+#include <android/IGraphicBufferSource.h>
+#include <android/IOMXBufferSource.h>
 
 #include <OMX_Component.h>
 #include <OMX_IndexExt.h>
@@ -213,7 +215,9 @@
       mDying(false),
       mSailed(false),
       mQueriedProhibitedExtensions(false),
-      mBufferIDCount(0)
+      mBufferIDCount(0),
+      mShouldRestorePts(false),
+      mRestorePtsFailed(false)
 {
     mName = ADebug::GetDebugName(name);
     DEBUG = ADebug::GetDebugLevelFromProperty(name, "debug.stagefright.omx-debug");
@@ -242,16 +246,15 @@
     mHandle = handle;
 }
 
-sp<GraphicBufferSource> OMXNodeInstance::getGraphicBufferSource() {
-    Mutex::Autolock autoLock(mGraphicBufferSourceLock);
-    return mGraphicBufferSource;
+sp<IOMXBufferSource> OMXNodeInstance::getBufferSource() {
+    Mutex::Autolock autoLock(mOMXBufferSourceLock);
+    return mOMXBufferSource;
 }
 
-void OMXNodeInstance::setGraphicBufferSource(
-        const sp<GraphicBufferSource>& bufferSource) {
-    Mutex::Autolock autoLock(mGraphicBufferSourceLock);
-    CLOG_INTERNAL(setGraphicBufferSource, "%p", bufferSource.get());
-    mGraphicBufferSource = bufferSource;
+void OMXNodeInstance::setBufferSource(const sp<IOMXBufferSource>& bufferSource) {
+    Mutex::Autolock autoLock(mOMXBufferSourceLock);
+    CLOG_INTERNAL(setBufferSource, "%p", bufferSource.get());
+    mOMXBufferSource = bufferSource;
 }
 
 OMX *OMXNodeInstance::owner() {
@@ -372,22 +375,18 @@
 
 status_t OMXNodeInstance::sendCommand(
         OMX_COMMANDTYPE cmd, OMX_S32 param) {
-    if (cmd == OMX_CommandStateSet) {
-        // There are no configurations past first StateSet command.
-        mSailed = true;
-    }
-    const sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
+    const sp<IOMXBufferSource> bufferSource(getBufferSource());
     if (bufferSource != NULL && cmd == OMX_CommandStateSet) {
         if (param == OMX_StateIdle) {
             // Initiating transition from Executing -> Idle
             // ACodec is waiting for all buffers to be returned, do NOT
             // submit any more buffers to the codec.
-            bufferSource->omxIdle();
+            bufferSource->onOmxIdle();
         } else if (param == OMX_StateLoaded) {
             // Initiating transition from Idle/Executing -> Loaded
             // Buffers are about to be freed.
-            bufferSource->omxLoaded();
-            setGraphicBufferSource(NULL);
+            bufferSource->onOmxLoaded();
+            setBufferSource(NULL);
         }
 
         // fall through
@@ -395,6 +394,11 @@
 
     Mutex::Autolock autoLock(mLock);
 
+    if (cmd == OMX_CommandStateSet) {
+        // There are no configurations past first StateSet command.
+        mSailed = true;
+    }
+
     // bump internal-state debug level for 2 input and output frames past a command
     {
         Mutex::Autolock _l(mDebugLock);
@@ -844,9 +848,9 @@
 
     addActiveBuffer(portIndex, *buffer);
 
-    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
+    sp<IOMXBufferSource> bufferSource(getBufferSource());
     if (bufferSource != NULL && portIndex == kPortIndexInput) {
-        bufferSource->addCodecBuffer(*buffer);
+        bufferSource->onInputBufferAdded(*buffer);
     }
 
     CLOG_BUFFER(useBuffer, NEW_BUFFER_FMT(
@@ -1068,7 +1072,11 @@
 }
 
 status_t OMXNodeInstance::createGraphicBufferSource(
-        OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) {
+        OMX_U32 portIndex, android_dataspace dataSpace,
+        const sp<IGraphicBufferConsumer> &bufferConsumer,
+        sp<IGraphicBufferProducer> *bufferProducer,
+        sp<IGraphicBufferSource> *bufferSource,
+        MetadataBufferType *type) {
     status_t err;
 
     // only allow graphic source on input port, when there are no allocated buffers yet
@@ -1080,8 +1088,7 @@
         return INVALID_OPERATION;
     }
 
-    const sp<GraphicBufferSource> surfaceCheck = getGraphicBufferSource();
-    if (surfaceCheck != NULL) {
+    if (getBufferSource() != NULL) {
         if (portIndex < NELEM(mMetadataType) && type != NULL) {
             *type = mMetadataType[portIndex];
         }
@@ -1125,7 +1132,7 @@
         usageBits = 0;
     }
 
-    sp<GraphicBufferSource> bufferSource = new GraphicBufferSource(
+    sp<GraphicBufferSource> graphicBufferSource = new GraphicBufferSource(
             mOwner,
             mNodeID,
             def.format.video.nFrameWidth,
@@ -1134,33 +1141,38 @@
             usageBits,
             bufferConsumer);
 
-    if ((err = bufferSource->initCheck()) != OK) {
+    if ((err = graphicBufferSource->initCheck()) != OK) {
         return err;
     }
-    setGraphicBufferSource(bufferSource);
+    setBufferSource(graphicBufferSource);
+
+    if (bufferConsumer == NULL) {
+        graphicBufferSource->setDefaultDataSpace(dataSpace);
+    }
+
+    if (bufferProducer != NULL) {
+        *bufferProducer = graphicBufferSource->getIGraphicBufferProducer();
+    }
+
+    *bufferSource = graphicBufferSource;
 
     return OK;
 }
 
 status_t OMXNodeInstance::createInputSurface(
         OMX_U32 portIndex, android_dataspace dataSpace,
-        sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
+        sp<IGraphicBufferProducer> *bufferProducer,
+        sp<IGraphicBufferSource> *bufferSource,
+        MetadataBufferType *type) {
     if (bufferProducer == NULL) {
         ALOGE("b/25884056");
         return BAD_VALUE;
     }
 
     Mutex::Autolock autolock(mLock);
-    status_t err = createGraphicBufferSource(portIndex, NULL /* bufferConsumer */, type);
-
-    if (err != OK) {
-        return err;
-    }
-
-    mGraphicBufferSource->setDefaultDataSpace(dataSpace);
-
-    *bufferProducer = mGraphicBufferSource->getIGraphicBufferProducer();
-    return OK;
+    return createGraphicBufferSource(
+            portIndex, dataSpace, NULL /* bufferConsumer */,
+            bufferProducer, bufferSource, type);
 }
 
 //static
@@ -1195,22 +1207,14 @@
 }
 
 status_t OMXNodeInstance::setInputSurface(
-        OMX_U32 portIndex, const sp<IGraphicBufferConsumer> &bufferConsumer,
+        OMX_U32 portIndex,
+        const sp<IGraphicBufferConsumer> &bufferConsumer,
+        sp<IGraphicBufferSource> *bufferSource,
         MetadataBufferType *type) {
     Mutex::Autolock autolock(mLock);
-    return createGraphicBufferSource(portIndex, bufferConsumer, type);
-}
-
-status_t OMXNodeInstance::signalEndOfInputStream() {
-    // For non-Surface input, the MediaCodec should convert the call to a
-    // pair of requests (dequeue input buffer, queue input buffer with EOS
-    // flag set).  Seems easier than doing the equivalent from here.
-    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
-    if (bufferSource == NULL) {
-        CLOGW("signalEndOfInputStream can only be used with Surface input");
-        return INVALID_OPERATION;
-    }
-    return bufferSource->signalEndOfInputStream();
+    return createGraphicBufferSource(
+            portIndex, android_dataspace::HAL_DATASPACE_UNKNOWN,
+            bufferConsumer, NULL, bufferSource, type);
 }
 
 status_t OMXNodeInstance::allocateSecureBuffer(
@@ -1260,9 +1264,9 @@
 
     addActiveBuffer(portIndex, *buffer);
 
-    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
+    sp<IOMXBufferSource> bufferSource(getBufferSource());
     if (bufferSource != NULL && portIndex == kPortIndexInput) {
-        bufferSource->addCodecBuffer(*buffer);
+        bufferSource->onInputBufferAdded(*buffer);
     }
     CLOG_BUFFER(allocateSecureBuffer, NEW_BUFFER_FMT(
             *buffer, portIndex, "%zu@%p:%p", size, *buffer_data,
@@ -1314,9 +1318,9 @@
 
     addActiveBuffer(portIndex, *buffer);
 
-    sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
+    sp<IOMXBufferSource> bufferSource(getBufferSource());
     if (bufferSource != NULL && portIndex == kPortIndexInput) {
-        bufferSource->addCodecBuffer(*buffer);
+        bufferSource->onInputBufferAdded(*buffer);
     }
 
     CLOG_BUFFER(allocateBufferWithBackup, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p :> %u@%p",
@@ -1390,7 +1394,7 @@
     Mutex::Autolock autoLock(mLock);
 
     // no emptybuffer if using input surface
-    if (getGraphicBufferSource() != NULL) {
+    if (getBufferSource() != NULL) {
         android_errorWriteLog(0x534e4554, "29422020");
         return INVALID_OPERATION;
     }
@@ -1538,7 +1542,7 @@
 // like emptyBuffer, but the data is already in header->pBuffer
 status_t OMXNodeInstance::emptyGraphicBuffer(
         OMX::buffer_id buffer, const sp<GraphicBuffer> &graphicBuffer,
-        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
+        OMX_U32 flags, OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd) {
     Mutex::Autolock autoLock(mLock);
 
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
@@ -1556,6 +1560,14 @@
         return err;
     }
 
+    // If we're required to restore original timestamp, origTimestamp will
+    // be set to non-negative number for all frames. If it's not required
+    // client will set it to -1ll for all frames.
+    if (origTimestamp >= 0ll && !mRestorePtsFailed) {
+        mShouldRestorePts = true;
+        mOriginalTimeUs.add(timestamp, origTimestamp);
+    }
+
     header->nOffset = 0;
     if (graphicBuffer == NULL) {
         header->nFilledLen = 0;
@@ -1567,6 +1579,38 @@
     return emptyBuffer_l(header, flags, timestamp, (intptr_t)header->pBuffer, fenceFd);
 }
 
+void OMXNodeInstance::codecBufferFilled(omx_message &msg) {
+    Mutex::Autolock autoLock(mBufferIDLock);
+
+    if (!mShouldRestorePts || mRestorePtsFailed) {
+        return;
+    }
+
+    OMX_U32 &flags = msg.u.extended_buffer_data.flags;
+    OMX_TICKS &timestamp = msg.u.extended_buffer_data.timestamp;
+
+    if (!(flags & OMX_BUFFERFLAG_CODECCONFIG)) {
+        ssize_t index = mOriginalTimeUs.indexOfKey(timestamp);
+        if (index >= 0) {
+            ALOGV("OUT timestamp: %lld -> %lld",
+                    static_cast<long long>(timestamp),
+                    static_cast<long long>(mOriginalTimeUs[index]));
+            timestamp = mOriginalTimeUs[index];
+            mOriginalTimeUs.removeItemsAt(index);
+        } else {
+            // giving up the effort as encoder doesn't appear to preserve pts
+            ALOGW("giving up limiting timestamp gap (pts = %lld)", timestamp);
+            mRestorePtsFailed = true;
+        }
+        if (mOriginalTimeUs.size() > BufferQueue::NUM_BUFFER_SLOTS) {
+            // something terribly wrong must have happened, giving up...
+            ALOGE("mOriginalTimeUs has too many entries (%zu)",
+                    mOriginalTimeUs.size());
+            mRestorePtsFailed = true;
+        }
+    }
+}
+
 status_t OMXNodeInstance::getExtensionIndex(
         const char *parameterName, OMX_INDEXTYPE *index) {
     Mutex::Autolock autoLock(mLock);
@@ -1577,133 +1621,7 @@
     return StatusFromOMXError(err);
 }
 
-inline static const char *asString(IOMX::InternalOptionType i, const char *def = "??") {
-    switch (i) {
-        case IOMX::INTERNAL_OPTION_SUSPEND:           return "SUSPEND";
-        case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
-            return "REPEAT_PREVIOUS_FRAME_DELAY";
-        case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP: return "MAX_TIMESTAMP_GAP";
-        case IOMX::INTERNAL_OPTION_MAX_FPS:           return "MAX_FPS";
-        case IOMX::INTERNAL_OPTION_START_TIME:        return "START_TIME";
-        case IOMX::INTERNAL_OPTION_TIME_LAPSE:        return "TIME_LAPSE";
-        case IOMX::INTERNAL_OPTION_TIME_OFFSET:       return "TIME_OFFSET";
-        default:                                      return def;
-    }
-}
-
-template<typename T>
-static bool getInternalOption(
-        const void *data, size_t size, T *out) {
-    if (size != sizeof(T)) {
-        return false;
-    }
-    *out = *(T*)data;
-    return true;
-}
-
-status_t OMXNodeInstance::setInternalOption(
-        OMX_U32 portIndex,
-        IOMX::InternalOptionType type,
-        const void *data,
-        size_t size) {
-    CLOG_CONFIG(setInternalOption, "%s(%d): %s:%u %zu@%p",
-            asString(type), type, portString(portIndex), portIndex, size, data);
-    switch (type) {
-        case IOMX::INTERNAL_OPTION_SUSPEND:
-        case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
-        case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP:
-        case IOMX::INTERNAL_OPTION_MAX_FPS:
-        case IOMX::INTERNAL_OPTION_START_TIME:
-        case IOMX::INTERNAL_OPTION_TIME_LAPSE:
-        case IOMX::INTERNAL_OPTION_TIME_OFFSET:
-        case IOMX::INTERNAL_OPTION_COLOR_ASPECTS:
-        {
-            const sp<GraphicBufferSource> &bufferSource =
-                getGraphicBufferSource();
-
-            if (bufferSource == NULL || portIndex != kPortIndexInput) {
-                CLOGW("setInternalOption is only for Surface input");
-                return ERROR_UNSUPPORTED;
-            }
-
-            if (type == IOMX::INTERNAL_OPTION_SUSPEND) {
-                bool suspend;
-                if (!getInternalOption(data, size, &suspend)) {
-                    return INVALID_OPERATION;
-                }
-
-                CLOG_CONFIG(setInternalOption, "suspend=%d", suspend);
-                bufferSource->suspend(suspend);
-            } else if (type == IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY) {
-                int64_t delayUs;
-                if (!getInternalOption(data, size, &delayUs)) {
-                    return INVALID_OPERATION;
-                }
-
-                CLOG_CONFIG(setInternalOption, "delayUs=%lld", (long long)delayUs);
-                return bufferSource->setRepeatPreviousFrameDelayUs(delayUs);
-            } else if (type == IOMX::INTERNAL_OPTION_TIME_OFFSET) {
-                int64_t timeOffsetUs;
-                if (!getInternalOption(data, size, &timeOffsetUs)) {
-                    return INVALID_OPERATION;
-                }
-                CLOG_CONFIG(setInternalOption, "bufferOffsetUs=%lld", (long long)timeOffsetUs);
-                return bufferSource->setInputBufferTimeOffset(timeOffsetUs);
-            } else if (type == IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP) {
-                int64_t maxGapUs;
-                if (!getInternalOption(data, size, &maxGapUs)) {
-                    return INVALID_OPERATION;
-                }
-
-                CLOG_CONFIG(setInternalOption, "gapUs=%lld", (long long)maxGapUs);
-                return bufferSource->setMaxTimestampGapUs(maxGapUs);
-            } else if (type == IOMX::INTERNAL_OPTION_MAX_FPS) {
-                float maxFps;
-                if (!getInternalOption(data, size, &maxFps)) {
-                    return INVALID_OPERATION;
-                }
-
-                CLOG_CONFIG(setInternalOption, "maxFps=%f", maxFps);
-                return bufferSource->setMaxFps(maxFps);
-            } else if (type == IOMX::INTERNAL_OPTION_START_TIME) {
-                int64_t skipFramesBeforeUs;
-                if (!getInternalOption(data, size, &skipFramesBeforeUs)) {
-                    return INVALID_OPERATION;
-                }
-
-                CLOG_CONFIG(setInternalOption, "beforeUs=%lld", (long long)skipFramesBeforeUs);
-                bufferSource->setSkipFramesBeforeUs(skipFramesBeforeUs);
-            } else if (type == IOMX::INTERNAL_OPTION_TIME_LAPSE) {
-                GraphicBufferSource::TimeLapseConfig config;
-                if (!getInternalOption(data, size, &config)) {
-                    return INVALID_OPERATION;
-                }
-
-                CLOG_CONFIG(setInternalOption, "perFrameUs=%lld perCaptureUs=%lld",
-                        (long long)config.mTimePerFrameUs, (long long)config.mTimePerCaptureUs);
-
-                return bufferSource->setTimeLapseConfig(config);
-            } else if (type == IOMX::INTERNAL_OPTION_COLOR_ASPECTS) {
-                ColorAspects aspects;
-                if (!getInternalOption(data, size, &aspects)) {
-                    return INVALID_OPERATION;
-                }
-
-                CLOG_CONFIG(setInternalOption, "setting color aspects");
-                bufferSource->setColorAspects(aspects);
-            }
-
-            return OK;
-        }
-
-        default:
-            return ERROR_UNSUPPORTED;
-    }
-}
-
 bool OMXNodeInstance::handleMessage(omx_message &msg) {
-    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
-
     if (msg.type == omx_message::FILL_BUFFER_DONE) {
         OMX_BUFFERHEADERTYPE *buffer =
             findBufferHeader(msg.u.extended_buffer_data.buffer, kPortIndexOutput);
@@ -1733,10 +1651,8 @@
         }
         buffer_meta->CopyFromOMX(buffer);
 
-        if (bufferSource != NULL) {
-            // fix up the buffer info (especially timestamp) if needed
-            bufferSource->codecBufferFilled(msg);
-        }
+        // fix up the buffer info (especially timestamp) if needed
+        codecBufferFilled(msg);
     } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
         OMX_BUFFERHEADERTYPE *buffer =
             findBufferHeader(msg.u.buffer_data.buffer, kPortIndexInput);
@@ -1752,13 +1668,15 @@
                     EBD, WITH_STATS(EMPTY_BUFFER(msg.u.buffer_data.buffer, buffer, msg.fenceFd)));
         }
 
+        const sp<IOMXBufferSource> bufferSource(getBufferSource());
+
         if (bufferSource != NULL) {
-            // This is one of the buffers used exclusively by
-            // GraphicBufferSource.
+            // This is one of the buffers used exclusively by IOMXBufferSource.
             // Don't dispatch a message back to ACodec, since it doesn't
             // know that anyone asked to have the buffer emptied and will
             // be very confused.
-            bufferSource->codecBufferEmptied(msg);
+            bufferSource->onInputBufferEmptied(
+                    msg.u.buffer_data.buffer, OMXFenceParcelable(msg.fenceFd));
             return true;
         }
     } else if (msg.type == omx_message::EVENT &&
@@ -1910,13 +1828,13 @@
 
     CLOGI_(level, onEvent, "%s(%x), %s(%x), %s(%x)",
             asString(event), event, arg1String, arg1, arg2String, arg2);
-    const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
+    const sp<IOMXBufferSource> bufferSource(getBufferSource());
 
     if (bufferSource != NULL
             && event == OMX_EventCmdComplete
             && arg1 == OMX_CommandStateSet
             && arg2 == OMX_StateExecuting) {
-        bufferSource->omxExecuting();
+        bufferSource->onOmxExecuting();
     }
 
     // allow configuration if we return to the loaded state