Merge "Re-implement HIDL effect processing using FMQ and IMemory"
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index f656008..ba2100c 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -335,7 +335,7 @@
         return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
     }
     out->numCameras = numCameras;
-    out->cameraIds = new const char*[numCameras] {nullptr};
+    out->cameraIds = new const char*[numCameras];
     if (!out->cameraIds) {
         ALOGE("Allocate memory for ACameraIdList failed!");
         deleteCameraIdList(out);
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index b28d509..9a236fc 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -124,29 +124,6 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:=         \
-	sf2.cpp    \
-
-LOCAL_SHARED_LIBRARIES := \
-	libstagefright liblog libutils libbinder libstagefright_foundation \
-	libmedia libgui libcutils
-
-LOCAL_C_INCLUDES:= \
-	frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE:= sf2
-
-include $(BUILD_EXECUTABLE)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
 LOCAL_SRC_FILES:=               \
 	codec.cpp               \
 	SimplePlayer.cpp        \
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
deleted file mode 100644
index 12bbfd1..0000000
--- a/cmds/stagefright/sf2.cpp
+++ /dev/null
@@ -1,788 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "sf2"
-#include <inttypes.h>
-#include <utils/Log.h>
-
-#include <signal.h>
-
-#include <binder/ProcessState.h>
-
-#include <media/IMediaHTTPService.h>
-
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-#include <media/stagefright/ACodec.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-#include <gui/SurfaceComposerClient.h>
-#include <gui/Surface.h>
-
-#include "include/ESDS.h"
-
-using namespace android;
-
-volatile static bool ctrlc = false;
-
-static sighandler_t oldhandler = NULL;
-
-static void mysighandler(int signum) {
-    if (signum == SIGINT) {
-        ctrlc = true;
-        return;
-    }
-    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)
-        : mURI(uri),
-          mDecodeAudio(decodeAudio),
-          mSurface(surface),
-          mRenderToSurface(renderToSurface),
-          mCodec(new ACodec),
-          mIsVorbis(false) {
-        CHECK(!mDecodeAudio || mSurface == NULL);
-    }
-
-    void startAsync() {
-        (new AMessage(kWhatStart, this))->post();
-    }
-
-protected:
-    virtual ~Controller() {
-    }
-
-    virtual void printStatistics() {
-        int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs;
-
-        if (mDecodeAudio) {
-            printf("%" PRId64 " bytes received. %.2f KB/sec\n",
-            mTotalBytesReceived,
-            mTotalBytesReceived * 1E6 / 1024 / delayUs);
-        } else {
-            printf("%d frames decoded, %.2f fps. %" PRId64 " bytes "
-                    "received. %.2f KB/sec\n",
-            mNumOutputBuffersReceived,
-            mNumOutputBuffersReceived * 1E6 / delayUs,
-            mTotalBytesReceived,
-            mTotalBytesReceived * 1E6 / 1024 / delayUs);
-        }
-    }
-
-    virtual void onMessageReceived(const sp<AMessage> &msg) {
-        if (ctrlc) {
-            printf("\n");
-            printStatistics();
-            (new AMessage(kWhatStop, this))->post();
-            ctrlc = false;
-        }
-        switch (msg->what()) {
-            case kWhatStart:
-            {
-#if 1
-                mDecodeLooper = looper();
-#else
-                mDecodeLooper = new ALooper;
-                mDecodeLooper->setName("sf2 decode looper");
-                mDecodeLooper->start();
-#endif
-
-                sp<DataSource> dataSource =
-                    DataSource::CreateFromURI(
-                            NULL /* httpService */, mURI.c_str());
-
-                sp<IMediaExtractor> extractor =
-                    MediaExtractor::Create(dataSource);
-
-                for (size_t i = 0; i < extractor->countTracks(); ++i) {
-                    sp<MetaData> meta = extractor->getTrackMetaData(i);
-
-                    const char *mime;
-                    CHECK(meta->findCString(kKeyMIMEType, &mime));
-
-                    if (!strncasecmp(mDecodeAudio ? "audio/" : "video/",
-                                     mime, 6)) {
-                        mSource = extractor->getTrack(i);
-
-                        if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
-                            mIsVorbis = true;
-                        } else {
-                            mIsVorbis = false;
-                        }
-                        break;
-                    }
-                }
-                if (mSource == NULL) {
-                    printf("no %s track found\n", mDecodeAudio ? "audio" : "video");
-                    exit (1);
-                }
-
-                CHECK_EQ(mSource->start(), (status_t)OK);
-
-                mDecodeLooper->registerHandler(mCodec);
-
-                mCodec->setCallback(
-                        std::make_shared<Sf2Callback>(new AMessage(kWhatCodecNotify, this)));
-
-                sp<AMessage> format = makeFormat(mSource->getFormat());
-
-                if (mSurface != NULL) {
-                    format->setObject("surface", mSurface);
-                }
-
-                mCodec->initiateSetup(format);
-
-                mCSDIndex = 0;
-                mStartTimeUs = ALooper::GetNowUs();
-                mNumOutputBuffersReceived = 0;
-                mTotalBytesReceived = 0;
-                mLeftOverBuffer = NULL;
-                mFinalResult = OK;
-                mSeekState = SEEK_NONE;
-
-                // (new AMessage(kWhatSeek, this))->post(5000000ll);
-                break;
-            }
-
-            case kWhatSeek:
-            {
-                printf("+");
-                fflush(stdout);
-
-                CHECK(mSeekState == SEEK_NONE
-                        || mSeekState == SEEK_FLUSH_COMPLETED);
-
-                if (mLeftOverBuffer != NULL) {
-                    mLeftOverBuffer->release();
-                    mLeftOverBuffer = NULL;
-                }
-
-                mSeekState = SEEK_FLUSHING;
-                mSeekTimeUs = 30000000ll;
-
-                mCodec->signalFlush();
-                break;
-            }
-
-            case kWhatStop:
-            {
-                if (mLeftOverBuffer != NULL) {
-                    mLeftOverBuffer->release();
-                    mLeftOverBuffer = NULL;
-                }
-
-                CHECK_EQ(mSource->stop(), (status_t)OK);
-                mSource.clear();
-
-                mCodec->initiateShutdown();
-                break;
-            }
-
-            case kWhatCodecNotify:
-            {
-                int32_t what;
-                CHECK(msg->findInt32("what", &what));
-
-                if (what == kWhatFillThisBuffer) {
-                    onFillThisBuffer(msg);
-                } else if (what == kWhatDrainThisBuffer) {
-                    if ((mNumOutputBuffersReceived++ % 16) == 0) {
-                        printf(".");
-                        fflush(stdout);
-                    }
-
-                    onDrainThisBuffer(msg);
-                } else if (what == kWhatEOS
-                        || what == kWhatError) {
-                    printf((what == kWhatEOS) ? "$\n" : "E\n");
-
-                    printStatistics();
-                    (new AMessage(kWhatStop, this))->post();
-                } else if (what == kWhatFlushCompleted) {
-                    mSeekState = SEEK_FLUSH_COMPLETED;
-                    mCodec->signalResume();
-
-                    (new AMessage(kWhatSeek, this))->post(5000000ll);
-                } else if (what == kWhatStopCompleted ||
-                        what == kWhatReleaseCompleted) {
-                    mDecodeLooper->unregisterHandler(mCodec->id());
-
-                    if (mDecodeLooper != looper()) {
-                        mDecodeLooper->stop();
-                    }
-
-                    looper()->stop();
-                }
-                break;
-            }
-
-            default:
-                TRESPASS();
-                break;
-        }
-    }
-
-private:
-    enum {
-        kWhatStart             = 'strt',
-        kWhatStop              = 'stop',
-        kWhatCodecNotify       = 'noti',
-        kWhatSeek              = 'seek',
-    };
-
-    sp<ALooper> mDecodeLooper;
-
-    AString mURI;
-    bool mDecodeAudio;
-    sp<Surface> mSurface;
-    bool mRenderToSurface;
-    sp<ACodec> mCodec;
-    sp<IMediaSource> mSource;
-    bool mIsVorbis;
-
-    Vector<sp<ABuffer> > mCSD;
-    size_t mCSDIndex;
-
-    MediaBuffer *mLeftOverBuffer;
-    status_t mFinalResult;
-
-    int64_t mStartTimeUs;
-    int32_t mNumOutputBuffersReceived;
-    int64_t mTotalBytesReceived;
-
-    enum SeekState {
-        SEEK_NONE,
-        SEEK_FLUSHING,
-        SEEK_FLUSH_COMPLETED,
-    };
-    SeekState mSeekState;
-    int64_t mSeekTimeUs;
-
-    sp<AMessage> makeFormat(const sp<MetaData> &meta) {
-        CHECK(mCSD.isEmpty());
-
-        const char *mime;
-        CHECK(meta->findCString(kKeyMIMEType, &mime));
-
-        sp<AMessage> msg = new AMessage;
-        msg->setString("mime", mime);
-
-        if (!strncasecmp("video/", mime, 6)) {
-            int32_t width, height;
-            CHECK(meta->findInt32(kKeyWidth, &width));
-            CHECK(meta->findInt32(kKeyHeight, &height));
-
-            msg->setInt32("width", width);
-            msg->setInt32("height", height);
-        } else {
-            CHECK(!strncasecmp("audio/", mime, 6));
-
-            int32_t numChannels, sampleRate;
-            CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
-            CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
-
-            msg->setInt32("channel-count", numChannels);
-            msg->setInt32("sample-rate", sampleRate);
-
-            int32_t isADTS;
-            if (meta->findInt32(kKeyIsADTS, &isADTS) && isADTS != 0) {
-                msg->setInt32("is-adts", true);
-            }
-        }
-
-        uint32_t type;
-        const void *data;
-        size_t size;
-        if (meta->findData(kKeyAVCC, &type, &data, &size)) {
-            // Parse the AVCDecoderConfigurationRecord
-
-            const uint8_t *ptr = (const uint8_t *)data;
-
-            CHECK(size >= 7);
-            CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
-            uint8_t profile __unused = ptr[1];
-            uint8_t level __unused = ptr[3];
-
-            // There is decodable content out there that fails the following
-            // assertion, let's be lenient for now...
-            // CHECK((ptr[4] >> 2) == 0x3f);  // reserved
-
-            size_t lengthSize __unused = 1 + (ptr[4] & 3);
-
-            // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
-            // violates it...
-            // CHECK((ptr[5] >> 5) == 7);  // reserved
-
-            size_t numSeqParameterSets = ptr[5] & 31;
-
-            ptr += 6;
-            size -= 6;
-
-            sp<ABuffer> buffer = new ABuffer(1024);
-            buffer->setRange(0, 0);
-
-            for (size_t i = 0; i < numSeqParameterSets; ++i) {
-                CHECK(size >= 2);
-                size_t length = U16_AT(ptr);
-
-                ptr += 2;
-                size -= 2;
-
-                CHECK(size >= length);
-
-                memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4);
-                memcpy(buffer->data() + buffer->size() + 4, ptr, length);
-                buffer->setRange(0, buffer->size() + 4 + length);
-
-                ptr += length;
-                size -= length;
-            }
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-
-            buffer = new ABuffer(1024);
-            buffer->setRange(0, 0);
-
-            CHECK(size >= 1);
-            size_t numPictureParameterSets = *ptr;
-            ++ptr;
-            --size;
-
-            for (size_t i = 0; i < numPictureParameterSets; ++i) {
-                CHECK(size >= 2);
-                size_t length = U16_AT(ptr);
-
-                ptr += 2;
-                size -= 2;
-
-                CHECK(size >= length);
-
-                memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4);
-                memcpy(buffer->data() + buffer->size() + 4, ptr, length);
-                buffer->setRange(0, buffer->size() + 4 + length);
-
-                ptr += length;
-                size -= length;
-            }
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-
-            msg->setBuffer("csd", buffer);
-        } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
-            ESDS esds((const char *)data, size);
-            CHECK_EQ(esds.InitCheck(), (status_t)OK);
-
-            const void *codec_specific_data;
-            size_t codec_specific_data_size;
-            esds.getCodecSpecificInfo(
-                    &codec_specific_data, &codec_specific_data_size);
-
-            sp<ABuffer> buffer = new ABuffer(codec_specific_data_size);
-
-            memcpy(buffer->data(), codec_specific_data,
-                   codec_specific_data_size);
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-        } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
-            sp<ABuffer> buffer = new ABuffer(size);
-            memcpy(buffer->data(), data, size);
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-
-            CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
-
-            buffer = new ABuffer(size);
-            memcpy(buffer->data(), data, size);
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-        }
-
-        int32_t maxInputSize;
-        if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
-            msg->setInt32("max-input-size", maxInputSize);
-        }
-
-        return msg;
-    }
-
-    void onFillThisBuffer(const sp<AMessage> &msg) {
-        sp<AMessage> reply;
-        CHECK(msg->findMessage("reply", &reply));
-
-        if (mSource == NULL || mSeekState == SEEK_FLUSHING) {
-            reply->setInt32("err", ERROR_END_OF_STREAM);
-            reply->post();
-            return;
-        }
-
-        sp<ABuffer> outBuffer;
-        CHECK(msg->findBuffer("buffer", &outBuffer));
-
-        if (mCSDIndex < mCSD.size()) {
-            outBuffer = mCSD.editItemAt(mCSDIndex++);
-            outBuffer->meta()->setInt64("timeUs", 0);
-        } else {
-            size_t sizeLeft = outBuffer->capacity();
-            outBuffer->setRange(0, 0);
-
-            int32_t n = 0;
-
-            for (;;) {
-                MediaBuffer *inBuffer;
-
-                if (mLeftOverBuffer != NULL) {
-                    inBuffer = mLeftOverBuffer;
-                    mLeftOverBuffer = NULL;
-                } else if (mFinalResult != OK) {
-                    break;
-                } else {
-                    MediaSource::ReadOptions options;
-                    if (mSeekState == SEEK_FLUSH_COMPLETED) {
-                        options.setSeekTo(mSeekTimeUs);
-                        mSeekState = SEEK_NONE;
-                    }
-                    status_t err = mSource->read(&inBuffer, &options);
-
-                    if (err != OK) {
-                        mFinalResult = err;
-                        break;
-                    }
-                }
-
-                size_t sizeNeeded = inBuffer->range_length();
-                if (mIsVorbis) {
-                    // Vorbis data is suffixed with the number of
-                    // valid samples on the page.
-                    sizeNeeded += sizeof(int32_t);
-                }
-
-                if (sizeNeeded > sizeLeft) {
-                    if (outBuffer->size() == 0) {
-                        ALOGE("Unable to fit even a single input buffer of size %zu.",
-                             sizeNeeded);
-                    }
-                    CHECK_GT(outBuffer->size(), 0u);
-
-                    mLeftOverBuffer = inBuffer;
-                    break;
-                }
-
-                ++n;
-
-                if (outBuffer->size() == 0) {
-                    int64_t timeUs;
-                    CHECK(inBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
-
-                    outBuffer->meta()->setInt64("timeUs", timeUs);
-                }
-
-                memcpy(outBuffer->data() + outBuffer->size(),
-                       (const uint8_t *)inBuffer->data()
-                        + inBuffer->range_offset(),
-                       inBuffer->range_length());
-
-                if (mIsVorbis) {
-                    int32_t numPageSamples;
-                    if (!inBuffer->meta_data()->findInt32(
-                                kKeyValidSamples, &numPageSamples)) {
-                        numPageSamples = -1;
-                    }
-
-                    memcpy(outBuffer->data()
-                            + outBuffer->size() + inBuffer->range_length(),
-                           &numPageSamples, sizeof(numPageSamples));
-                }
-
-                outBuffer->setRange(
-                        0, outBuffer->size() + sizeNeeded);
-
-                sizeLeft -= sizeNeeded;
-
-                inBuffer->release();
-                inBuffer = NULL;
-
-                break;  // Don't coalesce
-            }
-
-            ALOGV("coalesced %d input buffers", n);
-
-            if (outBuffer->size() == 0) {
-                CHECK_NE(mFinalResult, (status_t)OK);
-
-                reply->setInt32("err", mFinalResult);
-                reply->post();
-                return;
-            }
-        }
-
-        reply->setBuffer("buffer", outBuffer);
-        reply->post();
-    }
-
-    void onDrainThisBuffer(const sp<AMessage> &msg) {
-        sp<ABuffer> buffer;
-        CHECK(msg->findBuffer("buffer", &buffer));
-
-        mTotalBytesReceived += buffer->size();
-
-        sp<AMessage> reply;
-        CHECK(msg->findMessage("reply", &reply));
-
-        if (mRenderToSurface) {
-            reply->setInt32("render", 1);
-        }
-
-        reply->post();
-    }
-
-    DISALLOW_EVIL_CONSTRUCTORS(Controller);
-};
-
-static void usage(const char *me) {
-    fprintf(stderr, "usage: %s\n", me);
-    fprintf(stderr, "       -h(elp)\n");
-    fprintf(stderr, "       -a(udio)\n");
-
-    fprintf(stderr,
-            "       -S(urface) Allocate output buffers on a surface.\n"
-            "       -R(ender)  Render surface-allocated buffers.\n");
-}
-
-int main(int argc, char **argv) {
-    android::ProcessState::self()->startThreadPool();
-
-    bool decodeAudio = false;
-    bool useSurface = false;
-    bool renderToSurface = false;
-
-    int res;
-    while ((res = getopt(argc, argv, "haSR")) >= 0) {
-        switch (res) {
-            case 'a':
-                decodeAudio = true;
-                break;
-
-            case 'S':
-                useSurface = true;
-                break;
-
-            case 'R':
-                renderToSurface = true;
-                break;
-
-            case '?':
-            case 'h':
-            default:
-            {
-                usage(argv[0]);
-                return 1;
-            }
-        }
-    }
-
-    argc -= optind;
-    argv += optind;
-
-    if (argc != 1) {
-        usage(argv[-optind]);
-        return 1;
-    }
-
-    sp<ALooper> looper = new ALooper;
-    looper->setName("sf2");
-
-    sp<SurfaceComposerClient> composerClient;
-    sp<SurfaceControl> control;
-    sp<Surface> surface;
-
-    if (!decodeAudio && useSurface) {
-        composerClient = new SurfaceComposerClient;
-        CHECK_EQ(composerClient->initCheck(), (status_t)OK);
-
-        control = composerClient->createSurface(
-                String8("A Surface"),
-                1280,
-                800,
-                PIXEL_FORMAT_RGB_565,
-                0);
-
-        CHECK(control != NULL);
-        CHECK(control->isValid());
-
-        SurfaceComposerClient::openGlobalTransaction();
-        CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
-        CHECK_EQ(control->show(), (status_t)OK);
-        SurfaceComposerClient::closeGlobalTransaction();
-
-        surface = control->getSurface();
-        CHECK(surface != NULL);
-
-        CHECK_EQ((status_t)OK,
-                 native_window_api_connect(
-                     surface.get(), NATIVE_WINDOW_API_MEDIA));
-    }
-
-    sp<Controller> controller =
-        new Controller(argv[0], decodeAudio, surface, renderToSurface);
-
-    looper->registerHandler(controller);
-
-    signal(SIGINT, mysighandler);
-
-    controller->startAsync();
-
-    CHECK_EQ(looper->start(true /* runOnCallingThread */), (status_t)OK);
-
-    looper->unregisterHandler(controller->id());
-
-    if (!decodeAudio && useSurface) {
-        CHECK_EQ((status_t)OK,
-                 native_window_api_disconnect(
-                     surface.get(), NATIVE_WINDOW_API_MEDIA));
-
-        composerClient->dispose();
-    }
-
-    return 0;
-}
-
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index d42012b..3420617 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -35,6 +35,7 @@
 namespace android {
 
 struct ABuffer;
+class ACodecBufferChannel;
 class MediaCodecBuffer;
 class MemoryDealer;
 struct DescribeColorFormat2Params;
@@ -43,10 +44,9 @@
 struct ACodec : public AHierarchicalStateMachine, public CodecBase {
     ACodec();
 
-    virtual void setNotificationMessage(const sp<AMessage> &msg);
-
     void initiateSetup(const sp<AMessage> &msg);
 
+    virtual std::shared_ptr<BufferChannelBase> getBufferChannel() override;
     virtual void initiateAllocateComponent(const sp<AMessage> &msg);
     virtual void initiateConfigureComponent(const sp<AMessage> &msg);
     virtual void initiateCreateInputSurface();
@@ -72,23 +72,6 @@
         handleMessage(msg);
     }
 
-    struct PortDescription : public CodecBase::PortDescription {
-        size_t countBuffers();
-        IOMX::buffer_id bufferIDAt(size_t index) const;
-        sp<MediaCodecBuffer> bufferAt(size_t index) const;
-
-    private:
-        friend struct ACodec;
-
-        Vector<IOMX::buffer_id> mBufferIDs;
-        Vector<sp<MediaCodecBuffer> > mBuffers;
-
-        PortDescription();
-        void addBuffer(IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer);
-
-        DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
-    };
-
     // Returns 0 if configuration is not supported.  NOTE: this is treated by
     // some OMX components as auto level, and by others as invalid level.
     static int /* OMX_VIDEO_AVCLEVELTYPE */ getAVCLevelFor(
@@ -218,8 +201,6 @@
     KeyedVector<int64_t, BufferStats> mBufferStats;
 #endif
 
-    sp<AMessage> mNotify;
-
     sp<UninitializedState> mUninitializedState;
     sp<LoadedState> mLoadedState;
     sp<LoadedToIdleState> mLoadedToIdleState;
@@ -296,6 +277,8 @@
     OMX_INDEXTYPE mDescribeColorAspectsIndex;
     OMX_INDEXTYPE mDescribeHDRStaticInfoIndex;
 
+    std::shared_ptr<ACodecBufferChannel> mBufferChannel;
+
     status_t setCyclicIntraMacroblockRefresh(const sp<AMessage> &msg, int32_t mode);
     status_t allocateBuffersOnPort(OMX_U32 portIndex);
     status_t freeBuffersOnPort(OMX_U32 portIndex);
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index 516f698..cfbaea4 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -24,6 +24,7 @@
 
 #define STRINGIFY_ENUMS
 
+#include <media/ICrypto.h>
 #include <media/IOMX.h>
 #include <media/MediaCodecInfo.h>
 #include <media/stagefright/MediaErrors.h>
@@ -37,6 +38,7 @@
 
 namespace android {
 
+class BufferChannelBase;
 class BufferProducerWrapper;
 class MediaCodecBuffer;
 struct PersistentSurface;
@@ -44,43 +46,15 @@
 class Surface;
 
 struct CodecBase : public AHandler, /* static */ ColorUtils {
-    struct PortDescription;
-
     /**
      * This interface defines events firing from CodecBase back to MediaCodec.
      * All methods must not block.
      */
-    class Callback {
+    class CodecCallback {
     public:
-        virtual ~Callback() = default;
+        virtual ~CodecCallback() = 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
@@ -89,6 +63,10 @@
          */
         virtual void onEos(status_t err) = 0;
         /**
+         * Notify MediaCodec that start operation is complete.
+         */
+        virtual void onStartCompleted() = 0;
+        /**
          * Notify MediaCodec that stop operation is complete.
          */
         virtual void onStopCompleted() = 0;
@@ -169,27 +147,55 @@
          */
         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;
+        /**
+         * Notify MediaCodec that output buffers are changed.
+         */
+        virtual void onOutputBuffersChanged() = 0;
     };
 
+    /**
+     * This interface defines events firing from BufferChannelBase back to MediaCodec.
+     * All methods must not block.
+     */
+    class BufferCallback {
+    public:
+        virtual ~BufferCallback() = default;
+
+        /**
+         * Notify MediaCodec that an input buffer is available with given index.
+         * When BufferChannelBase::getInputBufferArray() is not called,
+         * BufferChannelBase may report different buffers with the same index if
+         * MediaCodec already queued/discarded the buffer. After calling
+         * BufferChannelBase::getInputBufferArray(), the buffer and index match the
+         * returned array.
+         */
+        virtual void onInputBufferAvailable(
+                size_t index, const sp<MediaCodecBuffer> &buffer) = 0;
+        /**
+         * Notify MediaCodec that an output buffer is available with given index.
+         * When BufferChannelBase::getOutputBufferArray() is not called,
+         * BufferChannelBase may report different buffers with the same index if
+         * MediaCodec already queued/discarded the buffer. After calling
+         * BufferChannelBase::getOutputBufferArray(), the buffer and index match the
+         * returned array.
+         */
+        virtual void onOutputBufferAvailable(
+                size_t index, const sp<MediaCodecBuffer> &buffer) = 0;
+    };
     enum {
         kMaxCodecBufferSize = 8192 * 4096 * 4, // 8K RGBA
     };
 
-    void setCallback(std::shared_ptr<Callback> &&callback);
+    inline void setCallback(std::unique_ptr<CodecCallback> &&callback) {
+        mCallback = std::move(callback);
+    }
+    virtual std::shared_ptr<BufferChannelBase> getBufferChannel() = 0;
 
     virtual void initiateAllocateComponent(const sp<AMessage> &msg) = 0;
     virtual void initiateConfigureComponent(const sp<AMessage> &msg) = 0;
@@ -215,33 +221,104 @@
     virtual void signalSetParameters(const sp<AMessage> &msg) = 0;
     virtual void signalEndOfInputStream() = 0;
 
-    struct PortDescription : public RefBase {
-        virtual size_t countBuffers() = 0;
-        virtual IOMX::buffer_id bufferIDAt(size_t index) const = 0;
-        virtual sp<MediaCodecBuffer> bufferAt(size_t index) const = 0;
-
-    protected:
-        PortDescription();
-        virtual ~PortDescription();
-
-    private:
-        DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
-    };
-
     /*
      * Codec-related defines
      */
 
 protected:
-    CodecBase();
-    virtual ~CodecBase();
+    CodecBase() = default;
+    virtual ~CodecBase() = default;
 
-    std::shared_ptr<Callback> mCallback;
+    std::unique_ptr<CodecCallback> mCallback;
 
 private:
     DISALLOW_EVIL_CONSTRUCTORS(CodecBase);
 };
 
+/**
+ * A channel between MediaCodec and CodecBase object which manages buffer
+ * passing. Only MediaCodec is expected to call these methods, and
+ * underlying CodecBase implementation should define its own interface
+ * separately for itself.
+ *
+ * Concurrency assumptions:
+ *
+ * 1) Clients may access the object at multiple threads concurrently.
+ * 2) All methods do not call underlying CodecBase object while holding a lock.
+ * 3) Code inside critical section executes within 1ms.
+ */
+class BufferChannelBase {
+public:
+    virtual ~BufferChannelBase() = default;
+
+    inline void setCallback(std::unique_ptr<CodecBase::BufferCallback> &&callback) {
+        mCallback = std::move(callback);
+    }
+
+    inline void setCrypto(const sp<ICrypto> &crypto) {
+        mCrypto = crypto;
+    }
+
+    /**
+     * Queue an input buffer into the buffer channel.
+     *
+     * @return    OK if successful;
+     *            -ENOENT if the buffer is not known (TODO: this should be
+     *            handled gracefully in the future, here and below).
+     */
+    virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) = 0;
+    /**
+     * Queue a secure input buffer into the buffer channel.
+     *
+     * @return    OK if successful;
+     *            -ENOENT if the buffer is not known;
+     *            -ENOSYS if mCrypto is not set so that decryption is not
+     *            possible;
+     *            other errors if decryption failed.
+     */
+    virtual status_t queueSecureInputBuffer(
+            const sp<MediaCodecBuffer> &buffer,
+            bool secure,
+            const uint8_t *key,
+            const uint8_t *iv,
+            CryptoPlugin::Mode mode,
+            CryptoPlugin::Pattern pattern,
+            const CryptoPlugin::SubSample *subSamples,
+            size_t numSubSamples,
+            AString *errorDetailMsg) = 0;
+    /**
+     * Request buffer rendering at specified time.
+     *
+     * @param     timestampNs   nanosecond timestamp for rendering time.
+     * @return    OK if successful;
+     *            -ENOENT if the buffer is not known.
+     */
+    virtual status_t renderOutputBuffer(
+            const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) = 0;
+    /**
+     * Discard a buffer to the underlying CodecBase object.
+     *
+     * TODO: remove once this operation can be handled by just clearing the
+     * reference.
+     *
+     * @return    OK if successful;
+     *            -ENOENT if the buffer is not known.
+     */
+    virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) = 0;
+    /**
+     * Clear and fill array with input buffers.
+     */
+    virtual void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) = 0;
+    /**
+     * Clear and fill array with output buffers.
+     */
+    virtual void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) = 0;
+
+protected:
+    std::unique_ptr<CodecBase::BufferCallback> mCallback;
+    sp<ICrypto> mCrypto;
+};
+
 }  // namespace android
 
 #endif  // CODEC_BASE_H_
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 1031de0..2e367bf 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -18,6 +18,9 @@
 
 #define MEDIA_CODEC_H_
 
+#include <memory>
+#include <vector>
+
 #include <gui/IGraphicBufferProducer.h>
 #include <media/hardware/CryptoAPI.h>
 #include <media/MediaCodecInfo.h>
@@ -32,12 +35,12 @@
 struct AMessage;
 struct AReplyToken;
 struct AString;
+class BufferChannelBase;
 struct CodecBase;
 class IBatteryStats;
 struct ICrypto;
 class MediaCodecBuffer;
 class IMemory;
-struct MemoryDealer;
 class IResourceManagerClient;
 class IResourceManagerService;
 struct PersistentSurface;
@@ -252,11 +255,9 @@
     };
 
     struct BufferInfo {
-        uint32_t mBufferID;
+        BufferInfo();
+
         sp<MediaCodecBuffer> mData;
-        sp<MediaCodecBuffer> mSecureData;
-        sp<IMemory> mSharedEncryptedBuffer;
-        sp<AMessage> mNotify;
         bool mOwnedByClient;
     };
 
@@ -301,7 +302,6 @@
     sp<AMessage> mInputFormat;
     sp<AMessage> mCallback;
     sp<AMessage> mOnFrameRenderedNotification;
-    sp<MemoryDealer> mDealer;
 
     sp<IResourceManagerClient> mResourceManagerClient;
     sp<ResourceManagerServiceProxy> mResourceManagerService;
@@ -327,8 +327,7 @@
     Mutex mBufferLock;
 
     List<size_t> mAvailPortBuffers[2];
-    Vector<BufferInfo> mPortBuffers[2];
-    Vector<sp<MediaCodecBuffer>> mPortBufferArrays[2];
+    std::vector<BufferInfo> mPortBuffers[2];
 
     int32_t mDequeueInputTimeoutGeneration;
     sp<AReplyToken> mDequeueInputReplyID;
@@ -345,6 +344,8 @@
     bool mHaveInputSurface;
     bool mHavePendingInputBuffers;
 
+    std::shared_ptr<BufferChannelBase> mBufferChannel;
+
     MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid);
 
     static sp<CodecBase> GetCodecBase(const AString &name, bool nameIsType = false);
diff --git a/include/media/stagefright/MediaFilter.h b/include/media/stagefright/MediaFilter.h
index c8b681c..0c10d11 100644
--- a/include/media/stagefright/MediaFilter.h
+++ b/include/media/stagefright/MediaFilter.h
@@ -21,6 +21,7 @@
 
 namespace android {
 
+class ACodecBufferChannel;
 struct GraphicBufferListener;
 class MemoryDealer;
 struct SimpleFilter;
@@ -28,6 +29,7 @@
 struct MediaFilter : public CodecBase {
     MediaFilter();
 
+    virtual std::shared_ptr<BufferChannelBase> getBufferChannel() override;
     virtual void initiateAllocateComponent(const sp<AMessage> &msg);
     virtual void initiateConfigureComponent(const sp<AMessage> &msg);
     virtual void initiateCreateInputSurface();
@@ -45,25 +47,6 @@
 
     virtual void onMessageReceived(const sp<AMessage> &msg);
 
-    struct PortDescription : public CodecBase::PortDescription {
-        virtual size_t countBuffers();
-        virtual IOMX::buffer_id bufferIDAt(size_t index) const;
-        virtual sp<MediaCodecBuffer> bufferAt(size_t index) const;
-
-    protected:
-        PortDescription();
-
-    private:
-        friend struct MediaFilter;
-
-        Vector<IOMX::buffer_id> mBufferIDs;
-        Vector<sp<MediaCodecBuffer> > mBuffers;
-
-        void addBuffer(IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer);
-
-        DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
-    };
-
 protected:
     virtual ~MediaFilter();
 
@@ -130,6 +113,8 @@
     sp<SimpleFilter> mFilter;
     sp<GraphicBufferListener> mGraphicBufferListener;
 
+    std::shared_ptr<ACodecBufferChannel> mBufferChannel;
+
     // helper functions
     void signalProcessBuffers();
     void signalError(status_t error);
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
new file mode 100644
index 0000000..03dce0c
--- /dev/null
+++ b/media/libaudioclient/Android.bp
@@ -0,0 +1,45 @@
+cc_library_shared {
+    name: "libaudioclient",
+    srcs: [
+        "AudioEffect.cpp",
+        "AudioPolicy.cpp",
+        "AudioRecord.cpp",
+        "AudioSystem.cpp",
+        "AudioTrack.cpp",
+        "AudioTrackShared.cpp",
+        "IAudioFlinger.cpp",
+        "IAudioFlingerClient.cpp",
+        "IAudioPolicyService.cpp",
+        "IAudioPolicyServiceClient.cpp",
+        "IAudioRecord.cpp",
+        "IAudioTrack.cpp",
+        "IEffect.cpp",
+        "IEffectClient.cpp",
+        "ToneGenerator.cpp",
+    ],
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libutils",
+        "libbinder",
+        "libdl",
+        "libaudioutils",
+    ],
+    export_shared_lib_headers: ["libbinder"],
+    // for memory heap analysis
+    static_libs: [
+        "libc_malloc_debug_backtrace",
+        "libc_logging",
+    ],
+    cflags: [
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+    sanitize: {
+        misc_undefined : [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libaudioclient/Android.mk b/media/libaudioclient/Android.mk
deleted file mode 100644
index 348ab50..0000000
--- a/media/libaudioclient/Android.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES += \
-    AudioEffect.cpp \
-    AudioPolicy.cpp \
-    AudioRecord.cpp \
-    AudioSystem.cpp \
-    AudioTrack.cpp \
-    AudioTrackShared.cpp \
-    IAudioFlinger.cpp \
-    IAudioFlingerClient.cpp \
-    IAudioPolicyService.cpp \
-    IAudioPolicyServiceClient.cpp \
-    IAudioRecord.cpp \
-    IAudioTrack.cpp \
-    IEffect.cpp \
-    IEffectClient.cpp \
-    ToneGenerator.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog libcutils libutils libbinder \
-        libdl libaudioutils \
-
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder
-
-# for memory heap analysis
-LOCAL_STATIC_LIBRARIES := libc_malloc_debug_backtrace libc_logging
-
-LOCAL_MODULE:= libaudioclient
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_C_INCLUDES := \
-    $(TOP)/frameworks/native/include/media/openmax \
-    $(TOP)/frameworks/av/include/media/ \
-    $(TOP)/frameworks/av/media/libstagefright \
-    $(TOP)/frameworks/av/media/libmedia/aidl \
-    $(call include-path-for, audio-utils)
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
-    frameworks/av/include/media \
-    frameworks/av/media/libmedia/aidl
-
-LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
-
-include $(BUILD_SHARED_LIBRARY)
-
diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c
index 323930a..f27d5ca 100644
--- a/media/libeffects/downmix/EffectDownmix.c
+++ b/media/libeffects/downmix/EffectDownmix.c
@@ -22,7 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "EffectDownmix.h"
 
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index 74d489b..554c14d 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -24,10 +24,10 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/config_utils.h>
 #include <cutils/misc.h>
 #include <cutils/properties.h>
+#include <log/log.h>
 
 #include <system/audio_effects/audio_effects_conf.h>
 
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
index 4f9f438..7ea0593 100644
--- a/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
@@ -21,7 +21,7 @@
 #endif
 //#define LOG_NDEBUG 0
 
-#include <android/log.h>
+#include <log/log.h>
 
 namespace le_fx {
 
diff --git a/media/libeffects/loudness/dsp/core/interpolator_base-inl.h b/media/libeffects/loudness/dsp/core/interpolator_base-inl.h
index bdb6818..fb87c79 100644
--- a/media/libeffects/loudness/dsp/core/interpolator_base-inl.h
+++ b/media/libeffects/loudness/dsp/core/interpolator_base-inl.h
@@ -21,7 +21,7 @@
 #endif
 //#define LOG_NDEBUG 0
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "dsp/core/basic.h"
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index f2e3e7c..d1ade1d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1347,26 +1347,26 @@
         flags |= Renderer::FLAG_REAL_TIME;
     }
 
-    sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
-    sp<MetaData> videoMeta = mSource->getFormatMeta(false /* audio */);
-    if (audioMeta == NULL && videoMeta == NULL) {
+    bool hasAudio = (mSource->getFormat(true /* audio */) != NULL);
+    bool hasVideo = (mSource->getFormat(false /* audio */) != NULL);
+    if (!hasAudio && !hasVideo) {
         ALOGE("no metadata for either audio or video source");
         mSource->stop();
         mSourceStarted = false;
         notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_MALFORMED);
         return;
     }
-    ALOGV_IF(audioMeta == NULL, "no metadata for audio source");  // video only stream
+    ALOGV_IF(!hasAudio, "no metadata for audio source");  // video only stream
+
+    sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
 
     audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
     if (mAudioSink != NULL) {
         streamType = mAudioSink->getAudioStreamType();
     }
 
-    sp<AMessage> videoFormat = mSource->getFormat(false /* audio */);
-
     mOffloadAudio =
-        canOffloadStream(audioMeta, (videoFormat != NULL), mSource->isStreaming(), streamType)
+        canOffloadStream(audioMeta, hasVideo, mSource->isStreaming(), streamType)
                 && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
     if (mOffloadAudio) {
         flags |= Renderer::FLAG_OFFLOAD_AUDIO;
@@ -1714,6 +1714,16 @@
         notifyListener(MEDIA_SET_VIDEO_SIZE, 0, 0);
         return;
     }
+    int32_t err = OK;
+    inputFormat->findInt32("err", &err);
+    if (err == -EWOULDBLOCK) {
+        ALOGW("Video meta is not available yet!");
+        return;
+    }
+    if (err != OK) {
+        ALOGW("Something is wrong with video meta!");
+        return;
+    }
 
     int32_t displayWidth, displayHeight;
     if (outputFormat != NULL) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index e190d07..f7e56e4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -33,6 +33,9 @@
 
 #include <media/IMediaAnalyticsService.h>
 
+static const int kDumpLockRetries = 50;
+static const int kDumpLockSleepUs = 20000;
+
 namespace android {
 
 
@@ -51,7 +54,7 @@
       mAtEOS(false),
       mLooping(false),
       mAutoLoop(false) {
-    ALOGV("NuPlayerDriver(%p)", this);
+    ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid);
     mLooper->setName("NuPlayerDriver Looper");
 
     // set up an analytics record
@@ -776,6 +779,24 @@
     AString logString(" NuPlayer\n");
     char buf[256] = {0};
 
+    bool locked = false;
+    for (int i = 0; i < kDumpLockRetries; ++i) {
+        if (mLock.tryLock() == NO_ERROR) {
+            locked = true;
+            break;
+        }
+        usleep(kDumpLockSleepUs);
+    }
+
+    if (locked) {
+        snprintf(buf, sizeof(buf), "  state(%d), atEOS(%d), looping(%d), autoLoop(%d)\n",
+                mState, mAtEOS, mLooping, mAutoLoop);
+        mLock.unlock();
+    } else {
+        snprintf(buf, sizeof(buf), "  NPD(%p) lock is taken\n", this);
+    }
+    logString.append(buf);
+
     for (size_t i = 0; i < trackStats.size(); ++i) {
         const sp<AMessage> &stats = trackStats.itemAt(i);
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 5197167..6006730 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -77,7 +77,11 @@
     // an error or ERROR_END_OF_STREAM if not.
     virtual status_t feedMoreTSData() = 0;
 
+    // Returns non-NULL format when the specified track exists.
+    // When the format has "err" set to -EWOULDBLOCK, source needs more time to get valid meta data.
+    // Returns NULL if the specified track doesn't exist or is invalid;
     virtual sp<AMessage> getFormat(bool audio);
+
     virtual sp<MetaData> getFormatMeta(bool /* audio */) { return NULL; }
     virtual sp<MetaData> getFileFormatMeta() const { return NULL; }
 
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index 7f9f913..d6b1e8c 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -234,8 +234,7 @@
     }
     status_t err = convertMetaDataToMessage(meta, &format);
     if (err != OK) { // format may have been cleared on error
-        format = new AMessage;
-        format->setInt32("err", err);
+        return NULL;
     }
     return format;
 }
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 13401fc..f247475 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -53,6 +53,7 @@
 #include <OMX_AsString.h>
 
 #include "include/avc_utils.h"
+#include "include/ACodecBufferChannel.h"
 #include "include/DataConverter.h"
 #include "include/SecureBuffer.h"
 #include "include/SharedMemoryBuffer.h"
@@ -564,16 +565,21 @@
 ACodec::~ACodec() {
 }
 
-void ACodec::setNotificationMessage(const sp<AMessage> &msg) {
-    mNotify = msg;
-}
-
 void ACodec::initiateSetup(const sp<AMessage> &msg) {
     msg->setWhat(kWhatSetup);
     msg->setTarget(this);
     msg->post();
 }
 
+std::shared_ptr<BufferChannelBase> ACodec::getBufferChannel() {
+    if (!mBufferChannel) {
+        mBufferChannel = std::make_shared<ACodecBufferChannel>(
+                new AMessage(kWhatInputBufferFilled, this),
+                new AMessage(kWhatOutputBufferDrained, this));
+    }
+    return mBufferChannel;
+}
+
 void ACodec::signalSetParameters(const sp<AMessage> &params) {
     sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
     msg->setMessage("params", params);
@@ -936,12 +942,17 @@
         return err;
     }
 
-    sp<PortDescription> desc = new PortDescription;
+    std::vector<ACodecBufferChannel::BufferAndId> array(mBuffers[portIndex].size());
     for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
-        const BufferInfo &info = mBuffers[portIndex][i];
-        desc->addBuffer(info.mBufferID, info.mData);
+        array[i] = {mBuffers[portIndex][i].mData, mBuffers[portIndex][i].mBufferID};
     }
-    mCallback->onBuffersAllocated(portIndex, desc);
+    if (portIndex == kPortIndexInput) {
+        mBufferChannel->setInputBufferArray(array);
+    } else if (portIndex == kPortIndexOutput) {
+        mBufferChannel->setOutputBufferArray(array);
+    } else {
+        TRESPASS();
+    }
 
     return OK;
 }
@@ -1432,6 +1443,12 @@
 }
 
 status_t ACodec::freeBuffersOnPort(OMX_U32 portIndex) {
+    if (portIndex == kPortIndexInput) {
+        mBufferChannel->setInputBufferArray({});
+    } else {
+        mBufferChannel->setOutputBufferArray({});
+    }
+
     status_t err = OK;
     for (size_t i = mBuffers[portIndex].size(); i > 0;) {
         i--;
@@ -5076,25 +5093,6 @@
     }
 }
 
-void ACodec::addKeyFormatChangesToRenderBufferNotification(sp<AMessage> &notify) {
-    AString mime;
-    CHECK(mOutputFormat->findString("mime", &mime));
-
-    if (mime == MEDIA_MIMETYPE_VIDEO_RAW && mNativeWindow != NULL) {
-        // notify renderer of the crop change and dataspace change
-        // NOTE: native window uses extended right-bottom coordinate
-        int32_t left, top, right, bottom;
-        if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) {
-            notify->setRect("crop", left, top, right + 1, bottom + 1);
-        }
-
-        int32_t dataSpace;
-        if (mOutputFormat->findInt32("android._dataspace", &dataSpace)) {
-            notify->setInt32("dataspace", dataSpace);
-        }
-    }
-}
-
 void ACodec::sendFormatChange() {
     AString mime;
     CHECK(mOutputFormat->findString("mime", &mime));
@@ -5156,29 +5154,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-ACodec::PortDescription::PortDescription() {
-}
-
-void ACodec::PortDescription::addBuffer(
-        IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer) {
-    mBufferIDs.push_back(id);
-    mBuffers.push_back(buffer);
-}
-
-size_t ACodec::PortDescription::countBuffers() {
-    return mBufferIDs.size();
-}
-
-IOMX::buffer_id ACodec::PortDescription::bufferIDAt(size_t index) const {
-    return mBufferIDs.itemAt(index);
-}
-
-sp<MediaCodecBuffer> ACodec::PortDescription::bufferAt(size_t index) const {
-    return mBuffers.itemAt(index);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
 ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
     : AState(parentState),
       mCodec(codec) {
@@ -5486,9 +5461,7 @@
     CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
 
     info->mData->setFormat(mCodec->mInputFormat);
-    sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, mCodec);
-    reply->setInt32("buffer-id", info->mBufferID);
-    mCodec->mCallback->fillThisBuffer(info->mBufferID, info->mData, reply);
+    mCodec->mBufferChannel->fillThisBuffer(info->mBufferID);
     info->mData.clear();
     info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
 }
@@ -5502,17 +5475,9 @@
     PortMode mode = getPortMode(kPortIndexInput);
     int32_t discarded = 0;
     if (msg->findInt32("discarded", &discarded) && discarded) {
-        /* these are unfilled buffers returned by client */
-        CHECK(msg->findInt32("err", &err));
-
-        if (err == OK) {
-            /* buffers with no errors are returned on MediaCodec.flush */
-            mode = KEEP_BUFFERS;
-        } else {
-            ALOGV("[%s] saw error %d instead of an input buffer",
-                 mCodec->mComponentName.c_str(), err);
-            eos = true;
-        }
+        // these are unfilled buffers returned by client
+        // buffers are returned on MediaCodec.flush
+        mode = KEEP_BUFFERS;
     }
     sp<RefBase> obj;
     CHECK(msg->findObject("buffer", &obj));
@@ -5839,7 +5804,6 @@
                 break;
             }
 
-            sp<AMessage> reply = new AMessage(kWhatOutputBufferDrained, mCodec);
             sp<MediaCodecBuffer> buffer = info->mData;
 
             if (mCodec->mOutputFormat != mCodec->mLastOutputFormat && rangeLength > 0) {
@@ -5847,12 +5811,7 @@
                 if (mCodec->mBaseOutputFormat == mCodec->mOutputFormat) {
                     mCodec->onOutputFormatChanged(mCodec->mOutputFormat);
                 }
-                mCodec->addKeyFormatChangesToRenderBufferNotification(reply);
                 mCodec->sendFormatChange();
-            } else if (rangeLength > 0 && mCodec->mNativeWindow != NULL) {
-                // If potentially rendering onto a surface, always save key format data (crop &
-                // data space) so that we can set it if and once the buffer is rendered.
-                mCodec->addKeyFormatChangesToRenderBufferNotification(reply);
             }
             buffer->setFormat(mCodec->mOutputFormat);
 
@@ -5897,9 +5856,7 @@
 
             info->mData.clear();
 
-            reply->setInt32("buffer-id", info->mBufferID);
-
-            mCodec->mCallback->drainThisBuffer(info->mBufferID, buffer, flags, reply);
+            mCodec->mBufferChannel->drainThisBuffer(info->mBufferID, flags);
 
             info->mStatus = BufferInfo::OWNED_BY_DOWNSTREAM;
 
@@ -5947,24 +5904,6 @@
         return;
     }
     info->mData = buffer;
-
-    android_native_rect_t crop;
-    if (msg->findRect("crop", &crop.left, &crop.top, &crop.right, &crop.bottom)
-            && memcmp(&crop, &mCodec->mLastNativeWindowCrop, sizeof(crop)) != 0) {
-        mCodec->mLastNativeWindowCrop = crop;
-        status_t err = native_window_set_crop(mCodec->mNativeWindow.get(), &crop);
-        ALOGW_IF(err != NO_ERROR, "failed to set crop: %d", err);
-    }
-
-    int32_t dataSpace;
-    if (msg->findInt32("dataspace", &dataSpace)
-            && dataSpace != mCodec->mLastNativeWindowDataSpace) {
-        status_t err = native_window_set_buffers_data_space(
-                mCodec->mNativeWindow.get(), (android_dataspace)dataSpace);
-        mCodec->mLastNativeWindowDataSpace = dataSpace;
-        ALOGW_IF(err != NO_ERROR, "failed to set dataspace: %d", err);
-    }
-
     int32_t render;
     if (mCodec->mNativeWindow != NULL
             && msg->findInt32("render", &render) && render != 0
@@ -5972,6 +5911,27 @@
         ATRACE_NAME("render");
         // The client wants this buffer to be rendered.
 
+        android_native_rect_t crop;
+        if (buffer->format()->findRect("crop", &crop.left, &crop.top, &crop.right, &crop.bottom)) {
+            // NOTE: native window uses extended right-bottom coordinate
+            ++crop.right;
+            ++crop.bottom;
+            if (memcmp(&crop, &mCodec->mLastNativeWindowCrop, sizeof(crop)) != 0) {
+                mCodec->mLastNativeWindowCrop = crop;
+                status_t err = native_window_set_crop(mCodec->mNativeWindow.get(), &crop);
+                ALOGW_IF(err != NO_ERROR, "failed to set crop: %d", err);
+            }
+        }
+
+        int32_t dataSpace;
+        if (buffer->format()->findInt32("android._dataspace", &dataSpace)
+                && dataSpace != mCodec->mLastNativeWindowDataSpace) {
+            status_t err = native_window_set_buffers_data_space(
+                    mCodec->mNativeWindow.get(), (android_dataspace)dataSpace);
+            mCodec->mLastNativeWindowDataSpace = dataSpace;
+            ALOGW_IF(err != NO_ERROR, "failed to set dataspace: %d", err);
+        }
+
         // save buffers sent to the surface so we can get render time when they return
         int64_t mediaTimeUs = -1;
         buffer->meta()->findInt64("timeUs", &mediaTimeUs);
@@ -6613,12 +6573,18 @@
 
 status_t ACodec::LoadedToIdleState::allocateBuffers() {
     status_t err = mCodec->allocateBuffersOnPort(kPortIndexInput);
-
     if (err != OK) {
         return err;
     }
 
-    return mCodec->allocateBuffersOnPort(kPortIndexOutput);
+    err = mCodec->allocateBuffersOnPort(kPortIndexOutput);
+    if (err != OK) {
+        return err;
+    }
+
+    mCodec->mCallback->onStartCompleted();
+
+    return OK;
 }
 
 bool ACodec::LoadedToIdleState::onMessageReceived(const sp<AMessage> &msg) {
@@ -7226,6 +7192,7 @@
                     err = mCodec->allocateBuffersOnPort(kPortIndexOutput);
                     ALOGE_IF(err != OK, "Failed to allocate output port buffers after port "
                             "reconfiguration: (%d)", err);
+                    mCodec->mCallback->onOutputBuffersChanged();
                 }
 
                 if (err != OK) {
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
new file mode 100644
index 0000000..1db7ab0
--- /dev/null
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ACodecBufferChannel"
+#include <utils/Log.h>
+
+#include <numeric>
+
+#include <binder/MemoryDealer.h>
+#include <media/openmax/OMX_Core.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/MediaCodecBuffer.h>
+#include <system/window.h>
+
+#include "include/ACodecBufferChannel.h"
+#include "include/SecureBuffer.h"
+#include "include/SharedMemoryBuffer.h"
+
+namespace android {
+
+using BufferInfo = ACodecBufferChannel::BufferInfo;
+using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
+
+static BufferInfoIterator findClientBuffer(
+        const std::shared_ptr<const std::vector<const BufferInfo>> &array,
+        const sp<MediaCodecBuffer> &buffer) {
+    return std::find_if(
+            array->begin(), array->end(),
+            [buffer](const BufferInfo &info) { return info.mClientBuffer == buffer; });
+}
+
+static BufferInfoIterator findBufferId(
+        const std::shared_ptr<const std::vector<const BufferInfo>> &array,
+        IOMX::buffer_id bufferId) {
+    return std::find_if(
+            array->begin(), array->end(),
+            [bufferId](const BufferInfo &info) { return bufferId == info.mBufferId; });
+}
+
+ACodecBufferChannel::BufferInfo::BufferInfo(
+        const sp<MediaCodecBuffer> &buffer,
+        IOMX::buffer_id bufferId,
+        const sp<IMemory> &sharedEncryptedBuffer)
+    : mClientBuffer(
+          (sharedEncryptedBuffer == nullptr)
+          ? buffer
+          : new SharedMemoryBuffer(buffer->format(), sharedEncryptedBuffer)),
+      mCodecBuffer(buffer),
+      mBufferId(bufferId),
+      mSharedEncryptedBuffer(sharedEncryptedBuffer) {
+}
+
+ACodecBufferChannel::ACodecBufferChannel(
+        const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained)
+    : mInputBufferFilled(inputBufferFilled),
+      mOutputBufferDrained(outputBufferDrained) {
+}
+
+status_t ACodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mInputBuffers));
+    BufferInfoIterator it = findClientBuffer(array, buffer);
+    if (it == array->end()) {
+        return -ENOENT;
+    }
+    ALOGV("queueInputBuffer #%d", it->mBufferId);
+    sp<AMessage> msg = mInputBufferFilled->dup();
+    msg->setObject("buffer", it->mCodecBuffer);
+    msg->setInt32("buffer-id", it->mBufferId);
+    msg->post();
+    return OK;
+}
+
+status_t ACodecBufferChannel::queueSecureInputBuffer(
+        const sp<MediaCodecBuffer> &buffer,
+        bool secure,
+        const uint8_t *key,
+        const uint8_t *iv,
+        CryptoPlugin::Mode mode,
+        CryptoPlugin::Pattern pattern,
+        const CryptoPlugin::SubSample *subSamples,
+        size_t numSubSamples,
+        AString *errorDetailMsg) {
+    if (mCrypto == nullptr) {
+        return -ENOSYS;
+    }
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mInputBuffers));
+    BufferInfoIterator it = findClientBuffer(array, buffer);
+    if (it == array->end()) {
+        return -ENOENT;
+    }
+
+    void *dst_pointer = nullptr;
+    ICrypto::DestinationType dst_type = ICrypto::kDestinationTypeOpaqueHandle;
+
+    if (secure) {
+        sp<SecureBuffer> secureData = static_cast<SecureBuffer *>(it->mCodecBuffer.get());
+        dst_pointer = secureData->getDestinationPointer();
+        dst_type = secureData->getDestinationType();
+    } else {
+        dst_pointer = it->mCodecBuffer->base();
+        dst_type = ICrypto::kDestinationTypeVmPointer;
+    }
+
+    ssize_t result = mCrypto->decrypt(
+            dst_type,
+            key,
+            iv,
+            mode,
+            pattern,
+            it->mSharedEncryptedBuffer,
+            it->mClientBuffer->offset(),
+            subSamples,
+            numSubSamples,
+            dst_pointer,
+            errorDetailMsg);
+
+    if (result < 0) {
+        return result;
+    }
+
+    it->mCodecBuffer->setRange(0, result);
+
+    // Copy metadata from client to codec buffer.
+    it->mCodecBuffer->meta()->clear();
+    int64_t timeUs;
+    CHECK(it->mClientBuffer->meta()->findInt64("timeUs", &timeUs));
+    it->mCodecBuffer->meta()->setInt64("timeUs", timeUs);
+    int32_t eos;
+    if (it->mClientBuffer->meta()->findInt32("eos", &eos)) {
+        it->mCodecBuffer->meta()->setInt32("eos", eos);
+    }
+    int32_t csd;
+    if (it->mClientBuffer->meta()->findInt32("csd", &csd)) {
+        it->mCodecBuffer->meta()->setInt32("csd", csd);
+    }
+
+    ALOGV("queueSecureInputBuffer #%d", it->mBufferId);
+    sp<AMessage> msg = mInputBufferFilled->dup();
+    msg->setObject("buffer", it->mCodecBuffer);
+    msg->setInt32("buffer-id", it->mBufferId);
+    msg->post();
+    return OK;
+}
+
+status_t ACodecBufferChannel::renderOutputBuffer(
+        const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mOutputBuffers));
+    BufferInfoIterator it = findClientBuffer(array, buffer);
+    if (it == array->end()) {
+        return -ENOENT;
+    }
+
+    ALOGV("renderOutputBuffer #%d", it->mBufferId);
+    sp<AMessage> msg = mOutputBufferDrained->dup();
+    msg->setObject("buffer", buffer);
+    msg->setInt32("buffer-id", it->mBufferId);
+    msg->setInt32("render", true);
+    msg->setInt64("timestampNs", timestampNs);
+    msg->post();
+    return OK;
+}
+
+status_t ACodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mInputBuffers));
+    bool input = true;
+    BufferInfoIterator it = findClientBuffer(array, buffer);
+    if (it == array->end()) {
+        array = std::atomic_load(&mOutputBuffers);
+        input = false;
+        it = findClientBuffer(array, buffer);
+        if (it == array->end()) {
+            return -ENOENT;
+        }
+    }
+    ALOGV("discardBuffer #%d", it->mBufferId);
+    sp<AMessage> msg = input ? mInputBufferFilled->dup() : mOutputBufferDrained->dup();
+    msg->setObject("buffer", it->mCodecBuffer);
+    msg->setInt32("buffer-id", it->mBufferId);
+    msg->setInt32("discarded", true);
+    msg->post();
+    return OK;
+}
+
+void ACodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
+    std::shared_ptr<const std::vector<const BufferInfo>> inputBuffers(
+            std::atomic_load(&mInputBuffers));
+    array->clear();
+    for (const BufferInfo &elem : *inputBuffers) {
+        array->push_back(elem.mClientBuffer);
+    }
+}
+
+void ACodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
+    std::shared_ptr<const std::vector<const BufferInfo>> outputBuffers(
+            std::atomic_load(&mOutputBuffers));
+    array->clear();
+    for (const BufferInfo &elem : *outputBuffers) {
+        array->push_back(elem.mClientBuffer);
+    }
+}
+
+void ACodecBufferChannel::setInputBufferArray(const std::vector<BufferAndId> &array) {
+    bool secure = (mCrypto != nullptr);
+    if (secure) {
+        size_t totalSize = std::accumulate(
+                array.begin(), array.end(), 0u,
+                [alignment = MemoryDealer::getAllocationAlignment()]
+                (size_t sum, const BufferAndId& elem) {
+                    return sum + align(elem.mBuffer->capacity(), alignment);
+                });
+        mDealer = new MemoryDealer(totalSize, "ACodecBufferChannel");
+    }
+    std::vector<const BufferInfo> inputBuffers;
+    for (const BufferAndId &elem : array) {
+        sp<IMemory> sharedEncryptedBuffer;
+        if (secure) {
+            sharedEncryptedBuffer = mDealer->allocate(elem.mBuffer->capacity());
+        }
+        inputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, sharedEncryptedBuffer);
+    }
+    std::atomic_store(
+            &mInputBuffers,
+            std::make_shared<const std::vector<const BufferInfo>>(inputBuffers));
+}
+
+void ACodecBufferChannel::setOutputBufferArray(const std::vector<BufferAndId> &array) {
+    std::vector<const BufferInfo> outputBuffers;
+    for (const BufferAndId &elem : array) {
+        outputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, nullptr);
+    }
+    std::atomic_store(
+            &mOutputBuffers,
+            std::make_shared<const std::vector<const BufferInfo>>(outputBuffers));
+}
+
+void ACodecBufferChannel::fillThisBuffer(IOMX::buffer_id bufferId) {
+    ALOGV("fillThisBuffer #%d", bufferId);
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mInputBuffers));
+    BufferInfoIterator it = findBufferId(array, bufferId);
+
+    if (it == array->end()) {
+        ALOGE("fillThisBuffer: unrecognized buffer #%d", bufferId);
+        return;
+    }
+    if (it->mClientBuffer != it->mCodecBuffer) {
+        it->mClientBuffer->setFormat(it->mCodecBuffer->format());
+    }
+
+    mCallback->onInputBufferAvailable(
+            std::distance(array->begin(), it),
+            it->mClientBuffer);
+}
+
+void ACodecBufferChannel::drainThisBuffer(
+        IOMX::buffer_id bufferId,
+        OMX_U32 omxFlags) {
+    ALOGV("drainThisBuffer #%d", bufferId);
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mOutputBuffers));
+    BufferInfoIterator it = findBufferId(array, bufferId);
+
+    if (it == array->end()) {
+        ALOGE("drainThisBuffer: unrecognized buffer #%d", bufferId);
+        return;
+    }
+    if (it->mClientBuffer != it->mCodecBuffer) {
+        it->mClientBuffer->setFormat(it->mCodecBuffer->format());
+    }
+
+    uint32_t flags = 0;
+    if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
+        flags |= MediaCodec::BUFFER_FLAG_SYNCFRAME;
+    }
+    if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+        flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
+    }
+    if (omxFlags & OMX_BUFFERFLAG_EOS) {
+        flags |= MediaCodec::BUFFER_FLAG_EOS;
+    }
+    it->mClientBuffer->meta()->setInt32("flags", flags);
+
+    mCallback->onOutputBufferAvailable(
+            std::distance(array->begin(), it),
+            it->mClientBuffer);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 8c42cfd..f3d622b 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -4,6 +4,7 @@
 
 LOCAL_SRC_FILES:=                         \
         ACodec.cpp                        \
+        ACodecBufferChannel.cpp           \
         AACExtractor.cpp                  \
         AACWriter.cpp                     \
         AMRExtractor.cpp                  \
@@ -14,7 +15,6 @@
         CallbackDataSource.cpp            \
         CameraSource.cpp                  \
         CameraSourceTimeLapse.cpp         \
-        CodecBase.cpp                     \
         DataConverter.cpp                 \
         DataSource.cpp                    \
         DataURISource.cpp                 \
diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp
deleted file mode 100644
index 3eca52a..0000000
--- a/media/libstagefright/CodecBase.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "CodecBase"
-
-#include <inttypes.h>
-
-#include <media/stagefright/CodecBase.h>
-
-namespace android {
-
-CodecBase::CodecBase() {
-}
-
-CodecBase::~CodecBase() {
-}
-
-CodecBase::PortDescription::PortDescription() {
-}
-
-CodecBase::PortDescription::~PortDescription() {
-}
-
-void CodecBase::setCallback(std::shared_ptr<Callback> &&callback) {
-    mCallback = callback;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
old mode 100644
new mode 100755
index 0d61bf5..ac15687
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -3260,8 +3260,8 @@
         mOwner->writeInt32(0);
     } else {
         int32_t width, height;
-        bool success = mMeta->findInt32(kKeyWidth, &width);
-        success = success && mMeta->findInt32(kKeyHeight, &height);
+        bool success = mMeta->findInt32(kKeyDisplayWidth, &width);
+        success = success && mMeta->findInt32(kKeyDisplayHeight, &height);
         CHECK(success);
 
         mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
@@ -3309,13 +3309,22 @@
 
 void MPEG4Writer::Track::writeMdhdBox(uint32_t now) {
     int64_t trakDurationUs = getDurationUs();
+    int64_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
     mOwner->beginBox("mdhd");
-    mOwner->writeInt32(0);             // version=0, flags=0
-    mOwner->writeInt32(now);           // creation time
-    mOwner->writeInt32(now);           // modification time
-    mOwner->writeInt32(mTimeScale);    // media timescale
-    int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
-    mOwner->writeInt32(mdhdDuration);  // use media timescale
+
+    if (mdhdDuration > UINT32_MAX) {
+        mOwner->writeInt32((1 << 24));            // version=1, flags=0
+        mOwner->writeInt64((int64_t)now);         // creation time
+        mOwner->writeInt64((int64_t)now);         // modification time
+        mOwner->writeInt32(mTimeScale);           // media timescale
+        mOwner->writeInt64(mdhdDuration);         // media timescale
+    } else {
+        mOwner->writeInt32(0);                      // version=0, flags=0
+        mOwner->writeInt32(now);                    // creation time
+        mOwner->writeInt32(now);                    // modification time
+        mOwner->writeInt32(mTimeScale);             // media timescale
+        mOwner->writeInt32((int32_t)mdhdDuration);  // use media timescale
+    }
     // Language follows the three letter standard ISO-639-2/T
     // 'e', 'n', 'g' for "English", for instance.
     // Each character is packed as the difference between its ASCII value and 0x60.
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index f29f786..9eca982 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -37,6 +37,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/ACodec.h>
 #include <media/stagefright/BufferProducerWrapper.h>
@@ -66,6 +67,7 @@
 
 static const int kMaxRetry = 2;
 static const int kMaxReclaimWaitTimeInUs = 500000;  // 0.5s
+static const int kNumBuffersAlign = 16;
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -175,12 +177,17 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+MediaCodec::BufferInfo::BufferInfo() : mOwnedByClient(false) {}
+
+////////////////////////////////////////////////////////////////////////////////
+
 namespace {
 
 enum {
     kWhatFillThisBuffer      = 'fill',
     kWhatDrainThisBuffer     = 'drai',
     kWhatEOS                 = 'eos ',
+    kWhatStartCompleted      = 'Scom',
     kWhatStopCompleted       = 'scom',
     kWhatReleaseCompleted    = 'rcom',
     kWhatFlushCompleted      = 'fcom',
@@ -190,20 +197,51 @@
     kWhatInputSurfaceCreated = 'isfc',
     kWhatInputSurfaceAccepted = 'isfa',
     kWhatSignaledInputEOS    = 'seos',
-    kWhatBuffersAllocated    = 'allc',
     kWhatOutputFramesRendered = 'outR',
+    kWhatOutputBuffersChanged = 'outC',
 };
 
-class MediaCodecCallback : public CodecBase::Callback {
+class BufferCallback : public CodecBase::BufferCallback {
 public:
-    explicit MediaCodecCallback(const sp<AMessage> &notify);
-    virtual ~MediaCodecCallback();
+    explicit BufferCallback(const sp<AMessage> &notify);
+    virtual ~BufferCallback() = default;
 
-    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 onInputBufferAvailable(
+            size_t index, const sp<MediaCodecBuffer> &buffer) override;
+    virtual void onOutputBufferAvailable(
+            size_t index, const sp<MediaCodecBuffer> &buffer) override;
+private:
+    const sp<AMessage> mNotify;
+};
+
+BufferCallback::BufferCallback(const sp<AMessage> &notify)
+    : mNotify(notify) {}
+
+void BufferCallback::onInputBufferAvailable(
+        size_t index, const sp<MediaCodecBuffer> &buffer) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatFillThisBuffer);
+    notify->setSize("index", index);
+    notify->setObject("buffer", buffer);
+    notify->post();
+}
+
+void BufferCallback::onOutputBufferAvailable(
+        size_t index, const sp<MediaCodecBuffer> &buffer) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatDrainThisBuffer);
+    notify->setSize("index", index);
+    notify->setObject("buffer", buffer);
+    notify->post();
+}
+
+class CodecCallback : public CodecBase::CodecCallback {
+public:
+    explicit CodecCallback(const sp<AMessage> &notify);
+    virtual ~CodecCallback() = default;
+
     virtual void onEos(status_t err) override;
+    virtual void onStartCompleted() override;
     virtual void onStopCompleted() override;
     virtual void onReleaseCompleted() override;
     virtual void onFlushCompleted() override;
@@ -221,69 +259,46 @@
             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;
+    virtual void onOutputBuffersChanged() override;
 private:
     const sp<AMessage> mNotify;
 };
 
-MediaCodecCallback::MediaCodecCallback(const sp<AMessage> &notify) : mNotify(notify) {}
+CodecCallback::CodecCallback(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) {
+void CodecCallback::onEos(status_t err) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatEOS);
     notify->setInt32("err", err);
     notify->post();
 }
 
-void MediaCodecCallback::onStopCompleted() {
+void CodecCallback::onStartCompleted() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatStartCompleted);
+    notify->post();
+}
+
+void CodecCallback::onStopCompleted() {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatStopCompleted);
     notify->post();
 }
 
-void MediaCodecCallback::onReleaseCompleted() {
+void CodecCallback::onReleaseCompleted() {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatReleaseCompleted);
     notify->post();
 }
 
-void MediaCodecCallback::onFlushCompleted() {
+void CodecCallback::onFlushCompleted() {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatFlushCompleted);
     notify->post();
 }
 
-void MediaCodecCallback::onError(status_t err, enum ActionCode actionCode) {
+void CodecCallback::onError(status_t err, enum ActionCode actionCode) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatError);
     notify->setInt32("err", err);
@@ -291,14 +306,14 @@
     notify->post();
 }
 
-void MediaCodecCallback::onComponentAllocated(const char *componentName) {
+void CodecCallback::onComponentAllocated(const char *componentName) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatComponentAllocated);
     notify->setString("componentName", componentName);
     notify->post();
 }
 
-void MediaCodecCallback::onComponentConfigured(
+void CodecCallback::onComponentConfigured(
         const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatComponentConfigured);
@@ -307,7 +322,7 @@
     notify->post();
 }
 
-void MediaCodecCallback::onInputSurfaceCreated(
+void CodecCallback::onInputSurfaceCreated(
         const sp<AMessage> &inputFormat,
         const sp<AMessage> &outputFormat,
         const sp<BufferProducerWrapper> &inputSurface) {
@@ -319,14 +334,14 @@
     notify->post();
 }
 
-void MediaCodecCallback::onInputSurfaceCreationFailed(status_t err) {
+void CodecCallback::onInputSurfaceCreationFailed(status_t err) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatInputSurfaceCreated);
     notify->setInt32("err", err);
     notify->post();
 }
 
-void MediaCodecCallback::onInputSurfaceAccepted(
+void CodecCallback::onInputSurfaceAccepted(
         const sp<AMessage> &inputFormat,
         const sp<AMessage> &outputFormat) {
     sp<AMessage> notify(mNotify->dup());
@@ -336,14 +351,14 @@
     notify->post();
 }
 
-void MediaCodecCallback::onInputSurfaceDeclined(status_t err) {
+void CodecCallback::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) {
+void CodecCallback::onSignaledInputEOS(status_t err) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatSignaledInputEOS);
     if (err != OK) {
@@ -352,16 +367,7 @@
     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) {
+void CodecCallback::onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatOutputFramesRendered);
     if (MediaCodec::CreateFramesRenderedMessage(done, notify)) {
@@ -369,6 +375,12 @@
     }
 }
 
+void CodecCallback::onOutputBuffersChanged() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatOutputBuffersChanged);
+    notify->post();
+}
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -573,7 +585,12 @@
     mLooper->registerHandler(this);
 
     mCodec->setCallback(
-            std::make_shared<MediaCodecCallback>(new AMessage(kWhatCodecNotify, this)));
+            std::unique_ptr<CodecBase::CodecCallback>(
+                    new CodecCallback(new AMessage(kWhatCodecNotify, this))));
+    mBufferChannel = mCodec->getBufferChannel();
+    mBufferChannel->setCallback(
+            std::unique_ptr<CodecBase::BufferCallback>(
+                    new BufferCallback(new AMessage(kWhatCodecNotify, this))));
 
     sp<AMessage> msg = new AMessage(kWhatInit, this);
     msg->setString("name", name);
@@ -800,14 +817,9 @@
 }
 
 bool MediaCodec::hasPendingBuffer(int portIndex) {
-    const Vector<BufferInfo> &buffers = mPortBuffers[portIndex];
-    for (size_t i = 0; i < buffers.size(); ++i) {
-        const BufferInfo &info = buffers.itemAt(i);
-        if (info.mOwnedByClient) {
-            return true;
-        }
-    }
-    return false;
+    return std::any_of(
+            mPortBuffers[portIndex].begin(), mPortBuffers[portIndex].end(),
+            [](const BufferInfo &info) { return info.mOwnedByClient; });
 }
 
 bool MediaCodec::hasPendingBuffer() {
@@ -1114,14 +1126,14 @@
     // we also don't want mOwnedByClient to change during this
     Mutex::Autolock al(mBufferLock);
 
-    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
-    if (index >= buffers->size()) {
+    std::vector<BufferInfo> &buffers = mPortBuffers[portIndex];
+    if (index >= buffers.size()) {
         ALOGE("getBufferAndFormat - trying to get buffer with "
-              "bad index (index=%zu buffer_size=%zu)", index, buffers->size());
+              "bad index (index=%zu buffer_size=%zu)", index, buffers.size());
         return INVALID_OPERATION;
     }
 
-    const BufferInfo &info = buffers->itemAt(index);
+    const BufferInfo &info = buffers[index];
     if (!info.mOwnedByClient) {
         ALOGE("getBufferAndFormat - invalid operation "
               "(the index %zu is not owned by client)", index);
@@ -1219,7 +1231,7 @@
         }
 
         const sp<MediaCodecBuffer> &buffer =
-            mPortBuffers[kPortIndexOutput].itemAt(index).mData;
+            mPortBuffers[kPortIndexOutput][index].mData;
 
         response->setSize("index", index);
         response->setSize("offset", buffer->offset());
@@ -1230,19 +1242,8 @@
 
         response->setInt64("timeUs", timeUs);
 
-        int32_t omxFlags;
-        CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags));
-
-        uint32_t flags = 0;
-        if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
-            flags |= BUFFER_FLAG_SYNCFRAME;
-        }
-        if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
-            flags |= BUFFER_FLAG_CODECCONFIG;
-        }
-        if (omxFlags & OMX_BUFFERFLAG_EOS) {
-            flags |= BUFFER_FLAG_EOS;
-        }
+        int32_t flags;
+        CHECK(buffer->meta()->findInt32("flags", &flags));
 
         response->setInt32("flags", flags);
         response->postReply(replyID);
@@ -1507,75 +1508,24 @@
                     break;
                 }
 
-
-                case kWhatBuffersAllocated:
+                case kWhatStartCompleted:
                 {
-                    Mutex::Autolock al(mBufferLock);
-                    int32_t portIndex;
-                    CHECK(msg->findInt32("portIndex", &portIndex));
-
-                    ALOGV("%s buffers allocated",
-                          portIndex == kPortIndexInput ? "input" : "output");
-
-                    CHECK(portIndex == kPortIndexInput
-                            || portIndex == kPortIndexOutput);
-
-                    mPortBuffers[portIndex].clear();
-                    mPortBufferArrays[portIndex].clear();
-
-                    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
-
-                    sp<RefBase> obj;
-                    CHECK(msg->findObject("portDesc", &obj));
-
-                    sp<CodecBase::PortDescription> portDesc =
-                        static_cast<CodecBase::PortDescription *>(obj.get());
-
-                    size_t numBuffers = portDesc->countBuffers();
-
-                    size_t totalSize = 0;
-                    for (size_t i = 0; i < numBuffers; ++i) {
-                        if (portIndex == kPortIndexInput && mCrypto != NULL) {
-                            totalSize += portDesc->bufferAt(i)->capacity();
-                        }
+                    CHECK_EQ(mState, STARTING);
+                    if (mIsVideo) {
+                        addResource(
+                                MediaResource::kGraphicMemory,
+                                MediaResource::kUnspecifiedSubType,
+                                getGraphicBufferSize());
                     }
+                    setState(STARTED);
+                    (new AMessage)->postReply(mReplyID);
+                    break;
+                }
 
-                    if (totalSize) {
-                        mDealer = new MemoryDealer(totalSize, "MediaCodec");
-                    }
-
-                    for (size_t i = 0; i < numBuffers; ++i) {
-                        BufferInfo info;
-                        info.mBufferID = portDesc->bufferIDAt(i);
-                        info.mOwnedByClient = false;
-                        sp<MediaCodecBuffer> buffer = portDesc->bufferAt(i);
-                        if (portIndex == kPortIndexInput && mCrypto != NULL) {
-                            info.mSharedEncryptedBuffer = mDealer->allocate(buffer->capacity());
-                            buffer = new SharedMemoryBuffer(
-                                    mInputFormat, info.mSharedEncryptedBuffer);
-                        }
-                        buffers->push_back(info);
-                        mPortBufferArrays[portIndex].push_back(buffer);
-                    }
-
-                    if (portIndex == kPortIndexOutput) {
-                        if (mState == STARTING) {
-                            // We're always allocating output buffers after
-                            // allocating input buffers, so this is a good
-                            // indication that now all buffers are allocated.
-                            if (mIsVideo) {
-                                addResource(
-                                        MediaResource::kGraphicMemory,
-                                        MediaResource::kUnspecifiedSubType,
-                                        getGraphicBufferSize());
-                            }
-                            setState(STARTED);
-                            (new AMessage)->postReply(mReplyID);
-                        } else {
-                            mFlags |= kFlagOutputBuffersChanged;
-                            postActivityNotificationIfPossible();
-                        }
-                    }
+                case kWhatOutputBuffersChanged:
+                {
+                    mFlags |= kFlagOutputBuffersChanged;
+                    postActivityNotificationIfPossible();
                     break;
                 }
 
@@ -1602,9 +1552,6 @@
                         break;
                     }
 
-                    // TODO: hold reference of buffer from downstream when
-                    // mPortBuffers is removed.
-
                     if (!mCSD.empty()) {
                         ssize_t index = dequeuePortBuffer(kPortIndexInput);
                         CHECK_GE(index, 0);
@@ -1663,12 +1610,7 @@
                     sp<RefBase> obj;
                     CHECK(msg->findObject("buffer", &obj));
                     sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
-                    // TODO: hold buffer's reference when we remove mPortBuffers
 
-                    int32_t omxFlags;
-                    CHECK(msg->findInt32("flags", &omxFlags));
-
-                    buffer->meta()->setInt32("omxFlags", omxFlags);
                     if (mOutputFormat != buffer->format()) {
                         mOutputFormat = buffer->format();
                         ALOGV("[%s] output format changed to: %s",
@@ -1701,7 +1643,9 @@
                             // Before we announce the format change we should
                             // collect codec specific data and amend the output
                             // format as necessary.
-                            if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+                            int32_t flags = 0;
+                            (void) buffer->meta()->findInt32("flags", &flags);
+                            if (flags & BUFFER_FLAG_CODECCONFIG) {
                                 status_t err =
                                     amendOutputFormatWithCodecSpecificData(buffer);
 
@@ -1924,6 +1868,7 @@
             }
 
             mCrypto = static_cast<ICrypto *>(crypto);
+            mBufferChannel->setCrypto(mCrypto);
 
             uint32_t flags;
             CHECK(msg->findInt32("flags", (int32_t *)&flags));
@@ -2351,10 +2296,10 @@
             // createInputSurface(), or persistent set by setInputSurface()),
             // give the client an empty input buffers array.
             if (portIndex != kPortIndexInput || !mHaveInputSurface) {
-                const Vector<sp<MediaCodecBuffer>> &srcBuffers = mPortBufferArrays[portIndex];
-
-                for (size_t i = 0; i < srcBuffers.size(); ++i) {
-                    dstBuffers->push_back(srcBuffers[i]);
+                if (portIndex == kPortIndexInput) {
+                    mBufferChannel->getInputBufferArray(dstBuffers);
+                } else {
+                    mBufferChannel->getOutputBufferArray(dstBuffers);
                 }
             }
 
@@ -2483,13 +2428,12 @@
 status_t MediaCodec::queueCSDInputBuffer(size_t bufferIndex) {
     CHECK(!mCSD.empty());
 
-    const BufferInfo *info =
-        &mPortBuffers[kPortIndexInput].itemAt(bufferIndex);
+    const BufferInfo &info = mPortBuffers[kPortIndexInput][bufferIndex];
 
     sp<ABuffer> csd = *mCSD.begin();
     mCSD.erase(mCSD.begin());
 
-    const sp<MediaCodecBuffer> &codecInputData = info->mData;
+    const sp<MediaCodecBuffer> &codecInputData = info.mData;
 
     if (csd->size() > codecInputData->capacity()) {
         return -EINVAL;
@@ -2557,31 +2501,19 @@
     CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
     Mutex::Autolock al(mBufferLock);
 
-    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
+    for (size_t i = 0; i < mPortBuffers[portIndex].size(); ++i) {
+        BufferInfo *info = &mPortBuffers[portIndex][i];
 
-    for (size_t i = 0; i < buffers->size(); ++i) {
-        BufferInfo *info = &buffers->editItemAt(i);
-
-        if (info->mNotify != NULL) {
-            sp<AMessage> msg = info->mNotify;
-            msg->setObject("buffer", (info->mSecureData != nullptr)
-                    ? info->mSecureData : info->mData);
-            msg->setInt32("discarded", true);
-            info->mNotify = NULL;
+        if (info->mData != nullptr) {
+            sp<MediaCodecBuffer> buffer = info->mData;
             if (isReclaim && info->mOwnedByClient) {
                 ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
                         portIndex, i);
             } else {
                 info->mOwnedByClient = false;
                 info->mData.clear();
-                info->mSecureData.clear();
             }
-
-            if (portIndex == kPortIndexInput) {
-                /* no error, just returning buffers */
-                msg->setInt32("err", OK);
-            }
-            msg->post();
+            mBufferChannel->discardBuffer(buffer);
         }
     }
 
@@ -2591,37 +2523,22 @@
 size_t MediaCodec::updateBuffers(
         int32_t portIndex, const sp<AMessage> &msg) {
     CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
-
-    uint32_t bufferID;
-    CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
+    size_t index;
+    CHECK(msg->findSize("index", &index));
     sp<RefBase> obj;
     CHECK(msg->findObject("buffer", &obj));
     sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
 
-    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
-
-    for (size_t i = 0; i < buffers->size(); ++i) {
-        BufferInfo *info = &buffers->editItemAt(i);
-
-        if (info->mBufferID == bufferID) {
-            CHECK(info->mNotify == NULL);
-            CHECK(msg->findMessage("reply", &info->mNotify));
-
-            if (portIndex == kPortIndexInput && mCrypto != NULL) {
-                info->mSecureData = buffer;
-                info->mData = mPortBufferArrays[portIndex][i];
-            } else {
-                info->mData = buffer;
-            }
-            mAvailPortBuffers[portIndex].push_back(i);
-
-            return i;
+    {
+        Mutex::Autolock al(mBufferLock);
+        if (mPortBuffers[portIndex].size() <= index) {
+            mPortBuffers[portIndex].resize(align(index + 1, kNumBuffersAlign));
         }
+        mPortBuffers[portIndex][index].mData = buffer;
     }
+    mAvailPortBuffers[portIndex].push_back(index);
 
-    TRESPASS();
-
-    return 0;
+    return index;
 }
 
 status_t MediaCodec::onQueueInputBuffer(const sp<AMessage> &msg) {
@@ -2686,9 +2603,9 @@
         return -ERANGE;
     }
 
-    BufferInfo *info = &mPortBuffers[kPortIndexInput].editItemAt(index);
+    BufferInfo *info = &mPortBuffers[kPortIndexInput][index];
 
-    if (info->mNotify == NULL || !info->mOwnedByClient) {
+    if (info->mData == nullptr || !info->mOwnedByClient) {
         return -EACCES;
     }
 
@@ -2696,69 +2613,44 @@
         return -EINVAL;
     }
 
-    sp<AMessage> reply = info->mNotify;
     info->mData->setRange(offset, size);
+    info->mData->meta()->setInt64("timeUs", timeUs);
+    if (flags & BUFFER_FLAG_EOS) {
+        info->mData->meta()->setInt32("eos", true);
+    }
+
+    if (flags & BUFFER_FLAG_CODECCONFIG) {
+        info->mData->meta()->setInt32("csd", true);
+    }
 
     sp<MediaCodecBuffer> buffer = info->mData;
+    status_t err = OK;
     if (mCrypto != NULL) {
         AString *errorDetailMsg;
         CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
 
-        void *dst_pointer = nullptr;
-        ICrypto::DestinationType dst_type = ICrypto::kDestinationTypeOpaqueHandle;
-
-        if ((mFlags & kFlagIsSecure) == 0) {
-            dst_pointer = info->mSecureData->base();
-            dst_type = ICrypto::kDestinationTypeVmPointer;
-        } else {
-            sp<SecureBuffer> secureData = static_cast<SecureBuffer *>(info->mSecureData.get());
-            dst_pointer = secureData->getDestinationPointer();
-            dst_type = secureData->getDestinationType();
-        }
-
-        ssize_t result = mCrypto->decrypt(
-                dst_type,
+        err = mBufferChannel->queueSecureInputBuffer(
+                buffer,
+                (mFlags & kFlagIsSecure),
                 key,
                 iv,
                 mode,
                 pattern,
-                info->mSharedEncryptedBuffer,
-                offset,
                 subSamples,
                 numSubSamples,
-                dst_pointer,
                 errorDetailMsg);
-
-        if (result < 0) {
-            return result;
-        }
-
-        info->mSecureData->setRange(0, result);
-        buffer = info->mSecureData;
-    }
-    buffer->meta()->setInt64("timeUs", timeUs);
-
-    if (flags & BUFFER_FLAG_EOS) {
-        buffer->meta()->setInt32("eos", true);
+    } else {
+        err = mBufferChannel->queueInputBuffer(buffer);
     }
 
-    if (flags & BUFFER_FLAG_CODECCONFIG) {
-        buffer->meta()->setInt32("csd", true);
-    }
-
-    // synchronization boundary for getBufferAndFormat
-    {
+    if (err == OK) {
+        // synchronization boundary for getBufferAndFormat
         Mutex::Autolock al(mBufferLock);
         info->mOwnedByClient = false;
+        info->mData.clear();
     }
-    info->mData.clear();
-    info->mSecureData.clear();
-    reply->setObject("buffer", buffer);
-    reply->post();
 
-    info->mNotify = NULL;
-
-    return OK;
+    return err;
 }
 
 //static
@@ -2795,23 +2687,24 @@
         return -ERANGE;
     }
 
-    BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
+    BufferInfo *info = &mPortBuffers[kPortIndexOutput][index];
 
-    if (info->mNotify == NULL || !info->mOwnedByClient) {
+    if (info->mData == nullptr || !info->mOwnedByClient) {
         return -EACCES;
     }
 
     // synchronization boundary for getBufferAndFormat
+    sp<MediaCodecBuffer> buffer;
     {
         Mutex::Autolock al(mBufferLock);
         info->mOwnedByClient = false;
+        buffer = info->mData;
+        info->mData.clear();
     }
 
-    if (render && info->mData != NULL && info->mData->size() != 0) {
-        info->mNotify->setInt32("render", true);
-
+    if (render && buffer->size() != 0) {
         int64_t mediaTimeUs = -1;
-        info->mData->meta()->findInt64("timeUs", &mediaTimeUs);
+        buffer->meta()->findInt64("timeUs", &mediaTimeUs);
 
         int64_t renderTimeNs = 0;
         if (!msg->findInt64("timestampNs", &renderTimeNs)) {
@@ -2819,12 +2712,11 @@
             ALOGV("using buffer PTS of %lld", (long long)mediaTimeUs);
             renderTimeNs = mediaTimeUs * 1000;
         }
-        info->mNotify->setInt64("timestampNs", renderTimeNs);
 
         if (mSoftRenderer != NULL) {
             std::list<FrameRenderTracker::Info> doneFrames = mSoftRenderer->render(
-                    info->mData->data(), info->mData->size(),
-                    mediaTimeUs, renderTimeNs, NULL, info->mData->format());
+                    buffer->data(), buffer->size(),
+                    mediaTimeUs, renderTimeNs, NULL, buffer->format());
 
             // if we are running, notify rendered frames
             if (!doneFrames.empty() && mState == STARTED && mOnFrameRenderedNotification != NULL) {
@@ -2836,13 +2728,11 @@
                 }
             }
         }
+        mBufferChannel->renderOutputBuffer(buffer, renderTimeNs);
+    } else {
+        mBufferChannel->discardBuffer(buffer);
     }
 
-    info->mNotify->setObject("buffer", info->mData);
-    info->mData.clear();
-    info->mNotify->post();
-    info->mNotify.clear();
-
     return OK;
 }
 
@@ -2858,7 +2748,7 @@
     size_t index = *availBuffers->begin();
     availBuffers->erase(availBuffers->begin());
 
-    BufferInfo *info = &mPortBuffers[portIndex].editItemAt(index);
+    BufferInfo *info = &mPortBuffers[portIndex][index];
     CHECK(!info->mOwnedByClient);
     {
         Mutex::Autolock al(mBufferLock);
@@ -2962,7 +2852,7 @@
     int32_t index;
     while ((index = dequeuePortBuffer(kPortIndexOutput)) >= 0) {
         const sp<MediaCodecBuffer> &buffer =
-            mPortBuffers[kPortIndexOutput].itemAt(index).mData;
+            mPortBuffers[kPortIndexOutput][index].mData;
         sp<AMessage> msg = mCallback->dup();
         msg->setInt32("callbackID", CB_OUTPUT_AVAILABLE);
         msg->setInt32("index", index);
@@ -2974,19 +2864,8 @@
 
         msg->setInt64("timeUs", timeUs);
 
-        int32_t omxFlags;
-        CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags));
-
-        uint32_t flags = 0;
-        if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
-            flags |= BUFFER_FLAG_SYNCFRAME;
-        }
-        if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
-            flags |= BUFFER_FLAG_CODECCONFIG;
-        }
-        if (omxFlags & OMX_BUFFERFLAG_EOS) {
-            flags |= BUFFER_FLAG_EOS;
-        }
+        int32_t flags;
+        CHECK(buffer->meta()->findInt32("flags", &flags));
 
         msg->setInt32("flags", flags);
 
@@ -3018,7 +2897,6 @@
     }
 }
 
-
 void MediaCodec::postActivityNotificationIfPossible() {
     if (mActivityNotify == NULL) {
         return;
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index de4d06f..5981b35 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -689,7 +689,9 @@
 
             sp<MediaCodecBuffer> inbuf;
             status_t err = mEncoder->getInputBuffer(bufferIndex, &inbuf);
-            if (err != OK || inbuf == NULL) {
+
+            if (err != OK || inbuf == NULL || inbuf->data() == NULL
+                    || mbuf->data() == NULL || mbuf->size() == 0) {
                 mbuf->release();
                 signalEOS();
                 break;
@@ -851,7 +853,8 @@
 
             sp<MediaCodecBuffer> outbuf;
             status_t err = mEncoder->getOutputBuffer(index, &outbuf);
-            if (err != OK || outbuf == NULL) {
+            if (err != OK || outbuf == NULL || outbuf->data() == NULL
+                || outbuf->size() == 0) {
                 signalEOS();
                 break;
             }
diff --git a/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp b/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp
index 9d9cd3b..5a47510 100644
--- a/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp
@@ -60,7 +60,7 @@
 ; INCLUDES
 ----------------------------------------------------------------------------*/
 #define LOG_TAG "a_refl"
-#include <android/log.h>
+#include <log/log.h>
 
 #include "a_refl.h"
 #include "typedef.h"
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp
index 5baa2a2..8393d79 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp
@@ -18,7 +18,7 @@
 
 #define LOG_TAG "conceal"
 
-#include "android/log.h"
+#include "log/log.h"
 
 #include "mp4dec_lib.h" /* video decoder function prototypes */
 #include "vlc_decode.h"
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
index 7290193..777ab5b 100644
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -42,6 +42,7 @@
 #include "SaturationFilter.h"
 #include "ZeroFilter.h"
 
+#include "../include/ACodecBufferChannel.h"
 #include "../include/SharedMemoryBuffer.h"
 
 namespace android {
@@ -53,6 +54,9 @@
     : mState(UNINITIALIZED),
       mGeneration(0),
       mGraphicBufferListener(NULL) {
+    mBufferChannel = std::make_shared<ACodecBufferChannel>(
+            new AMessage(kWhatInputBufferFilled, this),
+            new AMessage(kWhatOutputBufferDrained, this));
 }
 
 MediaFilter::~MediaFilter() {
@@ -60,6 +64,10 @@
 
 //////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////
 
+std::shared_ptr<BufferChannelBase> MediaFilter::getBufferChannel() {
+    return mBufferChannel;
+}
+
 void MediaFilter::initiateAllocateComponent(const sp<AMessage> &msg) {
     msg->setWhat(kWhatAllocateComponent);
     msg->setTarget(this);
@@ -189,29 +197,6 @@
     }
 }
 
-//////////////////// PORT DESCRIPTION //////////////////////////////////////////
-
-MediaFilter::PortDescription::PortDescription() {
-}
-
-void MediaFilter::PortDescription::addBuffer(
-        IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer) {
-    mBufferIDs.push_back(id);
-    mBuffers.push_back(buffer);
-}
-
-size_t MediaFilter::PortDescription::countBuffers() {
-    return mBufferIDs.size();
-}
-
-IOMX::buffer_id MediaFilter::PortDescription::bufferIDAt(size_t index) const {
-    return mBufferIDs.itemAt(index);
-}
-
-sp<MediaCodecBuffer> MediaFilter::PortDescription::bufferAt(size_t index) const {
-    return mBuffers.itemAt(index);
-}
-
 //////////////////// HELPER FUNCTIONS //////////////////////////////////////////
 
 void MediaFilter::signalProcessBuffers() {
@@ -259,14 +244,15 @@
         }
     }
 
-    sp<PortDescription> desc = new PortDescription;
-
+    std::vector<ACodecBufferChannel::BufferAndId> array(mBuffers[portIndex].size());
     for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
-        const BufferInfo &info = mBuffers[portIndex][i];
-
-        desc->addBuffer(info.mBufferID, info.mData);
+        array[i] = {mBuffers[portIndex][i].mData, mBuffers[portIndex][i].mBufferID};
     }
-    mCallback->onBuffersAllocated(portIndex, desc);
+    if (portIndex == kPortIndexInput) {
+        mBufferChannel->setInputBufferArray(array);
+    } else {
+        mBufferChannel->setOutputBufferArray(array);
+    }
 
     return OK;
 }
@@ -307,7 +293,7 @@
 
     info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
 
-    mCallback->fillThisBuffer(info->mBufferID, info->mData, reply);
+    mBufferChannel->fillThisBuffer(info->mBufferID);
 }
 
 void MediaFilter::postDrainThisBuffer(BufferInfo *info) {
@@ -318,8 +304,7 @@
     sp<AMessage> reply = new AMessage(kWhatOutputBufferDrained, this);
     reply->setInt32("buffer-id", info->mBufferID);
 
-    mCallback->drainThisBuffer(
-            info->mBufferID, info->mData, info->mOutputFlags, reply);
+    mBufferChannel->drainThisBuffer(info->mBufferID, info->mOutputFlags);
 
     info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
 }
@@ -505,6 +490,8 @@
 
     allocateBuffersOnPort(kPortIndexOutput);
 
+    mCallback->onStartCompleted();
+
     status_t err = mFilter->start();
     if (err != (status_t)OK) {
         ALOGE("Failed to start filter component, err %d", err);
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
new file mode 100644
index 0000000..d52ce53
--- /dev/null
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 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 A_BUFFER_CHANNEL_H_
+
+#define A_BUFFER_CHANNEL_H_
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <media/openmax/OMX_Types.h>
+#include <media/stagefright/CodecBase.h>
+#include <media/ICrypto.h>
+#include <media/IOMX.h>
+
+namespace android {
+
+/**
+ * BufferChannelBase implementation for ACodec.
+ */
+class ACodecBufferChannel : public BufferChannelBase {
+public:
+    struct BufferAndId {
+        sp<MediaCodecBuffer> mBuffer;
+        IOMX::buffer_id mBufferId;
+    };
+
+    struct BufferInfo {
+        BufferInfo(
+                const sp<MediaCodecBuffer> &buffer,
+                IOMX::buffer_id bufferId,
+                const sp<IMemory> &sharedEncryptedBuffer);
+
+        BufferInfo() = delete;
+
+        // Buffer facing MediaCodec and its clients.
+        const sp<MediaCodecBuffer> mClientBuffer;
+        // Buffer facing CodecBase.
+        const sp<MediaCodecBuffer> mCodecBuffer;
+        // OMX buffer ID.
+        const IOMX::buffer_id mBufferId;
+        // Encrypted buffer in case of secure input.
+        const sp<IMemory> mSharedEncryptedBuffer;
+    };
+
+    ACodecBufferChannel(
+            const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained);
+    virtual ~ACodecBufferChannel() = default;
+
+    // BufferChannelBase interface
+    virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
+    virtual status_t queueSecureInputBuffer(
+            const sp<MediaCodecBuffer> &buffer,
+            bool secure,
+            const uint8_t *key,
+            const uint8_t *iv,
+            CryptoPlugin::Mode mode,
+            CryptoPlugin::Pattern pattern,
+            const CryptoPlugin::SubSample *subSamples,
+            size_t numSubSamples,
+            AString *errorDetailMsg) override;
+    virtual status_t renderOutputBuffer(
+            const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override;
+    virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override;
+    virtual void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
+    virtual void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
+
+    // Methods below are interface for ACodec to use.
+
+    /**
+     * Set input buffer array.
+     *
+     * @param array     Newly allocated buffers. Empty if buffers are
+     *                  deallocated.
+     */
+    void setInputBufferArray(const std::vector<BufferAndId> &array);
+    /**
+     * Set output buffer array.
+     *
+     * @param array     Newly allocated buffers. Empty if buffers are
+     *                  deallocated.
+     */
+    void setOutputBufferArray(const std::vector<BufferAndId> &array);
+    /**
+     * Request MediaCodec to fill the specified input buffer.
+     *
+     * @param bufferId  ID of the buffer, assigned by underlying component.
+     */
+    void fillThisBuffer(IOMX::buffer_id bufferID);
+    /**
+     * Request MediaCodec to drain the specified output buffer.
+     *
+     * @param bufferId  ID of the buffer, assigned by underlying component.
+     * @param omxFlags  flags associated with this buffer (e.g. EOS).
+     */
+    void drainThisBuffer(IOMX::buffer_id bufferID, OMX_U32 omxFlags);
+
+private:
+    const sp<AMessage> mInputBufferFilled;
+    const sp<AMessage> mOutputBufferDrained;
+
+    sp<MemoryDealer> mDealer;
+
+    // These should only be accessed via std::atomic_* functions.
+    //
+    // Note on thread safety: since the vector and BufferInfo are const, it's
+    // safe to read them at any thread once the shared_ptr object is atomically
+    // obtained. Inside BufferInfo, mBufferId and mSharedEncryptedBuffer are
+    // immutable objects. We write internal states of mClient/CodecBuffer when
+    // the caller has given up the reference, so that access is also safe.
+    std::shared_ptr<const std::vector<const BufferInfo>> mInputBuffers;
+    std::shared_ptr<const std::vector<const BufferInfo>> mOutputBuffers;
+};
+
+}  // namespace android
+
+#endif  // A_BUFFER_CHANNEL_H_
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index 43624a0..8b7259d 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -22,8 +22,8 @@
 #include <stdlib.h>
 #include <sys/types.h>
 
-#include <android/log.h>
 #include <cutils/properties.h>
+#include <log/log.h>
 
 #include <audio_utils/primitives.h>
 #include "AudioResampler.h"
diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp
index d27dce7..9fb6699 100644
--- a/services/audioflinger/AudioResamplerCubic.cpp
+++ b/services/audioflinger/AudioResamplerCubic.cpp
@@ -19,7 +19,8 @@
 #include <stdint.h>
 #include <string.h>
 #include <sys/types.h>
-#include <android/log.h>
+
+#include <log/log.h>
 
 #include "AudioResampler.h"
 #include "AudioResamplerCubic.h"
diff --git a/services/audioflinger/tests/test_utils.h b/services/audioflinger/tests/test_utils.h
index 283c768..b61a929 100644
--- a/services/audioflinger/tests/test_utils.h
+++ b/services/audioflinger/tests/test_utils.h
@@ -17,6 +17,12 @@
 #ifndef ANDROID_AUDIO_TEST_UTILS_H
 #define ANDROID_AUDIO_TEST_UTILS_H
 
+#ifndef LOG_TAG
+#define LOG_TAG "test_utils"
+#endif
+
+#include <log/log.h>
+
 #include <audio_utils/sndfile.h>
 
 #ifndef ARRAY_SIZE
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 4a5250a..3aec562 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -68,13 +68,22 @@
     mLegacyMode = legacyMode;
 }
 
-status_t Camera2Client::initialize(CameraModule *module)
+status_t Camera2Client::initialize(CameraModule *module) {
+    return initializeImpl(module);
+}
+
+status_t Camera2Client::initialize(sp<CameraProviderManager> manager) {
+    return initializeImpl(manager);
+}
+
+template<typename TProviderPtr>
+status_t Camera2Client::initializeImpl(TProviderPtr providerPtr)
 {
     ATRACE_CALL();
     ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId);
     status_t res;
 
-    res = Camera2ClientBase::initialize(module);
+    res = Camera2ClientBase::initialize(providerPtr);
     if (res != OK) {
         return res;
     }
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index e2129f5..87c91a0 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -98,7 +98,8 @@
 
     virtual ~Camera2Client();
 
-    status_t initialize(CameraModule *module);
+    virtual status_t initialize(CameraModule *module) override;
+    virtual status_t initialize(sp<CameraProviderManager> manager) override;
 
     virtual status_t dump(int fd, const Vector<String16>& args);
 
@@ -219,6 +220,9 @@
 
     // Video snapshot jpeg size overriding helper function
     status_t overrideVideoSnapshotSize(Parameters &params);
+
+    template<typename TProviderPtr>
+    status_t initializeImpl(TProviderPtr providerPtr);
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 32b99ca..6efe4e3 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -917,6 +917,8 @@
     } else {
         allowZslMode = true;
     }
+    // TODO (b/34131351): turn ZSL back on after fixing the issue
+    allowZslMode = false;
 
     ALOGI("%s: allowZslMode: %d slowJpegMode %d", __FUNCTION__, allowZslMode, slowJpegMode);