Merge "MediaPlayer2: add native DataSourceDesc."
diff --git a/include/media/AudioPresentationInfo.h b/include/media/AudioPresentationInfo.h
new file mode 100644
index 0000000..e91a992
--- /dev/null
+++ b/include/media/AudioPresentationInfo.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 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 AUDIO_PRESENTATION_INFO_H_
+#define AUDIO_PRESENTATION_INFO_H_
+
+#include <sstream>
+#include <stdint.h>
+
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+enum mastering_indication {
+    MASTERING_NOT_INDICATED,
+    MASTERED_FOR_STEREO,
+    MASTERED_FOR_SURROUND,
+    MASTERED_FOR_3D,
+    MASTERED_FOR_HEADPHONE,
+};
+
+struct AudioPresentation : public RefBase {
+    int32_t mPresentationId;
+    int32_t mProgramId;
+    KeyedVector<String8, String8> mLabels;
+    String8 mLanguage;
+    int32_t mMasteringIndication;
+    bool mAudioDescriptionAvailable;
+    bool mSpokenSubtitlesAvailable;
+    bool mDialogueEnhancementAvailable;
+
+    AudioPresentation() {
+        mPresentationId = -1;
+        mProgramId = -1;
+        mLanguage = "";
+        mMasteringIndication = MASTERING_NOT_INDICATED;
+        mAudioDescriptionAvailable = false;
+        mSpokenSubtitlesAvailable = false;
+        mDialogueEnhancementAvailable = false;
+    }
+};
+
+typedef Vector<sp<AudioPresentation>> AudioPresentations;
+
+class AudioPresentationInfo : public RefBase {
+ public:
+    AudioPresentationInfo();
+
+    ~AudioPresentationInfo();
+
+    void addPresentation(sp<AudioPresentation> presentation);
+
+    size_t countPresentations() const;
+
+    const sp<AudioPresentation> getPresentation(size_t index) const;
+
+ private:
+    AudioPresentations mPresentations;
+};
+
+}  // namespace android
+
+#endif  // AUDIO_PRESENTATION_INFO_H_
diff --git a/include/media/MicrophoneInfo.h b/include/media/MicrophoneInfo.h
index b0199d4..2287aca 100644
--- a/include/media/MicrophoneInfo.h
+++ b/include/media/MicrophoneInfo.h
@@ -42,7 +42,7 @@
     MicrophoneInfo(audio_microphone_characteristic_t& characteristic) {
         mDeviceId = String16(&characteristic.device_id[0]);
         mPortId = characteristic.id;
-        mType = characteristic.type;
+        mType = characteristic.device;
         mAddress = String16(&characteristic.address[0]);
         mDeviceLocation = characteristic.location;
         mDeviceGroup = characteristic.group;
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index adc4904..854c691 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -251,8 +251,8 @@
 }
 
 audio_session_t AAudioConvert_aaudioToAndroidSessionId(aaudio_session_id_t sessionId) {
-    // If not a valid sessionId then convert to a safe value of AUDIO_SESSION_ALLOCATE.
-    return (sessionId < AAUDIO_SESSION_ID_MIN)
+    // If not a regular sessionId then convert to a safe value of AUDIO_SESSION_ALLOCATE.
+    return (sessionId == AAUDIO_SESSION_ID_ALLOCATE || sessionId == AAUDIO_SESSION_ID_NONE)
            ? AUDIO_SESSION_ALLOCATE
            : (audio_session_t) sessionId;
 }
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index 3673c34..dc6a671 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -27,9 +27,6 @@
 
 #include "aaudio/AAudio.h"
 
-
-constexpr aaudio_session_id_t AAUDIO_SESSION_ID_MIN = 1; // must be positive
-
 /**
  * Convert an AAudio result into the closest matching Android status.
  */
diff --git a/media/libaaudio/tests/test_session_id.cpp b/media/libaaudio/tests/test_session_id.cpp
index d9072af..3f7d4fc 100644
--- a/media/libaaudio/tests/test_session_id.cpp
+++ b/media/libaaudio/tests/test_session_id.cpp
@@ -97,7 +97,10 @@
 
     // Get the allocated ID from the stream.
     sessionId1 = AAudioStream_getSessionId(aaudioStream1);
-    ASSERT_LT(0, sessionId1); // Must be positive.
+
+    // Check for invalid session IDs.
+    ASSERT_NE(AAUDIO_SESSION_ID_NONE, sessionId1);
+    ASSERT_NE(AAUDIO_SESSION_ID_ALLOCATE, sessionId1);
 
     ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream1));
 
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 7dd3f29..55954f2 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -29,6 +29,7 @@
 #include <utils/Log.h>
 #include <private/media/AudioTrackShared.h>
 #include <media/IAudioFlinger.h>
+#include <media/AudioParameter.h>
 #include <media/AudioPolicyHelper.h>
 #include <media/AudioResamplerPublic.h>
 #include <media/MediaAnalyticsItem.h>
@@ -2354,6 +2355,17 @@
     return mAudioTrack->setParameters(keyValuePairs);
 }
 
+status_t AudioTrack::selectPresentation(int presentationId, int programId)
+{
+    AutoMutex lock(mLock);
+    AudioParameter param = AudioParameter();
+    param.addInt(String8(AudioParameter::keyPresentationId), presentationId);
+    param.addInt(String8(AudioParameter::keyProgramId), programId);
+    ALOGV("PresentationId/ProgramId[%s]",param.toString().string());
+
+    return mAudioTrack->setParameters(param.toString());
+}
+
 VolumeShaper::Status AudioTrack::applyVolumeShaper(
         const sp<VolumeShaper::Configuration>& configuration,
         const sp<VolumeShaper::Operation>& operation)
diff --git a/media/libaudioclient/include/media/AudioParameter.h b/media/libaudioclient/include/media/AudioParameter.h
index 1ace607..59ac1db 100644
--- a/media/libaudioclient/include/media/AudioParameter.h
+++ b/media/libaudioclient/include/media/AudioParameter.h
@@ -58,6 +58,12 @@
     static const char * const keyMonoOutput;
     static const char * const keyStreamHwAvSync;
 
+    //  keys for presentation selection
+    //  keyPresentationId: Audio presentation identifier
+    //  keyProgramId: Audio presentation program identifier
+    static const char * const keyPresentationId;
+    static const char * const keyProgramId;
+
     //  keyStreamConnect / Disconnect: value is an int in audio_devices_t
     static const char * const keyStreamConnect;
     static const char * const keyStreamDisconnect;
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index e5bb854..3eb627d 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -765,6 +765,9 @@
     /* Gets the volume shaper state */
             sp<media::VolumeShaper::State> getVolumeShaperState(int id);
 
+    /* Selects the presentation (if available) */
+            status_t    selectPresentation(int presentationId, int programId);
+
     /* Get parameters */
             String8     getParameters(const String8& keys);
 
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
index 65fc70b..cb0e927 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -34,6 +34,8 @@
 const char * const AudioParameter::keyScreenState = AUDIO_PARAMETER_KEY_SCREEN_STATE;
 const char * const AudioParameter::keyBtNrec = AUDIO_PARAMETER_KEY_BT_NREC;
 const char * const AudioParameter::keyHwAvSync = AUDIO_PARAMETER_HW_AV_SYNC;
+const char * const AudioParameter::keyPresentationId = AUDIO_PARAMETER_STREAM_PRESENTATION_ID;
+const char * const AudioParameter::keyProgramId = AUDIO_PARAMETER_STREAM_PROGRAM_ID;
 const char * const AudioParameter::keyMonoOutput = AUDIO_PARAMETER_MONO_OUTPUT;
 const char * const AudioParameter::keyStreamHwAvSync = AUDIO_PARAMETER_STREAM_HW_AV_SYNC;
 const char * const AudioParameter::keyStreamConnect = AUDIO_PARAMETER_DEVICE_CONNECT;
diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp
deleted file mode 100644
index 406074b..0000000
--- a/media/libstagefright/AVIExtractor.cpp
+++ /dev/null
@@ -1,1307 +0,0 @@
-/*
- * Copyright (C) 2011 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 "AVIExtractor"
-#include <utils/Log.h>
-
-#include "include/AVIExtractor.h"
-
-#include <binder/ProcessState.h>
-#include <media/DataSource.h>
-#include <media/stagefright/foundation/avc_utils.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-namespace android {
-
-struct AVIExtractor::AVISource : public MediaSource {
-    AVISource(const sp<AVIExtractor> &extractor, size_t trackIndex);
-
-    virtual status_t start(MetaData *params);
-    virtual status_t stop();
-
-    virtual sp<MetaData> getFormat();
-
-    virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options);
-
-protected:
-    virtual ~AVISource();
-
-private:
-    sp<AVIExtractor> mExtractor;
-    size_t mTrackIndex;
-    const AVIExtractor::Track &mTrack;
-    MediaBufferGroup *mBufferGroup;
-    size_t mSampleIndex;
-
-    sp<MP3Splitter> mSplitter;
-
-    DISALLOW_EVIL_CONSTRUCTORS(AVISource);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-struct AVIExtractor::MP3Splitter : public RefBase {
-    MP3Splitter();
-
-    void clear();
-    void append(MediaBuffer *buffer);
-    status_t read(MediaBuffer **buffer);
-
-protected:
-    virtual ~MP3Splitter();
-
-private:
-    bool mFindSync;
-    int64_t mBaseTimeUs;
-    int64_t mNumSamplesRead;
-    sp<ABuffer> mBuffer;
-
-    bool resync();
-
-    DISALLOW_EVIL_CONSTRUCTORS(MP3Splitter);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-AVIExtractor::AVISource::AVISource(
-        const sp<AVIExtractor> &extractor, size_t trackIndex)
-    : mExtractor(extractor),
-      mTrackIndex(trackIndex),
-      mTrack(mExtractor->mTracks.itemAt(trackIndex)),
-      mBufferGroup(NULL) {
-}
-
-AVIExtractor::AVISource::~AVISource() {
-    if (mBufferGroup) {
-        stop();
-    }
-}
-
-status_t AVIExtractor::AVISource::start(MetaData *params) {
-    CHECK(!mBufferGroup);
-
-    mBufferGroup = new MediaBufferGroup;
-
-    mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize));
-    mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize));
-    mSampleIndex = 0;
-
-    const char *mime;
-    CHECK(mTrack.mMeta->findCString(kKeyMIMEType, &mime));
-
-    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
-        mSplitter = new MP3Splitter;
-    } else {
-        mSplitter.clear();
-    }
-
-    return OK;
-}
-
-status_t AVIExtractor::AVISource::stop() {
-    CHECK(mBufferGroup);
-
-    delete mBufferGroup;
-    mBufferGroup = NULL;
-
-    mSplitter.clear();
-
-    return OK;
-}
-
-sp<MetaData> AVIExtractor::AVISource::getFormat() {
-    return mTrack.mMeta;
-}
-
-status_t AVIExtractor::AVISource::read(
-        MediaBuffer **buffer, const ReadOptions *options) {
-    CHECK(mBufferGroup);
-
-    *buffer = NULL;
-
-    int64_t seekTimeUs;
-    ReadOptions::SeekMode seekMode;
-    if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
-        status_t err =
-            mExtractor->getSampleIndexAtTime(
-                    mTrackIndex, seekTimeUs, seekMode, &mSampleIndex);
-
-        if (err != OK) {
-            return ERROR_END_OF_STREAM;
-        }
-
-        if (mSplitter != NULL) {
-            mSplitter->clear();
-        }
-    }
-
-    for (;;) {
-        if (mSplitter != NULL) {
-            status_t err = mSplitter->read(buffer);
-
-            if (err == OK) {
-                break;
-            } else if (err != -EAGAIN) {
-                return err;
-            }
-        }
-
-        off64_t offset;
-        size_t size;
-        bool isKey;
-        int64_t timeUs;
-        status_t err = mExtractor->getSampleInfo(
-                mTrackIndex, mSampleIndex, &offset, &size, &isKey, &timeUs);
-
-        ++mSampleIndex;
-
-        if (err != OK) {
-            return ERROR_END_OF_STREAM;
-        }
-
-        MediaBuffer *out;
-        CHECK_EQ(mBufferGroup->acquire_buffer(&out), (status_t)OK);
-
-        ssize_t n = mExtractor->mDataSource->readAt(offset, out->data(), size);
-
-        if (n < (ssize_t)size) {
-            return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED;
-        }
-
-        out->set_range(0, size);
-
-        out->meta_data()->setInt64(kKeyTime, timeUs);
-
-        if (isKey) {
-            out->meta_data()->setInt32(kKeyIsSyncFrame, 1);
-        }
-
-        if (mSplitter == NULL) {
-            *buffer = out;
-            break;
-        }
-
-        mSplitter->append(out);
-        out->release();
-        out = NULL;
-    }
-
-    return OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-AVIExtractor::MP3Splitter::MP3Splitter()
-    : mFindSync(true),
-      mBaseTimeUs(-1ll),
-      mNumSamplesRead(0) {
-}
-
-AVIExtractor::MP3Splitter::~MP3Splitter() {
-}
-
-void AVIExtractor::MP3Splitter::clear() {
-    mFindSync = true;
-    mBaseTimeUs = -1ll;
-    mNumSamplesRead = 0;
-
-    if (mBuffer != NULL) {
-        mBuffer->setRange(0, 0);
-    }
-}
-
-void AVIExtractor::MP3Splitter::append(MediaBuffer *buffer) {
-    size_t prevCapacity = (mBuffer != NULL) ? mBuffer->capacity() : 0;
-
-    if (mBaseTimeUs < 0) {
-        CHECK(mBuffer == NULL || mBuffer->size() == 0);
-        CHECK(buffer->meta_data()->findInt64(kKeyTime, &mBaseTimeUs));
-        mNumSamplesRead = 0;
-    }
-
-    if (mBuffer != NULL && mBuffer->offset() > 0) {
-        memmove(mBuffer->base(), mBuffer->data(), mBuffer->size());
-        mBuffer->setRange(0, mBuffer->size());
-    }
-
-    if (mBuffer == NULL
-            || mBuffer->size() + buffer->range_length() > prevCapacity) {
-        size_t newCapacity =
-            (prevCapacity + buffer->range_length() + 1023) & ~1023;
-
-        sp<ABuffer> newBuffer = new ABuffer(newCapacity);
-        if (mBuffer != NULL) {
-            memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
-            newBuffer->setRange(0, mBuffer->size());
-        } else {
-            newBuffer->setRange(0, 0);
-        }
-        mBuffer = newBuffer;
-    }
-
-    memcpy(mBuffer->data() + mBuffer->size(),
-           (const uint8_t *)buffer->data() + buffer->range_offset(),
-           buffer->range_length());
-
-    mBuffer->setRange(0, mBuffer->size() + buffer->range_length());
-}
-
-bool AVIExtractor::MP3Splitter::resync() {
-    if (mBuffer == NULL) {
-        return false;
-    }
-
-    bool foundSync = false;
-    for (size_t offset = 0; offset + 3 < mBuffer->size(); ++offset) {
-        uint32_t firstHeader = U32_AT(mBuffer->data() + offset);
-
-        size_t frameSize;
-        if (!GetMPEGAudioFrameSize(firstHeader, &frameSize)) {
-            continue;
-        }
-
-        size_t subsequentOffset = offset + frameSize;
-        size_t i = 3;
-        while (i > 0) {
-            if (subsequentOffset + 3 >= mBuffer->size()) {
-                break;
-            }
-
-            static const uint32_t kMask = 0xfffe0c00;
-
-            uint32_t header = U32_AT(mBuffer->data() + subsequentOffset);
-            if ((header & kMask) != (firstHeader & kMask)) {
-                break;
-            }
-
-            if (!GetMPEGAudioFrameSize(header, &frameSize)) {
-                break;
-            }
-
-            subsequentOffset += frameSize;
-            --i;
-        }
-
-        if (i == 0) {
-            foundSync = true;
-            memmove(mBuffer->data(),
-                    mBuffer->data() + offset,
-                    mBuffer->size() - offset);
-
-            mBuffer->setRange(0, mBuffer->size() - offset);
-            break;
-        }
-    }
-
-    return foundSync;
-}
-
-status_t AVIExtractor::MP3Splitter::read(MediaBuffer **out) {
-    *out = NULL;
-
-    if (mFindSync) {
-        if (!resync()) {
-            return -EAGAIN;
-        }
-
-        mFindSync = false;
-    }
-
-    if (mBuffer->size() < 4) {
-        return -EAGAIN;
-    }
-
-    uint32_t header = U32_AT(mBuffer->data());
-    size_t frameSize;
-    int sampleRate;
-    int numSamples;
-    if (!GetMPEGAudioFrameSize(
-                header, &frameSize, &sampleRate, NULL, NULL, &numSamples)) {
-        return ERROR_MALFORMED;
-    }
-
-    if (mBuffer->size() < frameSize) {
-        return -EAGAIN;
-    }
-
-    MediaBuffer *mbuf = new MediaBuffer(frameSize);
-    memcpy(mbuf->data(), mBuffer->data(), frameSize);
-
-    int64_t timeUs = mBaseTimeUs + (mNumSamplesRead * 1000000ll) / sampleRate;
-    mNumSamplesRead += numSamples;
-
-    mbuf->meta_data()->setInt64(kKeyTime, timeUs);
-
-    mBuffer->setRange(
-            mBuffer->offset() + frameSize, mBuffer->size() - frameSize);
-
-    *out = mbuf;
-
-    return OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-AVIExtractor::AVIExtractor(const sp<DataSource> &dataSource)
-    : mDataSource(dataSource) {
-    mInitCheck = parseHeaders();
-
-    if (mInitCheck != OK) {
-        mTracks.clear();
-    }
-}
-
-AVIExtractor::~AVIExtractor() {
-}
-
-size_t AVIExtractor::countTracks() {
-    return mTracks.size();
-}
-
-sp<MediaSource> AVIExtractor::getTrack(size_t index) {
-    return index < mTracks.size() ? new AVISource(this, index) : NULL;
-}
-
-sp<MetaData> AVIExtractor::getTrackMetaData(
-        size_t index, uint32_t flags) {
-    return index < mTracks.size() ? mTracks.editItemAt(index).mMeta : NULL;
-}
-
-sp<MetaData> AVIExtractor::getMetaData() {
-    sp<MetaData> meta = new MetaData;
-
-    if (mInitCheck == OK) {
-        meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_AVI);
-    }
-
-    return meta;
-}
-
-status_t AVIExtractor::parseHeaders() {
-    mTracks.clear();
-    mMovieOffset = 0;
-    mFoundIndex = false;
-    mOffsetsAreAbsolute = false;
-
-    ssize_t res = parseChunk(0ll, -1ll);
-
-    if (res < 0) {
-        return (status_t)res;
-    }
-
-    if (mMovieOffset == 0ll || !mFoundIndex) {
-        return ERROR_MALFORMED;
-    }
-
-    return OK;
-}
-
-ssize_t AVIExtractor::parseChunk(off64_t offset, off64_t size, int depth) {
-    if (size >= 0 && size < 8) {
-        return ERROR_MALFORMED;
-    }
-
-    uint8_t tmp[12];
-    ssize_t n = mDataSource->readAt(offset, tmp, 8);
-
-    if (n < 8) {
-        return (n < 0) ? n : (ssize_t)ERROR_MALFORMED;
-    }
-
-    uint32_t fourcc = U32_AT(tmp);
-    uint32_t chunkSize = U32LE_AT(&tmp[4]);
-
-    if (size >= 0 && chunkSize + 8 > size) {
-        return ERROR_MALFORMED;
-    }
-
-    static const char kPrefix[] = "                              ";
-    const char *prefix = &kPrefix[strlen(kPrefix) - 2 * depth];
-
-    if (fourcc == FOURCC('L', 'I', 'S', 'T')
-            || fourcc == FOURCC('R', 'I', 'F', 'F')) {
-        // It's a list of chunks
-
-        if (size >= 0 && size < 12) {
-            return ERROR_MALFORMED;
-        }
-
-        n = mDataSource->readAt(offset + 8, &tmp[8], 4);
-
-        if (n < 4) {
-            return (n < 0) ? n : (ssize_t)ERROR_MALFORMED;
-        }
-
-        uint32_t subFourcc = U32_AT(&tmp[8]);
-
-        ALOGV("%s offset 0x%08llx LIST of '%c%c%c%c', size %d",
-             prefix,
-             offset,
-             (char)(subFourcc >> 24),
-             (char)((subFourcc >> 16) & 0xff),
-             (char)((subFourcc >> 8) & 0xff),
-             (char)(subFourcc & 0xff),
-             chunkSize - 4);
-
-        if (subFourcc == FOURCC('m', 'o', 'v', 'i')) {
-            // We're not going to parse this, but will take note of the
-            // offset.
-
-            mMovieOffset = offset;
-        } else {
-            off64_t subOffset = offset + 12;
-            off64_t subOffsetLimit = subOffset + chunkSize - 4;
-            while (subOffset < subOffsetLimit) {
-                ssize_t res =
-                    parseChunk(subOffset, subOffsetLimit - subOffset, depth + 1);
-
-                if (res < 0) {
-                    return res;
-                }
-
-                subOffset += res;
-            }
-        }
-    } else {
-        ALOGV("%s offset 0x%08llx CHUNK '%c%c%c%c'",
-             prefix,
-             offset,
-             (char)(fourcc >> 24),
-             (char)((fourcc >> 16) & 0xff),
-             (char)((fourcc >> 8) & 0xff),
-             (char)(fourcc & 0xff));
-
-        status_t err = OK;
-
-        switch (fourcc) {
-            case FOURCC('s', 't', 'r', 'h'):
-            {
-                err = parseStreamHeader(offset + 8, chunkSize);
-                break;
-            }
-
-            case FOURCC('s', 't', 'r', 'f'):
-            {
-                err = parseStreamFormat(offset + 8, chunkSize);
-                break;
-            }
-
-            case FOURCC('i', 'd', 'x', '1'):
-            {
-                err = parseIndex(offset + 8, chunkSize);
-                break;
-            }
-
-            default:
-                break;
-        }
-
-        if (err != OK) {
-            return err;
-        }
-    }
-
-    if (chunkSize & 1) {
-        ++chunkSize;
-    }
-
-    return chunkSize + 8;
-}
-
-static const char *GetMIMETypeForHandler(uint32_t handler) {
-    switch (handler) {
-        // Wow... shamelessly copied from
-        // http://wiki.multimedia.cx/index.php?title=ISO_MPEG-4
-
-        case FOURCC('3', 'I', 'V', '2'):
-        case FOURCC('3', 'i', 'v', '2'):
-        case FOURCC('B', 'L', 'Z', '0'):
-        case FOURCC('D', 'I', 'G', 'I'):
-        case FOURCC('D', 'I', 'V', '1'):
-        case FOURCC('d', 'i', 'v', '1'):
-        case FOURCC('D', 'I', 'V', 'X'):
-        case FOURCC('d', 'i', 'v', 'x'):
-        case FOURCC('D', 'X', '5', '0'):
-        case FOURCC('d', 'x', '5', '0'):
-        case FOURCC('D', 'X', 'G', 'M'):
-        case FOURCC('E', 'M', '4', 'A'):
-        case FOURCC('E', 'P', 'H', 'V'):
-        case FOURCC('F', 'M', 'P', '4'):
-        case FOURCC('f', 'm', 'p', '4'):
-        case FOURCC('F', 'V', 'F', 'W'):
-        case FOURCC('H', 'D', 'X', '4'):
-        case FOURCC('h', 'd', 'x', '4'):
-        case FOURCC('M', '4', 'C', 'C'):
-        case FOURCC('M', '4', 'S', '2'):
-        case FOURCC('m', '4', 's', '2'):
-        case FOURCC('M', 'P', '4', 'S'):
-        case FOURCC('m', 'p', '4', 's'):
-        case FOURCC('M', 'P', '4', 'V'):
-        case FOURCC('m', 'p', '4', 'v'):
-        case FOURCC('M', 'V', 'X', 'M'):
-        case FOURCC('R', 'M', 'P', '4'):
-        case FOURCC('S', 'E', 'D', 'G'):
-        case FOURCC('S', 'M', 'P', '4'):
-        case FOURCC('U', 'M', 'P', '4'):
-        case FOURCC('W', 'V', '1', 'F'):
-        case FOURCC('X', 'V', 'I', 'D'):
-        case FOURCC('X', 'v', 'i', 'D'):
-        case FOURCC('x', 'v', 'i', 'd'):
-        case FOURCC('X', 'V', 'I', 'X'):
-            return MEDIA_MIMETYPE_VIDEO_MPEG4;
-
-        // from http://wiki.multimedia.cx/index.php?title=H264
-        case FOURCC('a', 'v', 'c', '1'):
-        case FOURCC('d', 'a', 'v', 'c'):
-        case FOURCC('x', '2', '6', '4'):
-        case FOURCC('H', '2', '6', '4'):
-        case FOURCC('v', 's', 's', 'h'):
-            return MEDIA_MIMETYPE_VIDEO_AVC;
-
-        default:
-            return NULL;
-    }
-}
-
-status_t AVIExtractor::parseStreamHeader(off64_t offset, size_t size) {
-    if (size != 56) {
-        return ERROR_MALFORMED;
-    }
-
-    if (mTracks.size() > 99) {
-        return -ERANGE;
-    }
-
-    sp<ABuffer> buffer = new ABuffer(size);
-    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
-
-    if (n < (ssize_t)size) {
-        return n < 0 ? (status_t)n : ERROR_MALFORMED;
-    }
-
-    const uint8_t *data = buffer->data();
-
-    uint32_t type = U32_AT(data);
-    uint32_t handler = U32_AT(&data[4]);
-    uint32_t flags = U32LE_AT(&data[8]);
-
-    sp<MetaData> meta = new MetaData;
-
-    uint32_t rate = U32LE_AT(&data[20]);
-    uint32_t scale = U32LE_AT(&data[24]);
-
-    uint32_t sampleSize = U32LE_AT(&data[44]);
-
-    const char *mime = NULL;
-    Track::Kind kind = Track::OTHER;
-
-    if (type == FOURCC('v', 'i', 'd', 's')) {
-        mime = GetMIMETypeForHandler(handler);
-
-        if (mime && strncasecmp(mime, "video/", 6)) {
-            return ERROR_MALFORMED;
-        }
-
-        if (mime == NULL) {
-            ALOGW("Unsupported video format '%c%c%c%c'",
-                 (char)(handler >> 24),
-                 (char)((handler >> 16) & 0xff),
-                 (char)((handler >> 8) & 0xff),
-                 (char)(handler & 0xff));
-        }
-
-        kind = Track::VIDEO;
-    } else if (type == FOURCC('a', 'u', 'd', 's')) {
-        if (mime && strncasecmp(mime, "audio/", 6)) {
-            return ERROR_MALFORMED;
-        }
-
-        kind = Track::AUDIO;
-    }
-
-    if (!mime) {
-        mime = "application/octet-stream";
-    }
-
-    meta->setCString(kKeyMIMEType, mime);
-
-    mTracks.push();
-    Track *track = &mTracks.editItemAt(mTracks.size() - 1);
-
-    track->mMeta = meta;
-    track->mRate = rate;
-    track->mScale = scale;
-    track->mBytesPerSample = sampleSize;
-    track->mKind = kind;
-    track->mNumSyncSamples = 0;
-    track->mThumbnailSampleSize = 0;
-    track->mThumbnailSampleIndex = -1;
-    track->mMaxSampleSize = 0;
-    track->mAvgChunkSize = 1.0;
-    track->mFirstChunkSize = 0;
-
-    return OK;
-}
-
-status_t AVIExtractor::parseStreamFormat(off64_t offset, size_t size) {
-    if (mTracks.isEmpty()) {
-        return ERROR_MALFORMED;
-    }
-
-    Track *track = &mTracks.editItemAt(mTracks.size() - 1);
-
-    if (track->mKind == Track::OTHER) {
-        // We don't support this content, but that's not a parsing error.
-        return OK;
-    }
-
-    bool isVideo = (track->mKind == Track::VIDEO);
-
-    if ((isVideo && size < 40) || (!isVideo && size < 16)) {
-        // Expected a BITMAPINFO or WAVEFORMAT(EX) structure, respectively.
-        return ERROR_MALFORMED;
-    }
-
-    sp<ABuffer> buffer = new ABuffer(size);
-    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
-
-    if (n < (ssize_t)size) {
-        return n < 0 ? (status_t)n : ERROR_MALFORMED;
-    }
-
-    const uint8_t *data = buffer->data();
-
-    if (isVideo) {
-        uint32_t width = U32LE_AT(&data[4]);
-        uint32_t height = U32LE_AT(&data[8]);
-
-        track->mMeta->setInt32(kKeyWidth, width);
-        track->mMeta->setInt32(kKeyHeight, height);
-    } else {
-        uint32_t format = U16LE_AT(data);
-
-        if (format == 0x55) {
-            track->mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
-        } else {
-            ALOGW("Unsupported audio format = 0x%04x", format);
-        }
-
-        uint32_t numChannels = U16LE_AT(&data[2]);
-        uint32_t sampleRate = U32LE_AT(&data[4]);
-
-        track->mMeta->setInt32(kKeyChannelCount, numChannels);
-        track->mMeta->setInt32(kKeySampleRate, sampleRate);
-    }
-
-    return OK;
-}
-
-// static
-bool AVIExtractor::IsCorrectChunkType(
-        ssize_t trackIndex, Track::Kind kind, uint32_t chunkType) {
-    uint32_t chunkBase = chunkType & 0xffff;
-
-    switch (kind) {
-        case Track::VIDEO:
-        {
-            if (chunkBase != FOURCC(0, 0, 'd', 'c')
-                    && chunkBase != FOURCC(0, 0, 'd', 'b')) {
-                return false;
-            }
-            break;
-        }
-
-        case Track::AUDIO:
-        {
-            if (chunkBase != FOURCC(0, 0, 'w', 'b')) {
-                return false;
-            }
-            break;
-        }
-
-        default:
-            break;
-    }
-
-    if (trackIndex < 0) {
-        return true;
-    }
-
-    uint8_t hi = chunkType >> 24;
-    uint8_t lo = (chunkType >> 16) & 0xff;
-
-    if (hi < '0' || hi > '9' || lo < '0' || lo > '9') {
-        return false;
-    }
-
-    if (trackIndex != (10 * (hi - '0') + (lo - '0'))) {
-        return false;
-    }
-
-    return true;
-}
-
-status_t AVIExtractor::parseIndex(off64_t offset, size_t size) {
-    if ((size % 16) != 0) {
-        return ERROR_MALFORMED;
-    }
-
-    sp<ABuffer> buffer = new ABuffer(size);
-    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
-
-    if (n < (ssize_t)size) {
-        return n < 0 ? (status_t)n : ERROR_MALFORMED;
-    }
-
-    const uint8_t *data = buffer->data();
-
-    while (size > 0) {
-        uint32_t chunkType = U32_AT(data);
-
-        uint8_t hi = chunkType >> 24;
-        uint8_t lo = (chunkType >> 16) & 0xff;
-
-        if (hi < '0' || hi > '9' || lo < '0' || lo > '9') {
-            return ERROR_MALFORMED;
-        }
-
-        size_t trackIndex = 10 * (hi - '0') + (lo - '0');
-
-        if (trackIndex >= mTracks.size()) {
-            return ERROR_MALFORMED;
-        }
-
-        Track *track = &mTracks.editItemAt(trackIndex);
-
-        if (!IsCorrectChunkType(-1, track->mKind, chunkType)) {
-            return ERROR_MALFORMED;
-        }
-
-        if (track->mKind == Track::OTHER) {
-            data += 16;
-            size -= 16;
-            continue;
-        }
-
-        uint32_t flags = U32LE_AT(&data[4]);
-        uint32_t offset = U32LE_AT(&data[8]);
-        uint32_t chunkSize = U32LE_AT(&data[12]);
-
-        if (chunkSize > track->mMaxSampleSize) {
-            track->mMaxSampleSize = chunkSize;
-        }
-
-        track->mSamples.push();
-
-        SampleInfo *info =
-            &track->mSamples.editItemAt(track->mSamples.size() - 1);
-
-        info->mOffset = offset;
-        info->mIsKey = (flags & 0x10) != 0;
-
-        if (info->mIsKey) {
-            static const size_t kMaxNumSyncSamplesToScan = 20;
-
-            if (track->mNumSyncSamples < kMaxNumSyncSamplesToScan) {
-                if (chunkSize > track->mThumbnailSampleSize) {
-                    track->mThumbnailSampleSize = chunkSize;
-
-                    track->mThumbnailSampleIndex =
-                        track->mSamples.size() - 1;
-                }
-            }
-
-            ++track->mNumSyncSamples;
-        }
-
-        data += 16;
-        size -= 16;
-    }
-
-    if (!mTracks.isEmpty()) {
-        off64_t offset;
-        size_t size;
-        bool isKey;
-        int64_t timeUs;
-        status_t err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
-
-        if (err != OK) {
-            mOffsetsAreAbsolute = !mOffsetsAreAbsolute;
-            err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
-
-            if (err != OK) {
-                return err;
-            }
-        }
-
-        ALOGV("Chunk offsets are %s",
-             mOffsetsAreAbsolute ? "absolute" : "movie-chunk relative");
-    }
-
-    for (size_t i = 0; i < mTracks.size(); ++i) {
-        Track *track = &mTracks.editItemAt(i);
-
-        if (track->mBytesPerSample > 0) {
-            // Assume all chunks are roughly the same size for now.
-
-            // Compute the avg. size of the first 128 chunks (if there are
-            // that many), but exclude the size of the first one, since
-            // it may be an outlier.
-            size_t numSamplesToAverage = track->mSamples.size();
-            if (numSamplesToAverage > 256) {
-                numSamplesToAverage = 256;
-            }
-
-            double avgChunkSize = 0;
-            size_t j;
-            for (j = 0; j <= numSamplesToAverage; ++j) {
-                off64_t offset;
-                size_t size;
-                bool isKey;
-                int64_t dummy;
-
-                status_t err =
-                    getSampleInfo(
-                            i, j,
-                            &offset, &size, &isKey, &dummy);
-
-                if (err != OK) {
-                    return err;
-                }
-
-                if (j == 0) {
-                    track->mFirstChunkSize = size;
-                    continue;
-                }
-
-                avgChunkSize += size;
-            }
-
-            avgChunkSize /= numSamplesToAverage;
-
-            track->mAvgChunkSize = avgChunkSize;
-        }
-
-        int64_t durationUs;
-        CHECK_EQ((status_t)OK,
-                 getSampleTime(i, track->mSamples.size() - 1, &durationUs));
-
-        ALOGV("track %d duration = %.2f secs", i, durationUs / 1E6);
-
-        track->mMeta->setInt64(kKeyDuration, durationUs);
-        track->mMeta->setInt32(kKeyMaxInputSize, track->mMaxSampleSize);
-
-        const char *tmp;
-        CHECK(track->mMeta->findCString(kKeyMIMEType, &tmp));
-
-        AString mime = tmp;
-
-        if (!strncasecmp("video/", mime.c_str(), 6)) {
-            if (track->mThumbnailSampleIndex >= 0) {
-                int64_t thumbnailTimeUs;
-                CHECK_EQ((status_t)OK,
-                         getSampleTime(i, track->mThumbnailSampleIndex,
-                                       &thumbnailTimeUs));
-
-                track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
-            }
-
-            status_t err = OK;
-
-            if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_MPEG4)) {
-                err = addMPEG4CodecSpecificData(i);
-            } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)) {
-                err = addH264CodecSpecificData(i);
-            }
-
-            if (err != OK) {
-                return err;
-            }
-        }
-    }
-
-    mFoundIndex = true;
-
-    return OK;
-}
-
-static size_t GetSizeWidth(size_t x) {
-    size_t n = 1;
-    while (x > 127) {
-        ++n;
-        x >>= 7;
-    }
-    return n;
-}
-
-static uint8_t *EncodeSize(uint8_t *dst, size_t x) {
-    while (x > 127) {
-        *dst++ = (x & 0x7f) | 0x80;
-        x >>= 7;
-    }
-    *dst++ = x;
-    return dst;
-}
-
-sp<ABuffer> MakeMPEG4VideoCodecSpecificData(const sp<ABuffer> &config) {
-    size_t len1 = config->size() + GetSizeWidth(config->size()) + 1;
-    size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13;
-    size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3;
-
-    sp<ABuffer> csd = new ABuffer(len3);
-    uint8_t *dst = csd->data();
-    *dst++ = 0x03;
-    dst = EncodeSize(dst, len2 + 3);
-    *dst++ = 0x00;  // ES_ID
-    *dst++ = 0x00;
-    *dst++ = 0x00;  // streamDependenceFlag, URL_Flag, OCRstreamFlag
-
-    *dst++ = 0x04;
-    dst = EncodeSize(dst, len1 + 13);
-    *dst++ = 0x01;  // Video ISO/IEC 14496-2 Simple Profile
-    for (size_t i = 0; i < 12; ++i) {
-        *dst++ = 0x00;
-    }
-
-    *dst++ = 0x05;
-    dst = EncodeSize(dst, config->size());
-    memcpy(dst, config->data(), config->size());
-    dst += config->size();
-
-    // hexdump(csd->data(), csd->size());
-
-    return csd;
-}
-
-status_t AVIExtractor::addMPEG4CodecSpecificData(size_t trackIndex) {
-    Track *track = &mTracks.editItemAt(trackIndex);
-
-    off64_t offset;
-    size_t size;
-    bool isKey;
-    int64_t timeUs;
-    status_t err =
-        getSampleInfo(trackIndex, 0, &offset, &size, &isKey, &timeUs);
-
-    if (err != OK) {
-        return err;
-    }
-
-    sp<ABuffer> buffer = new ABuffer(size);
-    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
-
-    if (n < (ssize_t)size) {
-        return n < 0 ? (status_t)n : ERROR_MALFORMED;
-    }
-
-    // Extract everything up to the first VOP start code from the first
-    // frame's encoded data and use it to construct an ESDS with the
-    // codec specific data.
-
-    size_t i = 0;
-    bool found = false;
-    while (i + 3 < buffer->size()) {
-        if (!memcmp("\x00\x00\x01\xb6", &buffer->data()[i], 4)) {
-            found = true;
-            break;
-        }
-
-        ++i;
-    }
-
-    if (!found) {
-        return ERROR_MALFORMED;
-    }
-
-    buffer->setRange(0, i);
-
-    sp<ABuffer> csd = MakeMPEG4VideoCodecSpecificData(buffer);
-    track->mMeta->setData(kKeyESDS, kTypeESDS, csd->data(), csd->size());
-
-    return OK;
-}
-
-status_t AVIExtractor::addH264CodecSpecificData(size_t trackIndex) {
-    Track *track = &mTracks.editItemAt(trackIndex);
-
-    off64_t offset;
-    size_t size;
-    bool isKey;
-    int64_t timeUs;
-
-    // Extract codec specific data from the first non-empty sample.
-
-    size_t sampleIndex = 0;
-    for (;;) {
-        status_t err =
-            getSampleInfo(
-                    trackIndex, sampleIndex, &offset, &size, &isKey, &timeUs);
-
-        if (err != OK) {
-            return err;
-        }
-
-        if (size > 0) {
-            break;
-        }
-
-        ++sampleIndex;
-    }
-
-    sp<ABuffer> buffer = new ABuffer(size);
-    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
-
-    if (n < (ssize_t)size) {
-        return n < 0 ? (status_t)n : ERROR_MALFORMED;
-    }
-
-    sp<MetaData> meta = MakeAVCCodecSpecificData(buffer);
-
-    if (meta == NULL) {
-        ALOGE("Unable to extract AVC codec specific data");
-        return ERROR_MALFORMED;
-    }
-
-    int32_t width, height;
-    CHECK(meta->findInt32(kKeyWidth, &width));
-    CHECK(meta->findInt32(kKeyHeight, &height));
-
-    uint32_t type;
-    const void *csd;
-    size_t csdSize;
-    CHECK(meta->findData(kKeyAVCC, &type, &csd, &csdSize));
-
-    track->mMeta->setInt32(kKeyWidth, width);
-    track->mMeta->setInt32(kKeyHeight, height);
-    track->mMeta->setData(kKeyAVCC, type, csd, csdSize);
-
-    return OK;
-}
-
-status_t AVIExtractor::getSampleInfo(
-        size_t trackIndex, size_t sampleIndex,
-        off64_t *offset, size_t *size, bool *isKey,
-        int64_t *sampleTimeUs) {
-    if (trackIndex >= mTracks.size()) {
-        return -ERANGE;
-    }
-
-    const Track &track = mTracks.itemAt(trackIndex);
-
-    if (sampleIndex >= track.mSamples.size()) {
-        return -ERANGE;
-    }
-
-    const SampleInfo &info = track.mSamples.itemAt(sampleIndex);
-
-    if (!mOffsetsAreAbsolute) {
-        *offset = info.mOffset + mMovieOffset + 8;
-    } else {
-        *offset = info.mOffset;
-    }
-
-    *size = 0;
-
-    uint8_t tmp[8];
-    ssize_t n = mDataSource->readAt(*offset, tmp, 8);
-
-    if (n < 8) {
-        return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED;
-    }
-
-    uint32_t chunkType = U32_AT(tmp);
-
-    if (!IsCorrectChunkType(trackIndex, track.mKind, chunkType)) {
-        return ERROR_MALFORMED;
-    }
-
-    *offset += 8;
-    *size = U32LE_AT(&tmp[4]);
-
-    *isKey = info.mIsKey;
-
-    if (track.mBytesPerSample > 0) {
-        size_t sampleStartInBytes;
-        if (sampleIndex == 0) {
-            sampleStartInBytes = 0;
-        } else {
-            sampleStartInBytes =
-                track.mFirstChunkSize + track.mAvgChunkSize * (sampleIndex - 1);
-        }
-
-        sampleIndex = sampleStartInBytes / track.mBytesPerSample;
-    }
-
-    *sampleTimeUs = (sampleIndex * 1000000ll * track.mRate) / track.mScale;
-
-    return OK;
-}
-
-status_t AVIExtractor::getSampleTime(
-        size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs) {
-    off64_t offset;
-    size_t size;
-    bool isKey;
-    return getSampleInfo(
-            trackIndex, sampleIndex, &offset, &size, &isKey, sampleTimeUs);
-}
-
-status_t AVIExtractor::getSampleIndexAtTime(
-        size_t trackIndex,
-        int64_t timeUs, MediaSource::ReadOptions::SeekMode mode,
-        size_t *sampleIndex) const {
-    if (trackIndex >= mTracks.size()) {
-        return -ERANGE;
-    }
-
-    const Track &track = mTracks.itemAt(trackIndex);
-
-    ssize_t closestSampleIndex;
-
-    if (track.mBytesPerSample > 0) {
-        size_t closestByteOffset =
-            (timeUs * track.mBytesPerSample)
-                / track.mRate * track.mScale / 1000000ll;
-
-        if (closestByteOffset <= track.mFirstChunkSize) {
-            closestSampleIndex = 0;
-        } else {
-            closestSampleIndex =
-                (closestByteOffset - track.mFirstChunkSize)
-                    / track.mAvgChunkSize;
-        }
-    } else {
-        // Each chunk contains a single sample.
-        closestSampleIndex = timeUs / track.mRate * track.mScale / 1000000ll;
-    }
-
-    ssize_t numSamples = track.mSamples.size();
-
-    if (closestSampleIndex < 0) {
-        closestSampleIndex = 0;
-    } else if (closestSampleIndex >= numSamples) {
-        closestSampleIndex = numSamples - 1;
-    }
-
-    if (mode == MediaSource::ReadOptions::SEEK_CLOSEST) {
-        *sampleIndex = closestSampleIndex;
-
-        return OK;
-    }
-
-    ssize_t prevSyncSampleIndex = closestSampleIndex;
-    while (prevSyncSampleIndex >= 0) {
-        const SampleInfo &info =
-            track.mSamples.itemAt(prevSyncSampleIndex);
-
-        if (info.mIsKey) {
-            break;
-        }
-
-        --prevSyncSampleIndex;
-    }
-
-    ssize_t nextSyncSampleIndex = closestSampleIndex;
-    while (nextSyncSampleIndex < numSamples) {
-        const SampleInfo &info =
-            track.mSamples.itemAt(nextSyncSampleIndex);
-
-        if (info.mIsKey) {
-            break;
-        }
-
-        ++nextSyncSampleIndex;
-    }
-
-    switch (mode) {
-        case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC:
-        {
-            *sampleIndex = prevSyncSampleIndex;
-
-            return prevSyncSampleIndex >= 0 ? OK : UNKNOWN_ERROR;
-        }
-
-        case MediaSource::ReadOptions::SEEK_NEXT_SYNC:
-        {
-            *sampleIndex = nextSyncSampleIndex;
-
-            return nextSyncSampleIndex < numSamples ? OK : UNKNOWN_ERROR;
-        }
-
-        case MediaSource::ReadOptions::SEEK_CLOSEST_SYNC:
-        {
-            if (prevSyncSampleIndex < 0 && nextSyncSampleIndex >= numSamples) {
-                return UNKNOWN_ERROR;
-            }
-
-            if (prevSyncSampleIndex < 0) {
-                *sampleIndex = nextSyncSampleIndex;
-                return OK;
-            }
-
-            if (nextSyncSampleIndex >= numSamples) {
-                *sampleIndex = prevSyncSampleIndex;
-                return OK;
-            }
-
-            size_t dist1 = closestSampleIndex - prevSyncSampleIndex;
-            size_t dist2 = nextSyncSampleIndex - closestSampleIndex;
-
-            *sampleIndex =
-                (dist1 < dist2) ? prevSyncSampleIndex : nextSyncSampleIndex;
-
-            return OK;
-        }
-
-        default:
-            TRESPASS();
-            break;
-    }
-}
-
-bool SniffAVI(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
-        sp<AMessage> *) {
-    char tmp[12];
-    if (source->readAt(0, tmp, 12) < 12) {
-        return false;
-    }
-
-    if (!memcmp(tmp, "RIFF", 4) && !memcmp(&tmp[8], "AVI ", 4)) {
-        mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_AVI);
-
-        // Just a tad over the mp3 extractor's confidence, since
-        // these .avi files may contain .mp3 content that otherwise would
-        // mistakenly lead to us identifying the entire file as a .mp3 file.
-        *confidence = 0.21;
-
-        return true;
-    }
-
-    return false;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 106688a..5240f7b 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -57,6 +57,7 @@
         "AACWriter.cpp",
         "AMRWriter.cpp",
         "AudioPlayer.cpp",
+        "AudioPresentationInfo.cpp",
         "AudioSource.cpp",
         "BufferImpl.cpp",
         "CCodec.cpp",
@@ -136,6 +137,8 @@
         "libRScpp",
         "libhidlbase",
         "libhidlmemory",
+        // TODO: Remove libv4l2_c2_componentstore.
+        "libv4l2_c2componentstore",
         "libziparchive",
         "android.hidl.allocator@1.0",
         "android.hardware.cas.native@1.0",
diff --git a/media/libstagefright/AudioPresentationInfo.cpp b/media/libstagefright/AudioPresentationInfo.cpp
new file mode 100644
index 0000000..86e1859
--- /dev/null
+++ b/media/libstagefright/AudioPresentationInfo.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 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 "AudioPresentationInfo"
+
+#include <media/AudioPresentationInfo.h>
+
+namespace android {
+
+AudioPresentationInfo::AudioPresentationInfo() {
+}
+
+AudioPresentationInfo::~AudioPresentationInfo() {
+    mPresentations.clear();
+}
+
+void AudioPresentationInfo::addPresentation(sp<AudioPresentation> presentation) {
+    mPresentations.push(presentation);
+}
+
+size_t AudioPresentationInfo::countPresentations() const {
+    return mPresentations.size();
+}
+
+// Returns an AudioPresentation for the given valid index
+// index must be >=0 and < countPresentations()
+const sp<AudioPresentation> AudioPresentationInfo::getPresentation(size_t index) const {
+    return mPresentations[index];
+}
+
+}  // namespace android
diff --git a/media/libstagefright/BufferImpl.cpp b/media/libstagefright/BufferImpl.cpp
index 9fb6d34..bd2443d 100644
--- a/media/libstagefright/BufferImpl.cpp
+++ b/media/libstagefright/BufferImpl.cpp
@@ -64,28 +64,51 @@
     return ICrypto::kDestinationTypeNativeHandle;
 }
 
-// Codec2Buffer
+// LinearBlockBuffer
 
 // static
-sp<Codec2Buffer> Codec2Buffer::allocate(
+sp<LinearBlockBuffer> LinearBlockBuffer::allocate(
         const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block) {
     C2WriteView writeView(block->map().get());
     if (writeView.error() != C2_OK) {
         return nullptr;
     }
-    return new Codec2Buffer(format, new ABuffer(writeView.base(), writeView.capacity()), block);
+    return new LinearBlockBuffer(format, std::move(writeView), block);
 }
 
-C2ConstLinearBlock Codec2Buffer::share() {
+C2ConstLinearBlock LinearBlockBuffer::share() {
     return mBlock->share(offset(), size(), C2Fence());
 }
 
-Codec2Buffer::Codec2Buffer(
+LinearBlockBuffer::LinearBlockBuffer(
         const sp<AMessage> &format,
-        const sp<ABuffer> &buffer,
+        C2WriteView&& writeView,
         const std::shared_ptr<C2LinearBlock> &block)
-    : MediaCodecBuffer(format, buffer),
+    : MediaCodecBuffer(format, new ABuffer(writeView.data(), writeView.size())),
+      mWriteView(writeView),
       mBlock(block) {
 }
 
+// ConstLinearBlockBuffer
+
+// static
+sp<ConstLinearBlockBuffer> ConstLinearBlockBuffer::allocate(
+        const sp<AMessage> &format, const C2ConstLinearBlock &block) {
+    C2ReadView readView(block.map().get());
+    if (readView.error() != C2_OK) {
+        return nullptr;
+    }
+    return new ConstLinearBlockBuffer(format, std::move(readView));
+}
+
+ConstLinearBlockBuffer::ConstLinearBlockBuffer(
+        const sp<AMessage> &format,
+        C2ReadView&& readView)
+    : MediaCodecBuffer(format, new ABuffer(
+            // NOTE: ABuffer only takes non-const pointer but this data is
+            //       supposed to be read-only.
+            const_cast<uint8_t *>(readView.data()), readView.capacity())),
+      mReadView(readView) {
+}
+
 }  // namespace android
diff --git a/media/libstagefright/CCodec.cpp b/media/libstagefright/CCodec.cpp
index 1e0a53f..84e98f8 100644
--- a/media/libstagefright/CCodec.cpp
+++ b/media/libstagefright/CCodec.cpp
@@ -16,11 +16,13 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "CCodec"
+#include <cutils/properties.h>
 #include <utils/Log.h>
 
 #include <thread>
 
 #include <C2PlatformSupport.h>
+#include <C2V4l2Support.h>
 
 #include <gui/Surface.h>
 #include <media/stagefright/BufferProducerWrapper.h>
@@ -187,7 +189,14 @@
     std::shared_ptr<C2Component> comp;
     c2_status_t err = GetCodec2PlatformComponentStore()->createComponent(
             componentName.c_str(), &comp);
+    static bool v4l2Enabled =
+            property_get_bool("debug.stagefright.ccodec_v4l2", false);
+    if (err != C2_OK && v4l2Enabled) {
+        err = GetCodec2VDAComponentStore()->createComponent(
+                componentName.c_str(), &comp);
+    }
     if (err != C2_OK) {
+        ALOGE("Failed Create component: %s", componentName.c_str());
         Mutexed<State>::Locked state(mState);
         state->set(RELEASED);
         state.unlock();
@@ -195,6 +204,7 @@
         state.lock();
         return;
     }
+    ALOGV("Success Create component: %s", componentName.c_str());
     comp->setListener_vb(mListener, C2_MAY_BLOCK);
     {
         Mutexed<State>::Locked state(mState);
diff --git a/media/libstagefright/CCodecBufferChannel.cpp b/media/libstagefright/CCodecBufferChannel.cpp
index 04f7593..ca4ddc8 100644
--- a/media/libstagefright/CCodecBufferChannel.cpp
+++ b/media/libstagefright/CCodecBufferChannel.cpp
@@ -249,7 +249,7 @@
     return std::distance(buffers->begin(), it);
 }
 
-sp<Codec2Buffer> allocateLinearBuffer(
+sp<LinearBlockBuffer> allocateLinearBuffer(
         const std::shared_ptr<C2BlockPool> &pool,
         const sp<AMessage> &format,
         size_t size,
@@ -264,7 +264,7 @@
         return nullptr;
     }
 
-    return Codec2Buffer::allocate(format, block);
+    return LinearBlockBuffer::allocate(format, block);
 }
 
 class Buffer1D : public C2Buffer {
@@ -283,7 +283,7 @@
 
     void add(
             size_t index,
-            const sp<Codec2Buffer> &clientBuffer,
+            const sp<LinearBlockBuffer> &clientBuffer,
             bool available) {
         if (mBufferArray.size() <= index) {
             // TODO: make this more efficient
@@ -340,7 +340,7 @@
 
 private:
     struct Entry {
-        sp<Codec2Buffer> clientBuffer;
+        sp<LinearBlockBuffer> clientBuffer;
         std::weak_ptr<C2Buffer> compBuffer;
         bool available;
     };
@@ -354,7 +354,7 @@
 
     bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
         *buffer = nullptr;
-        ssize_t ret = findBufferSlot<wp<Codec2Buffer>>(
+        ssize_t ret = findBufferSlot<wp<LinearBlockBuffer>>(
                 &mBuffers, kMinBufferArraySize,
                 [] (const auto &elem) { return elem.promote() == nullptr; });
         if (ret < 0) {
@@ -363,7 +363,7 @@
         // TODO: proper max input size and usage
         // TODO: read usage from intf
         C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
-        sp<Codec2Buffer> newBuffer = allocateLinearBuffer(mPool, mFormat, kLinearBufferSize, usage);
+        sp<LinearBlockBuffer> newBuffer = allocateLinearBuffer(mPool, mFormat, kLinearBufferSize, usage);
         if (newBuffer == nullptr) {
             return false;
         }
@@ -378,7 +378,7 @@
         if (it == mBuffers.end()) {
             return nullptr;
         }
-        sp<Codec2Buffer> codecBuffer = it->promote();
+        sp<LinearBlockBuffer> codecBuffer = it->promote();
         // We got sp<> reference from the caller so this should never happen..
         CHECK(codecBuffer != nullptr);
         return std::make_shared<Buffer1D>(codecBuffer->share());
@@ -394,7 +394,7 @@
         const size_t size = std::max(kMinBufferArraySize, mBuffers.size());
         mBuffers.resize(size);
         for (size_t i = 0; i < size; ++i) {
-            sp<Codec2Buffer> clientBuffer = mBuffers[i].promote();
+            sp<LinearBlockBuffer> clientBuffer = mBuffers[i].promote();
             bool available = false;
             if (clientBuffer == nullptr) {
                 // TODO: proper max input size
@@ -414,7 +414,7 @@
 private:
     // Buffers we passed to the client. The index of a buffer matches what
     // was passed in BufferCallback::onInputBufferAvailable().
-    std::vector<wp<Codec2Buffer>> mBuffers;
+    std::vector<wp<LinearBlockBuffer>> mBuffers;
 };
 
 class GraphicInputBuffers : public CCodecBufferChannel::InputBuffers {
@@ -617,9 +617,7 @@
         if (ret < 0) {
             return false;
         }
-        sp<MediaCodecBuffer> newBuffer = new MediaCodecBuffer(
-                mFormat,
-                convert(buffer));
+        sp<MediaCodecBuffer> newBuffer = convert(buffer);
         mBuffers[ret] = { newBuffer, buffer };
         *index = ret;
         *codecBuffer = newBuffer;
@@ -669,7 +667,7 @@
         // track of the flushed work.
     }
 
-    virtual sp<ABuffer> convert(const std::shared_ptr<C2Buffer> &buffer) = 0;
+    virtual sp<MediaCodecBuffer> convert(const std::shared_ptr<C2Buffer> &buffer) = 0;
 
 protected:
     struct BufferInfo {
@@ -687,9 +685,9 @@
 public:
     using FlexOutputBuffers::FlexOutputBuffers;
 
-    virtual sp<ABuffer> convert(const std::shared_ptr<C2Buffer> &buffer) override {
+    virtual sp<MediaCodecBuffer> convert(const std::shared_ptr<C2Buffer> &buffer) override {
         if (buffer == nullptr) {
-            return new ABuffer(nullptr, 0);
+            return new MediaCodecBuffer(mFormat, new ABuffer(nullptr, 0));
         }
         if (buffer->data().type() != C2BufferData::LINEAR) {
             // We expect linear output buffers from the component.
@@ -699,16 +697,7 @@
             // We expect one and only one linear block from the component.
             return nullptr;
         }
-        C2ReadView view = buffer->data().linearBlocks().front().map().get();
-        if (view.error() != C2_OK) {
-            // Mapping the linear block failed
-            return nullptr;
-        }
-        return new ABuffer(
-                // XXX: the data is supposed to be read-only. We don't have
-                // const equivalent of ABuffer however...
-                const_cast<uint8_t *>(view.data()),
-                view.capacity());
+        return ConstLinearBlockBuffer::allocate(mFormat, buffer->data().linearBlocks().front());
     }
 
     std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode() override {
@@ -737,8 +726,9 @@
 public:
     using FlexOutputBuffers::FlexOutputBuffers;
 
-    sp<ABuffer> convert(const std::shared_ptr<C2Buffer> &buffer) override {
-        return buffer ? new ABuffer(nullptr, 1) : new ABuffer(nullptr, 0);
+    sp<MediaCodecBuffer> convert(const std::shared_ptr<C2Buffer> &buffer) override {
+        return new MediaCodecBuffer(
+                mFormat, buffer ? new ABuffer(nullptr, 1) : new ABuffer(nullptr, 0));
     }
 
     std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode() override {
diff --git a/media/libstagefright/codec2/include/C2.h b/media/libstagefright/codec2/include/C2.h
index 442c89e..ab81cdc 100644
--- a/media/libstagefright/codec2/include/C2.h
+++ b/media/libstagefright/codec2/include/C2.h
@@ -189,6 +189,7 @@
 #define C2_CONST __attribute__((const))
 #define C2_HIDE __attribute__((visibility("hidden")))
 #define C2_INTERNAL __attribute__((internal_linkage))
+#define C2_ALLOW_OVERFLOW __attribute__((no_sanitize("integer")))
 
 #define DEFINE_OTHER_COMPARISON_OPERATORS(type) \
     inline bool operator!=(const type &other) const { return !(*this == other); } \
@@ -221,13 +222,13 @@
 template<typename T>
 struct C2_HIDE _c2_cntr_compat_helper {
     template<typename U, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline static constexpr T get(const U &value) {
         return T(value);
     }
 
     template<typename U, typename E=typename std::enable_if<(sizeof(U) >= sizeof(T))>::type>
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline static constexpr T get(const c2_cntr_t<U, void> &value) {
         return T(value.mValue);
     }
@@ -281,7 +282,7 @@
     /**
      * Peek as underlying signed type.
      */
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline constexpr typename std::make_signed<T>::type peek() const {
         return static_cast<typename std::make_signed<T>::type>(mValue);
     }
@@ -296,7 +297,7 @@
     /**
      * Peek as long long - e.g. for printing.
      */
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline constexpr long long peekll() const {
         return (long long)mValue;
     }
@@ -304,7 +305,7 @@
     /**
      * Peek as unsigned long long - e.g. for printing.
      */
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline constexpr unsigned long long peekull() const {
         return (unsigned long long)mValue;
     }
@@ -352,24 +353,24 @@
         return c2_cntr_t<T, void>(mValue op); \
     }
 
-    DEFINE_C2_CNTR_BINARY_OP(__attribute__((no_sanitize("integer"))), +, +=)
-    DEFINE_C2_CNTR_BINARY_OP(__attribute__((no_sanitize("integer"))), -, -=)
-    DEFINE_C2_CNTR_BINARY_OP(__attribute__((no_sanitize("integer"))), *, *=)
+    DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, +, +=)
+    DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, -, -=)
+    DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, *, *=)
 
-    DEFINE_C2_CNTR_UNARY_OP(__attribute__((no_sanitize("integer"))), -)
-    DEFINE_C2_CNTR_UNARY_OP(__attribute__((no_sanitize("integer"))), +)
+    DEFINE_C2_CNTR_UNARY_OP(C2_ALLOW_OVERFLOW, -)
+    DEFINE_C2_CNTR_UNARY_OP(C2_ALLOW_OVERFLOW, +)
 
-    DEFINE_C2_CNTR_CREMENT_OP(__attribute__((no_sanitize("integer"))), ++)
-    DEFINE_C2_CNTR_CREMENT_OP(__attribute__((no_sanitize("integer"))), --)
+    DEFINE_C2_CNTR_CREMENT_OP(C2_ALLOW_OVERFLOW, ++)
+    DEFINE_C2_CNTR_CREMENT_OP(C2_ALLOW_OVERFLOW, --)
 
     template<typename U, typename E=typename std::enable_if<std::is_unsigned<U>::value>::type>
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline constexpr c2_cntr_t<T> operator<<(const U &value) const {
         return c2_cntr_t<T>(mValue << value);
     }
 
     template<typename U, typename E=typename std::enable_if<std::is_unsigned<U>::value>::type>
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline c2_cntr_t<T> &operator<<=(const U &value) {
         mValue <<= value;
         return *this;
@@ -378,12 +379,12 @@
     /**
      * Comparison operators
      */
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline constexpr bool operator<=(const c2_cntr_t<T> &other) const {
         return T(other.mValue - mValue) < HALF_RANGE;
     }
 
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline constexpr bool operator>=(const c2_cntr_t<T> &other) const {
         return T(mValue - other.mValue) < HALF_RANGE;
     }
diff --git a/media/libstagefright/codec2/include/C2Buffer.h b/media/libstagefright/codec2/include/C2Buffer.h
index 2ca8222..45ad17f 100644
--- a/media/libstagefright/codec2/include/C2Buffer.h
+++ b/media/libstagefright/codec2/include/C2Buffer.h
@@ -126,9 +126,16 @@
      */
     bool isHW() const;
 
+    /**
+     * Null-fence. A fence that has fired.
+     */
+    constexpr C2Fence() : mImpl(nullptr) { }
+
 private:
     class Impl;
     std::shared_ptr<Impl> mImpl;
+    C2Fence(const std::shared_ptr<Impl> &impl);
+    friend struct _C2FenceFactory;
 };
 
 /**
@@ -245,13 +252,101 @@
 **************************************************************************************************/
 
 /**
+ * Basic segment math support.
+ */
+struct C2Segment {
+    uint32_t offset;
+    uint32_t size;
+
+    inline constexpr C2Segment(uint32_t offset_, uint32_t size_)
+        : offset(offset_),
+          size(size_) {
+    }
+
+    inline constexpr bool isEmpty() const {
+        return size == 0;
+    }
+
+    inline constexpr bool isValid() const {
+        return offset <= ~size;
+    }
+
+    inline constexpr operator bool() const {
+        return isValid() && !isEmpty();
+    }
+
+    inline constexpr bool operator!() const {
+        return !bool(*this);
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr bool contains(const C2Segment &other) const {
+        if (!isValid() || !other.isValid()) {
+            return false;
+        } else {
+            return offset <= other.offset
+                    && offset + size >= other.offset + other.size;
+        }
+    }
+
+    inline constexpr bool operator==(const C2Segment &other) const {
+        if (!isValid()) {
+            return !other.isValid();
+        } else {
+            return offset == other.offset && size == other.size;
+        }
+    }
+
+    inline constexpr bool operator!=(const C2Segment &other) const {
+        return !operator==(other);
+    }
+
+    inline constexpr bool operator>=(const C2Segment &other) const {
+        return contains(other);
+    }
+
+    inline constexpr bool operator>(const C2Segment &other) const {
+        return contains(other) && !operator==(other);
+    }
+
+    inline constexpr bool operator<=(const C2Segment &other) const {
+        return other.contains(*this);
+    }
+
+    inline constexpr bool operator<(const C2Segment &other) const {
+        return other.contains(*this) && !operator==(other);
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr uint32_t end() const {
+        return offset + size;
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr C2Segment intersect(const C2Segment &other) const {
+        if (!isValid()) {
+            return *this;
+        } else if (!other.isValid()) {
+            return other;
+        } else {
+            return C2Segment(c2_max(offset, other.offset),
+                             c2_min(end(), other.end()) - c2_max(offset, other.offset));
+        }
+    }
+};
+
+/**
  * Common aspect for all objects that have a linear capacity.
  */
 class _C2LinearCapacityAspect {
 /// \name Linear capacity interface
 /// @{
 public:
-    inline uint32_t capacity() const { return mCapacity; }
+    inline constexpr uint32_t capacity() const { return mCapacity; }
+
+    inline constexpr operator C2Segment() const {
+        return C2Segment(0, mCapacity);
+    }
 
 protected:
 
@@ -263,10 +358,10 @@
     inline explicit _C2LinearCapacityAspect(size_t capacity) = delete;
 #endif
 
-    inline explicit _C2LinearCapacityAspect(uint32_t capacity)
+    inline explicit constexpr _C2LinearCapacityAspect(uint32_t capacity)
       : mCapacity(capacity) { }
 
-    inline explicit _C2LinearCapacityAspect(const _C2LinearCapacityAspect *parent)
+    inline explicit constexpr _C2LinearCapacityAspect(const _C2LinearCapacityAspect *parent)
         : mCapacity(parent == nullptr ? 0 : parent->capacity()) { }
 
 private:
@@ -283,23 +378,35 @@
 /// \name Linear range interface
 /// @{
 public:
-    inline uint32_t offset() const { return mOffset; }
-    inline uint32_t endOffset() const { return mOffset + mSize; }
-    inline uint32_t size() const { return mSize; }
+    inline constexpr uint32_t offset() const { return mOffset; }
+    inline constexpr uint32_t endOffset() const { return mOffset + mSize; }
+    inline constexpr uint32_t size() const { return mSize; }
+
+    inline constexpr operator C2Segment() const {
+        return C2Segment(mOffset, mSize);
+    }
 
 protected:
-    inline explicit _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent)
+    // capacity range [0, capacity]
+    inline constexpr explicit _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent)
         : _C2LinearCapacityAspect(parent),
           mOffset(0),
           mSize(capacity()) { }
 
-    inline _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
+    // copy constructor (no error check)
+    inline constexpr _C2LinearRangeAspect(const _C2LinearRangeAspect &other)
+        : _C2LinearCapacityAspect(other.capacity()),
+          mOffset(other.offset()),
+          mSize(other.size()) { }
+
+    // subrange of capacity [0, capacity] & [size, size + offset]
+    inline constexpr _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
         : _C2LinearCapacityAspect(parent),
           mOffset(c2_min(offset, capacity())),
           mSize(c2_min(size, capacity() - mOffset)) { }
 
     // subsection of the two [offset, offset + size] ranges
-    inline _C2LinearRangeAspect(const _C2LinearRangeAspect *parent, size_t offset, size_t size)
+    inline constexpr _C2LinearRangeAspect(const _C2LinearRangeAspect *parent, size_t offset, size_t size)
         : _C2LinearCapacityAspect(parent == nullptr ? 0 : parent->capacity()),
           mOffset(c2_min(c2_max(offset, parent == nullptr ? 0 : parent->offset()), capacity())),
           mSize(c2_min(c2_min(size, parent == nullptr ? 0 : parent->size()), capacity() - mOffset)) { }
@@ -312,28 +419,31 @@
 /// @}
 };
 
-class C2_HIDE _C2LinearCapacityBase : public _C2LinearCapacityAspect {
-public:
-    inline explicit _C2LinearCapacityBase(size_t capacity)
-        : _C2LinearCapacityAspect(c2_min(capacity, std::numeric_limits<uint32_t>::max())) {}
-};
-
 /**
  * Utility class for safe range calculations.
  */
 class C2LinearRange : public _C2LinearRangeAspect {
 public:
-    inline C2LinearRange(const _C2LinearCapacityBase &parent, size_t offset, size_t size)
-        : _C2LinearRangeAspect(&parent, offset, size) {}
+    inline constexpr C2LinearRange(const _C2LinearCapacityAspect &parent, size_t offset, size_t size)
+        : _C2LinearRangeAspect(&parent, offset, size) { }
+
+    inline constexpr C2LinearRange(const _C2LinearRangeAspect &parent, size_t offset, size_t size)
+        : _C2LinearRangeAspect(&parent, offset, size) { }
+
+    inline constexpr C2LinearRange intersect(size_t offset, size_t size) const {
+        return C2LinearRange(*this, offset, size);
+    }
 };
 
 /**
  * Utility class for simple capacity and range construction.
  */
-class C2LinearCapacity : public _C2LinearCapacityBase {
+class C2LinearCapacity : public _C2LinearCapacityAspect {
 public:
-    using _C2LinearCapacityBase::_C2LinearCapacityBase;
-    inline C2LinearRange range(size_t offset, size_t size) {
+    inline constexpr explicit C2LinearCapacity(size_t capacity)
+        : _C2LinearCapacityAspect(c2_min(capacity, std::numeric_limits<uint32_t>::max())) { }
+
+    inline constexpr C2LinearRange range(size_t offset, size_t size) const {
         return C2LinearRange(*this, offset, size);
     }
 };
@@ -348,6 +458,9 @@
     inline explicit _C2EditableLinearRange(const _C2LinearCapacityAspect *parent)
         : _C2LinearRangeAspect(parent) { }
 
+    inline _C2EditableLinearRange(const _C2LinearRangeAspect &other)
+        : _C2LinearRangeAspect(other) { }
+
     inline _C2EditableLinearRange(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
         : _C2LinearRangeAspect(parent, offset, size) { }
 
@@ -379,6 +492,7 @@
         mOffset = offset;
         return true;
     }
+
     /**
      * Sets the size to |size|. Returns true if successful, which is equivalent to
      * if 0 <= |size| <= capacity() - offset().
@@ -394,6 +508,7 @@
             return true;
         }
     }
+
     /**
      * Sets the offset to |offset| with best effort. Same as setOffset() except that offset will
      * be clamped to the buffer capacity.
@@ -402,16 +517,9 @@
      * on the order of the operations. Always set offset first to ensure proper size.
      */
     inline void setOffset_be(uint32_t offset) {
-        if (offset > capacity()) {
-            offset = capacity();
-        }
-        if (offset > mOffset + mSize) {
-            mSize = 0;
-        } else {
-            mSize = mOffset + mSize - offset;
-        }
-        mOffset = offset;
+        (void)setOffset(c2_min(offset, capacity()));
     }
+
     /**
      * Sets the size to |size| with best effort. Same as setSize() except that the selected region
      * will be clamped to the buffer capacity (e.g. size is clamped to [0, capacity() - offset()]).
@@ -420,11 +528,471 @@
      * on the order of the operations. Always set offset first to ensure proper size.
      */
     inline void setSize_be(uint32_t size) {
-        mSize = std::min(size, capacity() - mOffset);
+        mSize = c2_min(size, capacity() - mOffset);
     }
 /// @}
 };
 
+/**************************************************************************************************
+  ALLOCATIONS
+**************************************************************************************************/
+
+/// \defgroup allocator Allocation and memory placement
+/// @{
+
+/**
+ * Buffer/memory usage bits. These are used by the allocators to select optimal memory type/pool and
+ * buffer layout.
+ *
+ * \note This struct has public fields without getters/setters. All methods are inline.
+ */
+struct C2MemoryUsage {
+// public:
+    // TODO: match these to gralloc1.h
+    enum Consumer : uint64_t {
+        // \todo do we need to distinguish often from rarely?
+        CPU_READ          = GRALLOC_USAGE_SW_READ_OFTEN,
+        RENDERSCRIPT_READ = GRALLOC_USAGE_RENDERSCRIPT,
+        HW_TEXTURE_READ   = GRALLOC_USAGE_HW_TEXTURE,
+        HW_COMPOSER_READ  = GRALLOC_USAGE_HW_COMPOSER,
+        HW_CODEC_READ     = GRALLOC_USAGE_HW_VIDEO_ENCODER,
+        READ_PROTECTED    = GRALLOC_USAGE_PROTECTED,
+    };
+
+    enum Producer : uint64_t {
+        CPU_WRITE          = GRALLOC_USAGE_SW_WRITE_OFTEN,
+        RENDERSCRIPT_WRITE = GRALLOC_USAGE_RENDERSCRIPT,
+        HW_TEXTURE_WRITE   = GRALLOC_USAGE_HW_RENDER,
+        HW_COMPOSER_WRITE  = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER,
+        HW_CODEC_WRITE     = GRALLOC_USAGE_HW_VIDEO_ENCODER,
+        WRITE_PROTECTED    = GRALLOC_USAGE_PROTECTED,
+    };
+
+    uint64_t consumer; // e.g. input
+    uint64_t producer; // e.g. output
+};
+
+class C2LinearAllocation;
+class C2GraphicAllocation;
+
+/**
+ *  Allocators are used by the framework to allocate memory (allocations) for buffers. They can
+ *  support either 1D or 2D allocations.
+ *
+ *  \note In theory they could support both, but in practice, we will use only one or the other.
+ *
+ *  Never constructed on stack.
+ *
+ *  Allocators are provided by vendors.
+ */
+class C2Allocator {
+public:
+    /**
+     * Allocator ID type.
+     */
+    typedef uint32_t id_t;
+    enum : id_t {
+        BAD_ID = 0xBADD, // invalid allocator ID
+    };
+
+    /**
+     * Allocation types. This is a bitmask and is used in C2Allocator::Info
+     * to list the supported allocation types of an allocator.
+     */
+    enum type_t : uint32_t {
+        LINEAR  = 1 << 0, //
+        GRAPHIC = 1 << 1,
+    };
+
+    /**
+     * Information about an allocator.
+     *
+     * Allocators don't have a query API so all queriable information is stored here.
+     */
+    struct Traits {
+        C2String name;              ///< allocator name
+        id_t id;                    ///< allocator ID
+        type_t supportedTypes;      ///< supported allocation types
+        C2MemoryUsage minimumUsage; ///< usage that is minimally required for allocations
+        C2MemoryUsage maximumUsage; ///< usage that is maximally allowed for allocations
+    };
+
+    /**
+     * Returns the unique name of this allocator.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return the name of this allocator.
+     * \retval an empty string if there was not enough memory to allocate the actual name.
+     */
+    virtual C2String getName() const = 0;
+
+    /**
+     * Returns a unique ID for this allocator. This ID is used to get this allocator from the
+     * allocator store, and to identify this allocator across all processes.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return a unique ID for this allocator.
+     */
+    virtual id_t getId() const = 0;
+
+    /**
+     * Returns the allocator traits.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * Allocators don't have a full-fledged query API, only this method.
+     *
+     * \return allocator information
+     */
+    virtual std::shared_ptr<const Traits> getTraits() const = 0;
+
+    /**
+     * Allocates a 1D allocation of given |capacity| and |usage|. If successful, the allocation is
+     * stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+     *
+     * \param capacity      the size of requested allocation (the allocation could be slightly
+     *                      larger, e.g. to account for any system-required alignment)
+     * \param usage         the memory usage info for the requested allocation. \note that the
+     *                      returned allocation may be later used/mapped with different usage.
+     *                      The allocator should layout the buffer to be optimized for this usage,
+     *                      but must support any usage. One exception: protected buffers can
+     *                      only be used in a protected scenario.
+     * \param allocation    pointer to where the allocation shall be stored on success. nullptr
+     *                      will be stored here on failure
+     *
+     * \retval C2_OK        the allocation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete the allocation
+     * \retval C2_TIMED_OUT the allocation timed out
+     * \retval C2_REFUSED   no permission to complete the allocation
+     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+     * \retval C2_OMITTED   this allocator does not support 1D allocations
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+     */
+    virtual c2_status_t newLinearAllocation(
+            uint32_t capacity __unused, C2MemoryUsage usage __unused,
+            std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
+        *allocation = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * (Re)creates a 1D allocation from a native |handle|. If successful, the allocation is stored
+     * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+     *
+     * \param handle      the handle for the existing allocation
+     * \param allocation  pointer to where the allocation shall be stored on success. nullptr
+     *                    will be stored here on failure
+     *
+     * \retval C2_OK        the allocation was recreated successfully
+     * \retval C2_NO_MEMORY not enough memory to recreate the allocation
+     * \retval C2_TIMED_OUT the recreation timed out (unexpected)
+     * \retval C2_REFUSED   no permission to recreate the allocation
+     * \retval C2_BAD_VALUE invalid handle (caller error)
+     * \retval C2_OMITTED   this allocator does not support 1D allocations
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+     */
+    virtual c2_status_t priorLinearAllocation(
+            const C2Handle *handle __unused,
+            std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
+        *allocation = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * Allocates a 2D allocation of given |width|, |height|, |format| and |usage|. If successful,
+     * the allocation is stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+     *
+     * \param width         the width of requested allocation (the allocation could be slightly
+     *                      larger, e.g. to account for any system-required alignment)
+     * \param height        the height of requested allocation (the allocation could be slightly
+     *                      larger, e.g. to account for any system-required alignment)
+     * \param format        the pixel format of requested allocation. This could be a vendor
+     *                      specific format.
+     * \param usage         the memory usage info for the requested allocation. \note that the
+     *                      returned allocation may be later used/mapped with different usage.
+     *                      The allocator should layout the buffer to be optimized for this usage,
+     *                      but must support any usage. One exception: protected buffers can
+     *                      only be used in a protected scenario.
+     * \param allocation    pointer to where the allocation shall be stored on success. nullptr
+     *                      will be stored here on failure
+     *
+     * \retval C2_OK        the allocation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete the allocation
+     * \retval C2_TIMED_OUT the allocation timed out
+     * \retval C2_REFUSED   no permission to complete the allocation
+     * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller error)
+     * \retval C2_OMITTED   this allocator does not support 2D allocations
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+     */
+    virtual c2_status_t newGraphicAllocation(
+            uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
+            C2MemoryUsage usage __unused,
+            std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
+        *allocation = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * (Re)creates a 2D allocation from a native handle.  If successful, the allocation is stored
+     * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+     *
+     * \param handle      the handle for the existing allocation
+     * \param allocation  pointer to where the allocation shall be stored on success. nullptr
+     *                    will be stored here on failure
+     *
+     * \retval C2_OK        the allocation was recreated successfully
+     * \retval C2_NO_MEMORY not enough memory to recreate the allocation
+     * \retval C2_TIMED_OUT the recreation timed out (unexpected)
+     * \retval C2_REFUSED   no permission to recreate the allocation
+     * \retval C2_BAD_VALUE invalid handle (caller error)
+     * \retval C2_OMITTED   this allocator does not support 2D allocations
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during recreation (unexpected)
+     */
+    virtual c2_status_t priorGraphicAllocation(
+            const C2Handle *handle __unused,
+            std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
+        *allocation = nullptr;
+        return C2_OMITTED;
+    }
+
+protected:
+    C2Allocator() = default;
+
+    virtual ~C2Allocator() = default;
+};
+
+/**
+ * \ingroup linear allocator
+ * 1D allocation interface.
+ */
+class C2LinearAllocation : public _C2LinearCapacityAspect {
+public:
+    /**
+     * Maps a portion of an allocation starting from |offset| with |size| into local process memory.
+     * Stores the starting address into |addr|, or NULL if the operation was unsuccessful.
+     * |fenceFd| is a file descriptor referring to an acquire sync fence object. If it is already
+     * safe to access the buffer contents, then -1.
+     *
+     * \param offset          starting position of the portion to be mapped (this does not have to
+     *                      be page aligned)
+     * \param size            size of the portion to be mapped (this does not have to be page
+     *                      aligned)
+     * \param usage           the desired usage. \todo this must be kSoftwareRead and/or
+     *                      kSoftwareWrite.
+     * \param fenceFd         a pointer to a file descriptor if an async mapping is requested. If
+     *                      not-null, and acquire fence FD will be stored here on success, or -1
+     *                      on failure. If null, the mapping will be synchronous.
+     * \param addr            a pointer to where the starting address of the mapped portion will be
+     *                      stored. On failure, nullptr will be stored here.
+     *
+     * \todo Only one portion can be mapped at the same time - this is true for gralloc, but there
+     *       is no need for this for 1D buffers.
+     * \todo Do we need to support sync operation as we could just wait for the fence?
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_REFUSED   no permission to map the portion
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_DUPLICATE if the allocation is already mapped.
+     * \retval C2_NO_MEMORY not enough memory to complete the operation
+     * \retval C2_BAD_VALUE the parameters (offset/size) are invalid or outside the allocation, or
+     *                      the usage flags are invalid (caller error)
+     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+     */
+    virtual c2_status_t map(
+            size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd /* nullable */,
+            void **addr /* nonnull */) = 0;
+
+    /**
+     * Unmaps a portion of an allocation at |addr| with |size|. These must be parameters previously
+     * passed to |map|; otherwise, this operation is a no-op.
+     *
+     * \param addr            starting address of the mapped region
+     * \param size            size of the mapped region
+     * \param fenceFd         a pointer to a file descriptor if an async unmapping is requested. If
+     *                      not-null, a release fence FD will be stored here on success, or -1
+     *                      on failure. This fence signals when the original allocation contains
+     *                      any changes that happened to the mapped region. If null, the unmapping
+     *                      will be synchronous.
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_NOT_FOUND if the allocation was not mapped previously.
+     * \retval C2_BAD_VALUE the parameters (addr/size) do not correspond to previously mapped
+     *                      regions (caller error)
+     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+     * \retval C2_REFUSED   no permission to unmap the portion (unexpected - system)
+     */
+    virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd /* nullable */) = 0;
+
+    /**
+     * Returns the allocator ID for this allocation. This is useful to put the handle into context.
+     */
+    virtual C2Allocator::id_t getAllocatorId() const = 0;
+
+    /**
+     * Returns a pointer to the allocation handle.
+     */
+    virtual const C2Handle *handle() const = 0;
+
+    /**
+     * Returns true if this is the same allocation as |other|.
+     */
+    virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const = 0;
+
+protected:
+    // \todo should we limit allocation directly?
+    C2LinearAllocation(size_t capacity) : _C2LinearCapacityAspect(c2_min(capacity, UINT32_MAX)) {}
+    virtual ~C2LinearAllocation() = default;
+};
+
+class C2CircularBlock;
+class C2LinearBlock;
+class C2GraphicBlock;
+
+/**
+ *  Block pools are used by components to obtain output buffers in an efficient way. They can
+ *  support either linear (1D), circular (1D) or graphic (2D) blocks.
+ *
+ *  Block pools decouple the recycling of memory/allocations from the components. They are meant to
+ *  be an opaque service (there are no public APIs other than obtaining blocks) provided by the
+ *  platform. Block pools are also meant to decouple allocations from memory used by buffers. This
+ *  is accomplished by allowing pools to allot multiple memory 'blocks' on a single allocation. As
+ *  their name suggest, block pools maintain a pool of memory blocks. When a component asks for
+ *  a memory block, pools will try to return a free memory block already in the pool. If no such
+ *  block exists, they will allocate memory using the backing allocator and allot a block on that
+ *  allocation. When blocks are no longer used in the system, they are recycled back to the block
+ *  pool and are available as free blocks.
+ *
+ *  Never constructed on stack.
+ */
+class C2BlockPool {
+public:
+    /**
+     * Block pool ID type.
+     */
+    typedef uint64_t local_id_t;
+
+    enum : local_id_t {
+        BASIC_LINEAR = 0,  ///< ID of basic (unoptimized) block pool for fetching 1D blocks
+        BASIC_GRAPHIC = 1, ///< ID of basic (unoptimized) block pool for fetching 2D blocks
+        PLATFORM_START = 0x10,
+    };
+
+    /**
+     * Returns the ID for this block pool. This ID is used to get this block pool from the platform.
+     * It is only valid in the current process.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return a local ID for this block pool.
+     */
+    virtual local_id_t getLocalId() const = 0;
+
+    /**
+     * Returns the ID of the backing allocator of this block pool.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return the ID of the backing allocator of this block pool.
+     */
+    virtual C2Allocator::id_t getAllocatorId() const = 0;
+
+    /**
+     * Obtains a linear writeable block of given |capacity| and |usage|. If successful, the
+     * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
+     *
+     * \param capacity the size of requested block.
+     * \param usage    the memory usage info for the requested block. Returned blocks will be
+     *                 optimized for this usage, but may be used with any usage. One exception:
+     *                 protected blocks/buffers can only be used in a protected scenario.
+     * \param block    pointer to where the obtained block shall be stored on success. nullptr will
+     *                 be stored here on failure
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_REFUSED   no permission to complete any required allocation
+     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+     * \retval C2_OMITTED   this pool does not support linear blocks
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+     */
+    virtual c2_status_t fetchLinearBlock(
+            uint32_t capacity __unused, C2MemoryUsage usage __unused,
+            std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+        *block = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * Obtains a circular writeable block of given |capacity| and |usage|. If successful, the
+     * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
+     *
+     * \param capacity the size of requested circular block. (note: the size of the obtained
+     *                 block could be slightly larger, e.g. to accommodate any system-required
+     *                 alignment)
+     * \param usage    the memory usage info for the requested block. Returned blocks will be
+     *                 optimized for this usage, but may be used with any usage. One exception:
+     *                 protected blocks/buffers can only be used in a protected scenario.
+     * \param block    pointer to where the obtained block shall be stored on success. nullptr
+     *                 will be stored here on failure
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_REFUSED   no permission to complete any required allocation
+     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+     * \retval C2_OMITTED   this pool does not support circular blocks
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+     */
+    virtual c2_status_t fetchCircularBlock(
+            uint32_t capacity __unused, C2MemoryUsage usage __unused,
+            std::shared_ptr<C2CircularBlock> *block /* nonnull */) {
+        *block = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * Obtains a 2D graphic block of given |width|, |height|, |format| and |usage|. If successful,
+     * the block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
+     *
+     * \param width  the width of requested block (the obtained block could be slightly larger, e.g.
+     *               to accommodate any system-required alignment)
+     * \param height the height of requested block (the obtained block could be slightly larger,
+     *               e.g. to accommodate any system-required alignment)
+     * \param format the pixel format of requested block. This could be a vendor specific format.
+     * \param usage  the memory usage info for the requested block. Returned blocks will be
+     *               optimized for this usage, but may be used with any usage. One exception:
+     *               protected blocks/buffers can only be used in a protected scenario.
+     * \param block  pointer to where the obtained block shall be stored on success. nullptr
+     *               will be stored here on failure
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_REFUSED   no permission to complete any required allocation
+     * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller
+     *                      error)
+     * \retval C2_OMITTED   this pool does not support 2D blocks
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+     */
+    virtual c2_status_t fetchGraphicBlock(
+            uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
+            C2MemoryUsage usage __unused,
+            std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+        *block = nullptr;
+        return C2_OMITTED;
+    }
+
+protected:
+    C2BlockPool() = default;
+
+    virtual ~C2BlockPool() = default;
+};
+
+/// @}
+
 // ================================================================================================
 //  BLOCKS
 // ================================================================================================
@@ -435,16 +1003,36 @@
 
 class C2LinearAllocation;
 
+/**
+ * A 1D block.
+ *
+ * \note capacity() is not meaningful for users of blocks; instead size() is the capacity of the
+ * usable portion. Use and offset() and size() if accessing the block directly through its handle
+ * to represent the allotted range of the underlying allocation to this block.
+ */
 class C2Block1D : public _C2LinearRangeAspect {
 public:
+    /**
+     * Returns the underlying handle for this allocation.
+     *
+     * \note that the block and its block pool has shared ownership of the handle
+     *       and if all references to the block are released, the underlying block
+     *       allocation may get reused even if a client keeps a clone of this handle.
+     */
     const C2Handle *handle() const;
 
-protected:
-    C2Block1D(std::shared_ptr<C2LinearAllocation> alloc);
-    C2Block1D(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size);
+    /**
+     * Returns the allocator's ID that created the underlying allocation for this block. This
+     * provides the context for understanding the handle.
+     */
+    C2Allocator::id_t getAllocatorId() const;
 
-private:
+protected:
     class Impl;
+    /** construct a block. */
+    C2Block1D(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range);
+
+    friend struct _C2BlockFactory;
     std::shared_ptr<Impl> mImpl;
 };
 
@@ -457,6 +1045,7 @@
 public:
     /**
      * \return pointer to the start of the block or nullptr on error.
+     *         This pointer is only valid during the lifetime of this view or until it is released.
      */
     const uint8_t *data() const;
 
@@ -476,13 +1065,20 @@
      */
     c2_status_t error() const;
 
+    /**
+     * Releases this view. This sets error to C2_NO_INIT.
+     */
+    //void release();
+
 protected:
-    C2ReadView(const _C2LinearCapacityAspect *parent, const uint8_t *data);
+    class Impl;
+    C2ReadView(std::shared_ptr<Impl> impl, uint32_t offset, uint32_t size);
     explicit C2ReadView(c2_status_t error);
 
 private:
-    class Impl;
+    friend struct _C2BlockFactory;
     std::shared_ptr<Impl> mImpl;
+    uint32_t mOffset; /**< offset into the linear block backing this read view */
 };
 
 /**
@@ -496,11 +1092,13 @@
      * Start of the block.
      *
      * \return pointer to the start of the block or nullptr on error.
+     *         This pointer is only valid during the lifetime of this view or until it is released.
      */
     uint8_t *base();
 
     /**
      * \return pointer to the block at the current offset or nullptr on error.
+     *         This pointer is only valid during the lifetime of this view or until it is released.
      */
     uint8_t *data();
 
@@ -509,14 +1107,18 @@
      */
     c2_status_t error() const;
 
+    /**
+     * Releases this view. This sets error to C2_NO_INIT.
+     */
+    //void release();
+
 protected:
-    C2WriteView(const _C2LinearRangeAspect *parent, uint8_t *base);
+    class Impl;
+    C2WriteView(std::shared_ptr<Impl> impl);
     explicit C2WriteView(c2_status_t error);
 
 private:
-    class Impl;
-    /// \todo should this be unique_ptr to make this movable only - to avoid inconsistent regions
-    /// between copies.
+    friend struct _C2BlockFactory;
     std::shared_ptr<Impl> mImpl;
 };
 
@@ -554,12 +1156,10 @@
     C2Fence fence() const { return mFence; }
 
 protected:
-    C2ConstLinearBlock(std::shared_ptr<C2LinearAllocation> alloc);
-    C2ConstLinearBlock(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size);
+    C2ConstLinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range, C2Fence mFence);
 
 private:
-    class Impl;
-    std::shared_ptr<Impl> mImpl;
+    friend struct _C2BlockFactory;
     C2Fence mFence;
 };
 
@@ -589,12 +1189,9 @@
     C2ConstLinearBlock share(size_t offset, size_t size, C2Fence fence);
 
 protected:
-    C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc);
-    C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size);
+    C2LinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range);
 
-private:
-    class Impl;
-    std::shared_ptr<Impl> mImpl;
+    friend struct _C2BlockFactory;
 };
 
 /// @}
@@ -800,27 +1397,26 @@
 
     // utility methods
 
-    inline bool isEmpty() const {
+    inline constexpr bool isEmpty() const {
         return width == 0 || height == 0;
     }
 
-    inline bool isValid() const {
+    inline constexpr bool isValid() const {
         return left <= ~width && top <= ~height;
     }
 
-    inline operator bool() const {
+    inline constexpr operator bool() const {
         return isValid() && !isEmpty();
     }
 
-    inline bool operator!() const {
+    inline constexpr bool operator!() const {
         return !bool(*this);
     }
 
-    inline bool contains(const C2Rect &other) const {
+    C2_ALLOW_OVERFLOW
+    inline constexpr bool contains(const C2Rect &other) const {
         if (!isValid() || !other.isValid()) {
             return false;
-        } else if (other.isEmpty()) {
-            return true;
         } else {
             return left <= other.left && top <= other.top
                     && left + width >= other.left + other.width
@@ -828,36 +1424,58 @@
         }
     }
 
-    inline bool operator==(const C2Rect &other) const {
+    inline constexpr bool operator==(const C2Rect &other) const {
         if (!isValid()) {
             return !other.isValid();
-        } else if (isEmpty()) {
-            return other.isEmpty();
         } else {
             return left == other.left && top == other.top
                     && width == other.width && height == other.height;
         }
     }
 
-    inline bool operator!=(const C2Rect &other) const {
+    inline constexpr bool operator!=(const C2Rect &other) const {
         return !operator==(other);
     }
 
-    inline bool operator>=(const C2Rect &other) const {
+    inline constexpr bool operator>=(const C2Rect &other) const {
         return contains(other);
     }
 
-    inline bool operator>(const C2Rect &other) const {
+    inline constexpr bool operator>(const C2Rect &other) const {
         return contains(other) && !operator==(other);
     }
 
-    inline bool operator<=(const C2Rect &other) const {
+    inline constexpr bool operator<=(const C2Rect &other) const {
         return other.contains(*this);
     }
 
-    inline bool operator<(const C2Rect &other) const {
+    inline constexpr bool operator<(const C2Rect &other) const {
         return other.contains(*this) && !operator==(other);
     }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr uint32_t right() const {
+        return left + width;
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr uint32_t bottom() const {
+        return top + height;
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr C2Rect intersect(const C2Rect &other) const {
+        if (!isValid()) {
+            return *this;
+        } else if (!other.isValid()) {
+            return other;
+        } else {
+            return C2Rect(c2_min(right(), other.right()) - c2_max(left, other.left),
+                          c2_min(bottom(), other.bottom()) - c2_max(top, other.top),
+                          c2_max(left, other.left),
+                          c2_max(top, other.top));
+        }
+    }
 };
 
 /**
@@ -1008,6 +1626,88 @@
 /// @}
 };
 
+/**
+ * \ingroup graphic allocator
+ * 2D allocation interface.
+ */
+class C2GraphicAllocation : public _C2PlanarCapacityAspect {
+public:
+    /**
+     * Maps a rectangular section (as defined by |rect|) of a 2D allocation into local process
+     * memory for flexible access. On success, it fills out |layout| with the plane specifications
+     * and fills the |addr| array with pointers to the first byte of the top-left pixel of each
+     * plane used. Otherwise, it leaves |layout| and |addr| untouched. |fenceFd| is a file
+     * descriptor referring to an acquire sync fence object. If it is already safe to access the
+     * buffer contents, then -1.
+     *
+     * \note Only one portion of the graphic allocation can be mapped at the same time. (This is
+     * from gralloc1 limitation.)
+     *
+     * \param rect            section to be mapped (this does not have to be aligned)
+     * \param usage           the desired usage. \todo this must be kSoftwareRead and/or
+     *                      kSoftwareWrite.
+     * \param fenceFd         a pointer to a file descriptor if an async mapping is requested. If
+     *                      not-null, and acquire fence FD will be stored here on success, or -1
+     *                      on failure. If null, the mapping will be synchronous.
+     * \param layout          a pointer to where the mapped planes' descriptors will be
+     *                      stored. On failure, nullptr will be stored here.
+     *
+     * \todo Do we need to support sync operation as we could just wait for the fence?
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_REFUSED   no permission to map the section
+     * \retval C2_DUPLICATE there is already a mapped region (caller error)
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_NO_MEMORY not enough memory to complete the operation
+     * \retval C2_BAD_VALUE the parameters (rect) are invalid or outside the allocation, or the
+     *                      usage flags are invalid (caller error)
+     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+
+     */
+    virtual c2_status_t map(
+            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+            // TODO: return <addr, size> buffers with plane sizes
+            C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) = 0;
+
+    /**
+     * Unmaps the last mapped rectangular section.
+     *
+     * \param fenceFd         a pointer to a file descriptor if an async unmapping is requested. If
+     *                      not-null, a release fence FD will be stored here on success, or -1
+     *                      on failure. This fence signals when the original allocation contains
+     *                      any changes that happened to the mapped section. If null, the unmapping
+     *                      will be synchronous.
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_NOT_FOUND there is no mapped region (caller error)
+     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+     * \retval C2_REFUSED   no permission to unmap the section (unexpected - system)
+     */
+    virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) = 0;
+
+    /**
+     * Returns true if this is a valid allocation.
+     *
+     * \todo remove?
+     */
+    virtual bool isValid() const = 0;
+
+    /**
+     * Returns a pointer to the allocation handle.
+     */
+    virtual const C2Handle *handle() const = 0;
+
+    /**
+     * Returns true if this is the same allocation as |other|.
+     */
+    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const = 0;
+
+protected:
+    using _C2PlanarCapacityAspect::_C2PlanarCapacityAspect;
+    virtual ~C2GraphicAllocation() = default;
+};
+
 class C2GraphicAllocation;
 
 class C2Block2D : public _C2PlanarSection {
@@ -1323,9 +2023,33 @@
      * \return true iff there is a metadata with the parameter type attached to this buffer.
      */
     bool hasInfo(C2Param::Type index) const;
+
+    /**
+     * Removes a metadata from the buffer.
+     */
     std::shared_ptr<C2Info> removeInfo(C2Param::Type index);
     ///@}
 
+    /**
+     * Creates a buffer containing a single linear block.
+     *
+     * \param block the content of the buffer.
+     *
+     * \return shared pointer to the created buffer.
+     */
+    static std::shared_ptr<C2Buffer> CreateLinearBuffer(const C2ConstLinearBlock &block);
+
+    /**
+     * Creates a buffer containing a single graphic block.
+     *
+     * \param block the content of the buffer.
+     *
+     * \return shared pointer to the created buffer.
+     */
+    static std::shared_ptr<C2Buffer> CreateGraphicBuffer(const C2ConstGraphicBlock &block);
+
+
+
 protected:
     // no public constructor
     explicit C2Buffer(const std::vector<C2ConstLinearBlock> &blocks);
@@ -1361,540 +2085,6 @@
 
 /// @}
 
-/**************************************************************************************************
-  ALLOCATIONS
-**************************************************************************************************/
-
-/// \defgroup allocator Allocation and memory placement
-/// @{
-
-/**
- * Buffer/memory usage bits. These are used by the allocators to select optimal memory type/pool and
- * buffer layout.
- *
- * \note This struct has public fields without getters/setters. All methods are inline.
- */
-struct C2MemoryUsage {
-// public:
-    // TODO: match these to gralloc1.h
-    enum Consumer : uint64_t {
-        // \todo do we need to distinguish often from rarely?
-        CPU_READ          = GRALLOC_USAGE_SW_READ_OFTEN,
-        RENDERSCRIPT_READ = GRALLOC_USAGE_RENDERSCRIPT,
-        HW_TEXTURE_READ   = GRALLOC_USAGE_HW_TEXTURE,
-        HW_COMPOSER_READ  = GRALLOC_USAGE_HW_COMPOSER,
-        HW_CODEC_READ     = GRALLOC_USAGE_HW_VIDEO_ENCODER,
-        READ_PROTECTED    = GRALLOC_USAGE_PROTECTED,
-    };
-
-    enum Producer : uint64_t {
-        CPU_WRITE          = GRALLOC_USAGE_SW_WRITE_OFTEN,
-        RENDERSCRIPT_WRITE = GRALLOC_USAGE_RENDERSCRIPT,
-        HW_TEXTURE_WRITE   = GRALLOC_USAGE_HW_RENDER,
-        HW_COMPOSER_WRITE  = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER,
-        HW_CODEC_WRITE     = GRALLOC_USAGE_HW_VIDEO_ENCODER,
-        WRITE_PROTECTED    = GRALLOC_USAGE_PROTECTED,
-    };
-
-    uint64_t consumer; // e.g. input
-    uint64_t producer; // e.g. output
-};
-
-/**
- * \ingroup linear allocator
- * 1D allocation interface.
- */
-class C2LinearAllocation : public _C2LinearCapacityAspect {
-public:
-    /**
-     * Maps a portion of an allocation starting from |offset| with |size| into local process memory.
-     * Stores the starting address into |addr|, or NULL if the operation was unsuccessful.
-     * |fenceFd| is a file descriptor referring to an acquire sync fence object. If it is already
-     * safe to access the buffer contents, then -1.
-     *
-     * \param offset          starting position of the portion to be mapped (this does not have to
-     *                      be page aligned)
-     * \param size            size of the portion to be mapped (this does not have to be page
-     *                      aligned)
-     * \param usage           the desired usage. \todo this must be kSoftwareRead and/or
-     *                      kSoftwareWrite.
-     * \param fenceFd         a pointer to a file descriptor if an async mapping is requested. If
-     *                      not-null, and acquire fence FD will be stored here on success, or -1
-     *                      on failure. If null, the mapping will be synchronous.
-     * \param addr            a pointer to where the starting address of the mapped portion will be
-     *                      stored. On failure, nullptr will be stored here.
-     *
-     * \todo Only one portion can be mapped at the same time - this is true for gralloc, but there
-     *       is no need for this for 1D buffers.
-     * \todo Do we need to support sync operation as we could just wait for the fence?
-     *
-     * \retval C2_OK        the operation was successful
-     * \retval C2_REFUSED   no permission to map the portion
-     * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_DUPLICATE if the allocation is already mapped.
-     * \retval C2_NO_MEMORY not enough memory to complete the operation
-     * \retval C2_BAD_VALUE the parameters (offset/size) are invalid or outside the allocation, or
-     *                      the usage flags are invalid (caller error)
-     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
-     */
-    virtual c2_status_t map(
-            size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd /* nullable */,
-            void **addr /* nonnull */) = 0;
-
-    /**
-     * Unmaps a portion of an allocation at |addr| with |size|. These must be parameters previously
-     * passed to |map|; otherwise, this operation is a no-op.
-     *
-     * \param addr            starting address of the mapped region
-     * \param size            size of the mapped region
-     * \param fenceFd         a pointer to a file descriptor if an async unmapping is requested. If
-     *                      not-null, a release fence FD will be stored here on success, or -1
-     *                      on failure. This fence signals when the original allocation contains
-     *                      any changes that happened to the mapped region. If null, the unmapping
-     *                      will be synchronous.
-     *
-     * \retval C2_OK        the operation was successful
-     * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_NOT_FOUND if the allocation was not mapped previously.
-     * \retval C2_BAD_VALUE the parameters (addr/size) do not correspond to previously mapped
-     *                      regions (caller error)
-     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
-     * \retval C2_REFUSED   no permission to unmap the portion (unexpected - system)
-     */
-    virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd /* nullable */) = 0;
-
-    /**
-     * Returns true if this is a valid allocation.
-     *
-     * \todo remove?
-     */
-    virtual bool isValid() const = 0;
-
-    /**
-     * Returns a pointer to the allocation handle.
-     */
-    virtual const C2Handle *handle() const = 0;
-
-    /**
-     * Returns true if this is the same allocation as |other|.
-     */
-    virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const = 0;
-
-protected:
-    // \todo should we limit allocation directly?
-    C2LinearAllocation(size_t capacity) : _C2LinearCapacityAspect(c2_min(capacity, UINT32_MAX)) {}
-    virtual ~C2LinearAllocation() = default;
-};
-
-/**
- * \ingroup graphic allocator
- * 2D allocation interface.
- */
-class C2GraphicAllocation : public _C2PlanarCapacityAspect {
-public:
-    /**
-     * Maps a rectangular section (as defined by |rect|) of a 2D allocation into local process
-     * memory for flexible access. On success, it fills out |layout| with the plane specifications
-     * and fills the |addr| array with pointers to the first byte of the top-left pixel of each
-     * plane used. Otherwise, it leaves |layout| and |addr| untouched. |fenceFd| is a file
-     * descriptor referring to an acquire sync fence object. If it is already safe to access the
-     * buffer contents, then -1.
-     *
-     * \note Only one portion of the graphic allocation can be mapped at the same time. (This is
-     * from gralloc1 limitation.)
-     *
-     * \param rect            section to be mapped (this does not have to be aligned)
-     * \param usage           the desired usage. \todo this must be kSoftwareRead and/or
-     *                      kSoftwareWrite.
-     * \param fenceFd         a pointer to a file descriptor if an async mapping is requested. If
-     *                      not-null, and acquire fence FD will be stored here on success, or -1
-     *                      on failure. If null, the mapping will be synchronous.
-     * \param layout          a pointer to where the mapped planes' descriptors will be
-     *                      stored. On failure, nullptr will be stored here.
-     *
-     * \todo Do we need to support sync operation as we could just wait for the fence?
-     *
-     * \retval C2_OK        the operation was successful
-     * \retval C2_REFUSED   no permission to map the section
-     * \retval C2_DUPLICATE there is already a mapped region (caller error)
-     * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_NO_MEMORY not enough memory to complete the operation
-     * \retval C2_BAD_VALUE the parameters (rect) are invalid or outside the allocation, or the
-     *                      usage flags are invalid (caller error)
-     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
-
-     */
-    virtual c2_status_t map(
-            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
-            // TODO: return <addr, size> buffers with plane sizes
-            C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) = 0;
-
-    /**
-     * Unmaps the last mapped rectangular section.
-     *
-     * \param fenceFd         a pointer to a file descriptor if an async unmapping is requested. If
-     *                      not-null, a release fence FD will be stored here on success, or -1
-     *                      on failure. This fence signals when the original allocation contains
-     *                      any changes that happened to the mapped section. If null, the unmapping
-     *                      will be synchronous.
-     *
-     * \retval C2_OK        the operation was successful
-     * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_NOT_FOUND there is no mapped region (caller error)
-     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
-     * \retval C2_REFUSED   no permission to unmap the section (unexpected - system)
-     */
-    virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) = 0;
-
-    /**
-     * Returns true if this is a valid allocation.
-     *
-     * \todo remove?
-     */
-    virtual bool isValid() const = 0;
-
-    /**
-     * Returns a pointer to the allocation handle.
-     */
-    virtual const C2Handle *handle() const = 0;
-
-    /**
-     * Returns true if this is the same allocation as |other|.
-     */
-    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const = 0;
-
-protected:
-    using _C2PlanarCapacityAspect::_C2PlanarCapacityAspect;
-    virtual ~C2GraphicAllocation() = default;
-};
-
-/**
- *  Allocators are used by the framework to allocate memory (allocations) for buffers. They can
- *  support either 1D or 2D allocations.
- *
- *  \note In theory they could support both, but in practice, we will use only one or the other.
- *
- *  Never constructed on stack.
- *
- *  Allocators are provided by vendors.
- */
-class C2Allocator {
-public:
-    /**
-     * Allocator ID type.
-     */
-    typedef uint32_t id_t;
-
-    /**
-     * Allocation types. This is a bitmask and is used in C2Allocator::Info
-     * to list the supported allocation types of an allocator.
-     */
-    enum type_t : uint32_t {
-        LINEAR  = 1 << 0, //
-        GRAPHIC = 1 << 1,
-    };
-
-    /**
-     * Information about an allocator.
-     *
-     * Allocators don't have a query API so all queriable information is stored here.
-     */
-    struct Traits {
-        C2String name;              ///< allocator name
-        id_t id;                    ///< allocator ID
-        type_t supportedTypes;      ///< supported allocation types
-        C2MemoryUsage minimumUsage; ///< usage that is minimally required for allocations
-        C2MemoryUsage maximumUsage; ///< usage that is maximally allowed for allocations
-    };
-
-    /**
-     * Returns the unique name of this allocator.
-     *
-     * This method MUST be "non-blocking" and return within 1ms.
-     *
-     * \return the name of this allocator.
-     * \retval an empty string if there was not enough memory to allocate the actual name.
-     */
-    virtual C2String getName() const = 0;
-
-    /**
-     * Returns a unique ID for this allocator. This ID is used to get this allocator from the
-     * allocator store, and to identify this allocator across all processes.
-     *
-     * This method MUST be "non-blocking" and return within 1ms.
-     *
-     * \return a unique ID for this allocator.
-     */
-    virtual id_t getId() const = 0;
-
-    /**
-     * Returns the allocator traits.
-     *
-     * This method MUST be "non-blocking" and return within 1ms.
-     *
-     * Allocators don't have a full-fledged query API, only this method.
-     *
-     * \return allocator information
-     */
-    virtual std::shared_ptr<const Traits> getTraits() const = 0;
-
-    /**
-     * Allocates a 1D allocation of given |capacity| and |usage|. If successful, the allocation is
-     * stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
-     *
-     * \param capacity      the size of requested allocation (the allocation could be slightly
-     *                      larger, e.g. to account for any system-required alignment)
-     * \param usage         the memory usage info for the requested allocation. \note that the
-     *                      returned allocation may be later used/mapped with different usage.
-     *                      The allocator should layout the buffer to be optimized for this usage,
-     *                      but must support any usage. One exception: protected buffers can
-     *                      only be used in a protected scenario.
-     * \param allocation    pointer to where the allocation shall be stored on success. nullptr
-     *                      will be stored here on failure
-     *
-     * \retval C2_OK        the allocation was successful
-     * \retval C2_NO_MEMORY not enough memory to complete the allocation
-     * \retval C2_TIMED_OUT the allocation timed out
-     * \retval C2_REFUSED   no permission to complete the allocation
-     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
-     * \retval C2_OMITTED   this allocator does not support 1D allocations
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
-     */
-    virtual c2_status_t newLinearAllocation(
-            uint32_t capacity __unused, C2MemoryUsage usage __unused,
-            std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
-        *allocation = nullptr;
-        return C2_OMITTED;
-    }
-
-    /**
-     * (Re)creates a 1D allocation from a native |handle|. If successful, the allocation is stored
-     * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
-     *
-     * \param handle      the handle for the existing allocation
-     * \param allocation  pointer to where the allocation shall be stored on success. nullptr
-     *                    will be stored here on failure
-     *
-     * \retval C2_OK        the allocation was recreated successfully
-     * \retval C2_NO_MEMORY not enough memory to recreate the allocation
-     * \retval C2_TIMED_OUT the recreation timed out (unexpected)
-     * \retval C2_REFUSED   no permission to recreate the allocation
-     * \retval C2_BAD_VALUE invalid handle (caller error)
-     * \retval C2_OMITTED   this allocator does not support 1D allocations
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
-     */
-    virtual c2_status_t priorLinearAllocation(
-            const C2Handle *handle __unused,
-            std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
-        *allocation = nullptr;
-        return C2_OMITTED;
-    }
-
-    /**
-     * Allocates a 2D allocation of given |width|, |height|, |format| and |usage|. If successful,
-     * the allocation is stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
-     *
-     * \param width         the width of requested allocation (the allocation could be slightly
-     *                      larger, e.g. to account for any system-required alignment)
-     * \param height        the height of requested allocation (the allocation could be slightly
-     *                      larger, e.g. to account for any system-required alignment)
-     * \param format        the pixel format of requested allocation. This could be a vendor
-     *                      specific format.
-     * \param usage         the memory usage info for the requested allocation. \note that the
-     *                      returned allocation may be later used/mapped with different usage.
-     *                      The allocator should layout the buffer to be optimized for this usage,
-     *                      but must support any usage. One exception: protected buffers can
-     *                      only be used in a protected scenario.
-     * \param allocation    pointer to where the allocation shall be stored on success. nullptr
-     *                      will be stored here on failure
-     *
-     * \retval C2_OK        the allocation was successful
-     * \retval C2_NO_MEMORY not enough memory to complete the allocation
-     * \retval C2_TIMED_OUT the allocation timed out
-     * \retval C2_REFUSED   no permission to complete the allocation
-     * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller error)
-     * \retval C2_OMITTED   this allocator does not support 2D allocations
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
-     */
-    virtual c2_status_t newGraphicAllocation(
-            uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
-            C2MemoryUsage usage __unused,
-            std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
-        *allocation = nullptr;
-        return C2_OMITTED;
-    }
-
-    /**
-     * (Re)creates a 2D allocation from a native handle.  If successful, the allocation is stored
-     * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
-     *
-     * \param handle      the handle for the existing allocation
-     * \param allocation  pointer to where the allocation shall be stored on success. nullptr
-     *                    will be stored here on failure
-     *
-     * \retval C2_OK        the allocation was recreated successfully
-     * \retval C2_NO_MEMORY not enough memory to recreate the allocation
-     * \retval C2_TIMED_OUT the recreation timed out (unexpected)
-     * \retval C2_REFUSED   no permission to recreate the allocation
-     * \retval C2_BAD_VALUE invalid handle (caller error)
-     * \retval C2_OMITTED   this allocator does not support 2D allocations
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during recreation (unexpected)
-     */
-    virtual c2_status_t priorGraphicAllocation(
-            const C2Handle *handle __unused,
-            std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
-        *allocation = nullptr;
-        return C2_OMITTED;
-    }
-
-protected:
-    C2Allocator() = default;
-
-    virtual ~C2Allocator() = default;
-};
-
-/**
- *  Block pools are used by components to obtain output buffers in an efficient way. They can
- *  support either linear (1D), circular (1D) or graphic (2D) blocks.
- *
- *  Block pools decouple the recycling of memory/allocations from the components. They are meant to
- *  be an opaque service (there are no public APIs other than obtaining blocks) provided by the
- *  platform. Block pools are also meant to decouple allocations from memory used by buffers. This
- *  is accomplished by allowing pools to allot multiple memory 'blocks' on a single allocation. As
- *  their name suggest, block pools maintain a pool of memory blocks. When a component asks for
- *  a memory block, pools will try to return a free memory block already in the pool. If no such
- *  block exists, they will allocate memory using the backing allocator and allot a block on that
- *  allocation. When blocks are no longer used in the system, they are recycled back to the block
- *  pool and are available as free blocks.
- *
- *  Never constructed on stack.
- */
-class C2BlockPool {
-public:
-    /**
-     * Block pool ID type.
-     */
-    typedef uint64_t local_id_t;
-
-    enum : local_id_t {
-        BASIC_LINEAR = 0,  ///< ID of basic (unoptimized) block pool for fetching 1D blocks
-        BASIC_GRAPHIC = 1, ///< ID of basic (unoptimized) block pool for fetching 2D blocks
-        PLATFORM_START = 0x10,
-    };
-
-    /**
-     * Returns the ID for this block pool. This ID is used to get this block pool from the platform.
-     * It is only valid in the current process.
-     *
-     * This method MUST be "non-blocking" and return within 1ms.
-     *
-     * \return a local ID for this block pool.
-     */
-    virtual local_id_t getLocalId() const = 0;
-
-    /**
-     * Returns the ID of the backing allocator of this block pool.
-     *
-     * This method MUST be "non-blocking" and return within 1ms.
-     *
-     * \return the ID of the backing allocator of this block pool.
-     */
-    virtual C2Allocator::id_t getAllocatorId() const = 0;
-
-    /**
-     * Obtains a linear writeable block of given |capacity| and |usage|. If successful, the
-     * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
-     *
-     * \param capacity the size of requested block.
-     * \param usage    the memory usage info for the requested block. Returned blocks will be
-     *                 optimized for this usage, but may be used with any usage. One exception:
-     *                 protected blocks/buffers can only be used in a protected scenario.
-     * \param block    pointer to where the obtained block shall be stored on success. nullptr will
-     *                 be stored here on failure
-     *
-     * \retval C2_OK        the operation was successful
-     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
-     * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_REFUSED   no permission to complete any required allocation
-     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
-     * \retval C2_OMITTED   this pool does not support linear blocks
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
-     */
-    virtual c2_status_t fetchLinearBlock(
-            uint32_t capacity __unused, C2MemoryUsage usage __unused,
-            std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
-        *block = nullptr;
-        return C2_OMITTED;
-    }
-
-    /**
-     * Obtains a circular writeable block of given |capacity| and |usage|. If successful, the
-     * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
-     *
-     * \param capacity the size of requested circular block. (note: the size of the obtained
-     *                 block could be slightly larger, e.g. to accommodate any system-required
-     *                 alignment)
-     * \param usage    the memory usage info for the requested block. Returned blocks will be
-     *                 optimized for this usage, but may be used with any usage. One exception:
-     *                 protected blocks/buffers can only be used in a protected scenario.
-     * \param block    pointer to where the obtained block shall be stored on success. nullptr
-     *                 will be stored here on failure
-     *
-     * \retval C2_OK        the operation was successful
-     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
-     * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_REFUSED   no permission to complete any required allocation
-     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
-     * \retval C2_OMITTED   this pool does not support circular blocks
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
-     */
-    virtual c2_status_t fetchCircularBlock(
-            uint32_t capacity __unused, C2MemoryUsage usage __unused,
-            std::shared_ptr<C2CircularBlock> *block /* nonnull */) {
-        *block = nullptr;
-        return C2_OMITTED;
-    }
-
-    /**
-     * Obtains a 2D graphic block of given |width|, |height|, |format| and |usage|. If successful,
-     * the block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
-     *
-     * \param width  the width of requested block (the obtained block could be slightly larger, e.g.
-     *               to accommodate any system-required alignment)
-     * \param height the height of requested block (the obtained block could be slightly larger,
-     *               e.g. to accommodate any system-required alignment)
-     * \param format the pixel format of requested block. This could be a vendor specific format.
-     * \param usage  the memory usage info for the requested block. Returned blocks will be
-     *               optimized for this usage, but may be used with any usage. One exception:
-     *               protected blocks/buffers can only be used in a protected scenario.
-     * \param block  pointer to where the obtained block shall be stored on success. nullptr
-     *               will be stored here on failure
-     *
-     * \retval C2_OK        the operation was successful
-     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
-     * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_REFUSED   no permission to complete any required allocation
-     * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller
-     *                      error)
-     * \retval C2_OMITTED   this pool does not support 2D blocks
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
-     */
-    virtual c2_status_t fetchGraphicBlock(
-            uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
-            C2MemoryUsage usage __unused,
-            std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
-        *block = nullptr;
-        return C2_OMITTED;
-    }
-
-protected:
-    C2BlockPool() = default;
-
-    virtual ~C2BlockPool() = default;
-};
-
-/// @}
-
 /// \cond INTERNAL
 
 /// \todo These are no longer used
diff --git a/media/libstagefright/codec2/include/C2Component.h b/media/libstagefright/codec2/include/C2Component.h
index aa0974a..721966b 100644
--- a/media/libstagefright/codec2/include/C2Component.h
+++ b/media/libstagefright/codec2/include/C2Component.h
@@ -696,6 +696,7 @@
         DEFAULT_GRAPHIC,    ///< basic graphic allocator type
         PLATFORM_START = 0x10,
         VENDOR_START   = 0x100,
+        BAD_ID         = C2Allocator::BAD_ID, ///< DO NOT USE
     };
 
     /**
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
index a310717..2de43c8 100644
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -29,10 +29,10 @@
 class C2BufferTest : public ::testing::Test {
 public:
     C2BufferTest()
-        : mLinearAllocator(std::make_shared<C2AllocatorIon>()),
+        : mLinearAllocator(std::make_shared<C2AllocatorIon>('i')),
           mSize(0u),
           mAddr(nullptr),
-          mGraphicAllocator(std::make_shared<C2AllocatorGralloc>()) {
+          mGraphicAllocator(std::make_shared<C2AllocatorGralloc>('g')) {
     }
 
     ~C2BufferTest() = default;
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
index a5ea511..155583d 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
@@ -540,7 +540,7 @@
     return C2_OK;
 }
 
-C2AllocatorGralloc::C2AllocatorGralloc() : mImpl(new Impl) {}
+C2AllocatorGralloc::C2AllocatorGralloc(id_t) : mImpl(new Impl) {}
 
 C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
 
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
index 34c68bb..4328a8d 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
@@ -119,14 +119,14 @@
         size_t offset, size_t size, C2MemoryUsage usage, int *fence,
         void **addr /* nonnull */) override;
     virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd) override;
-    virtual bool isValid() const override;
     virtual ~C2AllocationIon() override;
     virtual const C2Handle *handle() const override;
+    virtual id_t getAllocatorId() const override;
     virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const override;
 
     // internal methods
-    C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags);
-    C2AllocationIon(int ionFd, size_t size, int shareFd);
+    C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags, C2Allocator::id_t id);
+    C2AllocationIon(int ionFd, size_t size, int shareFd, C2Allocator::id_t id);
 
     c2_status_t status() const;
 
@@ -154,10 +154,11 @@
      *                  invalid if err is not 0.
      * \param err       errno during buffer allocation or import
      */
-    Impl(int ionFd, size_t capacity, int bufferFd, ion_user_handle_t buffer, int err)
+    Impl(int ionFd, size_t capacity, int bufferFd, ion_user_handle_t buffer, C2Allocator::id_t id, int err)
         : mIonFd(ionFd),
           mHandle(bufferFd, capacity),
           mBuffer(buffer),
+          mId(id),
           mInit(c2_map_errno<ENOMEM, EACCES, EINVAL>(err)),
           mMapFd(-1),
           mMapSize(0) {
@@ -183,10 +184,10 @@
      * \return created ion allocation (implementation) which may be invalid if the
      * import failed.
      */
-    static Impl *Import(int ionFd, size_t capacity, int bufferFd) {
+    static Impl *Import(int ionFd, size_t capacity, int bufferFd, C2Allocator::id_t id) {
         ion_user_handle_t buffer = -1;
         int ret = ion_import(ionFd, bufferFd, &buffer);
-        return new Impl(ionFd, capacity, bufferFd, buffer, ret);
+        return new Impl(ionFd, capacity, bufferFd, buffer, id, ret);
     }
 
     /**
@@ -201,7 +202,7 @@
      * \return created ion allocation (implementation) which may be invalid if the
      * allocation failed.
      */
-    static Impl *Alloc(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags) {
+    static Impl *Alloc(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags, C2Allocator::id_t id) {
         int bufferFd = -1;
         ion_user_handle_t buffer = -1;
         int ret = ion_alloc(ionFd, size, align, heapMask, flags, &buffer);
@@ -213,7 +214,7 @@
                 buffer = -1;
             }
         }
-        return new Impl(ionFd, size, bufferFd, buffer, ret);
+        return new Impl(ionFd, size, bufferFd, buffer, id, ret);
     }
 
     c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
@@ -311,10 +312,19 @@
         return &mHandle;
     }
 
+    C2Allocator::id_t getAllocatorId() const {
+        return mId;
+    }
+
+    ion_user_handle_t ionHandle() const {
+        return mBuffer;
+    }
+
 private:
     int mIonFd;
     C2HandleIon mHandle;
     ion_user_handle_t mBuffer;
+    C2Allocator::id_t mId;
     c2_status_t mInit;
     int mMapFd; // only one for now
     void *mMapAddr;
@@ -331,17 +341,21 @@
     return mImpl->unmap(addr, size, fenceFd);
 }
 
-bool C2AllocationIon::isValid() const {
-    return mImpl->status() == C2_OK;
-}
-
 c2_status_t C2AllocationIon::status() const {
     return mImpl->status();
 }
 
+C2Allocator::id_t C2AllocationIon::getAllocatorId() const {
+    return mImpl->getAllocatorId();
+}
+
 bool C2AllocationIon::equals(const std::shared_ptr<C2LinearAllocation> &other) const {
-    return other != nullptr &&
-        other->handle(); // TODO
+    if (!other || other->getAllocatorId() != getAllocatorId()) {
+        return false;
+    }
+    // get user handle to compare objects
+    std::shared_ptr<C2AllocationIon> otherAsIon = std::static_pointer_cast<C2AllocationIon>(other);
+    return mImpl->ionHandle() == otherAsIon->mImpl->ionHandle();
 }
 
 const C2Handle *C2AllocationIon::handle() const {
@@ -352,21 +366,28 @@
     delete mImpl;
 }
 
-C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags)
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align,
+                                 unsigned heapMask, unsigned flags, C2Allocator::id_t id)
     : C2LinearAllocation(size),
-      mImpl(Impl::Alloc(ionFd, size, align, heapMask, flags)) { }
+      mImpl(Impl::Alloc(ionFd, size, align, heapMask, flags, id)) { }
 
-C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd)
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd, C2Allocator::id_t id)
     : C2LinearAllocation(size),
-      mImpl(Impl::Import(ionFd, size, shareFd)) { }
+      mImpl(Impl::Import(ionFd, size, shareFd, id)) { }
 
 /* ======================================= ION ALLOCATOR ====================================== */
-C2AllocatorIon::C2AllocatorIon() : mInit(C2_OK), mIonFd(ion_open()) {
+C2AllocatorIon::C2AllocatorIon(id_t id)
+    : mInit(C2_OK),
+      mIonFd(ion_open()) {
     if (mIonFd < 0) {
         switch (errno) {
         case ENOENT:    mInit = C2_OMITTED; break;
         default:        mInit = c2_map_errno<EACCES>(errno); break;
         }
+    } else {
+        C2MemoryUsage minUsage = { 0, 0 }, maxUsage = { ~(uint64_t)0, ~(uint64_t)0 };
+        Traits traits = { "android.allocator.ion", id, LINEAR, minUsage, maxUsage };
+        mTraits = std::make_shared<Traits>(traits);
     }
 }
 
@@ -377,11 +398,15 @@
 }
 
 C2Allocator::id_t C2AllocatorIon::getId() const {
-    return 0; /// \todo implement ID
+    return mTraits->id;
 }
 
 C2String C2AllocatorIon::getName() const {
-    return "android.allocator.ion";
+    return mTraits->name;
+}
+
+std::shared_ptr<const C2Allocator::Traits> C2AllocatorIon::getTraits() const {
+    return mTraits;
 }
 
 c2_status_t C2AllocatorIon::newLinearAllocation(
@@ -410,7 +435,7 @@
 #endif
 
     std::shared_ptr<C2AllocationIon> alloc
-        = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags);
+        = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags, mTraits->id);
     c2_status_t ret = alloc->status();
     if (ret == C2_OK) {
         *allocation = alloc;
@@ -432,7 +457,7 @@
     // TODO: get capacity and validate it
     const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
     std::shared_ptr<C2AllocationIon> alloc
-        = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd());
+        = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd(), mTraits->id);
     c2_status_t ret = alloc->status();
     if (ret == C2_OK) {
         *allocation = alloc;
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index 4ab3e05..ff92679 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -21,49 +21,46 @@
 #include <map>
 
 #include <C2BufferPriv.h>
+#include <C2BlockInternal.h>
 
 namespace android {
 
 namespace {
 
+// This anonymous namespace contains the helper classes that allow our implementation to create
+// block/buffer objects.
+//
 // Inherit from the parent, share with the friend.
-
-class DummyCapacityAspect : public _C2LinearCapacityAspect {
-    using _C2LinearCapacityAspect::_C2LinearCapacityAspect;
-    friend class ::android::C2ReadView;
-    friend class ::android::C2ConstLinearBlock;
-};
-
-class C2DefaultReadView : public C2ReadView {
+class ReadViewBuddy : public C2ReadView {
     using C2ReadView::C2ReadView;
     friend class ::android::C2ConstLinearBlock;
 };
 
-class C2DefaultWriteView : public C2WriteView {
+class WriteViewBuddy : public C2WriteView {
     using C2WriteView::C2WriteView;
     friend class ::android::C2LinearBlock;
 };
 
-class C2AcquirableReadView : public C2Acquirable<C2ReadView> {
-    using C2Acquirable::C2Acquirable;
-    friend class ::android::C2ConstLinearBlock;
-};
-
-class C2AcquirableWriteView : public C2Acquirable<C2WriteView> {
-    using C2Acquirable::C2Acquirable;
-    friend class ::android::C2LinearBlock;
-};
-
-class C2DefaultConstLinearBlock : public C2ConstLinearBlock {
+class ConstLinearBlockBuddy : public C2ConstLinearBlock {
     using C2ConstLinearBlock::C2ConstLinearBlock;
     friend class ::android::C2LinearBlock;
 };
 
-class C2DefaultLinearBlock : public C2LinearBlock {
+class LinearBlockBuddy : public C2LinearBlock {
     using C2LinearBlock::C2LinearBlock;
     friend class ::android::C2BasicLinearBlockPool;
 };
 
+class AcquirableReadViewBuddy : public C2Acquirable<C2ReadView> {
+    using C2Acquirable::C2Acquirable;
+    friend class ::android::C2ConstLinearBlock;
+};
+
+class AcquirableWriteViewBuddy : public C2Acquirable<C2WriteView> {
+    using C2Acquirable::C2Acquirable;
+    friend class ::android::C2LinearBlock;
+};
+
 class C2DefaultGraphicView : public C2GraphicView {
     using C2GraphicView::C2GraphicView;
     friend class ::android::C2ConstGraphicBlock;
@@ -99,255 +96,230 @@
 
 /* ========================================== 1D BLOCK ========================================= */
 
-class C2Block1D::Impl {
+struct C2_HIDE _C2BlockPoolData;
+
+/**
+ * This class is the base class for all 1D block and view implementations.
+ *
+ * This is basically just a placeholder for the underlying 1D allocation and the range of the
+ * alloted portion to this block. There is also a placeholder for a blockpool data.
+ */
+class C2_HIDE _C2Block1DImpl : public _C2LinearRangeAspect {
 public:
-    const C2Handle *handle() const {
-        return mAllocation->handle();
+    _C2Block1DImpl(const std::shared_ptr<C2LinearAllocation> &alloc,
+            const std::shared_ptr<_C2BlockPoolData> &poolData = nullptr,
+            size_t offset = 0, size_t size = ~(size_t)0)
+        : _C2LinearRangeAspect(alloc.get(), offset, size),
+          mAllocation(alloc),
+          mPoolData(poolData) { }
+
+    _C2Block1DImpl(const _C2Block1DImpl &other, size_t offset = 0, size_t size = ~(size_t)0)
+        : _C2LinearRangeAspect(&other, offset, size),
+          mAllocation(other.mAllocation),
+          mPoolData(other.mPoolData) { }
+
+    /** returns const pool data  */
+    std::shared_ptr<const _C2BlockPoolData> poolData() const {
+        return mPoolData;
     }
 
-    Impl(std::shared_ptr<C2LinearAllocation> alloc)
-        : mAllocation(alloc) {}
+    /** returns native handle */
+    const C2Handle *handle() const {
+        return mAllocation ? mAllocation->handle() : nullptr;
+    }
+
+    /** returns the allocator's ID */
+    C2Allocator::id_t getAllocatorId() const {
+        // BAD_ID can only happen if this Impl class is initialized for a view - never for a block.
+        return mAllocation ? mAllocation->getAllocatorId() : C2Allocator::BAD_ID;
+    }
+
+    std::shared_ptr<C2LinearAllocation> getAllocation() const {
+        return mAllocation;
+    }
 
 private:
     std::shared_ptr<C2LinearAllocation> mAllocation;
+    std::shared_ptr<_C2BlockPoolData> mPoolData;
 };
 
-const C2Handle *C2Block1D::handle() const {
-    return mImpl->handle();
-};
-
-C2Block1D::C2Block1D(std::shared_ptr<C2LinearAllocation> alloc)
-    : _C2LinearRangeAspect(alloc.get()), mImpl(new Impl(alloc)) {
-}
-
-C2Block1D::C2Block1D(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size)
-    : _C2LinearRangeAspect(alloc.get(), offset, size), mImpl(new Impl(alloc)) {
-}
-
-class C2ReadView::Impl {
+/**
+ * This class contains the mapped data pointer, and the potential error.
+ *
+ * range is the mapped range of the underlying allocation (which is part of the allotted
+ * range).
+ */
+class C2_HIDE _C2MappedBlock1DImpl : public _C2Block1DImpl {
 public:
-    explicit Impl(const uint8_t *data)
-        : mData(data), mError(C2_OK) {}
+    _C2MappedBlock1DImpl(const _C2Block1DImpl &block, uint8_t *data,
+                         size_t offset = 0, size_t size = ~(size_t)0)
+        : _C2Block1DImpl(block, offset, size), mData(data), mError(C2_OK) { }
 
-    explicit Impl(c2_status_t error)
-        : mData(nullptr), mError(error) {}
+    _C2MappedBlock1DImpl(c2_status_t error)
+        : _C2Block1DImpl(nullptr), mData(nullptr), mError(error) {
+        // CHECK(error != C2_OK);
+    }
 
     const uint8_t *data() const {
         return mData;
     }
 
+    uint8_t *data() {
+        return mData;
+    }
+
     c2_status_t error() const {
         return mError;
     }
 
 private:
-    const uint8_t *mData;
+    uint8_t *mData;
     c2_status_t mError;
 };
 
-C2ReadView::C2ReadView(const _C2LinearCapacityAspect *parent, const uint8_t *data)
-    : _C2LinearCapacityAspect(parent), mImpl(std::make_shared<Impl>(data)) {}
+/**
+ * Block implementation.
+ */
+class C2Block1D::Impl : public _C2Block1DImpl {
+    using _C2Block1DImpl::_C2Block1DImpl;
+};
 
-C2ReadView::C2ReadView(c2_status_t error)
-    : _C2LinearCapacityAspect(0u), mImpl(std::make_shared<Impl>(error)) {}
+const C2Handle *C2Block1D::handle() const {
+    return mImpl->handle();
+};
 
-const uint8_t *C2ReadView::data() const {
-    return mImpl->data();
+C2Allocator::id_t C2Block1D::getAllocatorId() const {
+    return mImpl->getAllocatorId();
+};
+
+C2Block1D::C2Block1D(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range)
+    // always clamp subrange to parent (impl) range for safety
+    : _C2LinearRangeAspect(impl.get(), range.offset(), range.size()), mImpl(impl) {
 }
 
-C2ReadView C2ReadView::subView(size_t offset, size_t size) const {
-    if (offset > capacity()) {
-        offset = capacity();
-    }
-    if (size > capacity() - offset) {
-        size = capacity() - offset;
-    }
-    // TRICKY: newCapacity will just be used to grab the size.
-    DummyCapacityAspect newCapacity((uint32_t)size);
-    return C2ReadView(&newCapacity, data() + offset);
+/**
+ * Read view implementation.
+ *
+ * range of Impl is the mapped range of the underlying allocation (which is part of the allotted
+ * range). range of View is 0 to capacity() (not represented as an actual range). This maps to a
+ * subrange of Impl range starting at mImpl->offset() + _mOffset.
+ */
+class C2ReadView::Impl : public _C2MappedBlock1DImpl {
+    using _C2MappedBlock1DImpl::_C2MappedBlock1DImpl;
+};
+
+C2ReadView::C2ReadView(std::shared_ptr<Impl> impl, uint32_t offset, uint32_t size)
+    : _C2LinearCapacityAspect(C2LinearCapacity(impl->size()).range(offset, size).size()),
+      mImpl(impl),
+      mOffset(C2LinearCapacity(impl->size()).range(offset, size).offset()) { }
+
+C2ReadView::C2ReadView(c2_status_t error)
+    : _C2LinearCapacityAspect(0u), mImpl(std::make_shared<Impl>(error)), mOffset(0u) {
+    // CHECK(error != C2_OK);
+}
+
+const uint8_t *C2ReadView::data() const {
+    return mImpl->error() ? nullptr : mImpl->data() + mOffset;
 }
 
 c2_status_t C2ReadView::error() const {
     return mImpl->error();
 }
 
-class C2WriteView::Impl {
-public:
-    explicit Impl(uint8_t *base)
-        : mBase(base), mError(C2_OK) {}
+C2ReadView C2ReadView::subView(size_t offset, size_t size) const {
+    C2LinearRange subRange(*this, offset, size);
+    return C2ReadView(mImpl, mOffset + subRange.offset(), subRange.size());
+}
 
-    explicit Impl(c2_status_t error)
-        : mBase(nullptr), mError(error) {}
-
-    uint8_t *base() const {
-        return mBase;
-    }
-
-    c2_status_t error() const {
-        return mError;
-    }
-
-private:
-    uint8_t *mBase;
-    c2_status_t mError;
+/**
+ * Write view implementation.
+ */
+class C2WriteView::Impl : public _C2MappedBlock1DImpl {
+    using _C2MappedBlock1DImpl::_C2MappedBlock1DImpl;
 };
 
-C2WriteView::C2WriteView(const _C2LinearRangeAspect *parent, uint8_t *base)
-    : _C2EditableLinearRange(parent), mImpl(std::make_shared<Impl>(base)) {}
+C2WriteView::C2WriteView(std::shared_ptr<Impl> impl)
+// UGLY: _C2LinearRangeAspect requires a bona-fide object for capacity to prevent spoofing, so
+// this is what we have to do.
+    : _C2EditableLinearRange(std::make_unique<C2LinearCapacity>(impl->size()).get()), mImpl(impl) { }
 
 C2WriteView::C2WriteView(c2_status_t error)
     : _C2EditableLinearRange(nullptr), mImpl(std::make_shared<Impl>(error)) {}
 
-uint8_t *C2WriteView::base() { return mImpl->base(); }
+uint8_t *C2WriteView::base() { return mImpl->data(); }
 
-uint8_t *C2WriteView::data() { return mImpl->base() + offset(); }
+uint8_t *C2WriteView::data() { return mImpl->data() + offset(); }
 
 c2_status_t C2WriteView::error() const { return mImpl->error(); }
 
-class C2ConstLinearBlock::Impl {
-public:
-    explicit Impl(std::shared_ptr<C2LinearAllocation> alloc)
-        : mAllocation(alloc), mBase(nullptr), mSize(0u), mError(C2_CORRUPTED) {}
-
-    ~Impl() {
-        if (mBase != nullptr) {
-            // TODO: fence
-            c2_status_t err = mAllocation->unmap(mBase, mSize, nullptr);
-            if (err != C2_OK) {
-                // TODO: Log?
-            }
-        }
-    }
-
-    C2ConstLinearBlock subBlock(size_t offset, size_t size) const {
-        return C2ConstLinearBlock(mAllocation, offset, size);
-    }
-
-    void map(size_t offset, size_t size) {
-        if (mBase == nullptr) {
-            void *base = nullptr;
-            mError = mAllocation->map(
-                    offset, size, { C2MemoryUsage::CPU_READ, 0 }, nullptr, &base);
-            // TODO: fence
-            if (mError == C2_OK) {
-                mBase = (uint8_t *)base;
-                mSize = size;
-            }
-        }
-    }
-
-    const uint8_t *base() const { return mBase; }
-
-    c2_status_t error() const { return mError; }
-
-private:
-    std::shared_ptr<C2LinearAllocation> mAllocation;
-    uint8_t *mBase;
-    size_t mSize;
-    c2_status_t mError;
-};
-
-C2ConstLinearBlock::C2ConstLinearBlock(std::shared_ptr<C2LinearAllocation> alloc)
-    : C2Block1D(alloc), mImpl(std::make_shared<Impl>(alloc)) {}
-
-C2ConstLinearBlock::C2ConstLinearBlock(
-        std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size)
-    : C2Block1D(alloc, offset, size), mImpl(std::make_shared<Impl>(alloc)) {}
+/**
+ * Const linear block implementation.
+ */
+C2ConstLinearBlock::C2ConstLinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range, C2Fence fence)
+    : C2Block1D(impl, range), mFence(fence) { }
 
 C2Acquirable<C2ReadView> C2ConstLinearBlock::map() const {
-    mImpl->map(offset(), size());
-    if (mImpl->base() == nullptr) {
-        C2DefaultReadView view(mImpl->error());
-        return C2AcquirableReadView(mImpl->error(), mFence, view);
+    void *base = nullptr;
+    uint32_t len = size();
+    c2_status_t error = mImpl->getAllocation()->map(
+            offset(), len, { C2MemoryUsage::CPU_READ, 0 }, nullptr, &base);
+    // TODO: wait on fence
+    if (error == C2_OK) {
+        std::shared_ptr<ReadViewBuddy::Impl> rvi = std::shared_ptr<ReadViewBuddy::Impl>(
+                new ReadViewBuddy::Impl(*mImpl, (uint8_t *)base, offset(), len),
+                [base, len](ReadViewBuddy::Impl *i) {
+                    (void)i->getAllocation()->unmap(base, len, nullptr);
+        });
+        return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(rvi, 0, len));
+    } else {
+        return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(error));
     }
-    DummyCapacityAspect newCapacity(size());
-    C2DefaultReadView view(&newCapacity, mImpl->base());
-    return C2AcquirableReadView(mImpl->error(), mFence, view);
 }
 
-C2ConstLinearBlock C2ConstLinearBlock::subBlock(size_t offset, size_t size) const {
-    return mImpl->subBlock(offset, size);
+C2ConstLinearBlock C2ConstLinearBlock::subBlock(size_t offset_, size_t size_) const {
+    C2LinearRange subRange(*mImpl, offset_, size_);
+    return C2ConstLinearBlock(mImpl, subRange, mFence);
 }
 
-class C2LinearBlock::Impl {
-public:
-    Impl(std::shared_ptr<C2LinearAllocation> alloc)
-        : mAllocation(alloc), mBase(nullptr), mSize(0u), mError(C2_CORRUPTED) {}
-
-    ~Impl() {
-        if (mBase != nullptr) {
-            // TODO: fence
-            c2_status_t err = mAllocation->unmap(mBase, mSize, nullptr);
-            if (err != C2_OK) {
-                // TODO: Log?
-            }
-        }
-    }
-
-    void map(size_t capacity) {
-        if (mBase == nullptr) {
-            void *base = nullptr;
-            // TODO: fence
-            mError = mAllocation->map(
-                    0u,
-                    capacity,
-                    { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
-                    nullptr,
-                    &base);
-            if (mError == C2_OK) {
-                mBase = (uint8_t *)base;
-                mSize = capacity;
-            }
-        }
-    }
-
-    C2ConstLinearBlock share(size_t offset, size_t size, C2Fence &fence) {
-        // TODO
-        (void) fence;
-        return C2DefaultConstLinearBlock(mAllocation, offset, size);
-    }
-
-    uint8_t *base() const { return mBase; }
-
-    c2_status_t error() const { return mError; }
-
-    C2Fence fence() const { return mFence; }
-
-private:
-    std::shared_ptr<C2LinearAllocation> mAllocation;
-    uint8_t *mBase;
-    size_t mSize;
-    c2_status_t mError;
-    C2Fence mFence;
-};
-
-C2LinearBlock::C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc)
-    : C2Block1D(alloc),
-      mImpl(new Impl(alloc)) {}
-
-C2LinearBlock::C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size)
-    : C2Block1D(alloc, offset, size),
-      mImpl(new Impl(alloc)) {}
+/**
+ * Linear block implementation.
+ */
+C2LinearBlock::C2LinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range)
+    : C2Block1D(impl, range) { }
 
 C2Acquirable<C2WriteView> C2LinearBlock::map() {
-    mImpl->map(capacity());
-    if (mImpl->base() == nullptr) {
-        C2DefaultWriteView view(mImpl->error());
-        return C2AcquirableWriteView(mImpl->error(), mImpl->fence(), view);
+    void *base = nullptr;
+    uint32_t len = size();
+    c2_status_t error = mImpl->getAllocation()->map(
+            offset(), len, { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, nullptr, &base);
+    // TODO: wait on fence
+    if (error == C2_OK) {
+        std::shared_ptr<WriteViewBuddy::Impl> rvi = std::shared_ptr<WriteViewBuddy::Impl>(
+                new WriteViewBuddy::Impl(*mImpl, (uint8_t *)base, 0, len),
+                [base, len](WriteViewBuddy::Impl *i) {
+                    (void)i->getAllocation()->unmap(base, len, nullptr);
+        });
+        return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(rvi));
+    } else {
+        return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(error));
     }
-    C2DefaultWriteView view(this, mImpl->base());
-    view.setOffset_be(offset());
-    view.setSize_be(size());
-    return C2AcquirableWriteView(mImpl->error(), mImpl->fence(), view);
 }
 
-C2ConstLinearBlock C2LinearBlock::share(size_t offset, size_t size, C2Fence fence) {
-    return mImpl->share(offset, size, fence);
+C2ConstLinearBlock C2LinearBlock::share(size_t offset_, size_t size_, C2Fence fence) {
+    return ConstLinearBlockBuddy(mImpl, C2LinearRange(*this, offset_, size_), fence);
+}
+
+std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
+        const std::shared_ptr<C2LinearAllocation> &alloc,
+        const std::shared_ptr<_C2BlockPoolData> &data, size_t offset, size_t size) {
+    std::shared_ptr<C2Block1D::Impl> impl =
+        std::make_shared<C2Block1D::Impl>(alloc, data, offset, size);
+    return std::shared_ptr<C2LinearBlock>(new C2LinearBlock(impl, *impl));
 }
 
 C2BasicLinearBlockPool::C2BasicLinearBlockPool(
         const std::shared_ptr<C2Allocator> &allocator)
-  : mAllocator(allocator) {}
+  : mAllocator(allocator) { }
 
 c2_status_t C2BasicLinearBlockPool::fetchLinearBlock(
         uint32_t capacity,
@@ -361,7 +333,7 @@
         return err;
     }
 
-    block->reset(new C2DefaultLinearBlock(alloc));
+    *block = _C2BlockFactory::CreateLinearBlock(alloc);
 
     return C2_OK;
 }
diff --git a/media/libstagefright/codec2/vndk/C2Store.cpp b/media/libstagefright/codec2/vndk/C2Store.cpp
index a49fd24..05b46c3 100644
--- a/media/libstagefright/codec2/vndk/C2Store.cpp
+++ b/media/libstagefright/codec2/vndk/C2Store.cpp
@@ -40,14 +40,9 @@
  * \todo Move ion allocation into its HIDL or provide some mapping from memory usage to ion flags
  * \todo Make this allocator store extendable
  */
-class C2PlatformAllocatorStore : public C2AllocatorStore {
+class C2PlatformAllocatorStoreImpl : public C2PlatformAllocatorStore {
 public:
-    enum : id_t {
-        ION = PLATFORM_START,
-        GRALLOC,
-    };
-
-    C2PlatformAllocatorStore(
+    C2PlatformAllocatorStoreImpl(
         /* ionmapper */
     );
 
@@ -71,10 +66,10 @@
     std::shared_ptr<C2Allocator> fetchGrallocAllocator();
 };
 
-C2PlatformAllocatorStore::C2PlatformAllocatorStore() {
+C2PlatformAllocatorStoreImpl::C2PlatformAllocatorStoreImpl() {
 }
 
-c2_status_t C2PlatformAllocatorStore::fetchAllocator(
+c2_status_t C2PlatformAllocatorStoreImpl::fetchAllocator(
         id_t id, std::shared_ptr<C2Allocator> *const allocator) {
     allocator->reset();
     switch (id) {
@@ -98,32 +93,32 @@
     return C2_OK;
 }
 
-std::shared_ptr<C2Allocator> C2PlatformAllocatorStore::fetchIonAllocator() {
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchIonAllocator() {
     static std::mutex mutex;
     static std::weak_ptr<C2Allocator> ionAllocator;
     std::lock_guard<std::mutex> lock(mutex);
     std::shared_ptr<C2Allocator> allocator = ionAllocator.lock();
     if (allocator == nullptr) {
-        allocator = std::make_shared<C2AllocatorIon>();
+        allocator = std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
         ionAllocator = allocator;
     }
     return allocator;
 }
 
-std::shared_ptr<C2Allocator> C2PlatformAllocatorStore::fetchGrallocAllocator() {
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchGrallocAllocator() {
     static std::mutex mutex;
     static std::weak_ptr<C2Allocator> grallocAllocator;
     std::lock_guard<std::mutex> lock(mutex);
     std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
     if (allocator == nullptr) {
-        allocator = std::make_shared<C2AllocatorGralloc>();
+        allocator = std::make_shared<C2AllocatorGralloc>(C2PlatformAllocatorStore::GRALLOC);
         grallocAllocator = allocator;
     }
     return allocator;
 }
 
 std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore() {
-    return std::make_shared<C2PlatformAllocatorStore>();
+    return std::make_shared<C2PlatformAllocatorStoreImpl>();
 }
 
 c2_status_t GetCodec2BlockPool(
@@ -408,6 +403,8 @@
     mComponents.emplace("c2.google.aac.decoder", "libstagefright_soft_c2aacdec.so");
     mComponents.emplace("c2.google.aac.encoder", "libstagefright_soft_c2aacenc.so");
     mComponents.emplace("c2.google.mp3.decoder", "libstagefright_soft_c2mp3dec.so");
+    mComponents.emplace("c2.google.g711.alaw.decoder", "libstagefright_soft_c2g711alawdec.so");
+    mComponents.emplace("c2.google.g711.mlaw.decoder", "libstagefright_soft_c2g711mlawdec.so");
 }
 
 c2_status_t C2PlatformComponentStore::copyBuffer(
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
index 56fa317..0e1a3ac 100644
--- a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
@@ -61,7 +61,7 @@
             const C2Handle *handle,
             std::shared_ptr<C2GraphicAllocation> *allocation) override;
 
-    C2AllocatorGralloc();
+    C2AllocatorGralloc(id_t id = 0);
 
     c2_status_t status() const;
 
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
index bb815f9..716eae0 100644
--- a/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
@@ -33,9 +33,7 @@
 
     virtual C2String getName() const override;
 
-    virtual std::shared_ptr<const Traits> getTraits() const override {
-        return nullptr; // \todo
-    }
+    virtual std::shared_ptr<const Traits> getTraits() const override;
 
     virtual c2_status_t newLinearAllocation(
             uint32_t capacity, C2MemoryUsage usage,
@@ -45,13 +43,14 @@
             const C2Handle *handle,
             std::shared_ptr<C2LinearAllocation> *allocation) override;
 
-    C2AllocatorIon();
+    C2AllocatorIon(id_t id);
 
     virtual c2_status_t status() const { return mInit; }
 
     virtual ~C2AllocatorIon() override;
 
 private:
+    std::shared_ptr<const Traits> mTraits;
     c2_status_t mInit;
     int mIonFd;
     usage_mapper_fn mUsageMapper;
diff --git a/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h b/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h
new file mode 100644
index 0000000..cfea104
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 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 STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
+#define STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
+
+#include <C2Component.h>
+
+#include <functional>
+#include <memory>
+
+namespace android {
+
+/**
+ * Component factory object that enables to create a component and/or interface from a dynamically
+ * linked library. This is needed because the component/interfaces are managed objects, but we
+ * cannot safely create a managed object and pass it in C.
+ *
+ * Components/interfaces typically inherit from std::enable_shared_from_this, but C requires
+ * passing simple pointer, and shared_ptr constructor needs to know the class to be constructed
+ * derives from enable_shared_from_this.
+ *
+ */
+class C2ComponentFactory {
+public:
+    typedef std::function<void(::android::C2Component*)> ComponentDeleter;
+    typedef std::function<void(::android::C2ComponentInterface*)> InterfaceDeleter;
+
+    /**
+     * Creates a component.
+     *
+     * This method SHALL return within 100ms.
+     *
+     * \param id        component ID for the created component
+     * \param component shared pointer where the created component is stored. Cleared on
+     *                  failure and updated on success.
+     *
+     * \retval C2_OK        the component was created successfully
+     * \retval C2_TIMED_OUT could not create the component within the time limit (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented the creation of the component (unexpected)
+     *
+     * \retval C2_NO_MEMORY not enough memory to create the component
+     */
+    virtual c2_status_t createComponent(
+            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
+            ComponentDeleter deleter = std::default_delete<C2Component>()) = 0;
+
+    /**
+     * Creates a component interface.
+     *
+     * This method SHALL return within 100ms.
+     *
+     * \param id        component interface ID for the created interface
+     * \param interface shared pointer where the created interface is stored. Cleared on
+     *                  failure and updated on success.
+     *
+     * \retval C2_OK        the component interface was created successfully
+     * \retval C2_TIMED_OUT could not create the component interface within the time limit
+     *                      (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented the creation of the component interface
+     *                      (unexpected)
+     *
+     * \retval C2_NO_MEMORY not enough memory to create the component interface
+     */
+    virtual c2_status_t createInterface(
+            c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
+            InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) = 0;
+
+    virtual ~C2ComponentFactory() = default;
+
+    typedef ::android::C2ComponentFactory* (*CreateCodec2FactoryFunc)(void);
+    typedef void (*DestroyCodec2FactoryFunc)(::android::C2ComponentFactory*);
+};
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
index 2281dab..76b02ed 100644
--- a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
+++ b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
@@ -18,8 +18,8 @@
 #define STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
 
 #include <C2Component.h>
+#include <C2ComponentFactory.h>
 
-#include <functional>
 #include <memory>
 
 namespace android {
@@ -31,6 +31,34 @@
 std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore();
 
 /**
+ * Platform allocator store IDs
+ */
+class C2PlatformAllocatorStore : public C2AllocatorStore {
+public:
+    enum : id_t {
+        /**
+         * ID of the ion backed platform allocator.
+         *
+         * C2Handle consists of:
+         *   fd  shared ion buffer handle
+         *   int size (lo 32 bits)
+         *   int size (hi 32 bits)
+         *   int magic '\xc2io\x00'
+         */
+        ION = PLATFORM_START,
+
+        /**
+         * ID of the gralloc backed platform allocator.
+         *
+         * C2Handle layout is not public. Use C2AllocatorGralloc::UnwrapNativeCodec2GrallocHandle
+         * to get the underlying gralloc handle from a C2Handle, and WrapNativeCodec2GrallocHandle
+         * to create a C2Handle from a gralloc handle - for C2Allocator::priorAllocation.
+         */
+        GRALLOC,
+    };
+};
+
+/**
  * Retrieves a block pool for a component.
  *
  * \param id        the local ID of the block pool
@@ -54,73 +82,10 @@
         std::shared_ptr<C2BlockPool> *pool);
 
 /**
- * Component factory object that enables to create a component and/or interface from a dynamically
- * linked library. This is needed because the component/interfaces are managed objects, but we
- * cannot safely create a managed object and pass it in C.
- *
- * Components/interfaces typically inherit from std::enable_shared_from_this, but C requires
- * passing simple pointer, and shared_ptr constructor needs to know the class to be constructed
- * derives from enable_shared_from_this.
- *
- */
-class C2ComponentFactory {
-public:
-    typedef std::function<void(::android::C2Component*)> ComponentDeleter;
-    typedef std::function<void(::android::C2ComponentInterface*)> InterfaceDeleter;
-
-    /**
-     * Creates a component.
-     *
-     * This method SHALL return within 100ms.
-     *
-     * \param id        component ID for the created component
-     * \param component shared pointer where the created component is stored. Cleared on
-     *                  failure and updated on success.
-     *
-     * \retval C2_OK        the component was created successfully
-     * \retval C2_TIMED_OUT could not create the component within the time limit (unexpected)
-     * \retval C2_CORRUPTED some unknown error prevented the creation of the component (unexpected)
-     *
-     * \retval C2_NO_MEMORY not enough memory to create the component
-     */
-    virtual c2_status_t createComponent(
-            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
-            ComponentDeleter deleter = std::default_delete<C2Component>()) = 0;
-
-    /**
-     * Creates a component interface.
-     *
-     * This method SHALL return within 100ms.
-     *
-     * \param id        component interface ID for the created interface
-     * \param interface shared pointer where the created interface is stored. Cleared on
-     *                  failure and updated on success.
-     *
-     * \retval C2_OK        the component interface was created successfully
-     * \retval C2_TIMED_OUT could not create the component interface within the time limit
-     *                      (unexpected)
-     * \retval C2_CORRUPTED some unknown error prevented the creation of the component interface
-     *                      (unexpected)
-     *
-     * \retval C2_NO_MEMORY not enough memory to create the component interface
-     */
-    virtual c2_status_t createInterface(
-            c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
-            InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) = 0;
-
-    virtual ~C2ComponentFactory() = default;
-
-    typedef ::android::C2ComponentFactory* (*CreateCodec2FactoryFunc)(void);
-    typedef void (*DestroyCodec2FactoryFunc)(::android::C2ComponentFactory*);
-};
-
-/**
  * Returns the platform component store.
  * \retval nullptr if the platform component store could not be obtained
  */
 std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore();
-
-
 } // namespace android
 
 #endif // STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
diff --git a/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
new file mode 100644
index 0000000..c84d1fb
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 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 ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
+#define ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
+
+#include <C2Buffer.h>
+
+namespace android {
+
+struct _C2BlockPoolData;
+
+/**
+ * Interface for creating blocks by block pool/buffer passing implementations.
+ */
+struct C2_HIDE _C2BlockFactory {
+    static
+    std::shared_ptr<C2LinearBlock> C2_HIDE CreateLinearBlock(
+            const std::shared_ptr<C2LinearAllocation> &alloc,
+            const std::shared_ptr<_C2BlockPoolData> &data = nullptr,
+            size_t offset = 0,
+            size_t size = ~(size_t)0);
+};
+
+}
+
+#endif // ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
+
diff --git a/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp b/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp
index 7c281e3..911f0f8 100644
--- a/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp
+++ b/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp
@@ -654,7 +654,6 @@
         ALOGE("Unable to allocate memory for hold memory records: Size %zu",
                 mNumMemRecords * sizeof(iv_mem_rec_t));
         mSignalledError = true;
-        // TODO: notify(error, C2_CORRUPTED, 0, 0);
         return C2_CORRUPTED;
     }
 
@@ -697,8 +696,6 @@
         if (status != IV_SUCCESS) {
             ALOGE("Fill memory records failed = 0x%x\n",
                     s_fill_mem_rec_op.u4_error_code);
-            mSignalledError = true;
-            // TODO: notify(error, C2_CORRUPTED, 0, 0);
             return C2_CORRUPTED;
         }
     }
@@ -716,8 +713,6 @@
             if (ps_mem_rec->pv_base == NULL) {
                 ALOGE("Allocation failure for mem record id %zu size %u\n", i,
                         ps_mem_rec->u4_mem_size);
-                mSignalledError = true;
-                // TODO: notify(error, C2_CORRUPTED, 0, 0);
                 return C2_CORRUPTED;
 
             }
@@ -771,8 +766,6 @@
 
         if (status != IV_SUCCESS) {
             ALOGE("Init encoder failed = 0x%x\n", s_init_op.u4_error_code);
-            mSignalledError = true;
-            // TODO: notify(error, C2_CORRUPTED, 0 /* arg2 */, NULL /* data */);
             return C2_CORRUPTED;
         }
     }
@@ -1001,6 +994,7 @@
 void C2SoftAvcEnc::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    work->result = C2_OK;
     work->workletsProcessed = 0u;
 
     IV_STATUS_T status;
@@ -1011,7 +1005,8 @@
     if (mCodecCtx == NULL) {
         if (C2_OK != initEncoder()) {
             ALOGE("Failed to initialize encoder");
-            // TODO: notify(error, C2_CORRUPTED, 0 /* arg2 */, NULL /* data */);
+            work->workletsProcessed = 1u;
+            work->result = C2_CORRUPTED;
             return;
         }
     }
@@ -1031,7 +1026,8 @@
                 &s_encode_ip, &s_encode_op, NULL, header, kHeaderLength, timestamp);
         if (error != C2_OK) {
             mSignalledError = true;
-            // TODO: notify(error, C2_CORRUPTED, 0, 0);
+            work->workletsProcessed = 1u;
+            work->result = C2_CORRUPTED;
             return;
         }
         status = ive_api_function(mCodecCtx, &s_encode_ip, &s_encode_op);
@@ -1100,11 +1096,15 @@
         c2_status_t err = pool->fetchLinearBlock(mOutBufferSize, usage, &block);
         if (err != C2_OK) {
             ALOGE("fetch linear block err = %d", err);
+            work->workletsProcessed = 1u;
+            work->result = err;
             return;
         }
         C2WriteView wView = block->map().get();
         if (wView.error() != C2_OK) {
             ALOGE("write view map err = %d", wView.error());
+            work->workletsProcessed = 1u;
+            work->result = wView.error();
             return;
         }
 
@@ -1113,7 +1113,8 @@
         if (error != C2_OK) {
             mSignalledError = true;
             ALOGE("setEncodeArgs failed : %d", error);
-            // TODO: notify(error, C2_CORRUPTED, 0, 0);
+            work->workletsProcessed = 1u;
+            work->result = error;
             return;
         }
 
@@ -1136,7 +1137,8 @@
             ALOGE("Encode Frame failed = 0x%x\n",
                     s_encode_op.u4_error_code);
             mSignalledError = true;
-            // TODO: notify(error, C2_CORRUPTED, 0, 0);
+            work->workletsProcessed = 1u;
+            work->result = C2_CORRUPTED;
             return;
         }
     } while (IV_SUCCESS != status);
@@ -1155,7 +1157,8 @@
     /* If encoder frees up an input buffer, mark it as free */
     if (freed != NULL) {
         if (mBuffers.count(freed) == 0u) {
-            // TODO: error
+            work->workletsProcessed = 1u;
+            work->result = C2_CORRUPTED;
             return;
         }
         // Release input buffer reference
diff --git a/media/libstagefright/codecs/g711/dec/Android.bp b/media/libstagefright/codecs/g711/dec/Android.bp
index 3d97d8c..58a0a4d 100644
--- a/media/libstagefright/codecs/g711/dec/Android.bp
+++ b/media/libstagefright/codecs/g711/dec/Android.bp
@@ -1,4 +1,79 @@
 cc_library_shared {
+    name: "libstagefright_soft_c2g711alawdec",
+//    vendor_available: true,
+//    vndk: {
+//        enabled: true,
+//    },
+
+    srcs: [
+        "C2SoftG711.cpp",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-DALAW",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "libstagefright_codec2",
+        "libstagefright_codec2_vndk",
+        "libstagefright_foundation",
+        "libstagefright_simple_c2component",
+    ],
+}
+
+cc_library_shared {
+    name: "libstagefright_soft_c2g711mlawdec",
+//    vendor_available: true,
+//    vndk: {
+//        enabled: true,
+//    },
+
+    srcs: [
+        "C2SoftG711.cpp",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "libstagefright_codec2",
+        "libstagefright_codec2_vndk",
+        "libstagefright_foundation",
+        "libstagefright_simple_c2component",
+    ],
+}
+
+cc_library_shared {
     name: "libstagefright_soft_g711dec",
     vendor_available: true,
     vndk: {
diff --git a/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp b/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp
new file mode 100644
index 0000000..a26dbb9
--- /dev/null
+++ b/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2018 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 "C2SoftG711"
+#include <utils/Log.h>
+
+#include "C2SoftG711.h"
+
+#include <C2PlatformSupport.h>
+#include <SimpleC2Interface.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+
+#ifdef ALAW
+#define COMPONENT_NAME "g711a"
+#else
+#define COMPONENT_NAME "g711m"
+#endif
+
+namespace android {
+
+C2SoftG711::C2SoftG711(const char *name, c2_node_id_t id)
+    : SimpleC2Component(
+            SimpleC2Interface::Builder(name, id)
+            .inputFormat(C2FormatCompressed)
+            .outputFormat(C2FormatAudio)
+            .build()) {
+}
+
+C2SoftG711::~C2SoftG711() {
+    onRelease();
+}
+
+c2_status_t C2SoftG711::onInit() {
+    mSignalledOutputEos = false;
+    return C2_OK;
+}
+
+c2_status_t C2SoftG711::onStop() {
+    mSignalledOutputEos = false;
+    return C2_OK;
+}
+
+void C2SoftG711::onReset() {
+    (void)onStop();
+}
+
+void C2SoftG711::onRelease() {
+}
+
+c2_status_t C2SoftG711::onFlush_sm() {
+    return onStop();
+}
+
+void C2SoftG711::process(
+        const std::unique_ptr<C2Work> &work,
+        const std::shared_ptr<C2BlockPool> &pool) {
+    work->result = C2_OK;
+    work->workletsProcessed = 0u;
+    if (mSignalledOutputEos) {
+        work->result = C2_BAD_VALUE;
+        return;
+    }
+
+    const C2ConstLinearBlock &inBuffer =
+	work->input.buffers[0]->data().linearBlocks().front();
+    C2ReadView rView = inBuffer.map().get();
+    size_t inOffset = inBuffer.offset();
+    size_t inSize = inBuffer.size();
+    int outSize =  inSize * sizeof(int16_t);
+    if (inSize && rView.error()) {
+        ALOGE("read view map failed %d", rView.error());
+        work->result = C2_CORRUPTED;
+        return;
+    }
+    bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
+
+    ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
+          (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
+
+    if (inSize == 0) {
+        work->worklets.front()->output.flags = work->input.flags;
+        work->worklets.front()->output.buffers.clear();
+        work->worklets.front()->output.ordinal = work->input.ordinal;
+        work->workletsProcessed = 1u;
+        if (eos) {
+            mSignalledOutputEos = true;
+            ALOGV("signalled EOS");
+        }
+        return;
+    }
+
+    uint8_t *inputptr = const_cast<uint8_t *>(rView.data() + inOffset);
+
+    std::shared_ptr<C2LinearBlock> block;
+    C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+    c2_status_t err = pool->fetchLinearBlock(outSize, usage, &block);
+    if (err != C2_OK) {
+        ALOGE("fetchLinearBlock for Output failed with status %d", err);
+        work->result = C2_NO_MEMORY;
+        return;
+    }
+    C2WriteView wView = block->map().get();
+    if (wView.error()) {
+        ALOGE("write view map failed %d", wView.error());
+        work->result = C2_CORRUPTED;
+        return;
+    }
+    int16_t *outputptr = reinterpret_cast<int16_t *>(wView.data());
+
+#ifdef ALAW
+    DecodeALaw(outputptr, inputptr, inSize);
+#else
+    DecodeMLaw(outputptr, inputptr, inSize);
+#endif
+
+    work->worklets.front()->output.flags = work->input.flags;
+    work->worklets.front()->output.buffers.clear();
+    work->worklets.front()->output.buffers.push_back(createLinearBuffer(block));
+    work->worklets.front()->output.ordinal = work->input.ordinal;
+    work->workletsProcessed = 1u;
+
+    if (eos) {
+        mSignalledOutputEos = true;
+        ALOGV("signalled EOS");
+    }
+}
+
+c2_status_t C2SoftG711::drain(
+        uint32_t drainMode,
+        const std::shared_ptr<C2BlockPool> &pool) {
+    (void) pool;
+    if (drainMode == NO_DRAIN) {
+        ALOGW("drain with NO_DRAIN: no-op");
+        return C2_OK;
+    }
+    if (drainMode == DRAIN_CHAIN) {
+        ALOGW("DRAIN_CHAIN not supported");
+        return C2_OMITTED;
+    }
+
+    return C2_OK;
+}
+
+#ifdef ALAW
+void C2SoftG711::DecodeALaw(
+        int16_t *out, const uint8_t *in, size_t inSize) {
+    while (inSize > 0) {
+        inSize--;
+        int32_t x = *in++;
+
+        int32_t ix = x ^ 0x55;
+        ix &= 0x7f;
+
+        int32_t iexp = ix >> 4;
+        int32_t mant = ix & 0x0f;
+
+        if (iexp > 0) {
+            mant += 16;
+        }
+
+        mant = (mant << 4) + 8;
+
+        if (iexp > 1) {
+            mant = mant << (iexp - 1);
+        }
+
+        *out++ = (x > 127) ? mant : -mant;
+    }
+}
+#else
+void C2SoftG711::DecodeMLaw(
+        int16_t *out, const uint8_t *in, size_t inSize) {
+    while (inSize > 0) {
+        inSize--;
+        int32_t x = *in++;
+
+        int32_t mantissa = ~x;
+        int32_t exponent = (mantissa >> 4) & 7;
+        int32_t segment = exponent + 1;
+        mantissa &= 0x0f;
+
+        int32_t step = 4 << segment;
+
+        int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33;
+
+        *out++ = (x < 0x80) ? -abs : abs;
+    }
+}
+#endif
+
+class C2SoftG711DecFactory : public C2ComponentFactory {
+public:
+    virtual c2_status_t createComponent(
+            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
+            std::function<void(::android::C2Component*)> deleter) override {
+        *component = std::shared_ptr<C2Component>(new C2SoftG711(COMPONENT_NAME, id), deleter);
+        return C2_OK;
+    }
+
+    virtual c2_status_t createInterface(
+            c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
+            std::function<void(::android::C2ComponentInterface*)> deleter) override {
+        *interface =
+                SimpleC2Interface::Builder(COMPONENT_NAME, id, deleter)
+                .inputFormat(C2FormatCompressed)
+                .outputFormat(C2FormatAudio)
+                .build();
+        return C2_OK;
+    }
+
+    virtual ~C2SoftG711DecFactory() override = default;
+};
+
+}  // namespace android
+
+extern "C" ::android::C2ComponentFactory* CreateCodec2Factory() {
+    ALOGV("in %s", __func__);
+    return new ::android::C2SoftG711DecFactory();
+}
+
+extern "C" void DestroyCodec2Factory(::android::C2ComponentFactory* factory) {
+    ALOGV("in %s", __func__);
+    delete factory;
+}
diff --git a/media/libstagefright/codecs/g711/dec/C2SoftG711.h b/media/libstagefright/codecs/g711/dec/C2SoftG711.h
new file mode 100644
index 0000000..eed38c9
--- /dev/null
+++ b/media/libstagefright/codecs/g711/dec/C2SoftG711.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 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 C2_SOFT_G711_H_
+#define C2_SOFT_G711_H_
+
+#include <SimpleC2Component.h>
+
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+struct C2SoftG711 : public SimpleC2Component {
+    C2SoftG711(const char *name, c2_node_id_t id);
+    virtual ~C2SoftG711();
+
+    // From SimpleC2Component
+    c2_status_t onInit() override;
+    c2_status_t onStop() override;
+    void onReset() override;
+    void onRelease() override;
+    c2_status_t onFlush_sm() override;
+    void process(
+            const std::unique_ptr<C2Work> &work,
+            const std::shared_ptr<C2BlockPool> &pool) override;
+    c2_status_t drain(
+            uint32_t drainMode,
+            const std::shared_ptr<C2BlockPool> &pool) override;
+private:
+    bool mSignalledOutputEos;
+
+#ifdef ALAW
+    void DecodeALaw(int16_t *out, const uint8_t *in, size_t inSize);
+#else
+    void DecodeMLaw(int16_t *out, const uint8_t *in, size_t inSize);
+#endif
+
+    DISALLOW_EVIL_CONSTRUCTORS(C2SoftG711);
+};
+
+}  // namespace android
+
+#endif  // C2_SOFT_G711_H_
diff --git a/media/libstagefright/include/AVIExtractor.h b/media/libstagefright/include/AVIExtractor.h
deleted file mode 100644
index 1223c80..0000000
--- a/media/libstagefright/include/AVIExtractor.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2011 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 AVI_EXTRACTOR_H_
-
-#define AVI_EXTRACTOR_H_
-
-#include <media/MediaExtractor.h>
-#include <media/MediaSource.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-struct AVIExtractor : public MediaExtractor {
-    AVIExtractor(const sp<DataSource> &dataSource);
-
-    virtual size_t countTracks();
-
-    virtual sp<MediaSource> getTrack(size_t index);
-
-    virtual sp<MetaData> getTrackMetaData(
-            size_t index, uint32_t flags);
-
-    virtual sp<MetaData> getMetaData();
-    virtual const char * name() { return "AVIExtractor"; }
-
-protected:
-    virtual ~AVIExtractor();
-
-private:
-    struct AVISource;
-    struct MP3Splitter;
-
-    struct SampleInfo {
-        uint32_t mOffset;
-        bool mIsKey;
-    };
-
-    struct Track {
-        sp<MetaData> mMeta;
-        Vector<SampleInfo> mSamples;
-        uint32_t mRate;
-        uint32_t mScale;
-
-        // If bytes per sample == 0, each chunk represents a single sample,
-        // otherwise each chunk should me a multiple of bytes-per-sample in
-        // size.
-        uint32_t mBytesPerSample;
-
-        enum Kind {
-            AUDIO,
-            VIDEO,
-            OTHER
-
-        } mKind;
-
-        size_t mNumSyncSamples;
-        size_t mThumbnailSampleSize;
-        ssize_t mThumbnailSampleIndex;
-        size_t mMaxSampleSize;
-
-        // If mBytesPerSample > 0:
-        double mAvgChunkSize;
-        size_t mFirstChunkSize;
-    };
-
-    sp<DataSource> mDataSource;
-    status_t mInitCheck;
-    Vector<Track> mTracks;
-
-    off64_t mMovieOffset;
-    bool mFoundIndex;
-    bool mOffsetsAreAbsolute;
-
-    ssize_t parseChunk(off64_t offset, off64_t size, int depth = 0);
-    status_t parseStreamHeader(off64_t offset, size_t size);
-    status_t parseStreamFormat(off64_t offset, size_t size);
-    status_t parseIndex(off64_t offset, size_t size);
-
-    status_t parseHeaders();
-
-    status_t getSampleInfo(
-            size_t trackIndex, size_t sampleIndex,
-            off64_t *offset, size_t *size, bool *isKey,
-            int64_t *sampleTimeUs);
-
-    status_t getSampleTime(
-            size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs);
-
-    status_t getSampleIndexAtTime(
-            size_t trackIndex,
-            int64_t timeUs, MediaSource::ReadOptions::SeekMode mode,
-            size_t *sampleIndex) const;
-
-    status_t addMPEG4CodecSpecificData(size_t trackIndex);
-    status_t addH264CodecSpecificData(size_t trackIndex);
-
-    static bool IsCorrectChunkType(
-        ssize_t trackIndex, Track::Kind kind, uint32_t chunkType);
-
-    DISALLOW_EVIL_CONSTRUCTORS(AVIExtractor);
-};
-
-class String8;
-struct AMessage;
-
-bool SniffAVI(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
-        sp<AMessage> *);
-
-}  // namespace android
-
-#endif  // AVI_EXTRACTOR_H_
diff --git a/media/libstagefright/include/Codec2Buffer.h b/media/libstagefright/include/Codec2Buffer.h
index 0272cea..6d85e83 100644
--- a/media/libstagefright/include/Codec2Buffer.h
+++ b/media/libstagefright/include/Codec2Buffer.h
@@ -24,30 +24,48 @@
 
 namespace android {
 
-class C2Buffer;
-
 /**
  * MediaCodecBuffer implementation wraps around C2LinearBlock.
  */
-class Codec2Buffer : public MediaCodecBuffer {
+class LinearBlockBuffer : public MediaCodecBuffer {
 public:
-    static sp<Codec2Buffer> allocate(
+    static sp<LinearBlockBuffer> allocate(
             const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block);
 
-    virtual ~Codec2Buffer() = default;
+    virtual ~LinearBlockBuffer() = default;
 
     C2ConstLinearBlock share();
 
 private:
-    Codec2Buffer(
+    LinearBlockBuffer(
             const sp<AMessage> &format,
-            const sp<ABuffer> &buffer,
+            C2WriteView &&writeView,
             const std::shared_ptr<C2LinearBlock> &block);
-    Codec2Buffer() = delete;
+    LinearBlockBuffer() = delete;
 
+    C2WriteView mWriteView;
     std::shared_ptr<C2LinearBlock> mBlock;
 };
 
+/**
+ * MediaCodecBuffer implementation wraps around C2ConstLinearBlock.
+ */
+class ConstLinearBlockBuffer : public MediaCodecBuffer {
+public:
+    static sp<ConstLinearBlockBuffer> allocate(
+            const sp<AMessage> &format, const C2ConstLinearBlock &block);
+
+    virtual ~ConstLinearBlockBuffer() = default;
+
+private:
+    ConstLinearBlockBuffer(
+            const sp<AMessage> &format,
+            C2ReadView &&readView);
+    ConstLinearBlockBuffer() = delete;
+
+    C2ReadView mReadView;
+};
+
 }  // namespace android
 
 #endif  // CODEC2_BUFFER_H_
diff --git a/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl b/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
index aabbc69..eaf404c 100644
--- a/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
+++ b/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
@@ -31,6 +31,7 @@
     void onPlaybackStateChanged(in Bundle state);
     void onPlaylistChanged(in List<Bundle> playlist);
     void onPlaylistParamsChanged(in Bundle params);
+    void onPlaybackInfoChanged(in Bundle playbackInfo);
 
     /**
      * Called only when the controller is created with service's token.
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index 41dfd00..6ee79a0 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -74,6 +74,8 @@
     private List<MediaItem2> mPlaylist;
     @GuardedBy("mLock")
     private PlaylistParams mPlaylistParams;
+    @GuardedBy("mLock")
+    private PlaybackInfo mPlaybackInfo;
 
     // Assignment should be used with the lock hold, but should be used without a lock to prevent
     // potential deadlock.
@@ -293,12 +295,6 @@
     }
 
     @Override
-    public PlaybackInfo getPlaybackInfo_impl() {
-        // TODO(jaewan): Implement
-        return null;
-    }
-
-    @Override
     public void prepareFromUri_impl(Uri uri, Bundle extras) {
         // TODO(jaewan): Implement
     }
@@ -413,6 +409,13 @@
     }
 
     @Override
+    public PlaybackInfo getPlaybackInfo_impl() {
+        synchronized (mLock) {
+            return mPlaybackInfo;
+        }
+    }
+
+    @Override
     public void setPlaylistParams_impl(PlaylistParams params) {
         if (params == null) {
             throw new IllegalArgumentException("PlaylistParams should not be null!");
@@ -449,6 +452,18 @@
         });
     }
 
+    private void pushPlaybackInfoChanges(final PlaybackInfo info) {
+        synchronized (mLock) {
+            mPlaybackInfo = info;
+        }
+        mCallbackExecutor.execute(() -> {
+            if (!mInstance.isConnected()) {
+                return;
+            }
+            mCallback.onPlaybackInfoChanged(info);
+        });
+    }
+
     private void pushPlaylistChanges(final List<Bundle> list) {
         final List<MediaItem2> playlist = new ArrayList<>();
         for (int i = 0; i < list.size(); i++) {
@@ -603,6 +618,19 @@
         }
 
         @Override
+        public void onPlaybackInfoChanged(Bundle playbackInfo) throws RuntimeException {
+            final MediaController2Impl controller;
+            try {
+                controller = getController();
+            } catch (IllegalStateException e) {
+                Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+                return;
+            }
+            controller.pushPlaybackInfoChanges(
+                    PlaybackInfoImpl.fromBundle(controller.getContext(), playbackInfo));
+        }
+
+        @Override
         public void onConnectionChanged(IMediaSession2 sessionBinder, Bundle commandGroup)
                 throws RuntimeException {
             final MediaController2Impl controller;
diff --git a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
index 54c8d41..77bd334 100644
--- a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
@@ -28,7 +28,7 @@
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSessionService2;
 import android.media.SessionToken2;
-import android.media.VolumeProvider;
+import android.media.VolumeProvider2;
 import android.media.update.MediaLibraryService2Provider;
 import android.os.Bundle;
 
@@ -68,7 +68,7 @@
         private final MediaLibrarySessionCallback mCallback;
 
         public MediaLibrarySessionImpl(Context context,
-                MediaPlayerInterface player, String id, VolumeProvider volumeProvider,
+                MediaPlayerInterface player, String id, VolumeProvider2 volumeProvider,
                 int ratingType, PendingIntent sessionActivity, Executor callbackExecutor,
                 MediaLibrarySessionCallback callback) {
             super(context, player, id, volumeProvider, ratingType, sessionActivity,
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
index f820cdc..cde98d2 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
@@ -21,15 +21,19 @@
 import static android.media.SessionToken2.TYPE_SESSION;
 import static android.media.SessionToken2.TYPE_SESSION_SERVICE;
 
+import android.Manifest.permission;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.Manifest.permission;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.MediaController2;
+import android.media.MediaController2.PlaybackInfo;
 import android.media.MediaItem2;
 import android.media.MediaLibraryService2;
 import android.media.MediaMetadata2;
@@ -48,14 +52,13 @@
 import android.media.MediaSessionService2;
 import android.media.PlaybackState2;
 import android.media.SessionToken2;
-import android.media.VolumeProvider;
+import android.media.VolumeProvider2;
 import android.media.session.MediaSessionManager;
 import android.media.update.MediaSession2Provider;
-import android.media.update.MediaSession2Provider.CommandButtonProvider;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.Parcelable;
 import android.os.Process;
-import android.os.IBinder;
 import android.os.ResultReceiver;
 import android.support.annotation.GuardedBy;
 import android.text.TextUtils;
@@ -80,11 +83,16 @@
     private final SessionCallback mCallback;
     private final MediaSession2Stub mSessionStub;
     private final SessionToken2 mSessionToken;
+    private final AudioManager mAudioManager;
     private final List<PlaybackListenerHolder> mListeners = new ArrayList<>();
 
     @GuardedBy("mLock")
     private MediaPlayerInterface mPlayer;
     @GuardedBy("mLock")
+    private VolumeProvider2 mVolumeProvider;
+    @GuardedBy("mLock")
+    private PlaybackInfo mPlaybackInfo;
+    @GuardedBy("mLock")
     private MyPlaybackListener mListener;
     @GuardedBy("mLock")
     private PlaylistParams mPlaylistParams;
@@ -103,8 +111,8 @@
      * @param ratingType
      * @param sessionActivity
      */
-    public MediaSession2Impl(Context context, MediaPlayerInterface player,
-            String id, VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
+    public MediaSession2Impl(Context context, MediaPlayerInterface player, String id,
+            VolumeProvider2 volumeProvider, int ratingType, PendingIntent sessionActivity,
             Executor callbackExecutor, SessionCallback callback) {
         // TODO(jaewan): Keep other params.
         mInstance = createInstance();
@@ -116,6 +124,7 @@
         mCallback = callback;
         mCallbackExecutor = callbackExecutor;
         mSessionStub = new MediaSession2Stub(this);
+        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
 
         // Infer type from the id and package name.
         String libraryService = getServiceName(context, MediaLibraryService2.SERVICE_INTERFACE, id);
@@ -135,6 +144,8 @@
         }
 
         setPlayerLocked(player);
+        mVolumeProvider = volumeProvider;
+        mPlaybackInfo = createPlaybackInfo(volumeProvider, player.getAudioAttributes());
 
         // Ask server for the sanity check, and starts
         // Sanity check for making session ID unique 'per package' cannot be done in here.
@@ -178,12 +189,8 @@
         return serviceName;
     }
 
-    // TODO(jaewan): Add explicit release() and do not remove session object with the
-    //               setPlayer(null). Token can be available when player is null, and
-    //               controller can also attach to session.
     @Override
-    public void setPlayer_impl(MediaPlayerInterface player, VolumeProvider volumeProvider)
-            throws IllegalArgumentException {
+    public void setPlayer_impl(MediaPlayerInterface player) {
         ensureCallingThread();
         if (player == null) {
             throw new IllegalArgumentException("player shouldn't be null");
@@ -191,9 +198,37 @@
         if (player == mPlayer) {
             return;
         }
+        PlaybackInfo info =
+                createPlaybackInfo(null /* VolumeProvider */, player.getAudioAttributes());
         synchronized (mLock) {
             setPlayerLocked(player);
+            mVolumeProvider = null;
+            mPlaybackInfo = info;
         }
+        mSessionStub.notifyPlaybackInfoChanged(info);
+    }
+
+    @Override
+    public void setPlayer_impl(MediaPlayerInterface player, VolumeProvider2 volumeProvider)
+            throws IllegalArgumentException {
+        ensureCallingThread();
+        if (player == null) {
+            throw new IllegalArgumentException("player shouldn't be null");
+        }
+        if (volumeProvider == null) {
+            throw new IllegalArgumentException("volumeProvider shouldn't be null");
+        }
+        if (player == mPlayer) {
+            return;
+        }
+
+        PlaybackInfo info = createPlaybackInfo(volumeProvider, player.getAudioAttributes());
+        synchronized (mLock) {
+            setPlayerLocked(player);
+            mVolumeProvider = volumeProvider;
+            mPlaybackInfo = info;
+        }
+        mSessionStub.notifyPlaybackInfoChanged(info);
     }
 
     private void setPlayerLocked(MediaPlayerInterface player) {
@@ -206,6 +241,29 @@
         player.addPlaybackListener(mCallbackExecutor, mListener);
     }
 
+    private PlaybackInfo createPlaybackInfo(VolumeProvider2 volumeProvider, AudioAttributes attrs) {
+        PlaybackInfo info;
+        if (volumeProvider == null) {
+            int stream = attrs == null ? AudioManager.STREAM_MUSIC : attrs.getVolumeControlStream();
+            info = PlaybackInfoImpl.createPlaybackInfo(
+                    mContext,
+                    PlaybackInfo.PLAYBACK_TYPE_LOCAL,
+                    attrs,
+                    VolumeProvider2.VOLUME_CONTROL_ABSOLUTE,
+                    mAudioManager.getStreamMaxVolume(stream),
+                    mAudioManager.getStreamVolume(stream));
+        } else {
+            info = PlaybackInfoImpl.createPlaybackInfo(
+                    mContext,
+                    PlaybackInfo.PLAYBACK_TYPE_REMOTE /* ControlType */,
+                    attrs,
+                    volumeProvider.getControlType(),
+                    volumeProvider.getMaxVolume(),
+                    volumeProvider.getCurrentVolume());
+        }
+        return info;
+    }
+
     @Override
     public void close_impl() {
         // Stop system service from listening this session first.
@@ -320,10 +378,6 @@
     //////////////////////////////////////////////////////////////////////////////////////
     // TODO(jaewan): Implement follows
     //////////////////////////////////////////////////////////////////////////////////////
-    @Override
-    public void setPlayer_impl(MediaPlayerInterface player) {
-        // TODO(jaewan): Implement
-    }
 
     @Override
     public void setAllowedCommands_impl(ControllerInfo controller, CommandGroup commands) {
@@ -1032,7 +1086,7 @@
         String mId;
         Executor mCallbackExecutor;
         C mCallback;
-        VolumeProvider mVolumeProvider;
+        VolumeProvider2 mVolumeProvider;
         int mRatingType;
         PendingIntent mSessionActivity;
 
@@ -1058,7 +1112,7 @@
             mId = "";
         }
 
-        public void setVolumeProvider_impl(VolumeProvider volumeProvider) {
+        public void setVolumeProvider_impl(VolumeProvider2 volumeProvider) {
             mVolumeProvider = volumeProvider;
         }
 
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index 1f71187..5d3a06e 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -17,6 +17,7 @@
 package com.android.media;
 
 import android.content.Context;
+import android.media.MediaController2;
 import android.media.MediaItem2;
 import android.media.MediaLibraryService2.LibraryRoot;
 import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
@@ -130,6 +131,7 @@
                 // Controller may be died prematurely.
             }
             if (accept) {
+                // TODO(jaewan): We need to send current PlaybackInfo.
                 // If connection is accepted, notify the current state to the controller.
                 // It's needed because we cannot call synchronous calls between session/controller.
                 // Note: We're doing this after the onConnectionChanged(), but there's no guarantee
@@ -390,6 +392,21 @@
         }
     }
 
+    public void notifyPlaybackInfoChanged(MediaController2.PlaybackInfo playbackInfo) {
+        final List<ControllerInfo> list = getControllers();
+        for (int i = 0; i < list.size(); i++) {
+            IMediaSession2Callback callbackBinder =
+                    ControllerInfoImpl.from(list.get(i)).getControllerBinder();
+            try {
+                callbackBinder.onPlaybackInfoChanged(
+                        ((PlaybackInfoImpl) playbackInfo.getProvider()).toBundle());
+            } catch (RemoteException e) {
+                Log.w(TAG, "Controller is gone", e);
+                // TODO(jaewan): What to do when the controller is gone?
+            }
+        }
+    }
+
     public void sendCustomCommand(ControllerInfo controller, Command command, Bundle args,
             ResultReceiver receiver) {
         if (receiver != null && controller == null) {
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
index 661e252..46812e7 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
@@ -64,7 +64,7 @@
 import android.media.update.SessionToken2Provider;
 import android.media.update.StaticProvider;
 import android.media.update.VideoView2Provider;
-import android.media.update.ViewProvider;
+import android.media.update.ViewGroupProvider;
 import android.media.update.VolumeProvider2Provider;
 import android.os.Bundle;
 import android.os.IInterface;
@@ -205,16 +205,17 @@
     }
 
     @Override
-    public MediaControlView2Provider createMediaControlView2(
-            MediaControlView2 instance, ViewProvider superProvider) {
-        return new MediaControlView2Impl(instance, superProvider);
+    public MediaControlView2Provider createMediaControlView2(MediaControlView2 instance,
+            ViewGroupProvider superProvider, ViewGroupProvider privateProvider,
+            @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        return new MediaControlView2Impl(instance, superProvider, privateProvider);
     }
 
     @Override
     public VideoView2Provider createVideoView2(
-            VideoView2 instance, ViewProvider superProvider,
+            VideoView2 instance, ViewGroupProvider superProvider, ViewGroupProvider privateProvider,
             @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        return new VideoView2Impl(instance, superProvider, attrs, defStyleAttr, defStyleRes);
+        return new VideoView2Impl(instance, superProvider, privateProvider);
     }
 
     @Override
diff --git a/packages/MediaComponents/src/com/android/widget/BaseLayout.java b/packages/MediaComponents/src/com/android/widget/BaseLayout.java
new file mode 100644
index 0000000..fb6471d
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/widget/BaseLayout.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.widget;
+
+import android.graphics.drawable.Drawable;
+import android.media.update.ViewGroupProvider;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.ViewGroup.MarginLayoutParams;
+
+import java.util.ArrayList;
+
+public class BaseLayout extends ViewGroupImpl {
+    private final ViewGroup mInstance;
+    private final ViewGroupProvider mSuperProvider;
+    private final ViewGroupProvider mPrivateProvider;
+
+    private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
+
+    public BaseLayout(ViewGroup instance,
+            ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
+        super(instance, superProvider, privateProvider);
+        mInstance = instance;
+        mSuperProvider = superProvider;
+        mPrivateProvider = privateProvider;
+    }
+
+    @Override
+    public boolean checkLayoutParams_impl(LayoutParams p) {
+        return p instanceof MarginLayoutParams;
+    }
+
+    @Override
+    public LayoutParams generateDefaultLayoutParams_impl() {
+        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams_impl(AttributeSet attrs) {
+        return new MarginLayoutParams(mInstance.getContext(), attrs);
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams_impl(LayoutParams lp) {
+        if (lp instanceof MarginLayoutParams) {
+            return lp;
+        }
+        return new MarginLayoutParams(lp);
+    }
+
+    @Override
+    public void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec) {
+        int count = mInstance.getChildCount();
+
+        final boolean measureMatchParentChildren =
+                View.MeasureSpec.getMode(widthMeasureSpec) != View.MeasureSpec.EXACTLY ||
+                        View.MeasureSpec.getMode(heightMeasureSpec) != View.MeasureSpec.EXACTLY;
+        mMatchParentChildren.clear();
+
+        int maxHeight = 0;
+        int maxWidth = 0;
+        int childState = 0;
+
+        for (int i = 0; i < count; i++) {
+            final View child = mInstance.getChildAt(i);
+            if (child.getVisibility() != View.GONE) {
+                mPrivateProvider.measureChildWithMargins_impl(
+                        child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+                final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+                maxWidth = Math.max(maxWidth,
+                        child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
+                maxHeight = Math.max(maxHeight,
+                        child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
+                childState = childState | child.getMeasuredState();
+                if (measureMatchParentChildren) {
+                    if (lp.width == LayoutParams.MATCH_PARENT ||
+                            lp.height == LayoutParams.MATCH_PARENT) {
+                        mMatchParentChildren.add(child);
+                    }
+                }
+            }
+        }
+
+        // Account for padding too
+        maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();
+        maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();
+
+        // Check against our minimum height and width
+        maxHeight = Math.max(maxHeight, mPrivateProvider.getSuggestedMinimumHeight_impl());
+        maxWidth = Math.max(maxWidth, mPrivateProvider.getSuggestedMinimumWidth_impl());
+
+        // Check against our foreground's minimum height and width
+        final Drawable drawable = mInstance.getForeground();
+        if (drawable != null) {
+            maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
+            maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
+        }
+
+        mPrivateProvider.setMeasuredDimension_impl(
+                mInstance.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+                mInstance.resolveSizeAndState(maxHeight, heightMeasureSpec,
+                        childState << View.MEASURED_HEIGHT_STATE_SHIFT));
+
+        count = mMatchParentChildren.size();
+        if (count > 1) {
+            for (int i = 0; i < count; i++) {
+                final View child = mMatchParentChildren.get(i);
+                final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+
+                final int childWidthMeasureSpec;
+                if (lp.width == LayoutParams.MATCH_PARENT) {
+                    final int width = Math.max(0, mInstance.getMeasuredWidth()
+                            - getPaddingLeftWithForeground() - getPaddingRightWithForeground()
+                            - lp.leftMargin - lp.rightMargin);
+                    childWidthMeasureSpec = View.MeasureSpec.makeMeasureSpec(
+                            width, View.MeasureSpec.EXACTLY);
+                } else {
+                    childWidthMeasureSpec = mInstance.getChildMeasureSpec(widthMeasureSpec,
+                            getPaddingLeftWithForeground() + getPaddingRightWithForeground() +
+                                    lp.leftMargin + lp.rightMargin,
+                            lp.width);
+                }
+
+                final int childHeightMeasureSpec;
+                if (lp.height == LayoutParams.MATCH_PARENT) {
+                    final int height = Math.max(0, mInstance.getMeasuredHeight()
+                            - getPaddingTopWithForeground() - getPaddingBottomWithForeground()
+                            - lp.topMargin - lp.bottomMargin);
+                    childHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(
+                            height, View.MeasureSpec.EXACTLY);
+                } else {
+                    childHeightMeasureSpec = mInstance.getChildMeasureSpec(heightMeasureSpec,
+                            getPaddingTopWithForeground() + getPaddingBottomWithForeground() +
+                                    lp.topMargin + lp.bottomMargin,
+                            lp.height);
+                }
+
+                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+            }
+        }
+    }
+
+    @Override
+    public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+        final int count = mInstance.getChildCount();
+
+        final int parentLeft = getPaddingLeftWithForeground();
+        final int parentRight = right - left - getPaddingRightWithForeground();
+
+        final int parentTop = getPaddingTopWithForeground();
+        final int parentBottom = bottom - top - getPaddingBottomWithForeground();
+
+        for (int i = 0; i < count; i++) {
+            final View child = mInstance.getChildAt(i);
+            if (child.getVisibility() != View.GONE) {
+                final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+
+                final int width = child.getMeasuredWidth();
+                final int height = child.getMeasuredHeight();
+
+                int childLeft;
+                int childTop;
+
+                childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
+                        lp.leftMargin - lp.rightMargin;
+
+                childTop = parentTop + (parentBottom - parentTop - height) / 2 +
+                        lp.topMargin - lp.bottomMargin;
+
+                child.layout(childLeft, childTop, childLeft + width, childTop + height);
+            }
+        }
+    }
+
+    @Override
+    public boolean shouldDelayChildPressedState_impl() {
+        return false;
+    }
+
+    private int getPaddingLeftWithForeground() {
+        return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingLeft(), 0) :
+                mInstance.getPaddingLeft() + 0;
+    }
+
+    private int getPaddingRightWithForeground() {
+        return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingRight(), 0) :
+                mInstance.getPaddingRight() + 0;
+    }
+
+    private int getPaddingTopWithForeground() {
+        return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingTop(), 0) :
+                mInstance.getPaddingTop() + 0;
+    }
+
+    private int getPaddingBottomWithForeground() {
+        return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingBottom(), 0) :
+                mInstance.getPaddingBottom() + 0;
+    }
+}
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index 138232e..1cdaaee 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -21,8 +21,10 @@
 import android.media.session.MediaController;
 import android.media.session.PlaybackState;
 import android.media.update.MediaControlView2Provider;
-import android.media.update.ViewProvider;
+import android.media.update.ViewGroupProvider;
 import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
@@ -46,11 +48,10 @@
 import java.util.List;
 import java.util.Locale;
 
-public class MediaControlView2Impl implements MediaControlView2Provider {
+public class MediaControlView2Impl extends BaseLayout implements MediaControlView2Provider {
     private static final String TAG = "MediaControlView2";
 
     private final MediaControlView2 mInstance;
-    private final ViewProvider mSuperProvider;
 
     static final String ARGUMENT_KEY_FULLSCREEN = "fullScreen";
 
@@ -63,7 +64,7 @@
     private static final int REWIND_TIME_MS = 10000;
     private static final int FORWARD_TIME_MS = 30000;
 
-    private final AccessibilityManager mAccessibilityManager;
+    private AccessibilityManager mAccessibilityManager;
 
     private MediaController mController;
     private MediaController.TransportControls mControls;
@@ -113,10 +114,14 @@
     private MediaRouteButton mRouteButton;
     private MediaRouteSelector mRouteSelector;
 
-    public MediaControlView2Impl(
-            MediaControlView2 instance, ViewProvider superProvider) {
+    public MediaControlView2Impl(MediaControlView2 instance,
+            ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
+        super(instance, superProvider, privateProvider);
         mInstance = instance;
-        mSuperProvider = superProvider;
+    }
+
+    @Override
+    public void initialize(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         mAccessibilityManager = AccessibilityManager.getInstance(mInstance.getContext());
 
         // Inflate MediaControlView2 from XML
@@ -144,11 +149,6 @@
     }
 
     @Override
-    public boolean isShowing_impl() {
-        return (mInstance.getVisibility() == View.VISIBLE) ? true : false;
-    }
-
-    @Override
     public void setButtonVisibility_impl(int button, int visibility) {
         switch (button) {
             case MediaControlView2.BUTTON_PLAY_PAUSE:
@@ -233,39 +233,6 @@
     }
 
     @Override
-    public void onVisibilityAggregated_impl(boolean invisible) {
-        int visibility = mInstance.getVisibility();
-        if (mCurrentVisibility != visibility) {
-            mInstance.setVisibility(visibility);
-            mCurrentVisibility = visibility;
-
-            if (visibility == View.VISIBLE) {
-                setProgress();
-                disableUnsupportedButtons();
-                // cause the progress bar to be updated even if mShowing
-                // was already true.  This happens, for example, if we're
-                // paused with the progress bar showing the user hits play.
-                mInstance.post(mShowProgress);
-                resetFadeOutRunnable();
-            } else if (visibility == View.GONE) {
-                mInstance.removeCallbacks(mShowProgress);
-                // Remove existing call to mFadeOut to avoid from being called later.
-                mInstance.removeCallbacks(mFadeOut);
-            }
-        }
-    }
-
-    @Override
-    public void onAttachedToWindow_impl() {
-        mSuperProvider.onAttachedToWindow_impl();
-    }
-
-    @Override
-    public void onDetachedFromWindow_impl() {
-        mSuperProvider.onDetachedFromWindow_impl();
-    }
-
-    @Override
     public CharSequence getAccessibilityClassName_impl() {
         return MediaControlView2.class.getName();
     }
@@ -283,12 +250,9 @@
     }
 
     @Override
-    public void onFinishInflate_impl() {
-        mSuperProvider.onFinishInflate_impl();
-    }
-
-    @Override
     public void setEnabled_impl(boolean enabled) {
+        super.setEnabled_impl(enabled);
+
         if (mPlayPauseButton != null) {
             mPlayPauseButton.setEnabled(enabled);
         }
@@ -308,7 +272,31 @@
             mProgress.setEnabled(enabled);
         }
         disableUnsupportedButtons();
-        mSuperProvider.setEnabled_impl(enabled);
+    }
+
+    @Override
+    public void onVisibilityAggregated_impl(boolean invisible) {
+        super.onVisibilityAggregated_impl(invisible);
+
+        int visibility = mInstance.getVisibility();
+        if (mCurrentVisibility != visibility) {
+            mInstance.setVisibility(visibility);
+            mCurrentVisibility = visibility;
+
+            if (visibility == View.VISIBLE) {
+                setProgress();
+                disableUnsupportedButtons();
+                // cause the progress bar to be updated even if mShowing
+                // was already true.  This happens, for example, if we're
+                // paused with the progress bar showing the user hits play.
+                mInstance.post(mShowProgress);
+                resetFadeOutRunnable();
+            } else if (visibility == View.GONE) {
+                mInstance.removeCallbacks(mShowProgress);
+                // Remove existing call to mFadeOut to avoid from being called later.
+                mInstance.removeCallbacks(mFadeOut);
+            }
+        }
     }
 
     public void setRouteSelector(MediaRouteSelector selector) {
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 7218150..9f207b1 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -39,17 +39,16 @@
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
 import android.media.update.VideoView2Provider;
-import android.media.update.ViewProvider;
+import android.media.update.ViewGroupProvider;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.ResultReceiver;
 import android.support.annotation.Nullable;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
-import android.widget.FrameLayout.LayoutParams;
+import android.view.ViewGroup.LayoutParams;
 import android.widget.MediaControlView2;
 import android.widget.VideoView2;
 
@@ -67,12 +66,12 @@
 import java.util.Map;
 import java.util.concurrent.Executor;
 
-public class VideoView2Impl implements VideoView2Provider, VideoViewInterface.SurfaceListener {
+public class VideoView2Impl extends BaseLayout
+        implements VideoView2Provider, VideoViewInterface.SurfaceListener {
     private static final String TAG = "VideoView2";
     private static final boolean DEBUG = true; // STOPSHIP: Log.isLoggable(TAG, Log.DEBUG);
 
     private final VideoView2 mInstance;
-    private final ViewProvider mSuperProvider;
 
     private static final int STATE_ERROR = -1;
     private static final int STATE_IDLE = 0;
@@ -82,7 +81,7 @@
     private static final int STATE_PAUSED = 4;
     private static final int STATE_PLAYBACK_COMPLETED = 5;
 
-    private final AudioManager mAudioManager;
+    private AudioManager mAudioManager;
     private AudioAttributes mAudioAttributes;
     private int mAudioFocusType = AudioManager.AUDIOFOCUS_GAIN; // legacy focus gain
 
@@ -127,11 +126,14 @@
     // Refer: https://docs.google.com/document/d/1nzAfns6i2hJ3RkaUre3QMT6wsDedJ5ONLiA_OOBFFX8/edit
     private float mFallbackSpeed;  // keep the original speed before 'pause' is called.
 
-    public VideoView2Impl(VideoView2 instance, ViewProvider superProvider,
-            @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public VideoView2Impl(VideoView2 instance,
+            ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
+        super(instance, superProvider, privateProvider);
         mInstance = instance;
-        mSuperProvider = superProvider;
+    }
 
+    @Override
+    public void initialize(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         mVideoWidth = 0;
         mVideoHeight = 0;
         mSpeed = 1.0f;
@@ -150,7 +152,6 @@
         mSurfaceView = new VideoSurfaceView(mInstance.getContext());
         LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,
                 LayoutParams.MATCH_PARENT);
-        params.gravity = Gravity.CENTER;
         mTextureView.setLayoutParams(params);
         mSurfaceView.setLayoutParams(params);
         mTextureView.setSurfaceListener(this);
@@ -397,7 +398,7 @@
 
     @Override
     public void onAttachedToWindow_impl() {
-        mSuperProvider.onAttachedToWindow_impl();
+        super.onAttachedToWindow_impl();
 
         // Create MediaSession
         mMediaSession = new MediaSession(mInstance.getContext(), "VideoView2MediaSession");
@@ -412,8 +413,8 @@
 
     @Override
     public void onDetachedFromWindow_impl() {
-        Log.e(TAG, ".... Debugging. onDetachedFromWindow_impl()");
-        mSuperProvider.onDetachedFromWindow_impl();
+        super.onDetachedFromWindow_impl();
+
         mMediaSession.release();
         mMediaSession = null;
         mMediaController = null;
@@ -434,7 +435,8 @@
                 && isInPlaybackState() && mMediaControlView != null) {
             toggleMediaControlViewVisibility();
         }
-        return mSuperProvider.onTouchEvent_impl(ev);
+
+        return super.onTouchEvent_impl(ev);
     }
 
     @Override
@@ -443,17 +445,8 @@
                 && isInPlaybackState() && mMediaControlView != null) {
             toggleMediaControlViewVisibility();
         }
-        return mSuperProvider.onTrackballEvent_impl(ev);
-    }
 
-    @Override
-    public void onFinishInflate_impl() {
-        mSuperProvider.onFinishInflate_impl();
-    }
-
-    @Override
-    public void setEnabled_impl(boolean enabled) {
-        mSuperProvider.setEnabled_impl(enabled);
+        return super.onTrackballEvent_impl(ev);
     }
 
     ///////////////////////////////////////////////////
@@ -700,7 +693,7 @@
     }
 
     private void toggleMediaControlViewVisibility() {
-        if (mMediaControlView.isShowing()) {
+        if (mMediaControlView.getVisibility() == View.VISIBLE) {
             mMediaControlView.setVisibility(View.GONE);
         } else {
             mMediaControlView.setVisibility(View.VISIBLE);
diff --git a/packages/MediaComponents/src/com/android/widget/ViewGroupImpl.java b/packages/MediaComponents/src/com/android/widget/ViewGroupImpl.java
new file mode 100644
index 0000000..8598bb2
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/widget/ViewGroupImpl.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.widget;
+
+import android.media.update.ViewGroupProvider;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+public abstract class ViewGroupImpl implements ViewGroupProvider {
+    private final ViewGroupProvider mSuperProvider;
+
+    public ViewGroupImpl(ViewGroup instance,
+            ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
+        mSuperProvider = superProvider;
+    }
+
+    @Override
+    public void onAttachedToWindow_impl() {
+        mSuperProvider.onAttachedToWindow_impl();
+    }
+
+    @Override
+    public void onDetachedFromWindow_impl() {
+        mSuperProvider.onDetachedFromWindow_impl();
+    }
+
+    @Override
+    public CharSequence getAccessibilityClassName_impl() {
+        return mSuperProvider.getAccessibilityClassName_impl();
+    }
+
+    @Override
+    public boolean onTouchEvent_impl(MotionEvent ev) {
+        return mSuperProvider.onTouchEvent_impl(ev);
+    }
+
+    @Override
+    public boolean onTrackballEvent_impl(MotionEvent ev) {
+        return mSuperProvider.onTrackballEvent_impl(ev);
+    }
+
+    @Override
+    public void onFinishInflate_impl() {
+        mSuperProvider.onFinishInflate_impl();
+    }
+
+    @Override
+    public void setEnabled_impl(boolean enabled) {
+        mSuperProvider.setEnabled_impl(enabled);
+    }
+
+    @Override
+    public void onVisibilityAggregated_impl(boolean isVisible) {
+        mSuperProvider.onVisibilityAggregated_impl(isVisible);
+    }
+
+    @Override
+    public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+        mSuperProvider.onLayout_impl(changed, left, top, right, bottom);
+    }
+
+    @Override
+    public void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec) {
+        mSuperProvider.onMeasure_impl(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
+    public int getSuggestedMinimumWidth_impl() {
+        return mSuperProvider.getSuggestedMinimumWidth_impl();
+    }
+
+    @Override
+    public int getSuggestedMinimumHeight_impl() {
+        return mSuperProvider.getSuggestedMinimumHeight_impl();
+    }
+
+    @Override
+    public void setMeasuredDimension_impl(int measuredWidth, int measuredHeight) {
+        mSuperProvider.setMeasuredDimension_impl(measuredWidth, measuredHeight);
+    }
+
+    @Override
+    public boolean checkLayoutParams_impl(ViewGroup.LayoutParams p) {
+        return mSuperProvider.checkLayoutParams_impl(p);
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateDefaultLayoutParams_impl() {
+        return mSuperProvider.generateDefaultLayoutParams_impl();
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams_impl(AttributeSet attrs) {
+        return mSuperProvider.generateLayoutParams_impl(attrs);
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams_impl(ViewGroup.LayoutParams lp) {
+        return mSuperProvider.generateLayoutParams_impl(lp);
+    }
+
+    @Override
+    public boolean shouldDelayChildPressedState_impl() {
+        return mSuperProvider.shouldDelayChildPressedState_impl();
+    }
+
+    @Override
+    public void measureChildWithMargins_impl(View child,
+        int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
+        mSuperProvider.measureChildWithMargins_impl(child,
+                parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
+    }
+}
diff --git a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
index 38475a8..4cd8177 100644
--- a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
@@ -128,6 +128,13 @@
         }
 
         @Override
+        public void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {
+            if (mCallbackProxy != null) {
+                mCallbackProxy.onPlaybackInfoChanged(info);
+            }
+        }
+
+        @Override
         public void onCustomCommand(Command command, Bundle args, ResultReceiver receiver) {
             super.onCustomCommand(command, args, receiver);
             mCallbackProxy.onCustomCommand(command, args, receiver);
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
index ff8c2b7..43a6c2c 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
@@ -16,10 +16,16 @@
 
 package android.media;
 
+import static android.media.AudioAttributes.CONTENT_TYPE_MUSIC;
+import static android.media.TestUtils.ensurePlaylistParamsModeEquals;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 
-import static android.media.TestUtils.ensurePlaylistParamsModeEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
 
 import android.media.MediaPlayerInterface.PlaybackListener;
 import android.media.MediaSession2.Builder;
@@ -36,19 +42,17 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
 
-import java.util.ArrayList;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import static org.junit.Assert.*;
-
 /**
  * Tests {@link MediaSession2}.
  */
@@ -105,6 +109,48 @@
     }
 
     @Test
+    public void testSetPlayerWithVolumeProvider() throws Exception {
+        MockPlayer player = new MockPlayer(0);
+        AudioAttributes attrs = new AudioAttributes.Builder()
+                .setContentType(CONTENT_TYPE_MUSIC)
+                .build();
+        player.setAudioAttributes(attrs);
+
+        final int maxVolume = 100;
+        final int currentVolume = 23;
+        final int volumeControlType = VolumeProvider2.VOLUME_CONTROL_ABSOLUTE;
+        VolumeProvider2 volumeProvider =
+                new VolumeProvider2(mContext, volumeControlType, maxVolume, currentVolume) { };
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final TestControllerCallbackInterface callback = new TestControllerCallbackInterface() {
+            @Override
+            public void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {
+                assertEquals(MediaController2.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
+                        info.getPlaybackType());
+                assertEquals(attrs, info.getAudioAttributes());
+                assertEquals(volumeControlType, info.getPlaybackType());
+                assertEquals(maxVolume, info.getMaxVolume());
+                assertEquals(currentVolume, info.getCurrentVolume());
+                latch.countDown();
+            }
+        };
+
+        final MediaController2 controller = createController(mSession.getToken(), true, callback);
+        assertNull(controller.getPlaybackInfo());
+
+        mSession.setPlayer(player, volumeProvider);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+
+        MediaController2.PlaybackInfo infoOut = controller.getPlaybackInfo();
+        assertEquals(MediaController2.PlaybackInfo.PLAYBACK_TYPE_REMOTE, infoOut.getPlaybackType());
+        assertEquals(attrs, infoOut.getAudioAttributes());
+        assertEquals(volumeControlType, infoOut.getPlaybackType());
+        assertEquals(maxVolume, infoOut.getMaxVolume());
+        assertEquals(currentVolume, infoOut.getCurrentVolume());
+    }
+
+    @Test
     public void testPlay() throws Exception {
         sHandler.postAndSync(() -> {
             mSession.play();
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
index 5d94b17..513fa29 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
@@ -63,6 +63,7 @@
         // Add methods in ControllerCallback/BrowserCallback that you want to test.
         default void onPlaylistChanged(List<MediaItem2> playlist) {}
         default void onPlaylistParamsChanged(MediaSession2.PlaylistParams params) {}
+        default void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {}
 
         // Currently empty. Add methods in ControllerCallback/BrowserCallback that you want to test.
         default void onPlaybackStateChanged(PlaybackState2 state) { }
@@ -241,6 +242,13 @@
                 mCallbackProxy.onPlaylistParamsChanged(params);
             }
         }
+
+        @Override
+        public void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {
+            if (mCallbackProxy != null) {
+                mCallbackProxy.onPlaybackInfoChanged(info);
+            }
+        }
     }
 
     public class TestMediaController extends MediaController2 implements TestControllerInterface {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 592273e..e7140c2 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1984,7 +1984,7 @@
     for (size_t i = 0; i < fakeNum; i++) {
         struct audio_microphone_characteristic_t characteristics;
         sprintf(characteristics.device_id, "microphone:%zu", i);
-        characteristics.type = fakeTypes[i];
+        characteristics.device = fakeTypes[i];
         sprintf(characteristics.address, "");
         characteristics.location = AUDIO_MICROPHONE_LOCATION_MAINBODY;
         characteristics.group = 0;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 14d7e2e..24d862f 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7051,7 +7051,7 @@
     // Fake data
     struct audio_microphone_characteristic_t characteristic;
     sprintf(characteristic.device_id, "builtin_mic");
-    characteristic.type = AUDIO_DEVICE_IN_BUILTIN_MIC;
+    characteristic.device = AUDIO_DEVICE_IN_BUILTIN_MIC;
     sprintf(characteristic.address, "");
     characteristic.location = AUDIO_MICROPHONE_LOCATION_MAINBODY;
     characteristic.group = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 9ba8bb7..324201b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2400,7 +2400,7 @@
 
     Vector<camera3_stream_t*> streams;
     streams.setCapacity(config.num_streams);
-    std::vector<uint32_t> outBufSizes(mOutputStreams.size(), 0);
+    std::vector<uint32_t> bufferSizes(config.num_streams, 0);
 
 
     if (mInputStream != NULL) {
@@ -2435,7 +2435,9 @@
 
         if (outputStream->format == HAL_PIXEL_FORMAT_BLOB &&
                 outputStream->data_space == HAL_DATASPACE_V0_JFIF) {
-            outBufSizes[i] = static_cast<uint32_t>(
+            size_t k = i + ((mInputStream != nullptr) ? 1 : 0); // Input stream if present should
+                                                                // always occupy the initial entry.
+            bufferSizes[k] = static_cast<uint32_t>(
                     getJpegBufferSize(outputStream->width, outputStream->height));
         }
     }
@@ -2446,7 +2448,7 @@
     // max_buffers, usage, priv fields.
 
     const camera_metadata_t *sessionBuffer = sessionParams.getAndLock();
-    res = mInterface->configureStreams(sessionBuffer, &config, outBufSizes);
+    res = mInterface->configureStreams(sessionBuffer, &config, bufferSizes);
     sessionParams.unlock(sessionBuffer);
 
     if (res == BAD_VALUE) {
@@ -3504,7 +3506,7 @@
 }
 
 status_t Camera3Device::HalInterface::configureStreams(const camera_metadata_t *sessionParams,
-        camera3_stream_configuration *config, const std::vector<uint32_t>& outputBufferSizes) {
+        camera3_stream_configuration *config, const std::vector<uint32_t>& bufferSizes) {
     ATRACE_NAME("CameraHal::configureStreams");
     if (!valid()) return INVALID_OPERATION;
     status_t res = OK;
@@ -3545,7 +3547,7 @@
         dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
         dst3_2.rotation = mapToStreamRotation((camera3_stream_rotation_t) src->rotation);
         dst3_4.v3_2 = dst3_2;
-        dst3_4.bufferSize = outputBufferSizes[i];
+        dst3_4.bufferSize = bufferSizes[i];
         if (src->physical_camera_id != nullptr) {
             dst3_4.physicalCameraId = src->physical_camera_id;
         }
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index ccd9d7a..12cb6b4 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -283,7 +283,7 @@
                 /*out*/ camera_metadata_t **requestTemplate);
         status_t configureStreams(const camera_metadata_t *sessionParams,
                 /*inout*/ camera3_stream_configuration *config,
-                const std::vector<uint32_t>& outputBufferSizes);
+                const std::vector<uint32_t>& bufferSizes);
         status_t processCaptureRequest(camera3_capture_request_t *request);
         status_t processBatchCaptureRequests(
                 std::vector<camera3_capture_request_t*>& requests,