Merge "MediaSession2: Update Builder" into pi-dev
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
index 3b1b413..5418af9 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -81,11 +81,16 @@
     AMEDIAFORMAT_KEY_STRIDE,
     AMEDIAFORMAT_KEY_TRACK_ID,
     AMEDIAFORMAT_KEY_WIDTH,
+    AMEDIAFORMAT_KEY_DISPLAY_HEIGHT,
+    AMEDIAFORMAT_KEY_DISPLAY_WIDTH,
+    AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID,
+    AMEDIAFORMAT_KEY_TRACK_INDEX,
 };
 
 static const char *AMediaFormatKeyGroupInt64[] = {
     AMEDIAFORMAT_KEY_DURATION,
     AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER,
+    AMEDIAFORMAT_KEY_TIME_US,
 };
 
 static const char *AMediaFormatKeyGroupString[] = {
@@ -96,6 +101,14 @@
 
 static const char *AMediaFormatKeyGroupBuffer[] = {
     AMEDIAFORMAT_KEY_HDR_STATIC_INFO,
+    AMEDIAFORMAT_KEY_SEI,
+    AMEDIAFORMAT_KEY_MPEG_USER_DATA,
+};
+
+static const char *AMediaFormatKeyGroupCsd[] = {
+    AMEDIAFORMAT_KEY_CSD_0,
+    AMEDIAFORMAT_KEY_CSD_1,
+    AMEDIAFORMAT_KEY_CSD_2,
 };
 
 static const char *AMediaFormatKeyGroupRect[] = {
@@ -307,11 +320,19 @@
 }
 
 sp<AMessage> AMediaFormatWrapper::toAMessage() const {
+  sp<AMessage> msg;
+  writeToAMessage(msg);
+  return msg;
+}
+
+void AMediaFormatWrapper::writeToAMessage(sp<AMessage> &msg) const {
     if (mAMediaFormat == NULL) {
-        return NULL;
+        msg = NULL;
     }
 
-    sp<AMessage> msg = new AMessage;
+    if (msg == NULL) {
+        msg = new AMessage;
+    }
     for (auto& key : AMediaFormatKeyGroupInt32) {
         int32_t val;
         if (getInt32(key, &val)) {
@@ -338,6 +359,16 @@
             msg->setBuffer(key, buffer);
         }
     }
+    for (auto& key : AMediaFormatKeyGroupCsd) {
+        void *data;
+        size_t size;
+        if (getBuffer(key, &data, &size)) {
+            sp<ABuffer> buffer = ABuffer::CreateAsCopy(data, size);
+            buffer->meta()->setInt32(AMEDIAFORMAT_KEY_CSD, 1);
+            buffer->meta()->setInt64(AMEDIAFORMAT_KEY_TIME_US, 0);
+            msg->setBuffer(key, buffer);
+        }
+    }
     for (auto& key : AMediaFormatKeyGroupRect) {
         int32_t left, top, right, bottom;
         if (getRect(key, &left, &top, &right, &bottom)) {
@@ -355,7 +386,6 @@
             }
         }
     }
-    return msg;
 }
 
 const char* AMediaFormatWrapper::toString() const {
diff --git a/media/libmedia/include/media/NdkWrapper.h b/media/libmedia/include/media/NdkWrapper.h
index f17d2cc..191665a 100644
--- a/media/libmedia/include/media/NdkWrapper.h
+++ b/media/libmedia/include/media/NdkWrapper.h
@@ -45,6 +45,7 @@
 class MetaData;
 
 struct AMediaFormatWrapper : public RefBase {
+
     static sp<AMediaFormatWrapper> Create(const sp<AMessage> &message);
 
     AMediaFormatWrapper();
@@ -54,6 +55,7 @@
     AMediaFormat *getAMediaFormat() const;
 
     sp<AMessage> toAMessage() const ;
+    void writeToAMessage(sp<AMessage>&) const ;
     const char* toString() const ;
 
     status_t release();
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
index 936fb20..196b103 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
@@ -35,13 +35,13 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSourceFactory.h>
-#include <media/stagefright/FileSource.h>
 #include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaClock.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/NdkUtils.h>
 #include <media/stagefright/Utils.h>
 #include "../../libstagefright/include/NuCachedSource2.h"
 #include "../../libstagefright/include/HTTPBase.h"
@@ -161,29 +161,40 @@
 }
 
 status_t NuPlayer2::GenericSource2::initFromDataSource() {
-    sp<IMediaExtractor> extractor;
-    CHECK(mDataSource != NULL);
+    mExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
+    CHECK(mDataSource != NULL || mFd != -1);
     sp<DataSource> dataSource = mDataSource;
+    const int fd = mFd;
+    const int64_t offset = mOffset;
+    const int64_t length = mLength;
 
     mLock.unlock();
     // This might take long time if data source is not reliable.
-    extractor = MediaExtractorFactory::Create(dataSource, NULL);
+    status_t err;
+    if (dataSource != nullptr) {
+        mDataSourceWrapper = new AMediaDataSourceWrapper(dataSource);
+        err = mExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
+    } else {
+        err = mExtractor->setDataSource(fd, offset, length);
+    }
 
-    if (extractor == NULL) {
-        ALOGE("initFromDataSource, cannot create extractor!");
+    if (err != OK) {
+        ALOGE("initFromDataSource, failed to create data source!");
+        mLock.lock();
         return UNKNOWN_ERROR;
     }
 
-    sp<MetaData> fileMeta = extractor->getMetaData();
-
-    size_t numtracks = extractor->countTracks();
+    size_t numtracks = mExtractor->getTrackCount();
     if (numtracks == 0) {
         ALOGE("initFromDataSource, source has no track!");
+        mLock.lock();
         return UNKNOWN_ERROR;
     }
 
     mLock.lock();
-    mFileMeta = fileMeta;
+    mFd = -1;
+    mDataSource = dataSource;
+    mFileMeta = convertMediaFormatWrapperToMetaData(mExtractor->getFormat());
     if (mFileMeta != NULL) {
         int64_t duration;
         if (mFileMeta->findInt64(kKeyDuration, &duration)) {
@@ -196,18 +207,22 @@
     mMimes.clear();
 
     for (size_t i = 0; i < numtracks; ++i) {
-        sp<IMediaSource> track = extractor->getTrack(i);
-        if (track == NULL) {
-            continue;
-        }
 
-        sp<MetaData> meta = extractor->getTrackMetaData(i);
-        if (meta == NULL) {
+        sp<AMediaFormatWrapper> trackFormat = mExtractor->getTrackFormat(i);
+        if (trackFormat == NULL) {
             ALOGE("no metadata for track %zu", i);
             return UNKNOWN_ERROR;
         }
 
+        sp<AMediaExtractorWrapper> trackExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
+        if (mDataSourceWrapper != nullptr) {
+            err = trackExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
+        } else {
+            err = trackExtractor->setDataSource(fd, offset, length);
+        }
+
         const char *mime;
+        sp<MetaData> meta = convertMediaFormatWrapperToMetaData(trackFormat);
         CHECK(meta->findCString(kKeyMIMEType, &mime));
 
         ALOGV("initFromDataSource track[%zu]: %s", i, mime);
@@ -217,11 +232,11 @@
         // extractor operation, some extractors might modify meta
         // during getTrack() and make it invalid.
         if (!strncasecmp(mime, "audio/", 6)) {
-            if (mAudioTrack.mSource == NULL) {
+            if (mAudioTrack.mExtractor == NULL) {
                 mAudioTrack.mIndex = i;
-                mAudioTrack.mSource = track;
-                mAudioTrack.mPackets =
-                    new AnotherPacketSource(mAudioTrack.mSource->getFormat());
+                mAudioTrack.mExtractor = trackExtractor;
+                mAudioTrack.mExtractor->selectTrack(i);
+                mAudioTrack.mPackets = new AnotherPacketSource(meta);
 
                 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
                     mAudioIsVorbis = true;
@@ -232,18 +247,18 @@
                 mMimes.add(String8(mime));
             }
         } else if (!strncasecmp(mime, "video/", 6)) {
-            if (mVideoTrack.mSource == NULL) {
+            if (mVideoTrack.mExtractor == NULL) {
                 mVideoTrack.mIndex = i;
-                mVideoTrack.mSource = track;
-                mVideoTrack.mPackets =
-                    new AnotherPacketSource(mVideoTrack.mSource->getFormat());
+                mVideoTrack.mExtractor = trackExtractor;
+                mVideoTrack.mExtractor->selectTrack(i);
+                mVideoTrack.mPackets = new AnotherPacketSource(meta);
 
                 // video always at the beginning
                 mMimes.insertAt(String8(mime), 0);
             }
         }
 
-        mSources.push(track);
+        mExtractors.push(trackExtractor);
         int64_t durationUs;
         if (meta->findInt64(kKeyDuration, &durationUs)) {
             if (durationUs > mDurationUs) {
@@ -259,10 +274,10 @@
         }
     }
 
-    ALOGV("initFromDataSource mSources.size(): %zu  mIsSecure: %d  mime[0]: %s", mSources.size(),
+    ALOGV("initFromDataSource mExtractors.size(): %zu  mIsSecure: %d  mime[0]: %s", mExtractors.size(),
             mIsSecure, (mMimes.isEmpty() ? "NONE" : mMimes[0].string()));
 
-    if (mSources.size() == 0) {
+    if (mExtractors.size() == 0) {
         ALOGE("b/23705695");
         return UNKNOWN_ERROR;
     }
@@ -294,31 +309,10 @@
     return OK;
 }
 
-status_t NuPlayer2::GenericSource2::startSources() {
-    // Start the selected A/V tracks now before we start buffering.
-    // Widevine sources might re-initialize crypto when starting, if we delay
-    // this to start(), all data buffered during prepare would be wasted.
-    // (We don't actually start reading until start().)
-    //
-    // TODO: this logic may no longer be relevant after the removal of widevine
-    // support
-    if (mAudioTrack.mSource != NULL && mAudioTrack.mSource->start() != OK) {
-        ALOGE("failed to start audio track!");
-        return UNKNOWN_ERROR;
-    }
-
-    if (mVideoTrack.mSource != NULL && mVideoTrack.mSource->start() != OK) {
-        ALOGE("failed to start video track!");
-        return UNKNOWN_ERROR;
-    }
-
-    return OK;
-}
-
 int64_t NuPlayer2::GenericSource2::getLastReadPosition() {
-    if (mAudioTrack.mSource != NULL) {
+    if (mAudioTrack.mExtractor != NULL) {
         return mAudioTimeUs;
-    } else if (mVideoTrack.mSource != NULL) {
+    } else if (mVideoTrack.mExtractor != NULL) {
         return mVideoTimeUs;
     } else {
         return 0;
@@ -391,51 +385,16 @@
             if (!mDisconnected) {
                 mDataSource = dataSource;
             }
-        } else {
-            if (property_get_bool("media.stagefright.extractremote", true) &&
-                    !FileSource::requiresDrm(mFd, mOffset, mLength, nullptr /* mime */)) {
-                sp<IBinder> binder =
-                        defaultServiceManager()->getService(String16("media.extractor"));
-                if (binder != nullptr) {
-                    ALOGD("FileSource remote");
-                    sp<IMediaExtractorService> mediaExService(
-                            interface_cast<IMediaExtractorService>(binder));
-                    sp<IDataSource> source =
-                            mediaExService->makeIDataSource(mFd, mOffset, mLength);
-                    ALOGV("IDataSource(FileSource): %p %d %lld %lld",
-                            source.get(), mFd, (long long)mOffset, (long long)mLength);
-                    if (source.get() != nullptr) {
-                        mDataSource = CreateDataSourceFromIDataSource(source);
-                        if (mDataSource != nullptr) {
-                            // Close the local file descriptor as it is not needed anymore.
-                            close(mFd);
-                            mFd = -1;
-                        }
-                    } else {
-                        ALOGW("extractor service cannot make data source");
-                    }
-                } else {
-                    ALOGW("extractor service not running");
-                }
-            }
-            if (mDataSource == nullptr) {
-                ALOGD("FileSource local");
-                mDataSource = new FileSource(mFd, mOffset, mLength);
-            }
-            // TODO: close should always be done on mFd, see the lines following
-            // CreateDataSourceFromIDataSource above,
-            // and the FileSource constructor should dup the mFd argument as needed.
-            mFd = -1;
         }
 
-        if (mDataSource == NULL) {
+        if (mFd == -1 && mDataSource == NULL) {
             ALOGE("Failed to create data source!");
             notifyPreparedAndCleanup(UNKNOWN_ERROR);
             return;
         }
     }
 
-    if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
+    if (mDataSource != nullptr && mDataSource->flags() & DataSource::kIsCachingDataSource) {
         mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
     }
 
@@ -452,7 +411,7 @@
         return;
     }
 
-    if (mVideoTrack.mSource != NULL) {
+    if (mVideoTrack.mExtractor != NULL) {
         sp<MetaData> meta = getFormatMeta_l(false /* audio */);
         sp<AMessage> msg = new AMessage;
         err = convertMetaDataToMessage(meta, &msg);
@@ -479,13 +438,6 @@
 void NuPlayer2::GenericSource2::finishPrepareAsync() {
     ALOGV("finishPrepareAsync");
 
-    status_t err = startSources();
-    if (err != OK) {
-        ALOGE("Failed to init start data source!");
-        notifyPreparedAndCleanup(err);
-        return;
-    }
-
     if (mIsStreaming) {
         mCachedSource->resumeFetchingIfNecessary();
         mPreparing = true;
@@ -494,11 +446,11 @@
         notifyPrepared();
     }
 
-    if (mAudioTrack.mSource != NULL) {
+    if (mAudioTrack.mExtractor != NULL) {
         postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
     }
 
-    if (mVideoTrack.mSource != NULL) {
+    if (mVideoTrack.mExtractor != NULL) {
         postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
     }
 }
@@ -520,11 +472,11 @@
     Mutex::Autolock _l(mLock);
     ALOGI("start");
 
-    if (mAudioTrack.mSource != NULL) {
+    if (mAudioTrack.mExtractor != NULL) {
         postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
     }
 
-    if (mVideoTrack.mSource != NULL) {
+    if (mVideoTrack.mExtractor != NULL) {
         postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
     }
 
@@ -563,6 +515,9 @@
     } else if (httpSource != NULL) {
         static_cast<HTTPBase *>(httpSource.get())->disconnect();
     }
+
+    mDataSourceWrapper = NULL;
+
 }
 
 status_t NuPlayer2::GenericSource2::feedMoreTSData() {
@@ -630,30 +585,27 @@
       {
           int32_t trackIndex;
           CHECK(msg->findInt32("trackIndex", &trackIndex));
-          const sp<IMediaSource> source = mSources.itemAt(trackIndex);
+          const sp<AMediaExtractorWrapper> extractor = mExtractors.itemAt(trackIndex);
 
           Track* track;
-          const char *mime;
+          AString mime;
           media_track_type trackType, counterpartType;
-          sp<MetaData> meta = source->getFormat();
-          meta->findCString(kKeyMIMEType, &mime);
-          if (!strncasecmp(mime, "audio/", 6)) {
+          sp<AMediaFormatWrapper> format = extractor->getTrackFormat(trackIndex);
+          format->getString(AMEDIAFORMAT_KEY_MIME, &mime);
+          if (!strncasecmp(mime.c_str(), "audio/", 6)) {
               track = &mAudioTrack;
               trackType = MEDIA_TRACK_TYPE_AUDIO;
               counterpartType = MEDIA_TRACK_TYPE_VIDEO;;
           } else {
-              CHECK(!strncasecmp(mime, "video/", 6));
+              CHECK(!strncasecmp(mime.c_str(), "video/", 6));
               track = &mVideoTrack;
               trackType = MEDIA_TRACK_TYPE_VIDEO;
               counterpartType = MEDIA_TRACK_TYPE_AUDIO;;
           }
 
 
-          if (track->mSource != NULL) {
-              track->mSource->stop();
-          }
-          track->mSource = source;
-          track->mSource->start();
+          track->mExtractor = extractor;
+          track->mExtractor->selectSingleTrack(trackIndex);
           track->mIndex = trackIndex;
           ++mAudioDataGeneration;
           ++mVideoDataGeneration;
@@ -786,11 +738,10 @@
         return;
     }
 
-    uint32_t textType;
-    const void *data;
+    void *data = NULL;
     size_t size = 0;
-    if (mTimedTextTrack.mSource->getFormat()->findData(
-                    kKeyTextFormatData, &textType, &data, &size)) {
+    if (mTimedTextTrack.mExtractor->getTrackFormat(mTimedTextTrack.mIndex)->getBuffer(
+                    "text", &data, &size)) {
         mGlobalTimedText = new ABuffer(size);
         if (mGlobalTimedText->data()) {
             memcpy(mGlobalTimedText->data(), data, size);
@@ -806,19 +757,36 @@
     }
 }
 
+sp<AMessage> NuPlayer2::GenericSource2::getFormat(bool audio) {
+    Mutex::Autolock _l(mLock);
+    return getFormat_l(audio);
+}
+
 sp<MetaData> NuPlayer2::GenericSource2::getFormatMeta(bool audio) {
     Mutex::Autolock _l(mLock);
     return getFormatMeta_l(audio);
 }
 
-sp<MetaData> NuPlayer2::GenericSource2::getFormatMeta_l(bool audio) {
-    sp<IMediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
+sp<AMessage> NuPlayer2::GenericSource2::getFormat_l(bool audio) {
+    sp<AMediaExtractorWrapper> extractor = audio ? mAudioTrack.mExtractor : mVideoTrack.mExtractor;
+    size_t trackIndex = audio ? mAudioTrack.mIndex : mVideoTrack.mIndex;
 
-    if (source == NULL) {
+    if (extractor == NULL) {
         return NULL;
     }
 
-    return source->getFormat();
+    return extractor->getTrackFormat(trackIndex)->toAMessage();
+}
+
+sp<MetaData> NuPlayer2::GenericSource2::getFormatMeta_l(bool audio) {
+    sp<AMediaExtractorWrapper> extractor = audio ? mAudioTrack.mExtractor : mVideoTrack.mExtractor;
+    size_t trackIndex = audio ? mAudioTrack.mIndex : mVideoTrack.mIndex;
+
+    if (extractor == NULL) {
+        return NULL;
+    }
+
+    return convertMediaFormatWrapperToMetaData(extractor->getTrackFormat(trackIndex));
 }
 
 status_t NuPlayer2::GenericSource2::dequeueAccessUnit(
@@ -833,7 +801,7 @@
 
     Track *track = audio ? &mAudioTrack : &mVideoTrack;
 
-    if (track->mSource == NULL) {
+    if (track->mExtractor == NULL) {
         return -EWOULDBLOCK;
     }
 
@@ -878,11 +846,11 @@
     }
 
     if (result != OK) {
-        if (mSubtitleTrack.mSource != NULL) {
+        if (mSubtitleTrack.mExtractor != NULL) {
             mSubtitleTrack.mPackets->clear();
             mFetchSubtitleDataGeneration++;
         }
-        if (mTimedTextTrack.mSource != NULL) {
+        if (mTimedTextTrack.mExtractor != NULL) {
             mTimedTextTrack.mPackets->clear();
             mFetchTimedTextDataGeneration++;
         }
@@ -898,7 +866,7 @@
         mVideoLastDequeueTimeUs = timeUs;
     }
 
-    if (mSubtitleTrack.mSource != NULL
+    if (mSubtitleTrack.mExtractor != NULL
             && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
         sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
         msg->setInt64("timeUs", timeUs);
@@ -906,7 +874,7 @@
         msg->post();
     }
 
-    if (mTimedTextTrack.mSource != NULL
+    if (mTimedTextTrack.mExtractor != NULL
             && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
         sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
         msg->setInt64("timeUs", timeUs);
@@ -925,50 +893,47 @@
 
 size_t NuPlayer2::GenericSource2::getTrackCount() const {
     Mutex::Autolock _l(mLock);
-    return mSources.size();
+    return mExtractors.size();
 }
 
 sp<AMessage> NuPlayer2::GenericSource2::getTrackInfo(size_t trackIndex) const {
     Mutex::Autolock _l(mLock);
-    size_t trackCount = mSources.size();
+    size_t trackCount = mExtractors.size();
     if (trackIndex >= trackCount) {
         return NULL;
     }
 
-    sp<AMessage> format = new AMessage();
-    sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
-    if (meta == NULL) {
+    sp<AMessage> format = mExtractors.itemAt(trackIndex)->getTrackFormat(trackIndex)->toAMessage();
+    if (format == NULL) {
         ALOGE("no metadata for track %zu", trackIndex);
         return NULL;
     }
 
-    const char *mime;
-    CHECK(meta->findCString(kKeyMIMEType, &mime));
-    format->setString("mime", mime);
+    AString mime;
+    CHECK(format->findString(AMEDIAFORMAT_KEY_MIME, &mime));
 
     int32_t trackType;
-    if (!strncasecmp(mime, "video/", 6)) {
+    if (!strncasecmp(mime.c_str(), "video/", 6)) {
         trackType = MEDIA_TRACK_TYPE_VIDEO;
-    } else if (!strncasecmp(mime, "audio/", 6)) {
+    } else if (!strncasecmp(mime.c_str(), "audio/", 6)) {
         trackType = MEDIA_TRACK_TYPE_AUDIO;
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+    } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_TEXT_3GPP)) {
         trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
     } else {
         trackType = MEDIA_TRACK_TYPE_UNKNOWN;
     }
     format->setInt32("type", trackType);
 
-    const char *lang;
-    if (!meta->findCString(kKeyMediaLanguage, &lang)) {
-        lang = "und";
+    AString lang;
+    if (!format->findString("language", &lang)) {
+        format->setString("language", "und");
     }
-    format->setString("language", lang);
 
     if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
         int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
-        meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
-        meta->findInt32(kKeyTrackIsDefault, &isDefault);
-        meta->findInt32(kKeyTrackIsForced, &isForced);
+        format->findInt32(AMEDIAFORMAT_KEY_IS_AUTOSELECT, &isAutoselect);
+        format->findInt32(AMEDIAFORMAT_KEY_IS_DEFAULT, &isDefault);
+        format->findInt32(AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE, &isForced);
 
         format->setInt32("auto", !!isAutoselect);
         format->setInt32("default", !!isDefault);
@@ -998,7 +963,7 @@
         break;
     }
 
-    if (track != NULL && track->mSource != NULL) {
+    if (track != NULL && track->mExtractor != NULL) {
         return track->mIndex;
     }
 
@@ -1009,49 +974,45 @@
     Mutex::Autolock _l(mLock);
     ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
 
-    if (trackIndex >= mSources.size()) {
+    if (trackIndex >= mExtractors.size()) {
         return BAD_INDEX;
     }
 
     if (!select) {
         Track* track = NULL;
-        if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) {
+        if (mSubtitleTrack.mExtractor != NULL && trackIndex == mSubtitleTrack.mIndex) {
             track = &mSubtitleTrack;
             mFetchSubtitleDataGeneration++;
-        } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) {
+        } else if (mTimedTextTrack.mExtractor != NULL && trackIndex == mTimedTextTrack.mIndex) {
             track = &mTimedTextTrack;
             mFetchTimedTextDataGeneration++;
         }
         if (track == NULL) {
             return INVALID_OPERATION;
         }
-        track->mSource->stop();
-        track->mSource = NULL;
+        track->mExtractor = NULL;
         track->mPackets->clear();
         return OK;
     }
 
-    const sp<IMediaSource> source = mSources.itemAt(trackIndex);
-    sp<MetaData> meta = source->getFormat();
+    const sp<AMediaExtractorWrapper> extractor = mExtractors.itemAt(trackIndex);
+    sp<MetaData> meta = convertMediaFormatWrapperToMetaData(extractor->getTrackFormat(trackIndex));
     const char *mime;
     CHECK(meta->findCString(kKeyMIMEType, &mime));
     if (!strncasecmp(mime, "text/", 5)) {
         bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP);
         Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack;
-        if (track->mSource != NULL && track->mIndex == trackIndex) {
+        if (track->mExtractor != NULL && track->mIndex == trackIndex) {
             return OK;
         }
         track->mIndex = trackIndex;
-        if (track->mSource != NULL) {
-            track->mSource->stop();
-        }
-        track->mSource = mSources.itemAt(trackIndex);
-        track->mSource->start();
+        track->mExtractor = mExtractors.itemAt(trackIndex);
+        track->mExtractor->selectSingleTrack(trackIndex);
         if (track->mPackets == NULL) {
-            track->mPackets = new AnotherPacketSource(track->mSource->getFormat());
+            track->mPackets = new AnotherPacketSource(meta);
         } else {
             track->mPackets->clear();
-            track->mPackets->setFormat(track->mSource->getFormat());
+            track->mPackets->setFormat(meta);
 
         }
 
@@ -1062,7 +1023,7 @@
         }
 
         status_t eosResult; // ignored
-        if (mSubtitleTrack.mSource != NULL
+        if (mSubtitleTrack.mExtractor != NULL
                 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
             sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this);
             msg->setInt64("timeUs", timeUs);
@@ -1074,7 +1035,7 @@
         msg2->setInt32("generation", mFetchTimedTextDataGeneration);
         msg2->post();
 
-        if (mTimedTextTrack.mSource != NULL
+        if (mTimedTextTrack.mExtractor != NULL
                 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
             sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
             msg->setInt64("timeUs", timeUs);
@@ -1086,7 +1047,7 @@
     } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) {
         bool audio = !strncasecmp(mime, "audio/", 6);
         Track *track = audio ? &mAudioTrack : &mVideoTrack;
-        if (track->mSource != NULL && track->mIndex == trackIndex) {
+        if (track->mExtractor != NULL && track->mIndex == trackIndex) {
             return OK;
         }
 
@@ -1133,7 +1094,7 @@
 }
 
 status_t NuPlayer2::GenericSource2::doSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode) {
-    if (mVideoTrack.mSource != NULL) {
+    if (mVideoTrack.mExtractor != NULL) {
         ++mVideoDataGeneration;
 
         int64_t actualTimeUs;
@@ -1145,18 +1106,18 @@
         mVideoLastDequeueTimeUs = actualTimeUs;
     }
 
-    if (mAudioTrack.mSource != NULL) {
+    if (mAudioTrack.mExtractor != NULL) {
         ++mAudioDataGeneration;
         readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs, MediaPlayer2SeekMode::SEEK_CLOSEST);
         mAudioLastDequeueTimeUs = seekTimeUs;
     }
 
-    if (mSubtitleTrack.mSource != NULL) {
+    if (mSubtitleTrack.mExtractor != NULL) {
         mSubtitleTrack.mPackets->clear();
         mFetchSubtitleDataGeneration++;
     }
 
-    if (mTimedTextTrack.mSource != NULL) {
+    if (mTimedTextTrack.mExtractor != NULL) {
         mTimedTextTrack.mPackets->clear();
         mFetchTimedTextDataGeneration++;
     }
@@ -1227,10 +1188,12 @@
     }
 
     if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
-        const char *mime;
-        CHECK(mTimedTextTrack.mSource != NULL
-                && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime));
-        meta->setString("mime", mime);
+        AString mime;
+        sp<AMediaExtractorWrapper> extractor = mTimedTextTrack.mExtractor;
+        size_t trackIndex = mTimedTextTrack.mIndex;
+        CHECK(extractor != NULL
+                && extractor->getTrackFormat(trackIndex)->getString(AMEDIAFORMAT_KEY_MIME, &mime));
+        meta->setString("mime", mime.c_str());
     }
 
     int64_t durationUs;
@@ -1327,7 +1290,7 @@
             TRESPASS();
     }
 
-    if (track->mSource == NULL) {
+    if (track->mExtractor == NULL) {
         return;
     }
 
@@ -1335,109 +1298,77 @@
         *actualTimeUs = seekTimeUs;
     }
 
-    MediaSource::ReadOptions options;
 
     bool seeking = false;
+    sp<AMediaExtractorWrapper> extractor = track->mExtractor;
     if (seekTimeUs >= 0) {
-        options.setSeekTo(seekTimeUs, mode);
+        extractor->seekTo(seekTimeUs, mode);
         seeking = true;
     }
 
-    const bool couldReadMultiple = (track->mSource->supportReadMultiple());
-
-    if (couldReadMultiple) {
-        options.setNonBlocking();
-    }
-
     int32_t generation = getDataGeneration(trackType);
     for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
-        Vector<MediaBufferBase *> mediaBuffers;
-        status_t err = NO_ERROR;
+        Vector<sp<ABuffer> > aBuffers;
 
-        sp<IMediaSource> source = track->mSource;
         mLock.unlock();
-        if (couldReadMultiple) {
-            err = source->readMultiple(
-                    &mediaBuffers, maxBuffers - numBuffers, &options);
-        } else {
-            MediaBufferBase *mbuf = NULL;
-            err = source->read(&mbuf, &options);
-            if (err == OK && mbuf != NULL) {
-                mediaBuffers.push_back(mbuf);
-            }
+
+        sp<AMediaFormatWrapper> format;
+        ssize_t sampleSize = -1;
+        status_t err = extractor->getSampleFormat(format);
+        if (err == OK) {
+            sampleSize = extractor->getSampleSize();
         }
+
+        if (err != OK || sampleSize < 0) {
+            mLock.lock();
+            track->mPackets->signalEOS(err != OK ? err : ERROR_END_OF_STREAM);
+            break;
+        }
+
+        sp<ABuffer> abuf = new ABuffer(sampleSize);
+        sampleSize = extractor->readSampleData(abuf);
         mLock.lock();
 
-        options.clearNonPersistent();
-
-        size_t id = 0;
-        size_t count = mediaBuffers.size();
-
         // in case track has been changed since we don't have lock for some time.
         if (generation != getDataGeneration(trackType)) {
-            for (; id < count; ++id) {
-                mediaBuffers[id]->release();
-            }
             break;
         }
 
-        for (; id < count; ++id) {
-            int64_t timeUs;
-            MediaBufferBase *mbuf = mediaBuffers[id];
-            if (!mbuf->meta_data().findInt64(kKeyTime, &timeUs)) {
-                mbuf->meta_data().dumpToLog();
-                track->mPackets->signalEOS(ERROR_MALFORMED);
-                break;
-            }
-            if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
-                mAudioTimeUs = timeUs;
-            } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
-                mVideoTimeUs = timeUs;
-            }
-
-            queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
-
-            sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType);
-            if (numBuffers == 0 && actualTimeUs != nullptr) {
-                *actualTimeUs = timeUs;
-            }
-            if (seeking && buffer != nullptr) {
-                sp<AMessage> meta = buffer->meta();
-                if (meta != nullptr && mode == MediaPlayer2SeekMode::SEEK_CLOSEST
-                        && seekTimeUs > timeUs) {
-                    sp<AMessage> extra = new AMessage;
-                    extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
-                    meta->setMessage("extra", extra);
-                }
-            }
-
-            track->mPackets->queueAccessUnit(buffer);
-            formatChange = false;
-            seeking = false;
-            ++numBuffers;
-        }
-        if (id < count) {
-            // Error, some mediaBuffer doesn't have kKeyTime.
-            for (; id < count; ++id) {
-                mediaBuffers[id]->release();
-            }
+        int64_t timeUs = extractor->getSampleTime();
+        if (timeUs < 0) {
+            track->mPackets->signalEOS(ERROR_MALFORMED);
             break;
         }
 
-        if (err == WOULD_BLOCK) {
-            break;
-        } else if (err == INFO_FORMAT_CHANGED) {
-#if 0
-            track->mPackets->queueDiscontinuity(
-                    ATSParser::DISCONTINUITY_FORMATCHANGE,
-                    NULL,
-                    false /* discard */);
-#endif
-        } else if (err != OK) {
-            queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
-            track->mPackets->signalEOS(err);
-            break;
+        sp<AMessage> meta = abuf->meta();
+        format->writeToAMessage(meta);
+        meta->setInt64("timeUs", timeUs);
+        if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
+            mAudioTimeUs = timeUs;
+        } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
+            mVideoTimeUs = timeUs;
         }
+
+        queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
+
+        if (numBuffers == 0 && actualTimeUs != nullptr) {
+            *actualTimeUs = timeUs;
+        }
+        if (seeking) {
+            if (meta != nullptr && mode == MediaPlayer2SeekMode::SEEK_CLOSEST
+                    && seekTimeUs > timeUs) {
+                sp<AMessage> extra = new AMessage;
+                extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
+                meta->setMessage("extra", extra);
+            }
+        }
+
+        track->mPackets->queueAccessUnit(abuf);
+        formatChange = false;
+        seeking = false;
+        ++numBuffers;
+        extractor->advance();
+
     }
 
     if (mIsStreaming
@@ -1453,7 +1384,7 @@
             if (mPreparing || mSentPauseOnBuffering) {
                 Track *counterTrack =
                     (trackType == MEDIA_TRACK_TYPE_VIDEO ? &mAudioTrack : &mVideoTrack);
-                if (counterTrack->mSource != NULL) {
+                if (counterTrack->mExtractor != NULL) {
                     durationUs = counterTrack->mPackets->getBufferedDurationUs(&finalResult);
                 }
                 if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) {
@@ -1649,26 +1580,22 @@
     // same source without being reset (called by prepareAsync/initFromDataSource)
     mIsDrmReleased = false;
 
-    if (mFileMeta == NULL) {
-        ALOGI("checkDrmInfo: No metadata");
+    if (mExtractor == NULL) {
+        ALOGV("checkDrmInfo: No extractor");
         return OK; // letting the caller responds accordingly
     }
 
-    uint32_t type;
-    const void *pssh;
-    size_t psshsize;
-
-    if (!mFileMeta->findData(kKeyPssh, &type, &pssh, &psshsize)) {
+    PsshInfo *psshInfo = mExtractor->getPsshInfo();
+    if (psshInfo == NULL) {
         ALOGV("checkDrmInfo: No PSSH");
         return OK; // source without DRM info
     }
 
-    sp<ABuffer> drmInfoBuffer = NuPlayer2Drm::retrieveDrmInfo(pssh, psshsize);
-    ALOGV("checkDrmInfo: MEDIA2_DRM_INFO PSSH size: %d drmInfoBuffer size: %d",
-          (int)psshsize, (int)drmInfoBuffer->size());
+    sp<ABuffer> drmInfoBuffer = NuPlayer2Drm::retrieveDrmInfo(psshInfo);
+    ALOGV("checkDrmInfo: MEDIA_DRM_INFO PSSH drm info size: %d", (int)drmInfoBuffer->size());
 
     if (drmInfoBuffer->size() == 0) {
-        ALOGE("checkDrmInfo: Unexpected drmInfoBuffer size: 0");
+        ALOGE("checkDrmInfo: Unexpected parcel size: 0");
         return UNKNOWN_ERROR;
     }
 
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.h b/media/libmediaplayer2/nuplayer2/GenericSource2.h
index 896c397..9bc5182 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.h
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.h
@@ -25,6 +25,9 @@
 
 #include <media/stagefright/MediaBuffer.h>
 #include <mediaplayer2/mediaplayer2.h>
+#include <media/NdkMediaDataSource.h>
+#include <media/NdkMediaExtractor.h>
+#include <media/NdkWrapper.h>
 
 namespace android {
 
@@ -101,6 +104,7 @@
 
     virtual void onMessageReceived(const sp<AMessage> &msg);
 
+    virtual sp<AMessage> getFormat(bool audio);
     virtual sp<MetaData> getFormatMeta(bool audio);
 
 private:
@@ -122,19 +126,14 @@
 
     struct Track {
         size_t mIndex;
-        sp<IMediaSource> mSource;
+        sp<AMediaExtractorWrapper> mExtractor;
         sp<AnotherPacketSource> mPackets;
     };
 
-    Vector<sp<IMediaSource> > mSources;
-    Track mAudioTrack;
     int64_t mAudioTimeUs;
     int64_t mAudioLastDequeueTimeUs;
-    Track mVideoTrack;
     int64_t mVideoTimeUs;
     int64_t mVideoLastDequeueTimeUs;
-    Track mSubtitleTrack;
-    Track mTimedTextTrack;
 
     BufferingSettings mBufferingSettings;
     int32_t mPrevBufferPercentage;
@@ -164,12 +163,20 @@
     sp<NuCachedSource2> mCachedSource;
     sp<DataSource> mHttpSource;
     sp<MetaData> mFileMeta;
+    sp<AMediaDataSourceWrapper> mDataSourceWrapper;
+    sp<AMediaExtractorWrapper> mExtractor;
+    Vector<sp<AMediaExtractorWrapper> > mExtractors;
     bool mStarted;
     bool mPreparing;
     int64_t mBitrate;
     uint32_t mPendingReadBufferTypes;
     sp<ABuffer> mGlobalTimedText;
 
+    Track mVideoTrack;
+    Track mAudioTrack;
+    Track mSubtitleTrack;
+    Track mTimedTextTrack;
+
     mutable Mutex mLock;
 
     sp<ALooper> mLooper;
@@ -227,6 +234,7 @@
 
     void sendCacheStats();
 
+    sp<AMessage> getFormat_l(bool audio);
     sp<MetaData> getFormatMeta_l(bool audio);
     int32_t getDataGeneration(media_track_type type) const;
 
diff --git a/media/libstagefright/CCodecBufferChannel.cpp b/media/libstagefright/CCodecBufferChannel.cpp
index 449c6aa..5ce49d9 100644
--- a/media/libstagefright/CCodecBufferChannel.cpp
+++ b/media/libstagefright/CCodecBufferChannel.cpp
@@ -760,19 +760,18 @@
 
         ALOGV("graphic = %s", graphic ? "true" : "false");
         std::shared_ptr<C2BlockPool> pool;
-        err = GetCodec2BlockPool(
-                graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR,
-                component,
-                &pool);
+        if (graphic) {
+            err = GetCodec2BlockPool(C2BlockPool::BASIC_GRAPHIC, component, &pool);
+        } else {
+            err = CreateCodec2BlockPool(C2PlatformAllocatorStore::ION,
+                                        component, &pool);
+        }
+
         if (err == C2_OK) {
             (*buffers)->setPool(pool);
         } else {
             // TODO: error
         }
-        // TODO: remove once we switch to proper buffer pool.
-        if (!graphic) {
-            *buffers = (*buffers)->toArrayMode();
-        }
     }
 
     {
diff --git a/media/libstagefright/codec2/SimpleC2Component.cpp b/media/libstagefright/codec2/SimpleC2Component.cpp
index 333cfeb..0753b08 100644
--- a/media/libstagefright/codec2/SimpleC2Component.cpp
+++ b/media/libstagefright/codec2/SimpleC2Component.cpp
@@ -302,12 +302,15 @@
             if (err != C2_OK) {
                 return err;
             }
-            err = GetCodec2BlockPool(
-                    (outputFormat.value == C2FormatVideo)
-                    ? C2BlockPool::BASIC_GRAPHIC
-                    : C2BlockPool::BASIC_LINEAR,
-                    shared_from_this(),
-                    &mOutputBlockPool);
+            if (outputFormat.value == C2FormatVideo) {
+                err = GetCodec2BlockPool(
+                        C2BlockPool::BASIC_GRAPHIC,
+                        shared_from_this(), &mOutputBlockPool);
+            } else {
+                err = CreateCodec2BlockPool(
+                        C2PlatformAllocatorStore::ION,
+                        shared_from_this(), &mOutputBlockPool);
+            }
             if (err != C2_OK) {
                 return err;
             }
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
index 038be48..f389abc 100644
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -232,7 +232,8 @@
 class C2BufferTest : public ::testing::Test {
 public:
     C2BufferTest()
-        : mLinearAllocator(std::make_shared<C2AllocatorIon>('i')),
+        : mBlockPoolId(C2BlockPool::PLATFORM_START),
+          mLinearAllocator(std::make_shared<C2AllocatorIon>('i')),
           mSize(0u),
           mAddr(nullptr),
           mGraphicAllocator(std::make_shared<C2AllocatorGralloc>('g')) {
@@ -281,7 +282,7 @@
     }
 
     std::shared_ptr<C2BlockPool> makeLinearBlockPool() {
-        return std::make_shared<C2BasicLinearBlockPool>(mLinearAllocator);
+        return std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
     }
 
     void allocateGraphic(uint32_t width, uint32_t height) {
@@ -328,6 +329,7 @@
     }
 
 private:
+    C2BlockPool::local_id_t mBlockPoolId;
     std::shared_ptr<C2Allocator> mLinearAllocator;
     std::shared_ptr<C2LinearAllocation> mLinearAllocation;
     size_t mSize;
@@ -745,4 +747,23 @@
     EXPECT_FALSE(buffer->hasInfo(info2->type()));
 }
 
+TEST_F(C2BufferTest, MultipleLinearMapTest) {
+    std::shared_ptr<C2BlockPool> pool(makeLinearBlockPool());
+    constexpr size_t kCapacity = 524288u;
+    for (int i = 0; i < 100; ++i) {
+        std::vector<C2WriteView> wViews;
+        std::vector<C2ReadView> rViews;
+        for (int j = 0; j < 16; ++j) {
+            std::shared_ptr<C2LinearBlock> block;
+            ASSERT_EQ(C2_OK, pool->fetchLinearBlock(
+                    kCapacity,
+                    { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
+                    &block));
+            wViews.push_back(block->map().get());
+            C2ConstLinearBlock cBlock = block->share(0, kCapacity / 2, C2Fence());
+            rViews.push_back(cBlock.map().get());
+        }
+    }
+}
+
 } // namespace android
diff --git a/media/libstagefright/codec2/vndk/Android.bp b/media/libstagefright/codec2/vndk/Android.bp
index 47afd42..95e7c39 100644
--- a/media/libstagefright/codec2/vndk/Android.bp
+++ b/media/libstagefright/codec2/vndk/Android.bp
@@ -39,14 +39,17 @@
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.media.bufferpool@1.0",
         "libbinder",
         "libcutils",
         "libdl",
         "libhardware",
         "libhidlbase",
         "libion",
+        "libfmq",
         "liblog",
         "libstagefright_foundation",
+        "libstagefright_bufferpool@1.0",
         "libui",
         "libutils",
     ],
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
index cf7658a..664c09e 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
@@ -18,6 +18,8 @@
 #define LOG_TAG "C2AllocatorIon"
 #include <utils/Log.h>
 
+#include <list>
+
 #include <ion/ion.h>
 #include <sys/mman.h>
 #include <unistd.h>
@@ -148,6 +150,7 @@
      * so that we can capture the error.
      *
      * \param ionFd     ion client (ownership transferred to created object)
+     * \param owned     whehter native_handle_t is owned by an allocation or not.
      * \param capacity  size of allocation
      * \param bufferFd  buffer handle (ownership transferred to created object). Must be
      *                  invalid if err is not 0.
@@ -155,14 +158,14 @@
      *                  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, C2Allocator::id_t id, int err)
+    Impl(int ionFd, bool owned, size_t capacity, int bufferFd, ion_user_handle_t buffer, C2Allocator::id_t id, int err)
         : mIonFd(ionFd),
+          mHandleOwned(owned),
           mHandle(bufferFd, capacity),
           mBuffer(buffer),
           mId(id),
           mInit(c2_map_errno<ENOMEM, EACCES, EINVAL>(err)),
-          mMapFd(-1),
-          mMapSize(0) {
+          mMapFd(-1) {
         if (mInit != C2_OK) {
             // close ionFd now on error
             if (mIonFd >= 0) {
@@ -188,7 +191,7 @@
     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, id, ret);
+        return new Impl(ionFd, false, capacity, bufferFd, buffer, id, ret);
     }
 
     /**
@@ -215,13 +218,14 @@
                 buffer = -1;
             }
         }
-        return new Impl(ionFd, size, bufferFd, buffer, id, ret);
+        return new Impl(ionFd, true, size, bufferFd, buffer, id, ret);
     }
 
     c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
         (void)fence; // TODO: wait for fence
         *addr = nullptr;
-        if (mMapSize > 0) {
+        if (!mMappings.empty()) {
+            ALOGV("multiple map");
             // TODO: technically we should return DUPLICATE here, but our block views don't
             // actually unmap, so we end up remapping an ion buffer multiple times.
             //
@@ -244,54 +248,63 @@
         size_t alignmentBytes = offset % PAGE_SIZE;
         size_t mapOffset = offset - alignmentBytes;
         size_t mapSize = size + alignmentBytes;
+        Mapping map = { nullptr, alignmentBytes, mapSize };
 
         c2_status_t err = C2_OK;
         if (mMapFd == -1) {
             int ret = ion_map(mIonFd, mBuffer, mapSize, prot,
-                              flags, mapOffset, (unsigned char**)&mMapAddr, &mMapFd);
+                              flags, mapOffset, (unsigned char**)&map.addr, &mMapFd);
             if (ret) {
                 mMapFd = -1;
-                *addr = nullptr;
+                map.addr = *addr = nullptr;
                 err = c2_map_errno<EINVAL>(-ret);
             } else {
-                *addr = (uint8_t *)mMapAddr + alignmentBytes;
-                mMapAlignmentBytes = alignmentBytes;
-                mMapSize = mapSize;
+                *addr = (uint8_t *)map.addr + alignmentBytes;
             }
         } else {
-            mMapAddr = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
-            if (mMapAddr == MAP_FAILED) {
-                mMapAddr = *addr = nullptr;
+            map.addr = mmap(nullptr, mapSize, prot, flags, mMapFd, mapOffset);
+            if (map.addr == MAP_FAILED) {
+                map.addr = *addr = nullptr;
                 err = c2_map_errno<EINVAL>(errno);
             } else {
-                *addr = (uint8_t *)mMapAddr + alignmentBytes;
-                mMapAlignmentBytes = alignmentBytes;
-                mMapSize = mapSize;
+                *addr = (uint8_t *)map.addr + alignmentBytes;
             }
         }
+        if (map.addr) {
+            mMappings.push_back(map);
+        }
         return err;
     }
 
     c2_status_t unmap(void *addr, size_t size, C2Fence *fence) {
-        if (mMapFd < 0 || mMapSize == 0) {
+        if (mMapFd < 0 || mMappings.empty()) {
             return C2_NOT_FOUND;
         }
-        if (addr != (uint8_t *)mMapAddr + mMapAlignmentBytes ||
-                size + mMapAlignmentBytes != mMapSize) {
-            return C2_BAD_VALUE;
+        for (auto it = mMappings.begin(); it != mMappings.end(); ++it) {
+            if (addr != (uint8_t *)it->addr + it->alignmentBytes ||
+                    size + it->alignmentBytes != it->size) {
+                continue;
+            }
+            int err = munmap(it->addr, it->size);
+            if (err != 0) {
+                return c2_map_errno<EINVAL>(errno);
+            }
+            if (fence) {
+                *fence = C2Fence(); // not using fences
+            }
+            (void)mMappings.erase(it);
+            return C2_OK;
         }
-        int err = munmap(mMapAddr, mMapSize);
-        if (err != 0) {
-            return c2_map_errno<EINVAL>(errno);
-        }
-        if (fence) {
-            *fence = C2Fence(); // not using fences
-        }
-        mMapSize = 0;
-        return C2_OK;
+        return C2_BAD_VALUE;
     }
 
     ~Impl() {
+        if (!mMappings.empty()) {
+            ALOGD("Dangling mappings!");
+            for (const Mapping &map : mMappings) {
+                (void)munmap(map.addr, map.size);
+            }
+        }
         if (mMapFd >= 0) {
             close(mMapFd);
             mMapFd = -1;
@@ -302,7 +315,9 @@
         if (mIonFd >= 0) {
             close(mIonFd);
         }
-        native_handle_close(&mHandle);
+        if (mHandleOwned) {
+            native_handle_close(&mHandle);
+        }
     }
 
     c2_status_t status() const {
@@ -323,14 +338,18 @@
 
 private:
     int mIonFd;
+    bool mHandleOwned;
     C2HandleIon mHandle;
     ion_user_handle_t mBuffer;
     C2Allocator::id_t mId;
     c2_status_t mInit;
     int mMapFd; // only one for now
-    void *mMapAddr;
-    size_t mMapAlignmentBytes;
-    size_t mMapSize;
+    struct Mapping {
+        void *addr;
+        size_t alignmentBytes;
+        size_t size;
+    };
+    std::list<Mapping> mMappings;
 };
 
 c2_status_t C2AllocationIon::map(
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index dc765f5..91b21c2 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -25,8 +25,16 @@
 #include <C2BufferPriv.h>
 #include <C2BlockInternal.h>
 
+#include <ClientManager.h>
+
 namespace {
 
+using android::hardware::media::bufferpool::V1_0::ResultStatus;
+using android::hardware::media::bufferpool::V1_0::implementation::BufferPoolAllocation;
+using android::hardware::media::bufferpool::V1_0::implementation::BufferPoolAllocator;
+using android::hardware::media::bufferpool::V1_0::implementation::ClientManager;
+using android::hardware::media::bufferpool::V1_0::implementation::ConnectionId;
+
 // This anonymous namespace contains the helper classes that allow our implementation to create
 // block/buffer objects.
 //
@@ -341,6 +349,257 @@
     return std::shared_ptr<C2LinearBlock>(new C2LinearBlock(impl, *impl));
 }
 
+/**
+ * Wrapped C2Allocator which is injected to buffer pool on behalf of
+ * C2BlockPool.
+ */
+class _C2BufferPoolAllocator : public BufferPoolAllocator {
+public:
+    _C2BufferPoolAllocator(const std::shared_ptr<C2Allocator> &allocator)
+        : mAllocator(allocator) {}
+
+    ~_C2BufferPoolAllocator() override {}
+
+    ResultStatus allocate(const std::vector<uint8_t> &params,
+                          std::shared_ptr<BufferPoolAllocation> *alloc) override;
+
+    bool compatible(const std::vector<uint8_t> &newParams,
+                    const std::vector<uint8_t> &oldParams) override;
+
+    // Methods for codec2 component (C2BlockPool).
+    /**
+     * Transforms linear allocation parameters for C2Allocator to parameters
+     * for buffer pool.
+     *
+     * @param capacity      size of linear allocation
+     * @param usage         memory usage pattern for linear allocation
+     * @param params        allocation parameters for buffer pool
+     */
+    void getLinearParams(uint32_t capacity, C2MemoryUsage usage,
+                         std::vector<uint8_t> *params);
+
+    /**
+     * Transforms graphic allocation parameters for C2Allocator to parameters
+     * for buffer pool.
+     *
+     * @param width         width of graphic allocation
+     * @param height        height of graphic allocation
+     * @param format        color format of graphic allocation
+     * @param params        allocation parameter for buffer pool
+     */
+    void getGraphicParams(uint32_t width, uint32_t height,
+                          uint32_t format, C2MemoryUsage usage,
+                          std::vector<uint8_t> *params);
+
+    /**
+     * Transforms an existing native handle to an C2LinearAllcation.
+     * Wrapper to C2Allocator#priorLinearAllocation
+     */
+    c2_status_t priorLinearAllocation(
+            const C2Handle *handle,
+            std::shared_ptr<C2LinearAllocation> *c2Allocation);
+
+    /**
+     * Transforms an existing native handle to an C2GraphicAllcation.
+     * Wrapper to C2Allocator#priorGraphicAllocation
+     */
+    c2_status_t priorGraphicAllocation(
+            const C2Handle *handle,
+            std::shared_ptr<C2GraphicAllocation> *c2Allocation);
+
+private:
+    static constexpr int kMaxIntParams = 5; // large enough number;
+
+    enum AllocType : uint8_t {
+        ALLOC_NONE = 0,
+
+        ALLOC_LINEAR,
+        ALLOC_GRAPHIC,
+    };
+
+    union AllocParams {
+        struct {
+            AllocType allocType;
+            C2MemoryUsage usage;
+            uint32_t params[kMaxIntParams];
+        } data;
+        uint8_t array[0];
+
+        AllocParams() : data{ALLOC_NONE, {0, 0}, {0}} {}
+        AllocParams(C2MemoryUsage usage, uint32_t capacity)
+            : data{ALLOC_LINEAR, usage, {[0] = capacity}} {}
+        AllocParams(
+                C2MemoryUsage usage,
+                uint32_t width, uint32_t height, uint32_t format)
+                : data{ALLOC_GRAPHIC, usage, {width, height, format}} {}
+    };
+
+    const std::shared_ptr<C2Allocator> mAllocator;
+};
+
+struct LinearAllocationDtor {
+    LinearAllocationDtor(const std::shared_ptr<C2LinearAllocation> &alloc)
+        : mAllocation(alloc) {}
+
+    void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
+
+    const std::shared_ptr<C2LinearAllocation> mAllocation;
+};
+
+ResultStatus _C2BufferPoolAllocator::allocate(
+        const std::vector<uint8_t>  &params,
+        std::shared_ptr<BufferPoolAllocation> *alloc) {
+    AllocParams c2Params;
+    memcpy(&c2Params, params.data(), std::min(sizeof(AllocParams), params.size()));
+    std::shared_ptr<C2LinearAllocation> c2Linear;
+    c2_status_t status = C2_BAD_VALUE;
+    switch(c2Params.data.allocType) {
+        case ALLOC_NONE:
+            break;
+        case ALLOC_LINEAR:
+            status = mAllocator->newLinearAllocation(
+                    c2Params.data.params[0], c2Params.data.usage, &c2Linear);
+            if (status == C2_OK && c2Linear) {
+                BufferPoolAllocation *ptr = new BufferPoolAllocation(c2Linear->handle());
+                if (ptr) {
+                    *alloc = std::shared_ptr<BufferPoolAllocation>(
+                            ptr, LinearAllocationDtor(c2Linear));
+                    if (*alloc) {
+                        return ResultStatus::OK;
+                    }
+                    delete ptr;
+                }
+                return ResultStatus::NO_MEMORY;
+            }
+            break;
+        case ALLOC_GRAPHIC:
+            // TODO
+            break;
+        default:
+            break;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+bool _C2BufferPoolAllocator::compatible(
+        const std::vector<uint8_t>  &newParams,
+        const std::vector<uint8_t>  &oldParams) {
+    size_t newSize = newParams.size();
+    size_t oldSize = oldParams.size();
+
+    // TODO: support not exact matching. e.g) newCapacity < oldCapacity
+    if (newSize == oldSize) {
+        for (size_t i = 0; i < newSize; ++i) {
+            if (newParams[i] != oldParams[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+    return false;
+}
+
+void _C2BufferPoolAllocator::getLinearParams(
+        uint32_t capacity, C2MemoryUsage usage, std::vector<uint8_t> *params) {
+    AllocParams c2Params(usage, capacity);
+    params->assign(c2Params.array, c2Params.array + sizeof(AllocParams));
+}
+
+void _C2BufferPoolAllocator::getGraphicParams(
+        uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+        std::vector<uint8_t> *params) {
+    AllocParams c2Params(usage, width, height, format);
+    params->assign(c2Params.array, c2Params.array + sizeof(AllocParams));
+}
+
+c2_status_t _C2BufferPoolAllocator::priorLinearAllocation(
+        const C2Handle *handle,
+        std::shared_ptr<C2LinearAllocation> *c2Allocation) {
+    return mAllocator->priorLinearAllocation(handle, c2Allocation);
+}
+
+c2_status_t _C2BufferPoolAllocator::priorGraphicAllocation(
+        const C2Handle *handle,
+        std::shared_ptr<C2GraphicAllocation> *c2Allocation) {
+    return mAllocator->priorGraphicAllocation(handle, c2Allocation);
+}
+
+class C2PooledBlockPool::Impl {
+public:
+    Impl(const std::shared_ptr<C2Allocator> &allocator)
+            : mInit(C2_OK),
+              mBufferPoolManager(ClientManager::getInstance()),
+              mAllocator(std::make_shared<_C2BufferPoolAllocator>(allocator)) {
+        if (mAllocator && mBufferPoolManager) {
+            if (mBufferPoolManager->create(
+                    mAllocator, &mConnectionId) == ResultStatus::OK) {
+                return;
+            }
+        }
+        mInit = C2_NO_INIT;
+    }
+
+    ~Impl() {
+        if (mInit == C2_OK) {
+            mBufferPoolManager->close(mConnectionId);
+        }
+    }
+
+    c2_status_t fetchLinearBlock(
+            uint32_t capacity, C2MemoryUsage usage,
+            std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+        block->reset();
+        if (mInit != C2_OK) {
+            return mInit;
+        }
+        std::vector<uint8_t> params;
+        mAllocator->getLinearParams(capacity, usage, &params);
+        std::shared_ptr<_C2BlockPoolData> poolData;
+        ResultStatus status = mBufferPoolManager->allocate(
+                mConnectionId, params, &poolData);
+        if (status == ResultStatus::OK) {
+            std::shared_ptr<C2LinearAllocation> alloc;
+            c2_status_t err = mAllocator->priorLinearAllocation(
+                    poolData->mHandle, &alloc);
+            if (err == C2_OK && poolData && alloc) {
+                *block = _C2BlockFactory::CreateLinearBlock(
+                        alloc, poolData, 0, capacity);
+                if (*block) {
+                    return C2_OK;
+                }
+            }
+            return C2_NO_MEMORY;
+        }
+        if (status == ResultStatus::NO_MEMORY) {
+            return C2_NO_MEMORY;
+        }
+        return C2_CORRUPTED;
+    }
+
+private:
+    c2_status_t mInit;
+    const android::sp<ClientManager> mBufferPoolManager;
+    ConnectionId mConnectionId; // locally
+    const std::shared_ptr<_C2BufferPoolAllocator> mAllocator;
+};
+
+C2PooledBlockPool::C2PooledBlockPool(
+        const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId)
+        : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {}
+
+C2PooledBlockPool::~C2PooledBlockPool() {
+}
+
+c2_status_t C2PooledBlockPool::fetchLinearBlock(
+        uint32_t capacity,
+        C2MemoryUsage usage,
+        std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+    if (mImpl) {
+        return mImpl->fetchLinearBlock(capacity, usage, block);
+    }
+    return C2_CORRUPTED;
+}
+
 /* ========================================== 2D BLOCK ========================================= */
 
 /**
diff --git a/media/libstagefright/codec2/vndk/C2Store.cpp b/media/libstagefright/codec2/vndk/C2Store.cpp
index 216a897..6f752ae 100644
--- a/media/libstagefright/codec2/vndk/C2Store.cpp
+++ b/media/libstagefright/codec2/vndk/C2Store.cpp
@@ -152,6 +152,39 @@
     return res;
 }
 
+c2_status_t CreateCodec2BlockPool(
+        C2PlatformAllocatorStore::id_t allocatorId,
+        std::shared_ptr<const C2Component> component,
+        std::shared_ptr<C2BlockPool> *pool) {
+    pool->reset();
+    if (!component) {
+        return C2_BAD_VALUE;
+    }
+    // TODO: support caching block pool along with GetCodec2BlockPool.
+    static std::atomic_int sBlockPoolId(C2BlockPool::PLATFORM_START);
+    std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
+    std::shared_ptr<C2Allocator> allocator;
+    c2_status_t res = C2_NOT_FOUND;
+
+    switch (allocatorId) {
+    case C2PlatformAllocatorStore::ION:
+        res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
+        if (res == C2_OK) {
+            *pool = std::make_shared<C2PooledBlockPool>(allocator, sBlockPoolId++);
+            if (!*pool) {
+                res = C2_NO_MEMORY;
+            }
+        }
+        break;
+    case C2PlatformAllocatorStore::GRALLOC:
+        // TODO: support gralloc
+        break;
+    default:
+        break;
+    }
+    return res;
+}
+
 class C2PlatformComponentStore : public C2ComponentStore {
 public:
     virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override;
diff --git a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
index 977cf7b..211c13a 100644
--- a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
+++ b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
@@ -71,4 +71,32 @@
     const std::shared_ptr<C2Allocator> mAllocator;
 };
 
+class C2PooledBlockPool : public C2BlockPool {
+public:
+    C2PooledBlockPool(const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId);
+
+    virtual ~C2PooledBlockPool() override;
+
+    virtual C2Allocator::id_t getAllocatorId() const override {
+        return mAllocator->getId();
+    }
+
+    virtual local_id_t getLocalId() const override {
+        return mLocalId;
+    }
+
+    virtual c2_status_t fetchLinearBlock(
+            uint32_t capacity,
+            C2MemoryUsage usage,
+            std::shared_ptr<C2LinearBlock> *block /* nonnull */) override;
+
+    // TODO: fetchGraphicBlock, fetchCircularBlock
+private:
+    const std::shared_ptr<C2Allocator> mAllocator;
+    const local_id_t mLocalId;
+
+    class Impl;
+    std::unique_ptr<Impl> mImpl;
+};
+
 #endif // STAGEFRIGHT_CODEC2_BUFFER_PRIV_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
index afa51ee..211ee0c 100644
--- a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
+++ b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
@@ -82,6 +82,23 @@
         std::shared_ptr<C2BlockPool> *pool);
 
 /**
+ * Creates a block pool.
+ * \param allocatorId  the allocator ID which is used to allocate blocks
+ * \param component     the component using the block pool (must be non-null)
+ * \param pool          pointer to where the created block pool shall be store on success.
+ *                      nullptr will be stored here on failure
+ *
+ * \retval C2_OK        the operation was successful
+ * \retval C2_BAD_VALUE the component is null
+ * \retval C2_NOT_FOUND if the allocator does not exist
+ * \retval C2_NO_MEMORY not enough memory to create a block pool
+ */
+c2_status_t CreateCodec2BlockPool(
+        C2PlatformAllocatorStore::id_t allocatorId,
+        std::shared_ptr<const C2Component> component,
+        std::shared_ptr<C2BlockPool> *pool);
+
+/**
  * Returns the platform component store.
  * \retval nullptr if the platform component store could not be obtained
  */
diff --git a/media/libstagefright/codecs/cmds/codec2.cpp b/media/libstagefright/codecs/cmds/codec2.cpp
index 0ec1a77..5558bcf 100644
--- a/media/libstagefright/codecs/cmds/codec2.cpp
+++ b/media/libstagefright/codecs/cmds/codec2.cpp
@@ -93,6 +93,8 @@
 
     sp<IProducerListener> mProducerListener;
 
+    std::atomic_int mLinearPoolId;
+
     std::shared_ptr<C2Allocator> mAllocIon;
     std::shared_ptr<C2BlockPool> mLinearPool;
 
@@ -137,12 +139,13 @@
 SimplePlayer::SimplePlayer()
     : mListener(new Listener(this)),
       mProducerListener(new DummyProducerListener),
+      mLinearPoolId(C2BlockPool::PLATFORM_START),
       mComposerClient(new SurfaceComposerClient) {
     CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
 
     std::shared_ptr<C2AllocatorStore> store = GetCodec2PlatformAllocatorStore();
     CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mAllocIon), C2_OK);
-    mLinearPool = std::make_shared<C2BasicLinearBlockPool>(mAllocIon);
+    mLinearPool = std::make_shared<C2PooledBlockPool>(mAllocIon, mLinearPoolId++);
 
     mControl = mComposerClient->createSurface(
             String8("A Surface"),
@@ -284,7 +287,7 @@
     });
 
     long numFrames = 0;
-    mLinearPool.reset(new C2BasicLinearBlockPool(mAllocIon));
+    mLinearPool.reset(new C2PooledBlockPool(mAllocIon, mLinearPoolId++));
 
     for (;;) {
         size_t size = 0u;
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index abcaa0a..9bf450c 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -286,7 +286,13 @@
 EXPORT const char* AMEDIAFORMAT_KEY_COLOR_STANDARD = "color-standard";
 EXPORT const char* AMEDIAFORMAT_KEY_COLOR_TRANSFER = "color-transfer";
 EXPORT const char* AMEDIAFORMAT_KEY_COMPLEXITY = "complexity";
+EXPORT const char* AMEDIAFORMAT_KEY_CSD = "csd";
+EXPORT const char* AMEDIAFORMAT_KEY_CSD_0 = "csd-0";
+EXPORT const char* AMEDIAFORMAT_KEY_CSD_1 = "csd-1";
+EXPORT const char* AMEDIAFORMAT_KEY_CSD_2 = "csd-2";
 EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_CROP = "crop";
+EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_HEIGHT = "display-height";
+EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_WIDTH = "display-width";
 EXPORT const char* AMEDIAFORMAT_KEY_DURATION = "durationUs";
 EXPORT const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
 EXPORT const char* AMEDIAFORMAT_KEY_FRAME_RATE = "frame-rate";
@@ -323,6 +329,7 @@
 EXPORT const char* AMEDIAFORMAT_KEY_STRIDE = "stride";
 EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID = "temporal-layer-id";
 EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYERING = "ts-schema";
+EXPORT const char* AMEDIAFORMAT_KEY_TIME_US = "timeUs";
 EXPORT const char* AMEDIAFORMAT_KEY_TRACK_ID = "track-id";
 EXPORT const char* AMEDIAFORMAT_KEY_TRACK_INDEX = "track-index";
 EXPORT const char* AMEDIAFORMAT_KEY_WIDTH = "width";
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 464c127..1da9197 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -100,7 +100,13 @@
 extern const char* AMEDIAFORMAT_KEY_COLOR_STANDARD;
 extern const char* AMEDIAFORMAT_KEY_COLOR_TRANSFER;
 extern const char* AMEDIAFORMAT_KEY_COMPLEXITY;
+extern const char* AMEDIAFORMAT_KEY_CSD;
+extern const char* AMEDIAFORMAT_KEY_CSD_0;
+extern const char* AMEDIAFORMAT_KEY_CSD_1;
+extern const char* AMEDIAFORMAT_KEY_CSD_2;
 extern const char* AMEDIAFORMAT_KEY_DISPLAY_CROP;
+extern const char* AMEDIAFORMAT_KEY_DISPLAY_HEIGHT;
+extern const char* AMEDIAFORMAT_KEY_DISPLAY_WIDTH;
 extern const char* AMEDIAFORMAT_KEY_DURATION;
 extern const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL;
 extern const char* AMEDIAFORMAT_KEY_FRAME_RATE;
@@ -137,6 +143,7 @@
 extern const char* AMEDIAFORMAT_KEY_STRIDE;
 extern const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID;
 extern const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYERING;
+extern const char* AMEDIAFORMAT_KEY_TIME_US;
 extern const char* AMEDIAFORMAT_KEY_TRACK_ID;
 extern const char* AMEDIAFORMAT_KEY_TRACK_INDEX;
 extern const char* AMEDIAFORMAT_KEY_WIDTH;
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index 1940953..69febc2 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -75,6 +75,13 @@
     static final String KEY_STATE_IS_ADVERTISEMENT = "MediaTypeAdvertisement";
     static final String EVENT_UPDATE_MEDIA_TYPE_STATUS = "UpdateMediaTypeStatus";
 
+    // String for receiving command to show subtitle from MediaSession.
+    static final String COMMAND_SHOW_SUBTITLE = "showSubtitle";
+    // String for receiving command to hide subtitle from MediaSession.
+    static final String COMMAND_HIDE_SUBTITLE = "hideSubtitle";
+    // TODO: remove once the implementation is revised
+    public static final String COMMAND_SET_FULLSCREEN = "setFullscreen";
+
     private static final int MAX_PROGRESS = 1000;
     private static final int DEFAULT_PROGRESS_UPDATE_TIME_MS = 1000;
     private static final int REWIND_TIME_MS = 10000;
@@ -743,12 +750,12 @@
             if (!mSubtitleIsEnabled) {
                 mSubtitleButton.setImageDrawable(
                         mResources.getDrawable(R.drawable.ic_media_subtitle_enabled, null));
-                mController.sendCommand(MediaControlView2.COMMAND_SHOW_SUBTITLE, null, null);
+                mController.sendCommand(MediaControlView2Impl.COMMAND_SHOW_SUBTITLE, null, null);
                 mSubtitleIsEnabled = true;
             } else {
                 mSubtitleButton.setImageDrawable(
                         mResources.getDrawable(R.drawable.ic_media_subtitle_disabled, null));
-                mController.sendCommand(MediaControlView2.COMMAND_HIDE_SUBTITLE, null, null);
+                mController.sendCommand(MediaControlView2Impl.COMMAND_HIDE_SUBTITLE, null, null);
                 mSubtitleIsEnabled = false;
             }
         }
@@ -768,7 +775,7 @@
             }
             Bundle args = new Bundle();
             args.putBoolean(ARGUMENT_KEY_FULLSCREEN, isEnteringFullScreen);
-            mController.sendCommand(MediaControlView2.COMMAND_SET_FULLSCREEN, args, null);
+            mController.sendCommand(MediaControlView2Impl.COMMAND_SET_FULLSCREEN, args, null);
 
             mIsFullScreen = isEnteringFullScreen;
         }
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index d23395c..c3ca057 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -1001,13 +1001,13 @@
                 mRouteSessionCallback.onCommand(command, args, receiver);
             } else {
                 switch (command) {
-                    case MediaControlView2.COMMAND_SHOW_SUBTITLE:
+                    case MediaControlView2Impl.COMMAND_SHOW_SUBTITLE:
                         mInstance.setSubtitleEnabled(true);
                         break;
-                    case MediaControlView2.COMMAND_HIDE_SUBTITLE:
+                    case MediaControlView2Impl.COMMAND_HIDE_SUBTITLE:
                         mInstance.setSubtitleEnabled(false);
                         break;
-                    case MediaControlView2.COMMAND_SET_FULLSCREEN:
+                    case MediaControlView2Impl.COMMAND_SET_FULLSCREEN:
                         if (mFullScreenRequestListener != null) {
                             mFullScreenRequestListener.onFullScreenRequest(
                                     mInstance,