Merge "Add onExpirationUpdate and onKeyStatusChange listeners."
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index c908323..ac3be25 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -1290,16 +1290,21 @@
         }
         default:
             ALOGE("Unknown error from camera device: %d", errorCode);
-            // no break
+            [[fallthrough]];
         case ERROR_CAMERA_DEVICE:
         case ERROR_CAMERA_SERVICE:
         {
+            int32_t errorVal = ::ERROR_CAMERA_DEVICE;
+            // We keep this switch since this block might be encountered with
+            // more than just 2 states. The default fallthrough could have us
+            // handling more unmatched error cases.
             switch (errorCode) {
                 case ERROR_CAMERA_DEVICE:
                     dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
                     break;
                 case ERROR_CAMERA_SERVICE:
                     dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+                    errorVal = ::ERROR_CAMERA_SERVICE;
                     break;
                 default:
                     dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_UNKNOWN);
@@ -1309,7 +1314,7 @@
             msg->setPointer(kContextKey, dev->mAppCallbacks.context);
             msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
             msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onError);
-            msg->setInt32(kErrorCodeKey, errorCode);
+            msg->setInt32(kErrorCodeKey, errorVal);
             msg->post();
             break;
         }
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 1b8e8d9..7d3fbea 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -58,7 +58,36 @@
 #include "Overlay.h"
 #include "FrameOutput.h"
 
-using namespace android;
+using android::ABuffer;
+using android::ALooper;
+using android::AMessage;
+using android::AString;
+using android::DisplayInfo;
+using android::FrameOutput;
+using android::IBinder;
+using android::IGraphicBufferProducer;
+using android::ISurfaceComposer;
+using android::MediaCodec;
+using android::MediaCodecBuffer;
+using android::MediaMuxer;
+using android::Overlay;
+using android::PersistentSurface;
+using android::ProcessState;
+using android::Rect;
+using android::String8;
+using android::SurfaceComposerClient;
+using android::Vector;
+using android::sp;
+using android::status_t;
+
+using android::DISPLAY_ORIENTATION_0;
+using android::DISPLAY_ORIENTATION_180;
+using android::DISPLAY_ORIENTATION_90;
+using android::INFO_FORMAT_CHANGED;
+using android::INFO_OUTPUT_BUFFERS_CHANGED;
+using android::INVALID_OPERATION;
+using android::NO_ERROR;
+using android::UNKNOWN_ERROR;
 
 static const uint32_t kMinBitRate = 100000;         // 0.1Mbps
 static const uint32_t kMaxBitRate = 200 * 1000000;  // 200Mbps
diff --git a/include/media/VorbisComment.h b/include/media/VorbisComment.h
deleted file mode 120000
index adaa489..0000000
--- a/include/media/VorbisComment.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmediaextractor/include/media/VorbisComment.h
\ No newline at end of file
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
index 6282793..eda7b61 100644
--- a/media/extractors/flac/Android.bp
+++ b/media/extractors/flac/Android.bp
@@ -10,11 +10,14 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
     ],
 
     static_libs: [
         "libFLAC",
         "libstagefright_foundation",
+        "libstagefright_metadatautils",
+        "libutils",
     ],
 
     name: "libflacextractor",
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index 337ada5..fcfdaff 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -25,7 +25,7 @@
 #include "FLAC/stream_decoder.h"
 
 #include <media/MediaExtractorPluginApi.h>
-#include <media/VorbisComment.h>
+#include <media/NdkMediaFormat.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/base64.h>
@@ -33,24 +33,25 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/MetaDataUtils.h>
 #include <media/stagefright/MediaBufferBase.h>
 
 namespace android {
 
 class FLACParser;
 
-class FLACSource : public MediaTrackHelper {
+class FLACSource : public MediaTrackHelperV2 {
 
 public:
     FLACSource(
             DataSourceHelper *dataSource,
-            MetaDataBase &meta);
+            AMediaFormat *meta);
 
-    virtual status_t start();
-    virtual status_t stop();
-    virtual status_t getFormat(MetaDataBase &meta);
+    virtual media_status_t start();
+    virtual media_status_t stop();
+    virtual media_status_t getFormat(AMediaFormat *meta);
 
-    virtual status_t read(
+    virtual media_status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
@@ -58,7 +59,7 @@
 
 private:
     DataSourceHelper *mDataSource;
-    MetaDataBase mTrackMetadata;
+    AMediaFormat *mTrackMetadata;
     FLACParser *mParser;
     bool mInitCheck;
     bool mStarted;
@@ -81,8 +82,8 @@
     explicit FLACParser(
         DataSourceHelper *dataSource,
         // If metadata pointers aren't provided, we don't fill them
-        MetaDataBase *fileMetadata = 0,
-        MetaDataBase *trackMetadata = 0);
+        AMediaFormat *fileMetadata = 0,
+        AMediaFormat *trackMetadata = 0);
 
     virtual ~FLACParser();
 
@@ -119,8 +120,8 @@
 
 private:
     DataSourceHelper *mDataSource;
-    MetaDataBase *mFileMetadata;
-    MetaDataBase *mTrackMetadata;
+    AMediaFormat *mFileMetadata;
+    AMediaFormat *mTrackMetadata;
     bool mInitCheck;
 
     // media buffers
@@ -364,9 +365,8 @@
     case FLAC__METADATA_TYPE_PICTURE:
         if (mFileMetadata != 0) {
             const FLAC__StreamMetadata_Picture *p = &metadata->data.picture;
-            mFileMetadata->setData(kKeyAlbumArt,
-                    MetaData::TYPE_NONE, p->data, p->data_length);
-            mFileMetadata->setCString(kKeyAlbumArtMIME, p->mime_type);
+            AMediaFormat_setBuffer(mFileMetadata, AMEDIAFORMAT_KEY_ALBUMART,
+                   p->data, p->data_length);
         }
         break;
     default:
@@ -488,8 +488,8 @@
 
 FLACParser::FLACParser(
         DataSourceHelper *dataSource,
-        MetaDataBase *fileMetadata,
-        MetaDataBase *trackMetadata)
+        AMediaFormat *fileMetadata,
+        AMediaFormat *trackMetadata)
     : mDataSource(dataSource),
       mFileMetadata(fileMetadata),
       mTrackMetadata(trackMetadata),
@@ -615,20 +615,25 @@
         }
         // populate track metadata
         if (mTrackMetadata != 0) {
-            mTrackMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-            mTrackMetadata->setInt32(kKeyChannelCount, getChannels());
-            mTrackMetadata->setInt32(kKeySampleRate, getSampleRate());
-            mTrackMetadata->setInt32(kKeyPcmEncoding, kAudioEncodingPcm16bit);
+            AMediaFormat_setString(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
+            AMediaFormat_setInt32(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_CHANNEL_COUNT, getChannels());
+            AMediaFormat_setInt32(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_SAMPLE_RATE, getSampleRate());
+            AMediaFormat_setInt32(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_PCM_ENCODING, kAudioEncodingPcm16bit);
             // sample rate is non-zero, so division by zero not possible
-            mTrackMetadata->setInt64(kKeyDuration,
-                    (getTotalSamples() * 1000000LL) / getSampleRate());
+            AMediaFormat_setInt64(mTrackMetadata,
+                    AMEDIAFORMAT_KEY_DURATION, (getTotalSamples() * 1000000LL) / getSampleRate());
         }
     } else {
         ALOGE("missing STREAMINFO");
         return NO_INIT;
     }
     if (mFileMetadata != 0) {
-        mFileMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_FLAC);
+        AMediaFormat_setString(mFileMetadata,
+                AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_FLAC);
     }
     return OK;
 }
@@ -709,7 +714,7 @@
 
 FLACSource::FLACSource(
         DataSourceHelper *dataSource,
-        MetaDataBase &trackMetadata)
+        AMediaFormat *trackMetadata)
     : mDataSource(dataSource),
       mTrackMetadata(trackMetadata),
       mParser(0),
@@ -731,7 +736,7 @@
     delete mParser;
 }
 
-status_t FLACSource::start()
+media_status_t FLACSource::start()
 {
     ALOGV("FLACSource::start");
 
@@ -739,10 +744,10 @@
     mParser->allocateBuffers();
     mStarted = true;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t FLACSource::stop()
+media_status_t FLACSource::stop()
 {
     ALOGV("FLACSource::stop");
 
@@ -750,16 +755,15 @@
     mParser->releaseBuffers();
     mStarted = false;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t FLACSource::getFormat(MetaDataBase &meta)
+media_status_t FLACSource::getFormat(AMediaFormat *meta)
 {
-    meta = mTrackMetadata;
-    return OK;
+    return AMediaFormat_copy(meta, mTrackMetadata);
 }
 
-status_t FLACSource::read(
+media_status_t FLACSource::read(
         MediaBufferBase **outBuffer, const ReadOptions *options)
 {
     MediaBufferBase *buffer;
@@ -783,7 +787,7 @@
         buffer = mParser->readBuffer();
     }
     *outBuffer = buffer;
-    return buffer != NULL ? (status_t) OK : (status_t) ERROR_END_OF_STREAM;
+    return buffer != NULL ? AMEDIA_OK : AMEDIA_ERROR_END_OF_STREAM;
 }
 
 // FLACExtractor
@@ -796,7 +800,9 @@
 {
     ALOGV("FLACExtractor::FLACExtractor");
     // FLACParser will fill in the metadata for us
-    mParser = new FLACParser(mDataSource, &mFileMetadata, &mTrackMetadata);
+    mFileMetadata = AMediaFormat_new();
+    mTrackMetadata = AMediaFormat_new();
+    mParser = new FLACParser(mDataSource, mFileMetadata, mTrackMetadata);
     mInitCheck = mParser->initCheck();
 }
 
@@ -805,6 +811,8 @@
     ALOGV("~FLACExtractor::FLACExtractor");
     delete mParser;
     delete mDataSource;
+    AMediaFormat_delete(mFileMetadata);
+    AMediaFormat_delete(mTrackMetadata);
 }
 
 size_t FLACExtractor::countTracks()
@@ -812,7 +820,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-MediaTrackHelper *FLACExtractor::getTrack(size_t index)
+MediaTrackHelperV2 *FLACExtractor::getTrack(size_t index)
 {
     if (mInitCheck != OK || index > 0) {
         return NULL;
@@ -820,20 +828,18 @@
     return new FLACSource(mDataSource, mTrackMetadata);
 }
 
-status_t FLACExtractor::getTrackMetaData(
-        MetaDataBase &meta,
+media_status_t FLACExtractor::getTrackMetaData(
+        AMediaFormat *meta,
         size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index > 0) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
-    meta = mTrackMetadata;
-    return OK;
+    return AMediaFormat_copy(meta, mTrackMetadata);
 }
 
-status_t FLACExtractor::getMetaData(MetaDataBase &meta)
+media_status_t FLACExtractor::getMetaData(AMediaFormat *meta)
 {
-    meta = mFileMetadata;
-    return OK;
+    return AMediaFormat_copy(meta, mFileMetadata);
 }
 
 // Sniffer
@@ -862,22 +868,22 @@
 __attribute__ ((visibility ("default")))
 ExtractorDef GETEXTRACTORDEF() {
     return {
-        EXTRACTORDEF_VERSION,
+            EXTRACTORDEF_VERSION_CURRENT,
             UUID("1364b048-cc45-4fda-9934-327d0ebf9829"),
             1,
             "FLAC Extractor",
             {
-                [](
+                .v2 = [](
                         CDataSource *source,
                         float *confidence,
                         void **,
-                        FreeMetaFunc *) -> CreatorFunc {
+                        FreeMetaFunc *) -> CreatorFuncV2 {
                     DataSourceHelper helper(source);
                     if (SniffFLAC(&helper, confidence)) {
                         return [](
                                 CDataSource *source,
-                                void *) -> CMediaExtractor* {
-                            return wrap(new FLACExtractor(new DataSourceHelper(source)));};
+                                void *) -> CMediaExtractorV2* {
+                            return wrapV2(new FLACExtractor(new DataSourceHelper(source)));};
                     }
                     return NULL;
                 }
diff --git a/media/extractors/flac/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
index 829f661..323307b 100644
--- a/media/extractors/flac/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -20,23 +20,23 @@
 #include <media/DataSourceBase.h>
 #include <media/MediaExtractorPluginApi.h>
 #include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
 #include <utils/String8.h>
 
 namespace android {
 
 class FLACParser;
 
-class FLACExtractor : public MediaExtractorPluginHelper {
+class FLACExtractor : public MediaExtractorPluginHelperV2 {
 
 public:
     explicit FLACExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
-    virtual MediaTrackHelper *getTrack(size_t index);
-    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+    virtual MediaTrackHelperV2 *getTrack(size_t index);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "FLACExtractor"; }
 
 protected:
@@ -46,10 +46,10 @@
     DataSourceHelper *mDataSource;
     FLACParser *mParser;
     status_t mInitCheck;
-    MetaDataBase mFileMetadata;
+    AMediaFormat *mFileMetadata;
 
     // There is only one track
-    MetaDataBase mTrackMetadata;
+    AMediaFormat *mTrackMetadata;
 
     FLACExtractor(const FLACExtractor &);
     FLACExtractor &operator=(const FLACExtractor &);
diff --git a/media/extractors/mp3/Android.bp b/media/extractors/mp3/Android.bp
index a3aeaca..1025c46 100644
--- a/media/extractors/mp3/Android.bp
+++ b/media/extractors/mp3/Android.bp
@@ -13,6 +13,7 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
         "libstagefright_foundation",
     ],
 
diff --git a/media/extractors/mp3/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
index eca5711..621fd03 100644
--- a/media/extractors/mp3/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -207,19 +207,19 @@
     return valid;
 }
 
-class MP3Source : public MediaTrackHelper {
+class MP3Source : public MediaTrackHelperV2 {
 public:
     MP3Source(
-            MetaDataBase &meta, DataSourceHelper *source,
+            AMediaFormat *meta, DataSourceHelper *source,
             off64_t first_frame_pos, uint32_t fixed_header,
             MP3Seeker *seeker);
 
-    virtual status_t start();
-    virtual status_t stop();
+    virtual media_status_t start();
+    virtual media_status_t stop();
 
-    virtual status_t getFormat(MetaDataBase &meta);
+    virtual media_status_t getFormat(AMediaFormat *meta);
 
-    virtual status_t read(
+    virtual media_status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
@@ -227,7 +227,7 @@
 
 private:
     static const size_t kMaxFrameSize;
-    MetaDataBase &mMeta;
+    AMediaFormat *mMeta;
     DataSourceHelper *mDataSource;
     off64_t mFirstFramePos;
     uint32_t mFixedHeader;
@@ -283,6 +283,7 @@
     mFixedHeader = header;
     XINGSeeker *seeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos);
 
+    mMeta = AMediaFormat_new();
     if (seeker == NULL) {
         mSeeker = VBRISeeker::CreateFromSource(mDataSource, post_id3_pos);
     } else {
@@ -290,8 +291,8 @@
         int encd = seeker->getEncoderDelay();
         int encp = seeker->getEncoderPadding();
         if (encd != 0 || encp != 0) {
-            mMeta.setInt32(kKeyEncoderDelay, encd);
-            mMeta.setInt32(kKeyEncoderPadding, encp);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_DELAY, encd);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_PADDING, encp);
         }
     }
 
@@ -327,21 +328,23 @@
 
     switch (layer) {
         case 1:
-            mMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
+            AMediaFormat_setString(mMeta,
+                    AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
             break;
         case 2:
-            mMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+            AMediaFormat_setString(mMeta,
+                    AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
             break;
         case 3:
-            mMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+            AMediaFormat_setString(mMeta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG);
             break;
         default:
             TRESPASS();
     }
 
-    mMeta.setInt32(kKeySampleRate, sample_rate);
-    mMeta.setInt32(kKeyBitRate, bitrate * 1000);
-    mMeta.setInt32(kKeyChannelCount, num_channels);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, sample_rate);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_BIT_RATE, bitrate * 1000);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, num_channels);
 
     int64_t durationUs;
 
@@ -361,7 +364,7 @@
     }
 
     if (durationUs >= 0) {
-        mMeta.setInt64(kKeyDuration, durationUs);
+        AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, durationUs);
     }
 
     mInitCheck = OK;
@@ -389,8 +392,8 @@
 
                 int32_t delay, padding;
                 if (sscanf(value, " %*x %x %x %*x", &delay, &padding) == 2) {
-                    mMeta.setInt32(kKeyEncoderDelay, delay);
-                    mMeta.setInt32(kKeyEncoderPadding, padding);
+                    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_DELAY, delay);
+                    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_ENCODER_PADDING, padding);
                 }
                 break;
             }
@@ -404,13 +407,14 @@
 MP3Extractor::~MP3Extractor() {
     delete mSeeker;
     delete mDataSource;
+    AMediaFormat_delete(mMeta);
 }
 
 size_t MP3Extractor::countTracks() {
     return mInitCheck != OK ? 0 : 1;
 }
 
-MediaTrackHelper *MP3Extractor::getTrack(size_t index) {
+MediaTrackHelperV2 *MP3Extractor::getTrack(size_t index) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -420,14 +424,14 @@
             mSeeker);
 }
 
-status_t MP3Extractor::getTrackMetaData(
-        MetaDataBase &meta,
+media_status_t MP3Extractor::getTrackMetaData(
+        AMediaFormat *meta,
         size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index != 0) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
-    meta = mMeta;
-    return OK;
+    AMediaFormat_copy(meta, mMeta);
+    return AMEDIA_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -440,7 +444,7 @@
 // Set our max frame size to the nearest power of 2 above this size (aka, 4kB)
 const size_t MP3Source::kMaxFrameSize = (1 << 12); /* 4096 bytes */
 MP3Source::MP3Source(
-        MetaDataBase &meta, DataSourceHelper *source,
+        AMediaFormat *meta, DataSourceHelper *source,
         off64_t first_frame_pos, uint32_t fixed_header,
         MP3Seeker *seeker)
     : mMeta(meta),
@@ -462,7 +466,7 @@
     }
 }
 
-status_t MP3Source::start() {
+media_status_t MP3Source::start() {
     CHECK(!mStarted);
 
     mGroup = new MediaBufferGroup;
@@ -477,10 +481,10 @@
 
     mStarted = true;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MP3Source::stop() {
+media_status_t MP3Source::stop() {
     CHECK(mStarted);
 
     delete mGroup;
@@ -488,15 +492,14 @@
 
     mStarted = false;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MP3Source::getFormat(MetaDataBase &meta) {
-    meta = mMeta;
-    return OK;
+media_status_t MP3Source::getFormat(AMediaFormat *meta) {
+    return AMediaFormat_copy(meta, mMeta);
 }
 
-status_t MP3Source::read(
+media_status_t MP3Source::read(
         MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
@@ -509,11 +512,11 @@
         if (mSeeker == NULL
                 || !mSeeker->getOffsetForTime(&actualSeekTimeUs, &mCurrentPos)) {
             int32_t bitrate;
-            if (!mMeta.findInt32(kKeyBitRate, &bitrate)) {
+            if (!AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate)) {
                 // bitrate is in bits/sec.
                 ALOGI("no bitrate");
 
-                return ERROR_UNSUPPORTED;
+                return AMEDIA_ERROR_UNSUPPORTED;
             }
 
             mCurrentTimeUs = seekTimeUs;
@@ -530,7 +533,7 @@
     MediaBufferBase *buffer;
     status_t err = mGroup->acquire_buffer(&buffer);
     if (err != OK) {
-        return err;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
     size_t frame_size;
@@ -543,7 +546,7 @@
             buffer->release();
             buffer = NULL;
 
-            return (n < 0 ? n : ERROR_END_OF_STREAM);
+            return (n < 0 ? AMEDIA_ERROR_UNKNOWN : AMEDIA_ERROR_END_OF_STREAM);
         }
 
         uint32_t header = U32_AT((const uint8_t *)buffer->data());
@@ -572,7 +575,7 @@
             buffer->release();
             buffer = NULL;
 
-            return ERROR_END_OF_STREAM;
+            return AMEDIA_ERROR_END_OF_STREAM;
         }
 
         mCurrentPos = pos;
@@ -587,7 +590,7 @@
         buffer->release();
         buffer = NULL;
 
-        return (n < 0 ? n : ERROR_END_OF_STREAM);
+        return (n < 0 ? AMEDIA_ERROR_UNKNOWN : AMEDIA_ERROR_END_OF_STREAM);
     }
 
     buffer->set_range(0, frame_size);
@@ -602,40 +605,40 @@
 
     *out = buffer;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t MP3Extractor::getMetaData(MetaDataBase &meta) {
-    meta.clear();
+media_status_t MP3Extractor::getMetaData(AMediaFormat *meta) {
+    AMediaFormat_clear(meta);
     if (mInitCheck != OK) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
-    meta.setCString(kKeyMIMEType, "audio/mpeg");
+    AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, "audio/mpeg");
 
     DataSourceHelper helper(mDataSource);
     ID3 id3(&helper);
 
     if (!id3.isValid()) {
-        return OK;
+        return AMEDIA_OK;
     }
 
     struct Map {
-        int key;
+        const char *key;
         const char *tag1;
         const char *tag2;
     };
     static const Map kMap[] = {
-        { kKeyAlbum, "TALB", "TAL" },
-        { kKeyArtist, "TPE1", "TP1" },
-        { kKeyAlbumArtist, "TPE2", "TP2" },
-        { kKeyComposer, "TCOM", "TCM" },
-        { kKeyGenre, "TCON", "TCO" },
-        { kKeyTitle, "TIT2", "TT2" },
-        { kKeyYear, "TYE", "TYER" },
-        { kKeyAuthor, "TXT", "TEXT" },
-        { kKeyCDTrackNumber, "TRK", "TRCK" },
-        { kKeyDiscNumber, "TPA", "TPOS" },
-        { kKeyCompilation, "TCP", "TCMP" },
+        { AMEDIAFORMAT_KEY_ALBUM, "TALB", "TAL" },
+        { AMEDIAFORMAT_KEY_ARTIST, "TPE1", "TP1" },
+        { AMEDIAFORMAT_KEY_ALBUMARTIST, "TPE2", "TP2" },
+        { AMEDIAFORMAT_KEY_COMPOSER, "TCOM", "TCM" },
+        { AMEDIAFORMAT_KEY_GENRE, "TCON", "TCO" },
+        { AMEDIAFORMAT_KEY_TITLE, "TIT2", "TT2" },
+        { AMEDIAFORMAT_KEY_YEAR, "TYE", "TYER" },
+        { AMEDIAFORMAT_KEY_AUTHOR, "TXT", "TEXT" },
+        { AMEDIAFORMAT_KEY_CDTRACKNUMBER, "TRK", "TRCK" },
+        { AMEDIAFORMAT_KEY_DISCNUMBER, "TPA", "TPOS" },
+        { AMEDIAFORMAT_KEY_COMPILATION, "TCP", "TCMP" },
     };
     static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
 
@@ -655,7 +658,7 @@
         it->getString(&s);
         delete it;
 
-        meta.setCString(kMap[i].key, s);
+        AMediaFormat_setString(meta, kMap[i].key, s.string());
     }
 
     size_t dataSize;
@@ -663,21 +666,20 @@
     const void *data = id3.getAlbumArt(&dataSize, &mime);
 
     if (data) {
-        meta.setData(kKeyAlbumArt, MetaData::TYPE_NONE, data, dataSize);
-        meta.setCString(kKeyAlbumArtMIME, mime.string());
+        AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_ALBUMART, data, dataSize);
     }
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-static CMediaExtractor* CreateExtractor(
+static CMediaExtractorV2* CreateExtractor(
         CDataSource *source,
         void *meta) {
     Mp3Meta *metaData = static_cast<Mp3Meta *>(meta);
-    return wrap(new MP3Extractor(new DataSourceHelper(source), metaData));
+    return wrapV2(new MP3Extractor(new DataSourceHelper(source), metaData));
 }
 
-static CreatorFunc Sniff(
+static CreatorFuncV2 Sniff(
         CDataSource *source, float *confidence, void **meta,
         FreeMetaFunc *freeMeta) {
     off64_t pos = 0;
@@ -714,11 +716,11 @@
 __attribute__ ((visibility ("default")))
 ExtractorDef GETEXTRACTORDEF() {
     return {
-        EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION_CURRENT,
         UUID("812a3f6c-c8cf-46de-b529-3774b14103d4"),
         1, // version
         "MP3 Extractor",
-        { Sniff }
+        { .v2 = Sniff }
     };
 }
 
diff --git a/media/extractors/mp3/MP3Extractor.h b/media/extractors/mp3/MP3Extractor.h
index 92e0665..22547e2 100644
--- a/media/extractors/mp3/MP3Extractor.h
+++ b/media/extractors/mp3/MP3Extractor.h
@@ -21,7 +21,7 @@
 #include <utils/Errors.h>
 #include <media/MediaExtractorPluginApi.h>
 #include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
 
 namespace android {
 
@@ -32,16 +32,16 @@
 class String8;
 struct Mp3Meta;
 
-class MP3Extractor : public MediaExtractorPluginHelper {
+class MP3Extractor : public MediaExtractorPluginHelperV2 {
 public:
     MP3Extractor(DataSourceHelper *source, Mp3Meta *meta);
     ~MP3Extractor();
 
     virtual size_t countTracks();
-    virtual MediaTrackHelper *getTrack(size_t index);
-    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+    virtual MediaTrackHelperV2 *getTrack(size_t index);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "MP3Extractor"; }
 
 private:
@@ -49,7 +49,7 @@
 
     DataSourceHelper *mDataSource;
     off64_t mFirstFramePos;
-    MetaDataBase mMeta;
+    AMediaFormat *mMeta;
     uint32_t mFixedHeader;
     MP3Seeker *mSeeker;
 
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index e81e9b2..eec0392 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -3608,7 +3608,6 @@
 
         if (data) {
             mFileMetaData.setData(kKeyAlbumArt, MetaData::TYPE_NONE, data, dataSize);
-            mFileMetaData.setCString(kKeyAlbumArtMIME, mime.string());
         }
     }
 }
diff --git a/media/extractors/ogg/Android.bp b/media/extractors/ogg/Android.bp
index 7c6fc75..c6deb18 100644
--- a/media/extractors/ogg/Android.bp
+++ b/media/extractors/ogg/Android.bp
@@ -10,10 +10,12 @@
     shared_libs: [
         "liblog",
         "libmediaextractor",
+        "libmediandk",
     ],
 
     static_libs: [
         "libstagefright_foundation",
+        "libstagefright_metadatautils",
         "libutils",
         "libvorbisidec",
     ],
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 123ac91..1b4fe27 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -24,7 +24,6 @@
 #include <utils/Vector.h>
 #include <media/DataSourceBase.h>
 #include <media/ExtractorUtils.h>
-#include <media/VorbisComment.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/base64.h>
@@ -34,6 +33,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaDataBase.h>
+#include <media/stagefright/MetaDataUtils.h>
 #include <utils/String8.h>
 
 extern "C" {
@@ -47,15 +47,15 @@
 
 namespace android {
 
-struct OggSource : public MediaTrackHelper {
+struct OggSource : public MediaTrackHelperV2 {
     explicit OggSource(OggExtractor *extractor);
 
-    virtual status_t getFormat(MetaDataBase &);
+    virtual media_status_t getFormat(AMediaFormat *);
 
-    virtual status_t start();
-    virtual status_t stop();
+    virtual media_status_t start();
+    virtual media_status_t stop();
 
-    virtual status_t read(
+    virtual media_status_t read(
             MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
@@ -77,7 +77,7 @@
             int64_t seekPreRollUs);
     virtual ~MyOggExtractor();
 
-    status_t getFormat(MetaDataBase &) const;
+    media_status_t getFormat(AMediaFormat *) const;
 
     // Returns an approximate bitrate in bits per second.
     virtual uint64_t approxBitrate() const = 0;
@@ -88,9 +88,8 @@
 
     status_t init();
 
-    status_t getFileMetaData(MetaDataBase &meta) {
-        meta = mFileMeta;
-        return OK;
+    media_status_t getFileMetaData(AMediaFormat *meta) {
+        return AMediaFormat_copy(meta, mFileMeta);
     }
 
 protected:
@@ -129,8 +128,8 @@
     vorbis_info mVi;
     vorbis_comment mVc;
 
-    MetaDataBase mMeta;
-    MetaDataBase mFileMeta;
+    AMediaFormat *mMeta;
+    AMediaFormat *mFileMeta;
 
     Vector<TOCEntry> mTableOfContents;
 
@@ -237,27 +236,27 @@
     }
 }
 
-status_t OggSource::getFormat(MetaDataBase &meta) {
+media_status_t OggSource::getFormat(AMediaFormat *meta) {
     return mExtractor->mImpl->getFormat(meta);
 }
 
-status_t OggSource::start() {
+media_status_t OggSource::start() {
     if (mStarted) {
-        return INVALID_OPERATION;
+        return AMEDIA_ERROR_INVALID_OPERATION;
     }
 
     mStarted = true;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t OggSource::stop() {
+media_status_t OggSource::stop() {
     mStarted = false;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
-status_t OggSource::read(
+media_status_t OggSource::read(
         MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
@@ -266,7 +265,7 @@
     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
         status_t err = mExtractor->mImpl->seekToTime(seekTimeUs);
         if (err != OK) {
-            return err;
+            return AMEDIA_ERROR_UNKNOWN;
         }
     }
 
@@ -274,7 +273,7 @@
     status_t err = mExtractor->mImpl->readNextPacket(&packet);
 
     if (err != OK) {
-        return err;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
 #if 0
@@ -290,7 +289,7 @@
 
     *out = packet;
 
-    return OK;
+    return AMEDIA_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -316,16 +315,19 @@
 
     vorbis_info_init(&mVi);
     vorbis_comment_init(&mVc);
+    mMeta = AMediaFormat_new();
+    mFileMeta = AMediaFormat_new();
 }
 
 MyOggExtractor::~MyOggExtractor() {
+    AMediaFormat_delete(mFileMeta);
+    AMediaFormat_delete(mMeta);
     vorbis_comment_clear(&mVc);
     vorbis_info_clear(&mVi);
 }
 
-status_t MyOggExtractor::getFormat(MetaDataBase &meta) const {
-    meta = mMeta;
-    return OK;
+media_status_t MyOggExtractor::getFormat(AMediaFormat *meta) const {
+    return AMediaFormat_copy(meta, mMeta);
 }
 
 status_t MyOggExtractor::findNextPage(
@@ -832,7 +834,7 @@
 }
 
 status_t MyOggExtractor::init() {
-    mMeta.setCString(kKeyMIMEType, mMimeType);
+    AMediaFormat_setString(mMeta, AMEDIAFORMAT_KEY_MIME, mMimeType);
 
     status_t err;
     MediaBufferBase *packet;
@@ -865,7 +867,7 @@
 
         int64_t durationUs = getTimeUsOfGranule(lastGranulePosition);
 
-        mMeta.setInt64(kKeyDuration, durationUs);
+        AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, durationUs);
 
         buildTableOfContents();
     }
@@ -981,11 +983,14 @@
     mChannelCount = data[9];
     mCodecDelay = U16LE_AT(&data[10]);
 
-    mMeta.setData(kKeyOpusHeader, 0, data, size);
-    mMeta.setInt32(kKeySampleRate, kOpusSampleRate);
-    mMeta.setInt32(kKeyChannelCount, mChannelCount);
-    mMeta.setInt64(kKeyOpusSeekPreRoll /* ns */, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
-    mMeta.setInt64(kKeyOpusCodecDelay /* ns */,
+    // kKeyOpusHeader is csd-0
+    AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_0, data, size);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, kOpusSampleRate);
+    AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mChannelCount);
+    // are these actually used anywhere?
+    // (they are kKeyOpusSeekPreRoll and kKeyOpusCodecDelay respectively)
+    AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_CSD_2, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
+    AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_CSD_1,
             mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate);
 
     return OK;
@@ -1122,10 +1127,10 @@
                 return ERROR_MALFORMED;
             }
 
-            mMeta.setData(kKeyVorbisInfo, 0, data, size);
-            mMeta.setInt32(kKeySampleRate, mVi.rate);
-            mMeta.setInt32(kKeyChannelCount, mVi.channels);
-            mMeta.setInt32(kKeyBitRate, mVi.bitrate_nominal);
+            AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_0, data, size);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mVi.rate);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mVi.channels);
+            AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_BIT_RATE, mVi.bitrate_nominal);
 
             ALOGV("lower-bitrate = %ld", mVi.bitrate_lower);
             ALOGV("upper-bitrate = %ld", mVi.bitrate_upper);
@@ -1140,7 +1145,7 @@
             if (mSource->getSize(&size) == OK) {
                 uint64_t bps = approxBitrate();
                 if (bps != 0) {
-                    mMeta.setInt64(kKeyDuration, size * 8000000ll / bps);
+                    AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, size * 8000000ll / bps);
                 }
             }
             break;
@@ -1162,7 +1167,7 @@
                 return ERROR_MALFORMED;
             }
 
-            mMeta.setData(kKeyVorbisBooks, 0, data, size);
+            AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_1, data, size);
             break;
         }
     }
@@ -1180,12 +1185,12 @@
 
 
 void MyOggExtractor::parseFileMetaData() {
-    mFileMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
+    AMediaFormat_setString(mFileMeta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_CONTAINER_OGG);
 
     for (int i = 0; i < mVc.comments; ++i) {
         const char *comment = mVc.user_comments[i];
         size_t commentLength = mVc.comment_lengths[i];
-        parseVorbisComment(&mFileMeta, comment, commentLength);
+        parseVorbisComment(mFileMeta, comment, commentLength);
         //ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
     }
 }
@@ -1227,7 +1232,7 @@
     return mInitCheck != OK ? 0 : 1;
 }
 
-MediaTrackHelper *OggExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *OggExtractor::getTrack(size_t index) {
     if (index >= 1) {
         return NULL;
     }
@@ -1235,27 +1240,27 @@
     return new OggSource(this);
 }
 
-status_t OggExtractor::getTrackMetaData(
-        MetaDataBase &meta,
+media_status_t OggExtractor::getTrackMetaData(
+        AMediaFormat *meta,
         size_t index, uint32_t /* flags */) {
     if (index >= 1) {
-        return UNKNOWN_ERROR;
+        return AMEDIA_ERROR_UNKNOWN;
     }
 
     return mImpl->getFormat(meta);
 }
 
-status_t OggExtractor::getMetaData(MetaDataBase &meta) {
+media_status_t OggExtractor::getMetaData(AMediaFormat *meta) {
     return mImpl->getFileMetaData(meta);
 }
 
-static CMediaExtractor* CreateExtractor(
+static CMediaExtractorV2* CreateExtractor(
         CDataSource *source,
         void *) {
-    return wrap(new OggExtractor(new DataSourceHelper(source)));
+    return wrapV2(new OggExtractor(new DataSourceHelper(source)));
 }
 
-static CreatorFunc Sniff(
+static CreatorFuncV2 Sniff(
         CDataSource *source,
         float *confidence,
         void **,
@@ -1276,11 +1281,11 @@
 __attribute__ ((visibility ("default")))
 ExtractorDef GETEXTRACTORDEF() {
     return {
-        EXTRACTORDEF_VERSION,
+        EXTRACTORDEF_VERSION_CURRENT,
         UUID("8cc5cd06-f772-495e-8a62-cba9649374e9"),
         1, // version
         "Ogg Extractor",
-        { Sniff }
+        { .v2 = Sniff }
     };
 }
 
diff --git a/media/extractors/ogg/OggExtractor.h b/media/extractors/ogg/OggExtractor.h
index c70f832..cd674f3 100644
--- a/media/extractors/ogg/OggExtractor.h
+++ b/media/extractors/ogg/OggExtractor.h
@@ -21,6 +21,7 @@
 #include <utils/Errors.h>
 #include <media/MediaExtractorPluginApi.h>
 #include <media/MediaExtractorPluginHelper.h>
+#include <media/NdkMediaFormat.h>
 
 namespace android {
 
@@ -30,14 +31,14 @@
 struct MyOggExtractor;
 struct OggSource;
 
-struct OggExtractor : public MediaExtractorPluginHelper {
+struct OggExtractor : public MediaExtractorPluginHelperV2 {
     explicit OggExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
-    virtual MediaTrackHelper *getTrack(size_t index);
-    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+    virtual MediaTrackHelperV2 *getTrack(size_t index);
+    virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
-    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual media_status_t getMetaData(AMediaFormat *meta);
     virtual const char * name() { return "OggExtractor"; }
 
 protected:
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index ef272b0..319467e 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -19,6 +19,18 @@
 }
 
 cc_test {
+    name: "test_clock_model",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_clock_model.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libaudioutils",
+        "libcutils",
+        "libutils",
+    ],
+}
+
+cc_test {
     name: "test_block_adapter",
     defaults: ["libaaudio_tests_defaults"],
     srcs: ["test_block_adapter.cpp"],
diff --git a/media/libaaudio/tests/test_clock_model.cpp b/media/libaaudio/tests/test_clock_model.cpp
new file mode 100644
index 0000000..3c09025
--- /dev/null
+++ b/media/libaaudio/tests/test_clock_model.cpp
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+// Unit tests for Isochronous Clock Model
+
+#include <math.h>
+#include <stdlib.h>
+
+
+#include <aaudio/AAudio.h>
+#include <audio_utils/clock.h>
+#include <client/IsochronousClockModel.h>
+#include <gtest/gtest.h>
+
+using namespace aaudio;
+
+// We can use arbitrary values here because we are not opening a real audio stream.
+#define SAMPLE_RATE             48000
+#define HW_FRAMES_PER_BURST     48
+#define NANOS_PER_BURST         (NANOS_PER_SECOND * HW_FRAMES_PER_BURST / SAMPLE_RATE)
+
+class ClockModelTestFixture: public ::testing::Test {
+public:
+    ClockModelTestFixture() {
+    }
+
+    void SetUp() {
+        model.setSampleRate(SAMPLE_RATE);
+        model.setFramesPerBurst(HW_FRAMES_PER_BURST);
+    }
+
+    void TearDown() {
+
+    }
+
+    ~ClockModelTestFixture()  {
+        // cleanup any pending stuff, but no exceptions allowed
+    }
+
+    IsochronousClockModel model;
+};
+
+// Check default setup.
+TEST_F(ClockModelTestFixture, clock_setup) {
+    ASSERT_EQ(SAMPLE_RATE, model.getSampleRate());
+    ASSERT_EQ(HW_FRAMES_PER_BURST, model.getFramesPerBurst());
+}
+
+// Test delta calculations.
+TEST_F(ClockModelTestFixture, clock_deltas) {
+    int64_t position = model.convertDeltaTimeToPosition(NANOS_PER_SECOND);
+    ASSERT_EQ(SAMPLE_RATE, position);
+
+    // Deltas are not quantized.
+    // Compare time to the equivalent position in frames.
+    constexpr int64_t kNanosPerBurst = HW_FRAMES_PER_BURST * NANOS_PER_SECOND / SAMPLE_RATE;
+    position = model.convertDeltaTimeToPosition(NANOS_PER_SECOND + (kNanosPerBurst / 2));
+    ASSERT_EQ(SAMPLE_RATE + (HW_FRAMES_PER_BURST / 2), position);
+
+    int64_t time = model.convertDeltaPositionToTime(SAMPLE_RATE);
+    ASSERT_EQ(NANOS_PER_SECOND, time);
+
+    // Compare position in frames to the equivalent time.
+    time = model.convertDeltaPositionToTime(SAMPLE_RATE + (HW_FRAMES_PER_BURST / 2));
+    ASSERT_EQ(NANOS_PER_SECOND + (kNanosPerBurst / 2), time);
+}
+
+// start() should force the internal markers
+TEST_F(ClockModelTestFixture, clock_start) {
+    const int64_t startTime = 100000;
+    model.start(startTime);
+
+    int64_t position = model.convertTimeToPosition(startTime);
+    EXPECT_EQ(0, position);
+
+    int64_t time = model.convertPositionToTime(position);
+    EXPECT_EQ(startTime, time);
+
+    time = startTime + (500 * NANOS_PER_MICROSECOND);
+    position = model.convertTimeToPosition(time);
+    EXPECT_EQ(0, position);
+}
+
+// timestamps moves the window if outside the bounds
+// TODO test nudging the window
+TEST_F(ClockModelTestFixture, clock_timestamp) {
+    const int64_t startTime = 100000000;
+    model.start(startTime);
+
+    const int64_t position = HW_FRAMES_PER_BURST; // hardware
+    int64_t markerTime = startTime + NANOS_PER_MILLISECOND + (200 * NANOS_PER_MICROSECOND);
+
+    // Should set marker.
+    model.processTimestamp(position, markerTime);
+    EXPECT_EQ(position, model.convertTimeToPosition(markerTime));
+
+    // convertTimeToPosition rounds down
+    EXPECT_EQ(position, model.convertTimeToPosition(markerTime + (73 * NANOS_PER_MICROSECOND)));
+
+    // convertPositionToTime rounds up
+    EXPECT_EQ(markerTime + NANOS_PER_BURST, model.convertPositionToTime(position + 17));
+}
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 34c5428..038c854 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -1300,10 +1300,7 @@
     mNewPosition = position + mUpdatePeriod;
     status_t result = createRecord_l(position, mOpPackageName);
 
-    if (result != NO_ERROR) {
-        ALOGW("%s(%d): createRecord_l failed, do not retry", __func__, mId);
-        retries = 0;
-    } else {
+    if (result == NO_ERROR) {
         if (mActive) {
             // callback thread or sync event hasn't changed
             // FIXME this fails if we have a new AudioFlinger instance
@@ -1316,13 +1313,15 @@
     if (result != NO_ERROR) {
         ALOGW("%s(%d): failed status %d, retries %d", __func__, mId, result, retries);
         if (--retries > 0) {
+            // leave time for an eventual race condition to clear before retrying
+            usleep(500000);
             goto retry;
         }
-    }
-
-    if (result != NO_ERROR) {
-        ALOGW("%s(%d): failed status %d", __func__, mId, result);
-        mActive = false;
+        // if no retries left, set invalid bit to force restoring at next occasion
+        // and avoid inconsistent active state on client and server sides
+        if (mCblk != nullptr) {
+            android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+        }
     }
 
     return result;
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index e77abc6..c86d4ce 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -2308,10 +2308,7 @@
     // If a new IAudioTrack cannot be created, the previous (dead) instance will be left intact.
     status_t result = createTrack_l();
 
-    if (result != NO_ERROR) {
-        ALOGW("%s(%d): createTrack_l failed, do not retry", __func__, mId);
-        retries = 0;
-    } else {
+    if (result == NO_ERROR) {
         // take the frames that will be lost by track recreation into account in saved position
         // For streaming tracks, this is the amount we obtained from the user/client
         // (not the number actually consumed at the server - those are already lost).
@@ -2358,12 +2355,16 @@
     if (result != NO_ERROR) {
         ALOGW("%s(%d): failed status %d, retries %d", __func__, mId, result, retries);
         if (--retries > 0) {
+            // leave time for an eventual race condition to clear before retrying
+            usleep(500000);
             goto retry;
         }
-        mState = STATE_STOPPED;
-        mReleased = 0;
+        // if no retries left, set invalid bit to force restoring at next occasion
+        // and avoid inconsistent active state on client and server sides
+        if (mCblk != nullptr) {
+            android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+        }
     }
-
     return result;
 }
 
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 93fb667..25d28ff 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -153,7 +153,7 @@
 filegroup {
     name: "mediaupdateservice_aidl",
     srcs: [
-        "aidl/android/media/IMediaExtractorUpdateService.aidl",
+        "aidl/android/media/IMediaUpdateService.aidl",
     ],
 }
 
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
index 7d67262..9e09c7e 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -1244,37 +1244,15 @@
     return new AMediaCodecCryptoInfoWrapper(AMediaExtractor_getSampleCryptoInfo(mAMediaExtractor));
 }
 
-ssize_t AMediaDataSourceWrapper::AMediaDataSourceWrapper_getSize(void *userdata) {
-    DataSource *source = static_cast<DataSource *>(userdata);
-    off64_t size = -1;
-    source->getSize(&size);
-    return size;
-}
-
-ssize_t AMediaDataSourceWrapper::AMediaDataSourceWrapper_readAt(void *userdata, off64_t offset, void * buf, size_t size) {
-    DataSource *source = static_cast<DataSource *>(userdata);
-    return source->readAt(offset, buf, size);
-}
-
-void AMediaDataSourceWrapper::AMediaDataSourceWrapper_close(void *userdata) {
-    DataSource *source = static_cast<DataSource *>(userdata);
-    source->close();
-}
-
-AMediaDataSourceWrapper::AMediaDataSourceWrapper(const sp<DataSource> &dataSource)
-    : mDataSource(dataSource),
-      mAMediaDataSource(AMediaDataSource_new()) {
-    ALOGV("setDataSource (source: %p)", dataSource.get());
-    AMediaDataSource_setUserdata(mAMediaDataSource, dataSource.get());
-    AMediaDataSource_setReadAt(mAMediaDataSource, AMediaDataSourceWrapper_readAt);
-    AMediaDataSource_setGetSize(mAMediaDataSource, AMediaDataSourceWrapper_getSize);
-    AMediaDataSource_setClose(mAMediaDataSource, AMediaDataSourceWrapper_close);
+AMediaDataSourceWrapper::AMediaDataSourceWrapper(AMediaDataSource *aDataSource)
+    : mAMediaDataSource(aDataSource) {
 }
 
 AMediaDataSourceWrapper::~AMediaDataSourceWrapper() {
     if (mAMediaDataSource == NULL) {
         return;
     }
+    AMediaDataSource_close(mAMediaDataSource);
     AMediaDataSource_delete(mAMediaDataSource);
     mAMediaDataSource = NULL;
 }
@@ -1283,4 +1261,8 @@
     return mAMediaDataSource;
 }
 
+void AMediaDataSourceWrapper::close() {
+    AMediaDataSource_close(mAMediaDataSource);
+}
+
 }  // namespace android
diff --git a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl b/media/libmedia/aidl/android/media/IMediaUpdateService.aidl
similarity index 84%
rename from media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
rename to media/libmedia/aidl/android/media/IMediaUpdateService.aidl
index 57b1bc9..4777969 100644
--- a/media/libmedia/aidl/android/media/IMediaExtractorUpdateService.aidl
+++ b/media/libmedia/aidl/android/media/IMediaUpdateService.aidl
@@ -17,9 +17,9 @@
 package android.media;
 
 /**
- * Service to reload extractor plugins when update package is installed/uninstalled.
+ * Service to reload media component plugins when update package is installed/uninstalled.
  * @hide
  */
-interface IMediaExtractorUpdateService {
+interface IMediaUpdateService {
     void loadPlugins(@utf8InCpp String apkPath);
 }
diff --git a/media/libmedia/include/media/NdkWrapper.h b/media/libmedia/include/media/NdkWrapper.h
index 191665a..b3b0688 100644
--- a/media/libmedia/include/media/NdkWrapper.h
+++ b/media/libmedia/include/media/NdkWrapper.h
@@ -278,6 +278,30 @@
     DISALLOW_EVIL_CONSTRUCTORS(AMediaCodecWrapper);
 };
 
+struct AMediaDataSourceWrapper : public RefBase {
+
+    AMediaDataSourceWrapper(AMediaDataSource*);
+    AMediaDataSourceWrapper(int fd, int64_t offset, int64_t length);
+
+    AMediaDataSource *getAMediaDataSource();
+    int getFd() { return mFd; }
+    int64_t getOffset() { return mOffset; }
+    int64_t getLength() { return mLength; }
+
+    void close();
+
+protected:
+    virtual ~AMediaDataSourceWrapper();
+
+private:
+    AMediaDataSource *mAMediaDataSource;
+    int mFd;
+    int64_t mOffset;
+    int64_t mLength;
+
+    DISALLOW_EVIL_CONSTRUCTORS(AMediaDataSourceWrapper);
+};
+
 struct AMediaExtractorWrapper : public RefBase {
 
     AMediaExtractorWrapper(AMediaExtractor *aMediaExtractor);
@@ -337,31 +361,6 @@
     DISALLOW_EVIL_CONSTRUCTORS(AMediaExtractorWrapper);
 };
 
-struct AMediaDataSourceWrapper : public RefBase {
-
-    static status_t translate_error(media_status_t err);
-
-    static ssize_t AMediaDataSourceWrapper_getSize(void *userdata);
-
-    static ssize_t AMediaDataSourceWrapper_readAt(void *userdata, off64_t offset, void * buf, size_t size);
-
-    static void AMediaDataSourceWrapper_close(void *userdata);
-
-    AMediaDataSourceWrapper(const sp<DataSource> &dataSource);
-
-    AMediaDataSource *getAMediaDataSource();
-
-protected:
-    virtual ~AMediaDataSourceWrapper();
-
-private:
-    sp<DataSource> mDataSource;
-
-    AMediaDataSource *mAMediaDataSource;
-
-    DISALLOW_EVIL_CONSTRUCTORS(AMediaDataSourceWrapper);
-};
-
 }  // namespace android
 
 #endif  // NDK_WRAPPER_H_
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
index 4ffbb69..0871d60 100644
--- a/media/libmediaextractor/Android.bp
+++ b/media/libmediaextractor/Android.bp
@@ -38,7 +38,6 @@
         "MediaSource.cpp",
         "MetaData.cpp",
         "MetaDataBase.cpp",
-        "VorbisComment.cpp",
     ],
 
     clang: true,
diff --git a/media/libmediaextractor/VorbisComment.cpp b/media/libmediaextractor/VorbisComment.cpp
deleted file mode 100644
index fabaf51..0000000
--- a/media/libmediaextractor/VorbisComment.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * 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 "VorbisComment"
-#include <utils/Log.h>
-
-#include "media/VorbisComment.h"
-
-#include <media/stagefright/foundation/base64.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MetaDataBase.h>
-
-namespace android {
-
-static void extractAlbumArt(
-        MetaDataBase *fileMeta, const void *data, size_t size) {
-    ALOGV("extractAlbumArt from '%s'", (const char *)data);
-
-    sp<ABuffer> flacBuffer = decodeBase64(AString((const char *)data, size));
-    if (flacBuffer == NULL) {
-        ALOGE("malformed base64 encoded data.");
-        return;
-    }
-
-    size_t flacSize = flacBuffer->size();
-    uint8_t *flac = flacBuffer->data();
-    ALOGV("got flac of size %zu", flacSize);
-
-    uint32_t picType;
-    uint32_t typeLen;
-    uint32_t descLen;
-    uint32_t dataLen;
-    char type[128];
-
-    if (flacSize < 8) {
-        return;
-    }
-
-    picType = U32_AT(flac);
-
-    if (picType != 3) {
-        // This is not a front cover.
-        return;
-    }
-
-    typeLen = U32_AT(&flac[4]);
-    if (typeLen > sizeof(type) - 1) {
-        return;
-    }
-
-    // we've already checked above that flacSize >= 8
-    if (flacSize - 8 < typeLen) {
-        return;
-    }
-
-    memcpy(type, &flac[8], typeLen);
-    type[typeLen] = '\0';
-
-    ALOGV("picType = %d, type = '%s'", picType, type);
-
-    if (!strcmp(type, "-->")) {
-        // This is not inline cover art, but an external url instead.
-        return;
-    }
-
-    if (flacSize < 32 || flacSize - 32 < typeLen) {
-        return;
-    }
-
-    descLen = U32_AT(&flac[8 + typeLen]);
-    if (flacSize - 32 - typeLen < descLen) {
-        return;
-    }
-
-    dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
-
-    // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
-    if (flacSize - 32 - typeLen - descLen < dataLen) {
-        return;
-    }
-
-    ALOGV("got image data, %zu trailing bytes",
-         flacSize - 32 - typeLen - descLen - dataLen);
-
-    fileMeta->setData(
-            kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
-
-    fileMeta->setCString(kKeyAlbumArtMIME, type);
-}
-
-void parseVorbisComment(
-        MetaDataBase *fileMeta, const char *comment, size_t commentLength)
-{
-    struct {
-        const char *const mTag;
-        uint32_t mKey;
-    } kMap[] = {
-        { "TITLE", kKeyTitle },
-        { "ARTIST", kKeyArtist },
-        { "ALBUMARTIST", kKeyAlbumArtist },
-        { "ALBUM ARTIST", kKeyAlbumArtist },
-        { "COMPILATION", kKeyCompilation },
-        { "ALBUM", kKeyAlbum },
-        { "COMPOSER", kKeyComposer },
-        { "GENRE", kKeyGenre },
-        { "AUTHOR", kKeyAuthor },
-        { "TRACKNUMBER", kKeyCDTrackNumber },
-        { "DISCNUMBER", kKeyDiscNumber },
-        { "DATE", kKeyDate },
-        { "YEAR", kKeyYear },
-        { "LYRICIST", kKeyWriter },
-        { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
-        { "ANDROID_LOOP", kKeyAutoLoop },
-    };
-
-        for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
-            size_t tagLen = strlen(kMap[j].mTag);
-            if (!strncasecmp(kMap[j].mTag, comment, tagLen)
-                    && comment[tagLen] == '=') {
-                if (kMap[j].mKey == kKeyAlbumArt) {
-                    extractAlbumArt(
-                            fileMeta,
-                            &comment[tagLen + 1],
-                            commentLength - tagLen - 1);
-                } else if (kMap[j].mKey == kKeyAutoLoop) {
-                    if (!strcasecmp(&comment[tagLen + 1], "true")) {
-                        fileMeta->setInt32(kKeyAutoLoop, true);
-                    }
-                } else {
-                    fileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
-                }
-            }
-        }
-
-}
-
-}  // namespace android
diff --git a/media/libmediaextractor/include/media/VorbisComment.h b/media/libmediaextractor/include/media/VorbisComment.h
deleted file mode 100644
index 8ba3295..0000000
--- a/media/libmediaextractor/include/media/VorbisComment.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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 VORBIS_COMMENT_H_
-#define VORBIS_COMMENT_H_
-
-namespace android {
-
-class MetaDataBase;
-
-void parseVorbisComment(
-        MetaDataBase *fileMeta, const char *comment, size_t commentLength);
-
-}  // namespace android
-
-#endif // VORBIS_COMMENT_H_
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index fa5c723..0a99974 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -101,7 +101,6 @@
     kKeyTitle             = 'titl',  // cstring
     kKeyYear              = 'year',  // cstring
     kKeyAlbumArt          = 'albA',  // compressed image data
-    kKeyAlbumArtMIME      = 'alAM',  // cstring
     kKeyAuthor            = 'auth',  // cstring
     kKeyCDTrackNumber     = 'cdtr',  // cstring
     kKeyDiscNumber        = 'dnum',  // cstring
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
index a26cc81..75d1df0 100644
--- a/media/libmediaplayer2/Android.bp
+++ b/media/libmediaplayer2/Android.bp
@@ -28,6 +28,7 @@
         "libcrypto",
         "libmediametrics",
         "libmediandk",
+        "libmediandk_utils",
         "libmediautils",
         "libmemunreachable",
         "libnativewindow",
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
index 9dd5e4c..6b27ca7 100644
--- a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
+++ b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
@@ -44,8 +44,8 @@
     String8 result;
 
     result.append(" MediaPlayer2AudioOutput\n");
-    snprintf(buffer, 255, "  stream type(%d), left - right volume(%f, %f)\n",
-            mStreamType, mLeftVolume, mRightVolume);
+    snprintf(buffer, 255, "  stream type(%d), volume(%f)\n",
+            mStreamType, mVolume);
     result.append(buffer);
     snprintf(buffer, 255, "  msec per frame(%f), latency (%d)\n",
             mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1);
@@ -67,8 +67,7 @@
       mCallbackCookie(NULL),
       mCallbackData(NULL),
       mStreamType(AUDIO_STREAM_MUSIC),
-      mLeftVolume(1.0),
-      mRightVolume(1.0),
+      mVolume(1.0),
       mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
       mSampleRateHz(0),
       mMsecsPerFrame(0),
@@ -402,7 +401,7 @@
 
     mCallbackData = newcbd;
     ALOGV("setVolume");
-    t->setVolume(mLeftVolume, mRightVolume);
+    t->setVolume(mVolume);
 
     mSampleRateHz = sampleRate;
     mFlags = flags;
@@ -444,7 +443,7 @@
         mCallbackData->endTrackSwitch();
     }
     if (mTrack != 0) {
-        mTrack->setVolume(mLeftVolume, mRightVolume);
+        mTrack->setVolume(mVolume);
         mTrack->setAuxEffectSendLevel(mSendLevel);
         status_t status = mTrack->start();
         return status;
@@ -498,13 +497,12 @@
     // destruction of the track occurs outside of mutex.
 }
 
-void MediaPlayer2AudioOutput::setVolume(float left, float right) {
-    ALOGV("setVolume(%f, %f)", left, right);
+void MediaPlayer2AudioOutput::setVolume(float volume) {
+    ALOGV("setVolume(%f)", volume);
     Mutex::Autolock lock(mLock);
-    mLeftVolume = left;
-    mRightVolume = right;
+    mVolume = volume;
     if (mTrack != 0) {
-        mTrack->setVolume(left, right);
+        mTrack->setVolume(volume);
     }
 }
 
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
index ee67abf..fe1005b 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
@@ -77,7 +77,7 @@
     }
     void setAudioAttributes(const audio_attributes_t * attributes);
 
-    void setVolume(float left, float right);
+    void setVolume(float volume);
     virtual status_t setPlaybackRate(const AudioPlaybackRate& rate);
     virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */);
 
@@ -113,8 +113,7 @@
     CallbackData *          mCallbackData;
     audio_stream_type_t     mStreamType;
     audio_attributes_t *    mAttributes;
-    float                   mLeftVolume;
-    float                   mRightVolume;
+    float                   mVolume;
     AudioPlaybackRate       mPlaybackRate;
     uint32_t                mSampleRateHz; // sample rate of the content, as set in open()
     float                   mMsecsPerFrame;
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index 18254a1..4f73ad3 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -88,7 +88,7 @@
             status_t        getAudioStreamType(audio_stream_type_t *type);
             status_t        setLooping(int loop);
             bool            isLooping();
-            status_t        setVolume(float leftVolume, float rightVolume);
+            status_t        setVolume(float volume);
             void            notify(int64_t srcId, int msg, int ext1, int ext2,
                                    const PlayerMessage *obj = NULL);
             status_t        invoke(const PlayerMessage &request, PlayerMessage *reply);
@@ -142,8 +142,7 @@
     audio_stream_type_t         mStreamType;
     Parcel*                     mAudioAttributesParcel;
     bool                        mLoop;
-    float                       mLeftVolume;
-    float                       mRightVolume;
+    float                       mVolume;
     int                         mVideoWidth;
     int                         mVideoHeight;
     audio_session_t             mAudioSessionId;
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index d9c9826..3b155c5 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -321,7 +321,7 @@
     mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
     mCurrentState = MEDIA_PLAYER2_IDLE;
     mLoop = false;
-    mLeftVolume = mRightVolume = 1.0;
+    mVolume = 1.0;
     mVideoWidth = mVideoHeight = 0;
     mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
     AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
@@ -403,6 +403,15 @@
     if (dsd == NULL) {
         return BAD_VALUE;
     }
+    // Microsecond is used in NuPlayer2.
+    if (dsd->mStartPositionMs > INT64_MAX / 1000) {
+        dsd->mStartPositionMs = INT64_MAX / 1000;
+        ALOGW("setDataSource, start poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
+    }
+    if (dsd->mEndPositionMs > INT64_MAX / 1000) {
+        dsd->mEndPositionMs = INT64_MAX / 1000;
+        ALOGW("setDataSource, end poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
+    }
     ALOGV("setDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
 
     sp<MediaPlayer2Interface> oldPlayer;
@@ -630,7 +639,7 @@
         mPlayer->setLooping(mLoop);
 
         if (mAudioOutput != 0) {
-            mAudioOutput->setVolume(mLeftVolume, mRightVolume);
+            mAudioOutput->setVolume(mVolume);
         }
 
         if (mAudioOutput != 0) {
@@ -968,13 +977,12 @@
     return false;
 }
 
-status_t MediaPlayer2::setVolume(float leftVolume, float rightVolume) {
-    ALOGV("MediaPlayer2::setVolume(%f, %f)", leftVolume, rightVolume);
+status_t MediaPlayer2::setVolume(float volume) {
+    ALOGV("MediaPlayer2::setVolume(%f)", volume);
     Mutex::Autolock _l(mLock);
-    mLeftVolume = leftVolume;
-    mRightVolume = rightVolume;
+    mVolume = volume;
     if (mAudioOutput != 0) {
-        mAudioOutput->setVolume(leftVolume, rightVolume);
+        mAudioOutput->setVolume(volume);
     }
     return OK;
 }
diff --git a/media/libmediaplayer2/nuplayer2/Android.bp b/media/libmediaplayer2/nuplayer2/Android.bp
index 26da491..c3c94b6 100644
--- a/media/libmediaplayer2/nuplayer2/Android.bp
+++ b/media/libmediaplayer2/nuplayer2/Android.bp
@@ -28,6 +28,7 @@
         "frameworks/av/media/libstagefright/mpeg2ts",
         "frameworks/av/media/libstagefright/rtsp",
         "frameworks/av/media/libstagefright/timedtext",
+        "frameworks/av/media/ndk",
     ],
 
     cflags: [
@@ -49,6 +50,7 @@
         "libgui",
         "libmedia",
         "libmediandk",
+        "libmediandk_utils",
         "libpowermanager",
     ],
 
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
index 4ce1a88..6056ad9 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
@@ -21,29 +21,20 @@
 #include "NuPlayer2Drm.h"
 
 #include "AnotherPacketSource.h"
-#include <binder/IServiceManager.h>
 #include <cutils/properties.h>
 #include <media/DataSource.h>
 #include <media/MediaBufferHolder.h>
-#include <media/IMediaExtractorService.h>
-#include <media/IMediaSource.h>
-#include <media/MediaHTTPService.h>
-#include <media/MediaSource.h>
 #include <media/NdkWrapper.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/ClearDataSourceFactory.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"
+#include "NdkMediaDataSourceCallbacksPriv.h"
 
 namespace android {
 
@@ -88,9 +79,6 @@
 void NuPlayer2::GenericSource2::resetDataSource() {
     ALOGV("resetDataSource");
 
-    mHTTPService.clear();
-    mHttpSource.clear();
-    mDisconnected = false;
     mUri.clear();
     mUriHeaders.clear();
     if (mFd >= 0) {
@@ -109,7 +97,6 @@
 }
 
 status_t NuPlayer2::GenericSource2::setDataSource(
-        const sp<MediaHTTPService> &httpService,
         const char *url,
         const KeyedVector<String8, String8> *headers) {
     Mutex::Autolock _l(mLock);
@@ -117,7 +104,6 @@
 
     resetDataSource();
 
-    mHTTPService = httpService;
     mUri = url;
 
     if (headers) {
@@ -150,7 +136,8 @@
     ALOGV("setDataSource (source: %p)", source.get());
 
     resetDataSource();
-    mDataSource = source;
+    AMediaDataSource *aSource = convertDataSourceToAMediaDataSource(source);
+    mDataSourceWrapper = new AMediaDataSourceWrapper(aSource);
     return OK;
 }
 
@@ -161,24 +148,21 @@
 
 status_t NuPlayer2::GenericSource2::initFromDataSource() {
     mExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
-    CHECK(mDataSource != NULL || mFd != -1);
-    sp<DataSource> dataSource = mDataSource;
+    CHECK(mFd >=0 || mDataSourceWrapper != NULL);
+    sp<AMediaDataSourceWrapper> aSourceWrapper = mDataSourceWrapper;
     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.
     status_t err;
-    if (dataSource != nullptr) {
-        mDataSourceWrapper = new AMediaDataSourceWrapper(dataSource);
-        err = mExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
+    if (aSourceWrapper != NULL) {
+        err = mExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
     } else {
-        err = mExtractor->setDataSource(fd, offset, length);
+        err = mExtractor->setDataSource(fd, mOffset, mLength);
     }
 
     if (err != OK) {
-        ALOGE("initFromDataSource, failed to create data source!");
+        ALOGE("initFromDataSource, failed to set extractor data source!");
         mLock.lock();
         return UNKNOWN_ERROR;
     }
@@ -190,10 +174,8 @@
         return UNKNOWN_ERROR;
     }
 
-    mLock.lock();
-    mFd = -1;
-    mDataSource = dataSource;
     mFileMeta = convertMediaFormatWrapperToMetaData(mExtractor->getFormat());
+    mLock.lock();
     if (mFileMeta != NULL) {
         int64_t duration;
         if (mFileMeta->findInt64(kKeyDuration, &duration)) {
@@ -214,11 +196,7 @@
         }
 
         sp<AMediaExtractorWrapper> trackExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
-        if (mDataSourceWrapper != nullptr) {
-            err = trackExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
-        } else {
-            err = trackExtractor->setDataSource(fd, offset, length);
-        }
+        trackExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
 
         const char *mime;
         sp<MetaData> meta = convertMediaFormatWrapperToMetaData(trackFormat);
@@ -329,13 +307,13 @@
         mLooper->unregisterHandler(id());
         mLooper->stop();
     }
-    if (mDataSource != NULL) {
-        mDataSource->close();
+    if (mDataSourceWrapper != NULL) {
+        mDataSourceWrapper->close();
     }
     resetDataSource();
 }
 
-void NuPlayer2::GenericSource2::prepareAsync() {
+void NuPlayer2::GenericSource2::prepareAsync(int64_t startTimeUs) {
     Mutex::Autolock _l(mLock);
     ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
 
@@ -350,59 +328,45 @@
     }
 
     sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);
+    msg->setInt64("startTimeUs", startTimeUs);
+
     msg->post();
 }
 
-void NuPlayer2::GenericSource2::onPrepareAsync() {
-    ALOGV("onPrepareAsync: mDataSource: %d", (mDataSource != NULL));
+void NuPlayer2::GenericSource2::onPrepareAsync(int64_t startTimeUs) {
+    ALOGV("onPrepareAsync: mFd %d mUri %s mDataSourceWrapper: %p",
+            mFd, mUri.c_str(), mDataSourceWrapper.get());
 
-    // delayed data source creation
-    if (mDataSource == NULL) {
-        // set to false first, if the extractor
-        // comes back as secure, set it to true then.
-        mIsSecure = false;
-
-        if (!mUri.empty()) {
-            const char* uri = mUri.c_str();
-            String8 contentType;
-
-            if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
-                mHttpSource = ClearDataSourceFactory::CreateMediaHTTP(mHTTPService);
-                if (mHttpSource == NULL) {
-                    ALOGE("Failed to create http source!");
-                    notifyPreparedAndCleanup(UNKNOWN_ERROR);
-                    return;
-                }
-            }
-
-            mLock.unlock();
-            // This might take long time if connection has some issue.
-            sp<DataSource> dataSource = ClearDataSourceFactory::CreateFromURI(
-                   mHTTPService, uri, &mUriHeaders, &contentType,
-                   static_cast<HTTPBase *>(mHttpSource.get()));
-            mLock.lock();
-            if (!mDisconnected) {
-                mDataSource = dataSource;
-            }
+    if (!mUri.empty()) {
+        const char* uri = mUri.c_str();
+        size_t numheaders = mUriHeaders.size();
+        const char **key_values = numheaders ? new const char *[numheaders * 2] : NULL;
+        for (size_t i = 0; i < numheaders; ++i) {
+            key_values[i * 2] = mUriHeaders.keyAt(i).c_str();
+            key_values[i * 2 + 1] =  mUriHeaders.valueAt(i).c_str();
         }
-
-        if (mFd == -1 && mDataSource == NULL) {
-            ALOGE("Failed to create data source!");
-            notifyPreparedAndCleanup(UNKNOWN_ERROR);
-            return;
-        }
+        mLock.unlock();
+        AMediaDataSource *aSource = AMediaDataSource_newUri(uri, numheaders, key_values);
+        mLock.lock();
+        mDataSourceWrapper = aSource ? new AMediaDataSourceWrapper(aSource) : NULL;
+        delete[] key_values;
+        // For cached streaming cases, we need to wait for enough
+        // buffering before reporting prepared.
+        mIsStreaming = !strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8);
     }
 
-    if (mDataSource != nullptr && mDataSource->flags() & DataSource::kIsCachingDataSource) {
-        mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get());
+    if (mDisconnected || (mFd < 0 && mDataSourceWrapper == NULL)) {
+        ALOGE("mDisconnected(%d) or Failed to create data source!", mDisconnected);
+        notifyPreparedAndCleanup(UNKNOWN_ERROR);
+        return;
     }
 
-    // For cached streaming cases, we need to wait for enough
-    // buffering before reporting prepared.
-    mIsStreaming = (mCachedSource != NULL);
-
     // init extractor from data source
     status_t err = initFromDataSource();
+    if (mFd >= 0) {
+        close(mFd);
+        mFd = -1;
+    }
 
     if (err != OK) {
         ALOGE("Failed to init from data source!");
@@ -429,6 +393,7 @@
             FLAG_CAN_SEEK_FORWARD |
             FLAG_CAN_SEEK);
 
+    doSeek(startTimeUs, MediaPlayer2SeekMode::SEEK_CLOSEST);
     finishPrepareAsync();
 
     ALOGV("onPrepareAsync: Done");
@@ -438,8 +403,8 @@
     ALOGV("finishPrepareAsync");
 
     if (mIsStreaming) {
-        mCachedSource->resumeFetchingIfNecessary();
         mPreparing = true;
+        ++mPollBufferingGeneration;
         schedulePollBuffering();
     } else {
         notifyPrepared();
@@ -456,9 +421,7 @@
 
 void NuPlayer2::GenericSource2::notifyPreparedAndCleanup(status_t err) {
     if (err != OK) {
-        mDataSource.clear();
-        mCachedSource.clear();
-        mHttpSource.clear();
+        mDataSourceWrapper.clear();
 
         mBitrate = -1;
         mPrevBufferPercentage = -1;
@@ -498,53 +461,27 @@
 }
 
 void NuPlayer2::GenericSource2::disconnect() {
-    sp<DataSource> dataSource, httpSource;
     {
         Mutex::Autolock _l(mLock);
-        dataSource = mDataSource;
-        httpSource = mHttpSource;
         mDisconnected = true;
     }
-
-    if (dataSource != NULL) {
-        // disconnect data source
-        if (dataSource->flags() & DataSource::kIsCachingDataSource) {
-            static_cast<NuCachedSource2 *>(dataSource.get())->disconnect();
-        }
-    } else if (httpSource != NULL) {
-        static_cast<HTTPBase *>(httpSource.get())->disconnect();
+    if (mDataSourceWrapper != NULL) {
+        mDataSourceWrapper->close();
     }
-
-    mDataSourceWrapper = NULL;
-
 }
 
 status_t NuPlayer2::GenericSource2::feedMoreTSData() {
     return OK;
 }
 
-void NuPlayer2::GenericSource2::sendCacheStats() {
-    int32_t kbps = 0;
-    status_t err = UNKNOWN_ERROR;
-
-    if (mCachedSource != NULL) {
-        err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
-    }
-
-    if (err == OK) {
-        sp<AMessage> notify = dupNotify();
-        notify->setInt32("what", kWhatCacheStats);
-        notify->setInt32("bandwidth", kbps);
-        notify->post();
-    }
-}
-
 void NuPlayer2::GenericSource2::onMessageReceived(const sp<AMessage> &msg) {
     Mutex::Autolock _l(mLock);
     switch (msg->what()) {
       case kWhatPrepareAsync:
       {
-          onPrepareAsync();
+          int64_t startTimeUs;
+          CHECK(msg->findInt64("startTimeUs", &startTimeUs));
+          onPrepareAsync(startTimeUs);
           break;
       }
       case kWhatFetchSubtitleData:
@@ -834,8 +771,6 @@
             }
             if (track->mPackets->getAvailableBufferCount(&finalResult) < 2
                 && !mSentPauseOnBuffering && !mPreparing) {
-                mCachedSource->resumeFetchingIfNecessary();
-                sendCacheStats();
                 mSentPauseOnBuffering = true;
                 sp<AMessage> notify = dupNotify();
                 notify->setInt32("what", kWhatPauseOnBufferingStart);
@@ -1391,7 +1326,6 @@
                         notifyPrepared();
                         mPreparing = false;
                     } else {
-                        sendCacheStats();
                         mSentPauseOnBuffering = false;
                         sp<AMessage> notify = dupNotify();
                         notify->setInt32("what", kWhatResumeOnBufferingEnd);
@@ -1443,47 +1377,31 @@
 }
 
 void NuPlayer2::GenericSource2::schedulePollBuffering() {
-    sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
-    msg->setInt32("generation", mPollBufferingGeneration);
-    // Enquires buffering status every second.
-    msg->post(1000000ll);
+    if (mIsStreaming) {
+        sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
+        msg->setInt32("generation", mPollBufferingGeneration);
+        // Enquires buffering status every second.
+        msg->post(1000000ll);
+    }
 }
 
 void NuPlayer2::GenericSource2::onPollBuffering() {
-    status_t finalStatus = UNKNOWN_ERROR;
     int64_t cachedDurationUs = -1ll;
-    ssize_t cachedDataRemaining = -1;
 
-    if (mCachedSource != NULL) {
-        cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
-
-        if (finalStatus == OK) {
-            off64_t size;
-            int64_t bitrate = 0ll;
-            if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
-                // |bitrate| uses bits/second unit, while size is number of bytes.
-                bitrate = size * 8000000ll / mDurationUs;
-            } else if (mBitrate > 0) {
-                bitrate = mBitrate;
-            }
-            if (bitrate > 0) {
-                cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
-            }
-        }
+    sp<AMediaExtractorWrapper> extractor;
+    if (mVideoTrack.mExtractor != NULL) {
+        extractor = mVideoTrack.mExtractor;
+    } else if (mAudioTrack.mExtractor != NULL) {
+        extractor = mAudioTrack.mExtractor;
     }
 
-    if (finalStatus != OK) {
-        ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
-
-        if (finalStatus == ERROR_END_OF_STREAM) {
-            notifyBufferingUpdate(100);
-        }
-
-        return;
+    if (extractor != NULL) {
+        cachedDurationUs = extractor->getCachedDuration();
     }
 
     if (cachedDurationUs >= 0ll) {
-        if (mDurationUs > 0ll) {
+        ssize_t sampleSize = extractor->getSampleSize();
+        if (sampleSize >= 0ll) {
             int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
             int percentage = 100.0 * cachedPosUs / mDurationUs;
             if (percentage > 100) {
@@ -1491,9 +1409,11 @@
             }
 
             notifyBufferingUpdate(percentage);
+            ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
+        } else {
+            notifyBufferingUpdate(100);
+            ALOGV("onPollBuffering: EOS");
         }
-
-        ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f);
     }
 
     schedulePollBuffering();
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.h b/media/libmediaplayer2/nuplayer2/GenericSource2.h
index 9bc5182..ade1aa3 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.h
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.h
@@ -37,11 +37,9 @@
 class DataSource;
 class IDataSource;
 class IMediaSource;
-struct MediaHTTPService;
 struct MediaSource;
 class MediaBuffer;
 struct MediaClock;
-struct NuCachedSource2;
 
 struct NuPlayer2::GenericSource2 : public NuPlayer2::Source,
                                    public MediaBufferObserver // Modular DRM
@@ -50,7 +48,6 @@
                    const sp<MediaClock> &mediaClock);
 
     status_t setDataSource(
-            const sp<MediaHTTPService> &httpService,
             const char *url,
             const KeyedVector<String8, String8> *headers);
 
@@ -62,7 +59,7 @@
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
-    virtual void prepareAsync();
+    virtual void prepareAsync(int64_t startTimeUs);
 
     virtual void start();
     virtual void stop();
@@ -151,7 +148,6 @@
     bool mIsStreaming;
     uid_t mUID;
     const sp<MediaClock> mMediaClock;
-    sp<MediaHTTPService> mHTTPService;
     AString mUri;
     KeyedVector<String8, String8> mUriHeaders;
     int mFd;
@@ -159,9 +155,6 @@
     int64_t mLength;
 
     bool mDisconnected;
-    sp<DataSource> mDataSource;
-    sp<NuCachedSource2> mCachedSource;
-    sp<DataSource> mHttpSource;
     sp<MetaData> mFileMeta;
     sp<AMediaDataSourceWrapper> mDataSourceWrapper;
     sp<AMediaExtractorWrapper> mExtractor;
@@ -194,7 +187,7 @@
     void onSeek(const sp<AMessage>& msg);
     status_t doSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode);
 
-    void onPrepareAsync();
+    void onPrepareAsync(int64_t startTimeUs);
 
     void fetchTextData(
             uint32_t what, media_track_type type,
@@ -232,8 +225,6 @@
     void onPollBuffering();
     void notifyBufferingUpdate(int32_t percentage);
 
-    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/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
index a61cacd..175be53 100644
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.cpp
@@ -99,7 +99,8 @@
     return OK;
 }
 
-void NuPlayer2::HTTPLiveSource2::prepareAsync() {
+// TODO: fetch data starting from |startTimeUs|
+void NuPlayer2::HTTPLiveSource2::prepareAsync(int64_t /* startTimeUs */) {
     if (mLiveLooper == NULL) {
         mLiveLooper = new ALooper;
         mLiveLooper->setName("http live");
diff --git a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
index 97d3653..8fc71e2 100644
--- a/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
+++ b/media/libmediaplayer2/nuplayer2/HTTPLiveSource2.h
@@ -38,7 +38,7 @@
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
-    virtual void prepareAsync();
+    virtual void prepareAsync(int64_t startTimeUs);
     virtual void start();
 
     virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 5bd1674..018324e 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -212,7 +212,6 @@
     : mPID(pid),
       mUID(uid),
       mMediaClock(mediaClock),
-      mSourceFlags(0),
       mOffloadAudio(false),
       mAudioDecoderGeneration(0),
       mVideoDecoderGeneration(0),
@@ -240,8 +239,7 @@
       mPaused(false),
       mPausedByClient(true),
       mPausedForBuffering(false),
-      mIsDrmProtected(false),
-      mDataSourceType(DATA_SOURCE_TYPE_NONE) {
+      mIsDrmProtected(false) {
     CHECK(mediaClock != NULL);
     clearFlushComplete();
 }
@@ -309,7 +307,7 @@
                 sp<GenericSource2> genericSource =
                         new GenericSource2(notify, mUID, mMediaClock);
 
-                err = genericSource->setDataSource(httpService, url, headers);
+                err = genericSource->setDataSource(url, headers);
 
                 if (err == OK) {
                     *source = genericSource;
@@ -393,11 +391,13 @@
     // Now, source != NULL.
     */
 
-    mDataSourceType = dataSourceType;
+    mCurrentSourceInfo.mDataSourceType = dataSourceType;
 
     sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
     msg->setObject("source", source);
     msg->setInt64("srcId", dsd->mId);
+    msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
+    msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
     msg->post();
 }
 
@@ -415,11 +415,13 @@
     // Now, source != NULL.
     */
 
-    mNextDataSourceType = dataSourceType;
+    mNextSourceInfo.mDataSourceType = dataSourceType;
 
     sp<AMessage> msg = new AMessage(kWhatPrepareNextDataSource, this);
     msg->setObject("source", source);
     msg->setInt64("srcId", dsd->mId);
+    msg->setInt64("startTimeUs", dsd->mStartPositionMs * 1000);
+    msg->setInt64("endTimeUs", dsd->mEndPositionMs * 1000);
     msg->post();
 }
 
@@ -554,7 +556,7 @@
     sp<Source> source;
     {
         Mutex::Autolock autoLock(mSourceLock);
-        source = mSource;
+        source = mCurrentSourceInfo.mSource;
     }
 
     if (source != NULL) {
@@ -640,15 +642,17 @@
         {
             ALOGV("kWhatSetDataSource");
 
-            CHECK(mSource == NULL);
+            CHECK(mCurrentSourceInfo.mSource == NULL);
 
             status_t err = OK;
             sp<RefBase> obj;
             CHECK(msg->findObject("source", &obj));
             if (obj != NULL) {
                 Mutex::Autolock autoLock(mSourceLock);
-                CHECK(msg->findInt64("srcId", &mSrcId));
-                mSource = static_cast<Source *>(obj.get());
+                CHECK(msg->findInt64("srcId", &mCurrentSourceInfo.mSrcId));
+                CHECK(msg->findInt64("startTimeUs", &mCurrentSourceInfo.mStartTimeUs));
+                CHECK(msg->findInt64("endTimeUs", &mCurrentSourceInfo.mEndTimeUs));
+                mCurrentSourceInfo.mSource = static_cast<Source *>(obj.get());
             } else {
                 err = UNKNOWN_ERROR;
                 ALOGE("kWhatSetDataSource, source should not be NULL");
@@ -657,7 +661,7 @@
             CHECK(mDriver != NULL);
             sp<NuPlayer2Driver> driver = mDriver.promote();
             if (driver != NULL) {
-                driver->notifySetDataSourceCompleted(mSrcId, err);
+                driver->notifySetDataSourceCompleted(mCurrentSourceInfo.mSrcId, err);
             }
             break;
         }
@@ -671,9 +675,11 @@
             CHECK(msg->findObject("source", &obj));
             if (obj != NULL) {
                 Mutex::Autolock autoLock(mSourceLock);
-                CHECK(msg->findInt64("srcId", &mNextSrcId));
-                mNextSource = static_cast<Source *>(obj.get());
-                mNextSource->prepareAsync();
+                CHECK(msg->findInt64("srcId", &mNextSourceInfo.mSrcId));
+                CHECK(msg->findInt64("startTimeUs", &mNextSourceInfo.mStartTimeUs));
+                CHECK(msg->findInt64("endTimeUs", &mNextSourceInfo.mEndTimeUs));
+                mNextSourceInfo.mSource = static_cast<Source *>(obj.get());
+                mNextSourceInfo.mSource->prepareAsync(mNextSourceInfo.mStartTimeUs);
             } else {
                 err = UNKNOWN_ERROR;
             }
@@ -686,7 +692,7 @@
             ALOGV("kWhatPlayNextDataSource");
             int64_t srcId;
             CHECK(msg->findInt64("srcId", &srcId));
-            if (srcId != mNextSrcId) {
+            if (srcId != mNextSourceInfo.mSrcId) {
                 notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, 0);
                 return;
             }
@@ -715,8 +721,8 @@
             ALOGV("kWhatGetBufferingSettings");
             BufferingSettings buffering;
             status_t err = OK;
-            if (mSource != NULL) {
-                err = mSource->getBufferingSettings(&buffering);
+            if (mCurrentSourceInfo.mSource != NULL) {
+                err = mCurrentSourceInfo.mSource->getBufferingSettings(&buffering);
             } else {
                 err = INVALID_OPERATION;
             }
@@ -738,8 +744,8 @@
             BufferingSettings buffering;
             readFromAMessage(msg, &buffering);
             status_t err = OK;
-            if (mSource != NULL) {
-                err = mSource->setBufferingSettings(buffering);
+            if (mCurrentSourceInfo.mSource != NULL) {
+                err = mCurrentSourceInfo.mSource->setBufferingSettings(buffering);
             } else {
                 err = INVALID_OPERATION;
             }
@@ -753,7 +759,7 @@
         {
             ALOGV("onMessageReceived kWhatPrepare");
 
-            mSource->prepareAsync();
+            mCurrentSourceInfo.mSource->prepareAsync(mCurrentSourceInfo.mStartTimeUs);
             break;
         }
 
@@ -766,8 +772,8 @@
             CHECK(msg->findPointer("reply", (void**)&reply));
 
             size_t inbandTracks = 0;
-            if (mSource != NULL) {
-                inbandTracks = mSource->getTrackCount();
+            if (mCurrentSourceInfo.mSource != NULL) {
+                inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
             }
 
             size_t ccTracks = 0;
@@ -780,7 +786,7 @@
 
             // write inband tracks
             for (size_t i = 0; i < inbandTracks; ++i) {
-                writeTrackInfo(reply, mSource->getTrackInfo(i));
+                writeTrackInfo(reply, mCurrentSourceInfo.mSource->getTrackInfo(i));
             }
 
             // write CC track
@@ -796,13 +802,13 @@
         case kWhatGetSelectedTrack:
         {
             status_t err = INVALID_OPERATION;
-            if (mSource != NULL) {
+            if (mCurrentSourceInfo.mSource != NULL) {
                 err = OK;
 
                 int32_t type32;
                 CHECK(msg->findInt32("type", (int32_t*)&type32));
                 media_track_type type = (media_track_type)type32;
-                ssize_t selectedTrack = mSource->getSelectedTrack(type);
+                ssize_t selectedTrack = mCurrentSourceInfo.mSource->getSelectedTrack(type);
 
                 PlayerMessage* reply;
                 CHECK(msg->findPointer("reply", (void**)&reply));
@@ -833,8 +839,8 @@
             status_t err = INVALID_OPERATION;
 
             size_t inbandTracks = 0;
-            if (mSource != NULL) {
-                inbandTracks = mSource->getTrackCount();
+            if (mCurrentSourceInfo.mSource != NULL) {
+                inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
             }
             size_t ccTracks = 0;
             if (mCCDecoder != NULL) {
@@ -842,11 +848,11 @@
             }
 
             if (trackIndex < inbandTracks) {
-                err = mSource->selectTrack(trackIndex, select, timeUs);
+                err = mCurrentSourceInfo.mSource->selectTrack(trackIndex, select, timeUs);
 
                 if (!select && err == OK) {
                     int32_t type;
-                    sp<AMessage> info = mSource->getTrackInfo(trackIndex);
+                    sp<AMessage> info = mCurrentSourceInfo.mSource->getTrackInfo(trackIndex);
                     if (info != NULL
                             && info->findInt32("type", &type)
                             && type == MEDIA_TRACK_TYPE_TIMEDTEXT) {
@@ -879,10 +885,10 @@
             }
 
             int64_t durationUs;
-            if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
+            if (mDriver != NULL && mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
                 sp<NuPlayer2Driver> driver = mDriver.promote();
                 if (driver != NULL) {
-                    driver->notifyDuration(mSrcId, durationUs);
+                    driver->notifyDuration(mCurrentSourceInfo.mSrcId, durationUs);
                 }
             }
 
@@ -899,13 +905,15 @@
 
             ALOGD("onSetVideoSurface(%p, %s video decoder)",
                     (nww == NULL ? NULL : nww->getANativeWindow()),
-                    (mSource != NULL && mStarted && mSource->getFormat(false /* audio */) != NULL
+                    (mCurrentSourceInfo.mSource != NULL && mStarted
+                            && mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL
                             && mVideoDecoder != NULL) ? "have" : "no");
 
-            // Need to check mStarted before calling mSource->getFormat because NuPlayer2 might
-            // be in preparing state and it could take long time.
-            // When mStarted is true, mSource must have been set.
-            if (mSource == NULL || !mStarted || mSource->getFormat(false /* audio */) == NULL
+            // Need to check mStarted before calling mCurrentSourceInfo.mSource->getFormat
+            // because NuPlayer2 might be in preparing state and it could take long time.
+            // When mStarted is true, mCurrentSourceInfo.mSource must have been set.
+            if (mCurrentSourceInfo.mSource == NULL || !mStarted
+                    || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
                     // NOTE: mVideoDecoder's mNativeWindow is always non-null
                     || (mVideoDecoder != NULL && mVideoDecoder->setVideoSurface(nww) == OK)) {
                 performSetSurface(nww);
@@ -972,7 +980,7 @@
                 onStart(true /* play */);
             }
             mPausedByClient = false;
-            notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
             break;
         }
 
@@ -1130,21 +1138,22 @@
                     && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
                 // This is the first time we've found anything playable.
 
-                if (mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
+                if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION) {
                     schedulePollDuration();
                 }
             }
 
             status_t err;
-            if ((err = mSource->feedMoreTSData()) != OK) {
+            if ((err = mCurrentSourceInfo.mSource->feedMoreTSData()) != OK) {
                 if (mAudioDecoder == NULL && mVideoDecoder == NULL) {
                     // We're not currently decoding anything (no audio or
                     // video tracks found) and we just ran out of input data.
 
                     if (err == ERROR_END_OF_STREAM) {
-                        notifyListener(mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+                        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
                     } else {
-                        notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+                        notifyListener(
+                                mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
                     }
                 }
                 break;
@@ -1226,10 +1235,10 @@
                 CHECK(msg->findMessage("format", &format));
 
                 sp<AMessage> inputFormat =
-                        mSource->getFormat(false /* audio */);
+                        mCurrentSourceInfo.mSource->getFormat(false /* audio */);
 
                 setVideoScalingMode(mVideoScalingMode);
-                updateVideoSize(mSrcId, inputFormat, format);
+                updateVideoSize(mCurrentSourceInfo.mSrcId, inputFormat, format);
             } else if (what == DecoderBase::kWhatShutdownCompleted) {
                 ALOGV("%s shutdown completed", audio ? "audio" : "video");
                 if (audio) {
@@ -1296,28 +1305,39 @@
                         finishFlushIfPossible();  // Should not occur.
                         break;                    // Finish anyways.
                 }
-                if (mSource != nullptr) {
+                if (mCurrentSourceInfo.mSource != nullptr) {
                     if (audio) {
-                        if (mVideoDecoderError || mSource->getFormat(false /* audio */) == NULL
-                                || mNativeWindow == NULL || mNativeWindow->getANativeWindow() == NULL
+                        if (mVideoDecoderError
+                                || mCurrentSourceInfo.mSource->getFormat(false /* audio */) == NULL
+                                || mNativeWindow == NULL
+                                || mNativeWindow->getANativeWindow() == NULL
                                 || mVideoDecoder == NULL) {
                             // When both audio and video have error, or this stream has only audio
                             // which has error, notify client of error.
-                            notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+                            notifyListener(
+                                    mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+                                    MEDIA2_ERROR_UNKNOWN, err);
                         } else {
                             // Only audio track has error. Video track could be still good to play.
-                            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
+                            notifyListener(
+                                    mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+                                    MEDIA2_INFO_PLAY_AUDIO_ERROR, err);
                         }
                         mAudioDecoderError = true;
                     } else {
-                        if (mAudioDecoderError || mSource->getFormat(true /* audio */) == NULL
+                        if (mAudioDecoderError
+                                || mCurrentSourceInfo.mSource->getFormat(true /* audio */) == NULL
                                 || mAudioSink == NULL || mAudioDecoder == NULL) {
                             // When both audio and video have error, or this stream has only video
                             // which has error, notify client of error.
-                            notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+                            notifyListener(
+                                    mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+                                    MEDIA2_ERROR_UNKNOWN, err);
                         } else {
                             // Only video track has error. Audio track could be still good to play.
-                            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
+                            notifyListener(
+                                    mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+                                    MEDIA2_INFO_PLAY_VIDEO_ERROR, err);
                         }
                         mVideoDecoderError = true;
                     }
@@ -1367,12 +1387,13 @@
                          audio ? "audio" : "video", finalResult);
 
                     notifyListener(
-                            mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, finalResult);
+                            mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+                            MEDIA2_ERROR_UNKNOWN, finalResult);
                 }
 
                 if ((mAudioEOS || mAudioDecoder == NULL)
                         && (mVideoEOS || mVideoDecoder == NULL)) {
-                    notifyListener(mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
+                    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PLAYBACK_COMPLETE, 0, 0);
                 }
             } else if (what == Renderer::kWhatFlushComplete) {
                 int32_t audio;
@@ -1393,10 +1414,11 @@
                 handleFlushComplete(audio, false /* isDecoder */);
                 finishFlushIfPossible();
             } else if (what == Renderer::kWhatVideoRenderingStart) {
-                notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_VIDEO_RENDERING_START, 0);
+                notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO,
+                               MEDIA2_INFO_VIDEO_RENDERING_START, 0);
             } else if (what == Renderer::kWhatMediaRenderingStart) {
                 ALOGV("media rendering started");
-                notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+                notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
             } else if (what == Renderer::kWhatAudioTearDown) {
                 int32_t reason;
                 CHECK(msg->findInt32("reason", &reason));
@@ -1449,7 +1471,7 @@
             int64_t timerUs;
             CHECK(msg->findInt64("timerUs", &timerUs));
 
-            notifyListener(mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_NOTIFY_TIME, timerUs, 0);
             break;
         }
 
@@ -1468,20 +1490,20 @@
             if (!mStarted) {
                 if (!mSourceStarted) {
                     mSourceStarted = true;
-                    mSource->start();
+                    mCurrentSourceInfo.mSource->start();
                 }
                 if (seekTimeUs > 0) {
                     performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
                 }
 
                 if (needNotify) {
-                    notifyDriverSeekComplete(mSrcId);
+                    notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
                 }
                 break;
             }
 
             // seeks can take a while, so we essentially paused
-            notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
 
             mDeferredActions.push_back(
                     new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
@@ -1506,7 +1528,7 @@
                 onStart(false /* play */);
             }
             onPause();
-            notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_PAUSED, 0, 0);
             mPausedByClient = true;
             break;
         }
@@ -1559,8 +1581,8 @@
         return;
     }
     mPaused = false;
-    if (mSource != NULL) {
-        mSource->resume();
+    if (mCurrentSourceInfo.mSource != NULL) {
+        mCurrentSourceInfo.mSource->resume();
     } else {
         ALOGW("resume called when source is gone or not set");
     }
@@ -1583,7 +1605,7 @@
 
     if (!mSourceStarted) {
         mSourceStarted = true;
-        mSource->start();
+        mCurrentSourceInfo.mSource->start();
     }
 
     mOffloadAudio = false;
@@ -1594,22 +1616,23 @@
 
     uint32_t flags = 0;
 
-    if (mSource->isRealTime()) {
+    if (mCurrentSourceInfo.mSource->isRealTime()) {
         flags |= Renderer::FLAG_REAL_TIME;
     }
 
-    bool hasAudio = (mSource->getFormat(true /* audio */) != NULL);
-    bool hasVideo = (mSource->getFormat(false /* audio */) != NULL);
+    bool hasAudio = (mCurrentSourceInfo.mSource->getFormat(true /* audio */) != NULL);
+    bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /* audio */) != NULL);
     if (!hasAudio && !hasVideo) {
         ALOGE("no metadata for either audio or video source");
-        mSource->stop();
+        mCurrentSourceInfo.mSource->stop();
         mSourceStarted = false;
-        notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
+        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR,
+                       MEDIA2_ERROR_UNKNOWN, ERROR_MALFORMED);
         return;
     }
     ALOGV_IF(!hasAudio, "no metadata for audio source");  // video only stream
 
-    sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
+    sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
 
     audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
     if (mAudioSink != NULL) {
@@ -1617,7 +1640,7 @@
     }
 
     mOffloadAudio =
-        canOffloadStream(audioMeta, hasVideo, mSource->isStreaming(), streamType)
+        canOffloadStream(audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
                 && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
 
     // Modular DRM: Disabling audio offload if the source is protected
@@ -1641,9 +1664,9 @@
 
     status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings);
     if (err != OK) {
-        mSource->stop();
+        mCurrentSourceInfo.mSource->stop();
         mSourceStarted = false;
-        notifyListener(mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
         return;
     }
 
@@ -1665,7 +1688,7 @@
     }
 
     startPlaybackTimer("onstart");
-    notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
+    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
 
     postScanSources();
 }
@@ -1691,7 +1714,7 @@
             ALOGV("stopPlaybackTimer()  log  %20" PRId64 "", played);
 
             if (played > 0) {
-                driver->notifyMorePlayingTimeUs(mSrcId, (played+500)/1000);
+                driver->notifyMorePlayingTimeUs(mCurrentSourceInfo.mSrcId, (played+500)/1000);
             }
         }
         mLastStartedPlayingTimeNs = 0;
@@ -1709,7 +1732,8 @@
 void NuPlayer2::stopRebufferingTimer(bool exitingPlayback) {
     Mutex::Autolock autoLock(mPlayingTimeLock);
 
-    ALOGV("stopRebufferTimer()  time %20" PRId64 " (exiting %d)", mLastStartedRebufferingTimeNs, exitingPlayback);
+    ALOGV("stopRebufferTimer()  time %20" PRId64 " (exiting %d)",
+          mLastStartedRebufferingTimeNs, exitingPlayback);
 
     if (mLastStartedRebufferingTimeNs != 0) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
@@ -1719,9 +1743,10 @@
             ALOGV("stopRebufferingTimer()  log  %20" PRId64 "", rebuffered);
 
             if (rebuffered > 0) {
-                driver->notifyMoreRebufferingTimeUs(mSrcId, (rebuffered+500)/1000);
+                driver->notifyMoreRebufferingTimeUs(
+                        mCurrentSourceInfo.mSrcId, (rebuffered+500)/1000);
                 if (exitingPlayback) {
-                    driver->notifyRebufferingWhenExit(mSrcId, true);
+                    driver->notifyRebufferingWhenExit(mCurrentSourceInfo.mSrcId, true);
                 }
             }
         }
@@ -1737,8 +1762,8 @@
         return;
     }
     mPaused = true;
-    if (mSource != NULL) {
-        mSource->pause();
+    if (mCurrentSourceInfo.mSource != NULL) {
+        mCurrentSourceInfo.mSource->pause();
     } else {
         ALOGW("pause called when source is gone or not set");
     }
@@ -1828,7 +1853,7 @@
 
     status_t err = mRenderer->openAudioSink(
             format, true /* offloadOnly */, hasVideo,
-            AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio, mSource->isStreaming());
+            AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio, mCurrentSourceInfo.mSource->isStreaming());
     if (err != OK) {
         // Any failure we turn off mOffloadAudio.
         mOffloadAudio = false;
@@ -1881,7 +1906,7 @@
 }
 
 void NuPlayer2::determineAudioModeChange(const sp<AMessage> &audioFormat) {
-    if (mSource == NULL || mAudioSink == NULL) {
+    if (mCurrentSourceInfo.mSource == NULL || mAudioSink == NULL) {
         return;
     }
 
@@ -1891,12 +1916,12 @@
         return;
     }
 
-    sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
-    sp<AMessage> videoFormat = mSource->getFormat(false /* audio */);
+    sp<MetaData> audioMeta = mCurrentSourceInfo.mSource->getFormatMeta(true /* audio */);
+    sp<AMessage> videoFormat = mCurrentSourceInfo.mSource->getFormat(false /* audio */);
     audio_stream_type_t streamType = mAudioSink->getAudioStreamType();
     const bool hasVideo = (videoFormat != NULL);
     bool canOffload = canOffloadStream(
-            audioMeta, hasVideo, mSource->isStreaming(), streamType)
+            audioMeta, hasVideo, mCurrentSourceInfo.mSource->isStreaming(), streamType)
                     && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
 
     // Modular DRM: Disabling audio offload if the source is protected
@@ -1927,7 +1952,7 @@
         return OK;
     }
 
-    sp<AMessage> format = mSource->getFormat(audio);
+    sp<AMessage> format = mCurrentSourceInfo.mSource->getFormat(audio);
 
     if (format == NULL) {
         return UNKNOWN_ERROR;
@@ -1949,11 +1974,11 @@
             mCCDecoder = new CCDecoder(ccNotify);
         }
 
-        if (mSourceFlags & Source::FLAG_SECURE) {
+        if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) {
             format->setInt32("secure", true);
         }
 
-        if (mSourceFlags & Source::FLAG_PROTECTED) {
+        if (mCurrentSourceInfo.mSourceFlags & Source::FLAG_PROTECTED) {
             format->setInt32("protected", true);
         }
 
@@ -1972,16 +1997,16 @@
             determineAudioModeChange(format);
         }
         if (mOffloadAudio) {
-            mSource->setOffloadAudio(true /* offload */);
+            mCurrentSourceInfo.mSource->setOffloadAudio(true /* offload */);
 
-            const bool hasVideo = (mSource->getFormat(false /*audio */) != NULL);
+            const bool hasVideo = (mCurrentSourceInfo.mSource->getFormat(false /*audio */) != NULL);
             format->setInt32("has-video", hasVideo);
-            *decoder = new DecoderPassThrough(notify, mSource, mRenderer);
+            *decoder = new DecoderPassThrough(notify, mCurrentSourceInfo.mSource, mRenderer);
             ALOGV("instantiateDecoder audio DecoderPassThrough  hasVideo: %d", hasVideo);
         } else {
-            mSource->setOffloadAudio(false /* offload */);
+            mCurrentSourceInfo.mSource->setOffloadAudio(false /* offload */);
 
-            *decoder = new Decoder(notify, mSource, mPID, mUID, mRenderer);
+            *decoder = new Decoder(notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer);
             ALOGV("instantiateDecoder audio Decoder");
         }
         mAudioDecoderError = false;
@@ -1991,7 +2016,8 @@
         notify->setInt32("generation", mVideoDecoderGeneration);
 
         *decoder = new Decoder(
-                notify, mSource, mPID, mUID, mRenderer, mNativeWindow, mCCDecoder);
+                notify, mCurrentSourceInfo.mSource, mPID, mUID, mRenderer, mNativeWindow,
+                mCCDecoder);
         mVideoDecoderError = false;
 
         // enable FRC if high-quality AV sync is requested, even if not
@@ -2008,8 +2034,8 @@
     // Modular DRM
     if (mIsDrmProtected) {
         format->setObject("crypto", mCrypto);
-        ALOGV("instantiateDecoder: mCrypto: %p isSecure: %d", mCrypto.get(),
-                (mSourceFlags & Source::FLAG_SECURE) != 0);
+        ALOGV("instantiateDecoder: mCrypto: %p isSecure: %d",
+                mCrypto.get(), (mCurrentSourceInfo.mSourceFlags & Source::FLAG_SECURE) != 0);
     }
 
     (*decoder)->configure(format);
@@ -2277,11 +2303,11 @@
 }
 
 sp<MetaData> NuPlayer2::getFileMeta() {
-    return mSource->getFileFormatMeta();
+    return mCurrentSourceInfo.mSource->getFileFormatMeta();
 }
 
 float NuPlayer2::getFrameRate() {
-    sp<MetaData> meta = mSource->getFormatMeta(false /* audio */);
+    sp<MetaData> meta = mCurrentSourceInfo.mSource->getFormatMeta(false /* audio */);
     if (meta == NULL) {
         return 0;
     }
@@ -2339,16 +2365,16 @@
     ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), mode=%d",
           (long long)seekTimeUs, seekTimeUs / 1E6, mode);
 
-    if (mSource == NULL) {
+    if (mCurrentSourceInfo.mSource == NULL) {
         // This happens when reset occurs right before the loop mode
         // asynchronously seeks to the start of the stream.
         LOG_ALWAYS_FATAL_IF(mAudioDecoder != NULL || mVideoDecoder != NULL,
-                "mSource is NULL and decoders not NULL audio(%p) video(%p)",
+                "mCurrentSourceInfo.mSource is NULL and decoders not NULL audio(%p) video(%p)",
                 mAudioDecoder.get(), mVideoDecoder.get());
         return;
     }
     mPreviousSeekTimeUs = seekTimeUs;
-    mSource->seekTo(seekTimeUs, mode);
+    mCurrentSourceInfo.mSource->seekTo(seekTimeUs, mode);
     ++mTimedTextGeneration;
 
     // everything's flushed, continue playback.
@@ -2395,17 +2421,17 @@
     mRenderer.clear();
     ++mRendererGeneration;
 
-    if (mSource != NULL) {
-        mSource->stop();
+    if (mCurrentSourceInfo.mSource != NULL) {
+        mCurrentSourceInfo.mSource->stop();
 
         Mutex::Autolock autoLock(mSourceLock);
-        mSource.clear();
+        mCurrentSourceInfo.mSource.clear();
     }
 
     if (mDriver != NULL) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
         if (driver != NULL) {
-            driver->notifyResetComplete(mSrcId);
+            driver->notifyResetComplete(mCurrentSourceInfo.mSrcId);
         }
     }
 
@@ -2440,25 +2466,26 @@
 
     ++mRendererGeneration;
 
-    if (mSource != NULL) {
-        mSource->stop();
+    if (mCurrentSourceInfo.mSource != NULL) {
+        mCurrentSourceInfo.mSource->stop();
     }
 
     long previousSrcId;
     {
         Mutex::Autolock autoLock(mSourceLock);
-        mSource = mNextSource;
-        mNextSource = NULL;
-        previousSrcId = mSrcId;
-        mSrcId = mNextSrcId;
-        ++mNextSrcId;  // to distinguish the two sources.
+        mCurrentSourceInfo.mSource = mNextSourceInfo.mSource;
+        mNextSourceInfo.mSource = NULL;
+        previousSrcId = mCurrentSourceInfo.mSrcId;
+        mCurrentSourceInfo.mSrcId = mNextSourceInfo.mSrcId;
+        ++mNextSourceInfo.mSrcId;  // to distinguish the two sources.
     }
 
     if (mDriver != NULL) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
         if (driver != NULL) {
             notifyListener(previousSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_END, 0);
-            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
+            notifyListener(
+                    mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
         }
     }
 
@@ -2482,7 +2509,7 @@
 
     onStart(true /* play */);
     mPausedByClient = false;
-    notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_STARTED, 0, 0);
 }
 
 void NuPlayer2::performScanSources() {
@@ -2508,7 +2535,7 @@
     if (mDriver != NULL) {
         sp<NuPlayer2Driver> driver = mDriver.promote();
         if (driver != NULL) {
-            driver->notifySetSurfaceComplete(mSrcId);
+            driver->notifySetSurfaceComplete(mCurrentSourceInfo.mSrcId);
         }
     }
 }
@@ -2540,7 +2567,7 @@
 void NuPlayer2::finishResume() {
     if (mResumePending) {
         mResumePending = false;
-        notifyDriverSeekComplete(mSrcId);
+        notifyDriverSeekComplete(mCurrentSourceInfo.mSrcId);
     }
 }
 
@@ -2562,8 +2589,9 @@
     switch (what) {
         case Source::kWhatPrepared:
         {
-            ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source: %p", mSource.get());
-            if (mSource == NULL) {
+            ALOGV("NuPlayer2::onSourceNotify Source::kWhatPrepared source: %p",
+                  mCurrentSourceInfo.mSource.get());
+            if (mCurrentSourceInfo.mSource == NULL) {
                 // This is a stale notification from a source that was
                 // asynchronously preparing when the client called reset().
                 // We handled the reset, the source is gone.
@@ -2588,7 +2616,7 @@
                 // notify duration first, so that it's definitely set when
                 // the app received the "prepare complete" callback.
                 int64_t durationUs;
-                if (mSource->getDuration(&durationUs) == OK) {
+                if (mCurrentSourceInfo.mSource->getDuration(&durationUs) == OK) {
                     driver->notifyDuration(srcId, durationUs);
                 }
                 driver->notifyPrepareCompleted(srcId, err);
@@ -2640,16 +2668,21 @@
                 driver->notifyFlagsChanged(srcId, flags);
             }
 
-            if ((mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
-                    && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
-                cancelPollDuration();
-            } else if (!(mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
-                    && (flags & Source::FLAG_DYNAMIC_DURATION)
-                    && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
-                schedulePollDuration();
-            }
+            if (srcId == mCurrentSourceInfo.mSrcId) {
+                if ((mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
+                        && (!(flags & Source::FLAG_DYNAMIC_DURATION))) {
+                    cancelPollDuration();
+                } else if (!(mCurrentSourceInfo.mSourceFlags & Source::FLAG_DYNAMIC_DURATION)
+                        && (flags & Source::FLAG_DYNAMIC_DURATION)
+                        && (mAudioDecoder != NULL || mVideoDecoder != NULL)) {
+                    schedulePollDuration();
+                }
 
-            mSourceFlags = flags;
+                mCurrentSourceInfo.mSourceFlags = flags;
+            } else if (srcId == mNextSourceInfo.mSrcId) {
+                // TODO: handle duration polling for next source.
+                mNextSourceInfo.mSourceFlags = flags;
+            }
             break;
         }
 
@@ -2800,8 +2833,8 @@
             CHECK(msg->findBuffer("buffer", &buffer));
 
             size_t inbandTracks = 0;
-            if (mSource != NULL) {
-                inbandTracks = mSource->getTrackCount();
+            if (mCurrentSourceInfo.mSource != NULL) {
+                inbandTracks = mCurrentSourceInfo.mSource->getTrackCount();
             }
 
             sendSubtitleData(buffer, inbandTracks);
@@ -2810,7 +2843,7 @@
 
         case NuPlayer2::CCDecoder::kWhatTrackAdded:
         {
-            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
+            notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_INFO, MEDIA2_INFO_METADATA_UPDATE, 0);
 
             break;
         }
@@ -2835,7 +2868,7 @@
     playerMsg.add_values()->set_int64_value(durationUs);
     playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
 
-    notifyListener(mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &playerMsg);
+    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_SUBTITLE_DATA, 0, 0, &playerMsg);
 }
 
 void NuPlayer2::sendTimedMetaData(const sp<ABuffer> &buffer) {
@@ -2846,7 +2879,7 @@
     playerMsg.add_values()->set_int64_value(timeUs);
     playerMsg.add_values()->set_bytes_value(buffer->data(), buffer->size());
 
-    notifyListener(mSrcId, MEDIA2_META_DATA, 0, 0, &playerMsg);
+    notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_META_DATA, 0, 0, &playerMsg);
 }
 
 void NuPlayer2::sendTimedTextData(const sp<ABuffer> &buffer) {
@@ -2876,14 +2909,14 @@
     }
 
     if (playerMsg.values_size() > 0) {
-        notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
+        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0, &playerMsg);
     } else {  // send an empty timed text
-        notifyListener(mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
+        notifyListener(mCurrentSourceInfo.mSrcId, MEDIA2_TIMED_TEXT, 0, 0);
     }
 }
 
 const char *NuPlayer2::getDataSourceType() {
-    switch (mDataSourceType) {
+    switch (mCurrentSourceInfo.mDataSourceType) {
         case DATA_SOURCE_TYPE_HTTP_LIVE:
             return "HTTPLive";
 
@@ -2957,7 +2990,7 @@
     ALOGD("onPrepareDrm ");
 
     status_t status = INVALID_OPERATION;
-    if (mSource == NULL) {
+    if (mCurrentSourceInfo.mSource == NULL) {
         ALOGE("onPrepareDrm: No source. onPrepareDrm failed with %d.", status);
         return status;
     }
@@ -2970,12 +3003,12 @@
     status = OK;
     sp<AMediaCryptoWrapper> crypto = NULL;
 
-    status = mSource->prepareDrm(uuid, *drmSessionId, &crypto);
+    status = mCurrentSourceInfo.mSource->prepareDrm(uuid, *drmSessionId, &crypto);
     if (crypto == NULL) {
-        ALOGE("onPrepareDrm: mSource->prepareDrm failed. status: %d", status);
+        ALOGE("onPrepareDrm: mCurrentSourceInfo.mSource->prepareDrm failed. status: %d", status);
         return status;
     }
-    ALOGV("onPrepareDrm: mSource->prepareDrm succeeded");
+    ALOGV("onPrepareDrm: mCurrentSourceInfo.mSource->prepareDrm succeeded");
 
     if (mCrypto != NULL) {
         ALOGE("onPrepareDrm: Unexpected. Already having mCrypto: %p", mCrypto.get());
@@ -3004,8 +3037,8 @@
     status_t status;
     if (mCrypto != NULL) {
         // notifying the source first before removing crypto from codec
-        if (mSource != NULL) {
-            mSource->releaseDrm();
+        if (mCurrentSourceInfo.mSource != NULL) {
+            mCurrentSourceInfo.mSource->releaseDrm();
         }
 
         status=OK;
@@ -3090,4 +3123,12 @@
     TRESPASS();
 }
 
+NuPlayer2::SourceInfo::SourceInfo()
+    : mDataSourceType(DATA_SOURCE_TYPE_NONE),
+      mSrcId(0),
+      mSourceFlags(0),
+      mStartTimeUs(0),
+      mEndTimeUs(INT64_MAX) {
+}
+
 }  // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
index e55cdbe..4db0cbf 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
@@ -156,17 +156,33 @@
         kWhatReleaseDrm                 = 'rDrm',
     };
 
+    typedef enum {
+        DATA_SOURCE_TYPE_NONE,
+        DATA_SOURCE_TYPE_HTTP_LIVE,
+        DATA_SOURCE_TYPE_RTSP,
+        DATA_SOURCE_TYPE_GENERIC_URL,
+        DATA_SOURCE_TYPE_GENERIC_FD,
+        DATA_SOURCE_TYPE_MEDIA,
+    } DATA_SOURCE_TYPE;
+
+    struct SourceInfo {
+        SourceInfo();
+
+        sp<Source> mSource;
+        std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
+        int64_t mSrcId;
+        uint32_t mSourceFlags;
+        int64_t mStartTimeUs;
+        int64_t mEndTimeUs;
+    };
+
     wp<NuPlayer2Driver> mDriver;
     pid_t mPID;
     uid_t mUID;
     const sp<MediaClock> mMediaClock;
     Mutex mSourceLock;  // guard |mSource|.
-    sp<Source> mSource;
-    int64_t mSrcId;
-    uint32_t mSourceFlags;
-    sp<Source> mNextSource;
-    int64_t mNextSrcId;
-    uint32_t mNextSourceFlags;
+    SourceInfo mCurrentSourceInfo;
+    SourceInfo mNextSourceInfo;
     sp<ANativeWindowWrapper> mNativeWindow;
     sp<MediaPlayer2Interface::AudioSink> mAudioSink;
     sp<DecoderBase> mVideoDecoder;
@@ -252,18 +268,6 @@
     sp<AMediaCryptoWrapper> mCrypto;
     bool mIsDrmProtected;
 
-    typedef enum {
-        DATA_SOURCE_TYPE_NONE,
-        DATA_SOURCE_TYPE_HTTP_LIVE,
-        DATA_SOURCE_TYPE_RTSP,
-        DATA_SOURCE_TYPE_GENERIC_URL,
-        DATA_SOURCE_TYPE_GENERIC_FD,
-        DATA_SOURCE_TYPE_MEDIA,
-    } DATA_SOURCE_TYPE;
-
-    std::atomic<DATA_SOURCE_TYPE> mDataSourceType;
-    std::atomic<DATA_SOURCE_TYPE> mNextDataSourceType;
-
     inline const sp<DecoderBase> &getDecoder(bool audio) {
         return audio ? mAudioDecoder : mVideoDecoder;
     }
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
index 662235f..9298a99 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Source.h
@@ -69,7 +69,7 @@
             BufferingSettings* buffering /* nonnull */) = 0;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) = 0;
 
-    virtual void prepareAsync() = 0;
+    virtual void prepareAsync(int64_t startTimeUs) = 0;
 
     virtual void start() = 0;
     virtual void stop() {}
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
index 1dfe383..53c66c0 100644
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/RTSPSource2.cpp
@@ -96,7 +96,8 @@
     return OK;
 }
 
-void NuPlayer2::RTSPSource2::prepareAsync() {
+// TODO: fetch data starting from |startTimeUs|
+void NuPlayer2::RTSPSource2::prepareAsync(int64_t /* startTimeUs */) {
     if (mIsSDP && mHTTPService == NULL) {
         notifyPrepared(BAD_VALUE);
         return;
diff --git a/media/libmediaplayer2/nuplayer2/RTSPSource2.h b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
index 712c3e5..e5f1716 100644
--- a/media/libmediaplayer2/nuplayer2/RTSPSource2.h
+++ b/media/libmediaplayer2/nuplayer2/RTSPSource2.h
@@ -43,7 +43,7 @@
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
-    virtual void prepareAsync();
+    virtual void prepareAsync(int64_t startTimeUs);
     virtual void start();
     virtual void stop();
 
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b058552..3080db5 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1748,29 +1748,32 @@
     }
 
     int32_t storeMeta;
-    if (encoder
-            && msg->findInt32("android._input-metadata-buffer-type", &storeMeta)
-            && storeMeta != kMetadataBufferTypeInvalid) {
-        IOMX::PortMode mode;
-        if (storeMeta == kMetadataBufferTypeNativeHandleSource) {
-            mode = IOMX::kPortModeDynamicNativeHandle;
-        } else if (storeMeta == kMetadataBufferTypeANWBuffer ||
-                storeMeta == kMetadataBufferTypeGrallocSource) {
-            mode = IOMX::kPortModeDynamicANWBuffer;
-        } else {
-            return BAD_VALUE;
+    if (encoder) {
+        IOMX::PortMode mode = IOMX::kPortModePresetByteBuffer;
+        if (msg->findInt32("android._input-metadata-buffer-type", &storeMeta)
+                && storeMeta != kMetadataBufferTypeInvalid) {
+            if (storeMeta == kMetadataBufferTypeNativeHandleSource) {
+                mode = IOMX::kPortModeDynamicNativeHandle;
+            } else if (storeMeta == kMetadataBufferTypeANWBuffer ||
+                    storeMeta == kMetadataBufferTypeGrallocSource) {
+                mode = IOMX::kPortModeDynamicANWBuffer;
+            } else {
+                return BAD_VALUE;
+            }
         }
         err = setPortMode(kPortIndexInput, mode);
         if (err != OK) {
             return err;
         }
 
-        uint32_t usageBits;
-        if (mOMXNode->getParameter(
-                (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
-                &usageBits, sizeof(usageBits)) == OK) {
-            inputFormat->setInt32(
-                    "using-sw-read-often", !!(usageBits & GRALLOC_USAGE_SW_READ_OFTEN));
+        if (mode != IOMX::kPortModePresetByteBuffer) {
+            uint32_t usageBits;
+            if (mOMXNode->getParameter(
+                    (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
+                    &usageBits, sizeof(usageBits)) == OK) {
+                inputFormat->setInt32(
+                        "using-sw-read-often", !!(usageBits & GRALLOC_USAGE_SW_READ_OFTEN));
+            }
         }
     }
 
diff --git a/media/libstagefright/MetaDataUtils.cpp b/media/libstagefright/MetaDataUtils.cpp
index 5672145..2cf79c3 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -19,8 +19,10 @@
 #include <utils/Log.h>
 
 #include <media/stagefright/foundation/avc_utils.h>
+#include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaDataUtils.h>
 #include <media/stagefright/Utils.h>
@@ -192,4 +194,135 @@
     return true;
 }
 
+
+static void extractAlbumArt(
+        AMediaFormat *fileMeta, const void *data, size_t size) {
+    ALOGV("extractAlbumArt from '%s'", (const char *)data);
+
+    size_t inLen = strnlen((const char *)data, size);
+    size_t flacSize = inLen / 4 * 3;
+    uint8_t *flac = new uint8_t[flacSize];
+    if (!decodeBase64(flac, &flacSize, (const char*)data)) {
+        ALOGE("malformed base64 encoded data.");
+        delete[] flac;
+        return;
+    }
+
+    ALOGV("got flac of size %zu", flacSize);
+
+    uint32_t picType;
+    uint32_t typeLen;
+    uint32_t descLen;
+    uint32_t dataLen;
+    char type[128];
+
+    if (flacSize < 8) {
+        delete[] flac;
+        return;
+    }
+
+    picType = U32_AT(flac);
+
+    if (picType != 3) {
+        // This is not a front cover.
+        delete[] flac;
+        return;
+    }
+
+    typeLen = U32_AT(&flac[4]);
+    if (typeLen > sizeof(type) - 1) {
+        delete[] flac;
+        return;
+    }
+
+    // we've already checked above that flacSize >= 8
+    if (flacSize - 8 < typeLen) {
+        delete[] flac;
+        return;
+    }
+
+    memcpy(type, &flac[8], typeLen);
+    type[typeLen] = '\0';
+
+    ALOGV("picType = %d, type = '%s'", picType, type);
+
+    if (!strcmp(type, "-->")) {
+        // This is not inline cover art, but an external url instead.
+        delete[] flac;
+        return;
+    }
+
+    if (flacSize < 32 || flacSize - 32 < typeLen) {
+        delete[] flac;
+        return;
+    }
+
+    descLen = U32_AT(&flac[8 + typeLen]);
+    if (flacSize - 32 - typeLen < descLen) {
+        delete[] flac;
+        return;
+    }
+
+    dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
+
+    // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
+    if (flacSize - 32 - typeLen - descLen < dataLen) {
+        delete[] flac;
+        return;
+    }
+
+    ALOGV("got image data, %zu trailing bytes",
+         flacSize - 32 - typeLen - descLen - dataLen);
+
+    AMediaFormat_setBuffer(fileMeta, AMEDIAFORMAT_KEY_ALBUMART,
+            &flac[8 + typeLen + 4 + descLen + 20], dataLen);
+
+    delete[] flac;
+}
+
+void parseVorbisComment(
+        AMediaFormat *fileMeta, const char *comment, size_t commentLength) {
+    struct {
+        const char *const mTag;
+        const char *mKey;
+    } kMap[] = {
+        { "TITLE", AMEDIAFORMAT_KEY_TITLE },
+        { "ARTIST", AMEDIAFORMAT_KEY_ARTIST },
+        { "ALBUMARTIST", AMEDIAFORMAT_KEY_ALBUMARTIST },
+        { "ALBUM ARTIST", AMEDIAFORMAT_KEY_ALBUMARTIST },
+        { "COMPILATION", AMEDIAFORMAT_KEY_COMPILATION },
+        { "ALBUM", AMEDIAFORMAT_KEY_ALBUM },
+        { "COMPOSER", AMEDIAFORMAT_KEY_COMPOSER },
+        { "GENRE", AMEDIAFORMAT_KEY_GENRE },
+        { "AUTHOR", AMEDIAFORMAT_KEY_AUTHOR },
+        { "TRACKNUMBER", AMEDIAFORMAT_KEY_CDTRACKNUMBER },
+        { "DISCNUMBER", AMEDIAFORMAT_KEY_DISCNUMBER },
+        { "DATE", AMEDIAFORMAT_KEY_DATE },
+        { "YEAR", AMEDIAFORMAT_KEY_YEAR },
+        { "LYRICIST", AMEDIAFORMAT_KEY_LYRICIST },
+        { "METADATA_BLOCK_PICTURE", AMEDIAFORMAT_KEY_ALBUMART },
+        { "ANDROID_LOOP", AMEDIAFORMAT_KEY_LOOP },
+    };
+
+        for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
+            size_t tagLen = strlen(kMap[j].mTag);
+            if (!strncasecmp(kMap[j].mTag, comment, tagLen)
+                    && comment[tagLen] == '=') {
+                if (kMap[j].mKey == AMEDIAFORMAT_KEY_ALBUMART) {
+                    extractAlbumArt(
+                            fileMeta,
+                            &comment[tagLen + 1],
+                            commentLength - tagLen - 1);
+                } else if (kMap[j].mKey == AMEDIAFORMAT_KEY_LOOP) {
+                    if (!strcasecmp(&comment[tagLen + 1], "true")) {
+                        AMediaFormat_setInt32(fileMeta, AMEDIAFORMAT_KEY_LOOP, 1);
+                    }
+                } else {
+                    AMediaFormat_setString(fileMeta, kMap[j].mKey, &comment[tagLen + 1]);
+                }
+            }
+        }
+
+}
+
 }  // namespace android
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index ebc3b33..456e2e3 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -569,6 +569,62 @@
 }
 
 
+std::vector<std::pair<const char *, uint32_t>> tagMappings {
+    {
+        { "album", kKeyAlbum },
+        { "albumartist", kKeyAlbumArtist },
+        { "artist", kKeyArtist },
+        { "author", kKeyAuthor },
+        { "cdtracknum", kKeyCDTrackNumber },
+        { "compilation", kKeyCompilation },
+        { "composer", kKeyComposer },
+        { "date", kKeyDate },
+        { "discnum", kKeyDiscNumber },
+        { "genre", kKeyGenre },
+        { "lyricist", kKeyWriter },
+        { "title", kKeyTitle },
+        { "year", kKeyYear },
+    }
+};
+
+void convertMessageToMetaDataTags(const sp<AMessage> &msg, sp<MetaData> &meta) {
+    for (auto elem : tagMappings) {
+        AString value;
+        if (msg->findString(elem.first, &value)) {
+            meta->setCString(elem.second, value.c_str());
+        }
+    }
+    sp<ABuffer> buf;
+    if (msg->findBuffer("albumart", &buf)) {
+        meta->setData(kKeyAlbumArt, MetaDataBase::Type::TYPE_NONE, buf->data(), buf->size());
+    }
+
+    int32_t loop;
+    if (msg->findInt32("loop", &loop)) {
+        meta->setInt32(kKeyAutoLoop, loop);
+    }
+}
+
+void convertMetaDataToMessageTags(const MetaDataBase *meta, sp<AMessage> format) {
+    for (auto elem : tagMappings) {
+        const char *value;
+        if (meta->findCString(elem.second, &value)) {
+            format->setString(elem.first, value, strlen(value));
+        }
+    }
+    uint32_t type;
+    const void* data;
+    size_t size;
+    if (meta->findData(kKeyAlbumArt, &type, &data, &size)) {
+        sp<ABuffer> buf = ABuffer::CreateAsCopy(data, size);
+        format->setBuffer("albumart", buf);
+    }
+    int32_t loop;
+    if (meta->findInt32(kKeyAutoLoop, &loop)) {
+        format->setInt32("loop", loop);
+    }
+}
+
 status_t convertMetaDataToMessage(
         const sp<MetaData> &meta, sp<AMessage> *format) {
     return convertMetaDataToMessage(meta.get(), format);
@@ -592,6 +648,8 @@
     sp<AMessage> msg = new AMessage;
     msg->setString("mime", mime);
 
+    convertMetaDataToMessageTags(meta, msg);
+
     uint32_t type;
     const void *data;
     size_t size;
@@ -1298,6 +1356,8 @@
         ALOGW("did not find mime type");
     }
 
+    convertMessageToMetaDataTags(msg, meta);
+
     int64_t durationUs;
     if (msg->findInt64("durationUs", &durationUs)) {
         meta->setInt64(kKeyDuration, durationUs);
diff --git a/media/libstagefright/bqhelper/GraphicBufferSource.cpp b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
index 6d93807..8c1da76 100644
--- a/media/libstagefright/bqhelper/GraphicBufferSource.cpp
+++ b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
@@ -1106,6 +1106,14 @@
         consumerUsage |= GRALLOC_USAGE_HW_VIDEO_ENCODER;
         mConsumer->setConsumerUsageBits(consumerUsage);
 
+        // Set impl. defined format as default. Depending on the usage flags
+        // the device-specific implementation will derive the exact format.
+        err = mConsumer->setDefaultBufferFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+        if (err != NO_ERROR) {
+            ALOGE("Failed to configure surface default format ret: %d", err);
+            return err;
+        }
+
         // Sets the default buffer data space
         ALOGD("setting dataspace: %#x, acquired=%d", dataSpace, mNumOutstandingAcquires);
         mConsumer->setDefaultBufferDataSpace((android_dataspace)dataSpace);
diff --git a/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp b/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp
index 4868822..36a7393 100644
--- a/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp
+++ b/media/libstagefright/codecs/amrwb/src/dec_acelp_4p_in_64.cpp
@@ -234,6 +234,7 @@
                 dec_6p_6N_2(L_index, 4, 0, pos);
                 add_pulses(pos, 6, k, code);
             }
+            break;
         default:
             break;
     }
diff --git a/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp b/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp
index 0325311..4d1126e 100644
--- a/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp
+++ b/media/libstagefright/codecs/amrwb/src/normalize_amr_wb.cpp
@@ -170,6 +170,7 @@
         case 0x38000000:
         case 0x30000000:
             i++;
+            break;
 
         default:
             ;
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp
index e579bbd..885ab08 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_normalize.cpp
@@ -160,6 +160,7 @@
         case 0x38000000:
         case 0x30000000:
             i++;
+            break;
 
         default:
             ;
diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
index 8f32582..834b88f 100644
--- a/media/libstagefright/foundation/base64.cpp
+++ b/media/libstagefright/foundation/base64.cpp
@@ -28,14 +28,31 @@
         return NULL;
     }
 
+    size_t bufSize = n / 4 * 3;
+    sp<ABuffer> buf = new ABuffer(bufSize);
+
+    if (decodeBase64(buf->data(), &bufSize, s.c_str())) {
+        buf->setRange(0, bufSize);
+        return buf;
+    }
+    return NULL;
+}
+
+bool decodeBase64(uint8_t *out, size_t *inOutBufSize, const char* s) {
+    size_t n = strlen(s);
+
+    if ((n % 4) != 0) {
+        return false;
+    }
+
     size_t padding = 0;
-    if (n >= 1 && s.c_str()[n - 1] == '=') {
+    if (n >= 1 && s[n - 1] == '=') {
         padding = 1;
 
-        if (n >= 2 && s.c_str()[n - 2] == '=') {
+        if (n >= 2 && s[n - 2] == '=') {
             padding = 2;
 
-            if (n >= 3 && s.c_str()[n - 3] == '=') {
+            if (n >= 3 && s[n - 3] == '=') {
                 padding = 3;
             }
         }
@@ -45,15 +62,13 @@
     // already made sure that n % 4 == 0.
     size_t outLen = (n / 4) * 3 - padding;
 
-    sp<ABuffer> buffer = new ABuffer(outLen);
-    uint8_t *out = buffer->data();
-    if (out == NULL || buffer->size() < outLen) {
-        return NULL;
+    if (out == NULL || *inOutBufSize < outLen) {
+        return false;
     }
     size_t j = 0;
     uint32_t accum = 0;
     for (size_t i = 0; i < n; ++i) {
-        char c = s.c_str()[i];
+        char c = s[i];
         unsigned value;
         if (c >= 'A' && c <= 'Z') {
             value = c - 'A';
@@ -66,10 +81,10 @@
         } else if (c == '/' || c == '_') {
             value = 63;
         } else if (c != '=') {
-            return NULL;
+            return false;
         } else {
             if (i < n - padding) {
-                return NULL;
+                return false;
             }
 
             value = 0;
@@ -86,7 +101,8 @@
         }
     }
 
-    return buffer;
+    *inOutBufSize = j;
+    return true;
 }
 
 static char encode6Bit(unsigned x) {
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
index abc95e0..60fb9ff 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
@@ -26,6 +26,9 @@
 struct AString;
 
 sp<ABuffer> decodeBase64(const AString &s);
+
+bool decodeBase64(uint8_t *out, size_t *inOutBufSize, const char* s);
+
 void encodeBase64(const void *data, size_t size, AString *out);
 
 void encodeBase64Url(const void *data, size_t size, AString *out);
diff --git a/media/libstagefright/include/media/stagefright/MetaDataUtils.h b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
index fd79a9e..e87c7f9 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataUtils.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
@@ -34,6 +34,9 @@
 bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
         unsigned channel_configuration);
 
+void parseVorbisComment(
+        AMediaFormat *fileMeta, const char *comment, size_t commentLength);
+
 }  // namespace android
 
 #endif  // META_DATA_UTILS_H_
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 99762b9..68b375a 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -536,6 +536,9 @@
     }
 
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (cmd == OMX_CommandStateSet) {
         // There are no configurations past first StateSet command.
@@ -600,6 +603,9 @@
 status_t OMXNodeInstance::getParameter(
         OMX_INDEXTYPE index, void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (isProhibitedIndex_l(index)) {
         android_errorWriteLog(0x534e4554, "29422020");
@@ -618,6 +624,10 @@
 status_t OMXNodeInstance::setParameter(
         OMX_INDEXTYPE index, const void *params, size_t size) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
 
@@ -639,6 +649,9 @@
 status_t OMXNodeInstance::getConfig(
         OMX_INDEXTYPE index, void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (isProhibitedIndex_l(index)) {
         android_errorWriteLog(0x534e4554, "29422020");
@@ -657,6 +670,10 @@
 status_t OMXNodeInstance::setConfig(
         OMX_INDEXTYPE index, const void *params, size_t size) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     CLOG_CONFIG(setConfig, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
 
@@ -673,6 +690,9 @@
 
 status_t OMXNodeInstance::setPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (portIndex >= NELEM(mPortMode)) {
         ALOGE("b/31385713, portIndex(%u)", portIndex);
@@ -855,6 +875,9 @@
 status_t OMXNodeInstance::getGraphicBufferUsage(
         OMX_U32 portIndex, OMX_U32* usage) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     OMX_INDEXTYPE index;
     OMX_STRING name = const_cast<OMX_STRING>(
@@ -968,6 +991,10 @@
         OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
         OMX_U32 maxFrameHeight) {
     Mutex::Autolock autolock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     if (mSailed) {
         android_errorWriteLog(0x534e4554, "29422020");
         return INVALID_OPERATION;
@@ -1008,6 +1035,10 @@
         OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync,
         native_handle_t **sidebandHandle) {
     Mutex::Autolock autolock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     if (mSailed) {
         android_errorWriteLog(0x534e4554, "29422020");
         return INVALID_OPERATION;
@@ -1062,6 +1093,10 @@
     }
 
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     if (!mSailed) {
         ALOGE("b/35467458");
         android_errorWriteLog(0x534e4554, "35467458");
@@ -1478,6 +1513,9 @@
 status_t OMXNodeInstance::setInputSurface(
         const sp<IOMXBufferSource> &bufferSource) {
     Mutex::Autolock autolock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     status_t err;
 
@@ -1544,6 +1582,9 @@
     }
 
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     if (!mSailed) {
         ALOGE("b/35467458");
@@ -1600,6 +1641,10 @@
 status_t OMXNodeInstance::freeBuffer(
         OMX_U32 portIndex, IOMX::buffer_id buffer) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
+
     CLOG_BUFFER(freeBuffer, "%s:%u %#x", portString(portIndex), portIndex, buffer);
 
     removeActiveBuffer(portIndex, buffer);
@@ -1627,6 +1672,9 @@
 status_t OMXNodeInstance::fillBuffer(
         IOMX::buffer_id buffer, const OMXBuffer &omxBuffer, int fenceFd) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexOutput);
     if (header == NULL) {
@@ -1677,6 +1725,9 @@
         buffer_id buffer, const OMXBuffer &omxBuffer,
         OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     switch (omxBuffer.mBufferType) {
     case OMXBuffer::kBufferTypePreset:
@@ -1991,6 +2042,9 @@
 status_t OMXNodeInstance::getExtensionIndex(
         const char *parameterName, OMX_INDEXTYPE *index) {
     Mutex::Autolock autoLock(mLock);
+    if (mHandle == NULL) {
+        return DEAD_OBJECT;
+    }
 
     OMX_ERRORTYPE err = OMX_GetExtensionIndex(
             mHandle, const_cast<char *>(parameterName), index);
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 0667df1..49e01c0 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -400,8 +400,10 @@
         switch (count) {
             case 3:
                 data[offset++] = 0;
+                [[fallthrough]];
             case 2:
                 data[offset++] = 0;
+                [[fallthrough]];
             case 1:
                 data[offset++] = 0;
         }
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 43c89bb..3c10024 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -224,6 +224,11 @@
     }
 
     sp<DataSource> source = DataSourceFactory::CreateFromURI(service, uri, &headers);
+    if (source == NULL) {
+        ALOGE("AMediaDataSource_newUri source is null");
+        return NULL;
+    }
+    ALOGI("AMediaDataSource_newUri source %s flags %u", source->toString().c_str(), source->flags());
     AMediaDataSource* aSource = convertDataSourceToAMediaDataSource(source);
     aSource->mImpl = source;
     aSource->mFlags = source->flags();
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 503f726..22fbb42 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -268,27 +268,40 @@
 EXPORT const char* AMEDIAFORMAT_KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count";
 EXPORT const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile";
 EXPORT const char* AMEDIAFORMAT_KEY_AAC_SBR_MODE = "aac-sbr-mode";
+EXPORT const char* AMEDIAFORMAT_KEY_ALBUM = "album";
+EXPORT const char* AMEDIAFORMAT_KEY_ALBUMART = "albumart";
+EXPORT const char* AMEDIAFORMAT_KEY_ALBUMARTIST = "albumartist";
+EXPORT const char* AMEDIAFORMAT_KEY_ARTIST = "artist";
 EXPORT const char* AMEDIAFORMAT_KEY_AUDIO_SESSION_ID = "audio-session-id";
+EXPORT const char* AMEDIAFORMAT_KEY_AUTHOR = "author";
 EXPORT const char* AMEDIAFORMAT_KEY_BITRATE_MODE = "bitrate-mode";
 EXPORT const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate";
 EXPORT const char* AMEDIAFORMAT_KEY_CAPTURE_RATE = "capture-rate";
+EXPORT const char* AMEDIAFORMAT_KEY_CDTRACKNUMBER = "cdtracknum";
 EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count";
 EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_MASK = "channel-mask";
 EXPORT const char* AMEDIAFORMAT_KEY_COLOR_FORMAT = "color-format";
 EXPORT const char* AMEDIAFORMAT_KEY_COLOR_RANGE = "color-range";
 EXPORT const char* AMEDIAFORMAT_KEY_COLOR_STANDARD = "color-standard";
 EXPORT const char* AMEDIAFORMAT_KEY_COLOR_TRANSFER = "color-transfer";
+EXPORT const char* AMEDIAFORMAT_KEY_COMPILATION = "compilation";
 EXPORT const char* AMEDIAFORMAT_KEY_COMPLEXITY = "complexity";
+EXPORT const char* AMEDIAFORMAT_KEY_COMPOSER = "composer";
 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_DATE = "date";
+EXPORT const char* AMEDIAFORMAT_KEY_DISCNUMBER = "discnum";
 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_ENCODER_DELAY = "encoder-delay";
+EXPORT const char* AMEDIAFORMAT_KEY_ENCODER_PADDING = "encoder-padding";
 EXPORT const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
 EXPORT const char* AMEDIAFORMAT_KEY_FRAME_RATE = "frame-rate";
+EXPORT const char* AMEDIAFORMAT_KEY_GENRE = "genre";
 EXPORT const char* AMEDIAFORMAT_KEY_GRID_COLUMNS = "grid-cols";
 EXPORT const char* AMEDIAFORMAT_KEY_GRID_ROWS = "grid-rows";
 EXPORT const char* AMEDIAFORMAT_KEY_HDR_STATIC_INFO = "hdr-static-info";
@@ -302,6 +315,8 @@
 EXPORT const char* AMEDIAFORMAT_KEY_LANGUAGE = "language";
 EXPORT const char* AMEDIAFORMAT_KEY_LATENCY = "latency";
 EXPORT const char* AMEDIAFORMAT_KEY_LEVEL = "level";
+EXPORT const char* AMEDIAFORMAT_KEY_LOOP = "loop";
+EXPORT const char* AMEDIAFORMAT_KEY_LYRICIST = "lyricist";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
 EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";
@@ -323,9 +338,11 @@
 EXPORT const char* AMEDIAFORMAT_KEY_TILE_HEIGHT = "tile-height";
 EXPORT const char* AMEDIAFORMAT_KEY_TILE_WIDTH = "tile-width";
 EXPORT const char* AMEDIAFORMAT_KEY_TIME_US = "timeUs";
+EXPORT const char* AMEDIAFORMAT_KEY_TITLE = "title";
 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";
+EXPORT const char* AMEDIAFORMAT_KEY_YEAR = "year";
 
 
 } // extern "C"
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 3f853d0..3fc28f3 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -86,10 +86,6 @@
 void AMediaFormat_setBuffer(AMediaFormat*, const char* name, const void* data, size_t size) __INTRODUCED_IN(21);
 
 
-
-/**
- * XXX should these be ints/enums that we look up in a table as needed?
- */
 extern const char* AMEDIAFORMAT_KEY_AAC_DRC_ATTENUATION_FACTOR __INTRODUCED_IN(28);
 extern const char* AMEDIAFORMAT_KEY_AAC_DRC_BOOST_FACTOR __INTRODUCED_IN(28);
 extern const char* AMEDIAFORMAT_KEY_AAC_DRC_HEAVY_COMPRESSION __INTRODUCED_IN(28);
@@ -156,7 +152,6 @@
 extern const char* AMEDIAFORMAT_KEY_TRACK_ID __INTRODUCED_IN(28);
 extern const char* AMEDIAFORMAT_KEY_TRACK_INDEX __INTRODUCED_IN(28);
 extern const char* AMEDIAFORMAT_KEY_WIDTH __INTRODUCED_IN(21);
-
 #endif /* __ANDROID_API__ >= 21 */
 
 #if __ANDROID_API__ >= 28
@@ -180,6 +175,25 @@
  * copy one AMediaFormat to another
  */
 media_status_t AMediaFormat_copy(AMediaFormat *to, AMediaFormat *from) __INTRODUCED_IN(29);
+
+extern const char* AMEDIAFORMAT_KEY_ALBUM __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ALBUMART __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ALBUMARTIST __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ARTIST __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_AUTHOR __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_CDTRACKNUMBER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_COMPILATION __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_COMPOSER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_DATE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_DISCNUMBER __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ENCODER_DELAY __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_ENCODER_PADDING __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_GENRE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_LOOP __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_LYRICIST __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_TITLE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_YEAR __INTRODUCED_IN(29);
+
 #endif /* __ANDROID_API__ >= 29 */
 
 __END_DECLS
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 7f16289..802f86f 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -35,7 +35,6 @@
 import android.media.MediaPlayer2;
 import android.media.MediaPlayer2.EventCallback;
 import android.media.MediaPlayer2Impl;
-import android.media.Metadata;
 import android.media.PlaybackParams;
 import android.media.SessionToken2;
 import android.media.SubtitleData;
@@ -125,7 +124,7 @@
     private MediaControlView2 mMediaControlView;
     private MediaSession mMediaSession;
     private MediaController mMediaController;
-    private Metadata mMetadata;
+    private boolean mSeekable;
     private MediaMetadata2 mMediaMetadata;
     private MediaMetadataRetriever mRetriever;
     private boolean mNeedUpdateMediaType;
@@ -262,6 +261,7 @@
         mSpeed = 1.0f;
         mFallbackSpeed = mSpeed;
         mSelectedSubtitleTrackIndex = INVALID_TRACK_INDEX;
+        mSeekable = true;
         // TODO: add attributes to get this value.
         mShowControllerIntervalMs = DEFAULT_SHOW_CONTROLLER_INTERVAL_MS;
 
@@ -795,33 +795,11 @@
 
     private void updatePlaybackState() {
         if (mStateBuilder == null) {
-            // Get the capabilities of the player for this stream
-            mMetadata = mMediaPlayer.getMetadata(MediaPlayer2.METADATA_ALL,
-                    MediaPlayer2.BYPASS_METADATA_FILTER);
-
             // Add Play action as default
-            long playbackActions = PlaybackState.ACTION_PLAY;
-            if (mMetadata != null) {
-                if (!mMetadata.has(Metadata.PAUSE_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.PAUSE_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_PAUSE;
-                }
-                if (!mMetadata.has(Metadata.SEEK_BACKWARD_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_REWIND;
-                }
-                if (!mMetadata.has(Metadata.SEEK_FORWARD_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_FAST_FORWARD;
-                }
-                if (!mMetadata.has(Metadata.SEEK_AVAILABLE)
-                        || mMetadata.getBoolean(Metadata.SEEK_AVAILABLE)) {
-                    playbackActions |= PlaybackState.ACTION_SEEK_TO;
-                }
-            } else {
-                playbackActions |= (PlaybackState.ACTION_PAUSE |
-                        PlaybackState.ACTION_REWIND | PlaybackState.ACTION_FAST_FORWARD |
-                        PlaybackState.ACTION_SEEK_TO);
+            long playbackActions = PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE;
+            if (mSeekable) {
+                playbackActions |= (PlaybackState.ACTION_REWIND |
+                        PlaybackState.ACTION_FAST_FORWARD | PlaybackState.ACTION_SEEK_TO);
             }
             mStateBuilder = new PlaybackState.Builder();
             mStateBuilder.setActions(playbackActions);
@@ -1004,9 +982,6 @@
     private void extractMetadata() {
         // Get and set duration and title values as MediaMetadata for MediaControlView2
         MediaMetadata.Builder builder = new MediaMetadata.Builder();
-        if (mMetadata != null && mMetadata.has(Metadata.TITLE)) {
-            mTitle = mMetadata.getString(Metadata.TITLE);
-        }
         builder.putString(MediaMetadata.METADATA_KEY_TITLE, mTitle);
         builder.putLong(
                 MediaMetadata.METADATA_KEY_DURATION, mMediaPlayer.getDuration());
@@ -1169,6 +1144,8 @@
                         this.onCompletion(mp, dsd);
                     } else if (what == MediaPlayer2.MEDIA_INFO_BUFFERING_UPDATE) {
                         this.onBufferingUpdate(mp, dsd, extra);
+                    } else if (what == MediaPlayer2.MEDIA_INFO_NOT_SEEKABLE) {
+                        mSeekable = false;
                     }
                 }
 
@@ -1180,6 +1157,7 @@
                     }
                     mCurrentState = STATE_ERROR;
                     mTargetState = STATE_ERROR;
+                    mSeekable = true;
                     updatePlaybackState();
 
                     if (mMediaControlView != null) {
@@ -1254,6 +1232,7 @@
                 private void onCompletion(MediaPlayer2 mp, DataSourceDesc dsd) {
                     mCurrentState = STATE_PLAYBACK_COMPLETED;
                     mTargetState = STATE_PLAYBACK_COMPLETED;
+                    mSeekable = true;
                     updatePlaybackState();
                     if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {
                         mAudioManager.abandonAudioFocus(null);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 01c5ea2..52a8fa8 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -6654,6 +6654,7 @@
 
                 case TrackBase::PAUSING:
                     mActiveTracks.remove(activeTrack);
+                    activeTrack->mState = TrackBase::PAUSED;
                     doBroadcast = true;
                     size--;
                     continue;
@@ -6675,12 +6676,12 @@
                     allStopped = false;
                     break;
 
-                case TrackBase::IDLE:
-                    i++;
-                    continue;
-
+                case TrackBase::IDLE:    // cannot be on ActiveTracks if idle
+                case TrackBase::PAUSED:  // cannot be on ActiveTracks if paused
+                case TrackBase::STOPPED: // cannot be on ActiveTracks if destroyed/terminated
                 default:
-                    LOG_ALWAYS_FATAL("Unexpected activeTrackState %d", activeTrackState);
+                    LOG_ALWAYS_FATAL("%s: Unexpected active track state:%d, id:%d, tracks:%zu",
+                            __func__, activeTrackState, activeTrack->id(), size);
                 }
 
                 activeTracks.add(activeTrack);
@@ -7323,8 +7324,14 @@
     {
         // This section is a rendezvous between binder thread executing start() and RecordThread
         AutoMutex lock(mLock);
+        if (recordTrack->isInvalid()) {
+            recordTrack->clearSyncStartEvent();
+            return INVALID_OPERATION;
+        }
         if (mActiveTracks.indexOf(recordTrack) >= 0) {
             if (recordTrack->mState == TrackBase::PAUSING) {
+                // We haven't stopped yet (moved to PAUSED and not in mActiveTracks)
+                // so no need to startInput().
                 ALOGV("active record track PAUSING -> ACTIVE");
                 recordTrack->mState = TrackBase::ACTIVE;
             } else {
@@ -7344,11 +7351,30 @@
             bool silenced;
             status = AudioSystem::startInput(recordTrack->portId(), &silenced);
             mLock.lock();
-            // FIXME should verify that recordTrack is still in mActiveTracks
+            if (recordTrack->isInvalid()) {
+                recordTrack->clearSyncStartEvent();
+                if (status == NO_ERROR && recordTrack->mState == TrackBase::STARTING_1) {
+                    recordTrack->mState = TrackBase::STARTING_2;
+                    // STARTING_2 forces destroy to call stopInput.
+                }
+                return INVALID_OPERATION;
+            }
+            if (recordTrack->mState != TrackBase::STARTING_1) {
+                ALOGW("%s(%d): unsynchronized mState:%d change",
+                    __func__, recordTrack->id(), recordTrack->mState);
+                // Someone else has changed state, let them take over,
+                // leave mState in the new state.
+                recordTrack->clearSyncStartEvent();
+                return INVALID_OPERATION;
+            }
+            // we're ok, but perhaps startInput has failed
             if (status != NO_ERROR) {
+                ALOGW("%s(%d): startInput failed, status %d",
+                    __func__, recordTrack->id(), status);
+                // We are in ActiveTracks if STARTING_1 and valid, so remove from ActiveTracks,
+                // leave in STARTING_1, so destroy() will not call stopInput.
                 mActiveTracks.remove(recordTrack);
                 recordTrack->clearSyncStartEvent();
-                ALOGV("RecordThread::start error %d", status);
                 return status;
             }
             recordTrack->setSilenced(silenced);
@@ -7366,21 +7392,8 @@
         recordTrack->mState = TrackBase::STARTING_2;
         // signal thread to start
         mWaitWorkCV.broadcast();
-        if (mActiveTracks.indexOf(recordTrack) < 0) {
-            ALOGV("Record failed to start");
-            status = BAD_VALUE;
-            goto startError;
-        }
         return status;
     }
-
-startError:
-    if (recordTrack->isExternalTrack()) {
-        AudioSystem::stopInput(recordTrack->portId());
-    }
-    recordTrack->clearSyncStartEvent();
-    // FIXME I wonder why we do not reset the state here?
-    return status;
 }
 
 void AudioFlinger::RecordThread::syncStartEventCallback(const wp<SyncEvent>& event)
@@ -7399,24 +7412,26 @@
 bool AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
     ALOGV("RecordThread::stop");
     AutoMutex _l(mLock);
+    // if we're invalid, we can't be on the ActiveTracks.
     if (mActiveTracks.indexOf(recordTrack) < 0 || recordTrack->mState == TrackBase::PAUSING) {
         return false;
     }
     // note that threadLoop may still be processing the track at this point [without lock]
     recordTrack->mState = TrackBase::PAUSING;
-    // signal thread to stop
-    mWaitWorkCV.broadcast();
-    // do not wait for mStartStopCond if exiting
-    if (exitPending()) {
-        return true;
+
+    while (recordTrack->mState == TrackBase::PAUSING && !recordTrack->isInvalid()) {
+        mWaitWorkCV.broadcast(); // signal thread to stop
+        mStartStopCond.wait(mLock);
     }
-    // FIXME incorrect usage of wait: no explicit predicate or loop
-    mStartStopCond.wait(mLock);
-    // if we have been restarted, recordTrack is in mActiveTracks here
-    if (exitPending() || mActiveTracks.indexOf(recordTrack) < 0) {
+
+    if (recordTrack->mState == TrackBase::PAUSED) { // successful stop
         ALOGV("Record stopped OK");
         return true;
     }
+
+    // don't handle anything - we've been invalidated or restarted and in a different state
+    ALOGW_IF("%s(%d): unsynchronized stop, state: %d",
+            __func__, recordTrack->id(), recordTrack->mState);
     return false;
 }
 
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 92e79f2..c94639b 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -25,13 +25,13 @@
 public:
     enum track_state {
         IDLE,
-        FLUSHED,
+        FLUSHED,        // for PlaybackTracks only
         STOPPED,
         // next 2 states are currently used for fast tracks
         // and offloaded tracks only
         STOPPING_1,     // waiting for first underrun
         STOPPING_2,     // waiting for presentation complete
-        RESUMING,
+        RESUMING,       // for PlaybackTracks only
         ACTIVE,
         PAUSING,
         PAUSED,
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index a99bbe1..f2617ae 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1823,17 +1823,34 @@
     // see comments at AudioFlinger::PlaybackThread::Track::destroy()
     sp<RecordTrack> keep(this);
     {
-        if (isExternalTrack()) {
-            if (mState == ACTIVE || mState == RESUMING) {
-                AudioSystem::stopInput(mPortId);
-            }
-            AudioSystem::releaseInput(mPortId);
-        }
+        track_state priorState = mState;
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
             Mutex::Autolock _l(thread->mLock);
             RecordThread *recordThread = (RecordThread *) thread.get();
-            recordThread->destroyTrack_l(this);
+            priorState = mState;
+            recordThread->destroyTrack_l(this); // move mState to STOPPED, terminate
+        }
+        // APM portid/client management done outside of lock.
+        // NOTE: if thread doesn't exist, the input descriptor probably doesn't either.
+        if (isExternalTrack()) {
+            switch (priorState) {
+            case ACTIVE:     // invalidated while still active
+            case STARTING_2: // invalidated/start-aborted after startInput successfully called
+            case PAUSING:    // invalidated while in the middle of stop() pausing (still active)
+                AudioSystem::stopInput(mPortId);
+                break;
+
+            case STARTING_1: // invalidated/start-aborted and startInput not successful
+            case PAUSED:     // OK, not active
+            case IDLE:       // OK, not active
+                break;
+
+            case STOPPED:    // unexpected (destroyed)
+            default:
+                LOG_ALWAYS_FATAL("%s(%d): invalid prior state: %d", __func__, mId, priorState);
+            }
+            AudioSystem::releaseInput(mPortId);
         }
     }
 }
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index f42cdd3..97f7fdc 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -551,9 +551,11 @@
         return DONE;
     }
 
-    if (l.mParameters.isDeviceZslSupported) {
+    if ((l.mParameters.isDeviceZslSupported) && (l.mParameters.state != Parameters::RECORD) &&
+            (l.mParameters.state != Parameters::VIDEO_SNAPSHOT)) {
         // If device ZSL is supported, drop all pending preview buffers to reduce the chance of
         // rendering preview frames newer than the still frame.
+        // Additionally, preview must not get interrupted during video recording.
         client->getCameraDevice()->dropStreamBuffers(true, client->getPreviewStreamId());
     }
 
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index 314ff01..789548d 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -72,7 +72,27 @@
 LOCAL_REQUIRED_MODULES_arm := crash_dump.policy mediacodec.policy
 LOCAL_REQUIRED_MODULES_x86 := crash_dump.policy mediacodec.policy
 endif
-LOCAL_SRC_FILES := main_swcodecservice.cpp
+LOCAL_SRC_FILES := \
+    main_swcodecservice.cpp \
+    MediaCodecUpdateService.cpp \
+
+sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
+  $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+  $(UBSAN_RUNTIME_LIBRARY) \
+  $(TSAN_RUNTIME_LIBRARY) \
+  $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+  $(2ND_UBSAN_RUNTIME_LIBRARY) \
+  $(2ND_TSAN_RUNTIME_LIBRARY)))
+
+# $(info Sanitizer:  $(sanitizer_runtime_libraries))
+
+llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\
+  $(LLNDK_LIBRARIES)))
+
+# $(info LLNDK:  $(llndk_libraries))
+
+LOCAL_CFLAGS := -DLINKED_LIBRARIES='"$(sanitizer_runtime_libraries):$(llndk_libraries)"'
+
 LOCAL_SHARED_LIBRARIES := \
     libavservices_minijail \
     libbase \
@@ -89,6 +109,9 @@
 LOCAL_INIT_RC := mediaswcodec.rc
 LOCAL_32_BIT_ONLY := true
 
+sanitizer_runtime_libraries :=
+llndk_libraries :=
+
 include $(BUILD_EXECUTABLE)
 
 ####################################################################
diff --git a/services/mediacodec/MediaCodecUpdateService.cpp b/services/mediacodec/MediaCodecUpdateService.cpp
new file mode 100644
index 0000000..a2bb469
--- /dev/null
+++ b/services/mediacodec/MediaCodecUpdateService.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MediaCodecUpdateService"
+//#define LOG_NDEBUG 0
+
+#include <android/dlext.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <media/CodecServiceRegistrant.h>
+#include <utils/Log.h>
+#include <ziparchive/zip_archive.h>
+#include <cutils/properties.h>
+
+#include "MediaCodecUpdateService.h"
+
+// Copied from GraphicsEnv.cpp
+// TODO(b/37049319) Get this from a header once one exists
+extern "C" {
+  android_namespace_t* android_create_namespace(const char* name,
+                                                const char* ld_library_path,
+                                                const char* default_library_path,
+                                                uint64_t type,
+                                                const char* permitted_when_isolated_path,
+                                                android_namespace_t* parent);
+  bool android_link_namespaces(android_namespace_t* from,
+                               android_namespace_t* to,
+                               const char* shared_libs_sonames);
+  enum {
+     ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+  };
+}
+
+namespace android {
+namespace media {
+
+binder::Status MediaCodecUpdateService::loadPlugins(const ::std::string& apkPath) {
+    ALOGV("loadPlugins %s", apkPath.c_str());
+
+    ZipArchiveHandle zipHandle;
+    void *registrantLib = NULL;
+    int32_t ret = OpenArchive(apkPath.c_str(), &zipHandle);
+
+    if (ret == 0) {
+        char abilist32[PROPERTY_VALUE_MAX];
+        property_get("ro.product.cpu.abilist32", abilist32, "armeabi-v7a");
+
+        auto abis = base::Split(abilist32, ",");
+        if (abis.empty()) {
+            ALOGW("abilist is empty, trying armeabi-v7a ...");
+            abis.push_back("armeabi-v7a");
+        }
+
+        // TODO: Only try the first entry in abilist32 for now.
+        // We probably should try the next if it fails.
+        String8 libPathInApk = String8("lib/") + String8(abis[0].c_str());
+        String8 defaultLibPath = String8(apkPath.c_str()) + "!/" + libPathInApk;
+        String8 libPath = defaultLibPath + "/libmedia_codecserviceregistrant.so";
+
+        ZipEntry entry;
+        ZipString name(libPathInApk + "/libmedia_codecserviceregistrant.so");
+        ret = FindEntry(zipHandle, name, &entry);
+
+        if (ret == 0) {
+            android_namespace_t *codecNs = android_create_namespace("codecs",
+                    nullptr,  // ld_library_path
+                    defaultLibPath.c_str(),
+                    ANDROID_NAMESPACE_TYPE_ISOLATED,
+                    nullptr,  // permitted_when_isolated_path
+                    nullptr); // parent
+
+            if (codecNs != nullptr) {
+                String8 linked_libraries(LINKED_LIBRARIES);
+                if (android_link_namespaces(
+                        codecNs, nullptr, linked_libraries.c_str())) {
+                    const android_dlextinfo dlextinfo = {
+                            .flags = ANDROID_DLEXT_USE_NAMESPACE,
+                            .library_namespace = codecNs,
+                    };
+
+                    registrantLib = android_dlopen_ext(
+                            libPath.string(),
+                            RTLD_NOW | RTLD_LOCAL, &dlextinfo);
+
+                    if (registrantLib == NULL) {
+                        ALOGE("Failed to load lib from archive: %s", dlerror());
+                    }
+                } else {
+                    ALOGE("Failed to link namespace");
+                }
+            } else {
+                ALOGE("Failed to create codec namespace");
+            }
+        } else {
+            ALOGE("Failed to find entry (ret=%d)", ret);
+        }
+
+        CloseArchive(zipHandle);
+    } else {
+        ALOGE("Failed to open archive (ret=%d)", ret);
+    }
+
+    if (registrantLib) {
+        RegisterCodecServicesFunc registerCodecServices =
+                reinterpret_cast<RegisterCodecServicesFunc>(
+                dlsym(registrantLib, "RegisterCodecServices"));
+        if (registerCodecServices) {
+            registerCodecServices();
+        } else {
+            LOG(WARNING) << "Cannot register codec services "
+                    "-- corrupted library.";
+        }
+    } else {
+        LOG(ERROR) << "Cannot find codec service registrant.";
+    }
+
+    return binder::Status::ok();
+}
+
+}   // namespace media
+}   // namespace android
diff --git a/services/mediacodec/MediaCodecUpdateService.h b/services/mediacodec/MediaCodecUpdateService.h
new file mode 100644
index 0000000..7b7cee9
--- /dev/null
+++ b/services/mediacodec/MediaCodecUpdateService.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
+#define ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
+
+#include <binder/BinderService.h>
+#include <android/media/BnMediaUpdateService.h>
+
+namespace android {
+namespace media {
+
+class MediaCodecUpdateService
+    : public BinderService<MediaCodecUpdateService>, public BnMediaUpdateService
+{
+    friend class BinderService<MediaCodecUpdateService>;
+public:
+    MediaCodecUpdateService() : BnMediaUpdateService() { }
+    virtual ~MediaCodecUpdateService() { }
+    static const char* getServiceName() { return "media.codec.update"; }
+    binder::Status loadPlugins(const ::std::string& apkPath);
+};
+
+}   // namespace media
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
diff --git a/services/mediacodec/main_swcodecservice.cpp b/services/mediacodec/main_swcodecservice.cpp
index 1729c3f..386abb2 100644
--- a/services/mediacodec/main_swcodecservice.cpp
+++ b/services/mediacodec/main_swcodecservice.cpp
@@ -20,10 +20,13 @@
 // from LOCAL_C_INCLUDES
 #include "minijail.h"
 
+#include <android-base/properties.h>
 #include <binder/ProcessState.h>
+#include <dlfcn.h>
 #include <hidl/HidlTransportSupport.h>
 #include <media/CodecServiceRegistrant.h>
-#include <dlfcn.h>
+
+#include "MediaCodecUpdateService.h"
 
 using namespace android;
 
@@ -40,6 +43,11 @@
     signal(SIGPIPE, SIG_IGN);
     SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
 
+    std::string value = base::GetProperty("ro.build.type", "unknown");
+    if (value == "userdebug" || value == "eng") {
+        media::MediaCodecUpdateService::instantiate();
+    }
+
     android::ProcessState::self()->startThreadPool();
 
     ::android::hardware::configureRpcThreadpool(64, false);
diff --git a/services/mediaextractor/MediaExtractorUpdateService.h b/services/mediaextractor/MediaExtractorUpdateService.h
index 4115f6d..ea34c9d 100644
--- a/services/mediaextractor/MediaExtractorUpdateService.h
+++ b/services/mediaextractor/MediaExtractorUpdateService.h
@@ -18,17 +18,17 @@
 #define ANDROID_MEDIA_EXTRACTOR_UPDATE_SERVICE_H
 
 #include <binder/BinderService.h>
-#include <android/media/BnMediaExtractorUpdateService.h>
+#include <android/media/BnMediaUpdateService.h>
 
 namespace android {
 namespace media {
 
 class MediaExtractorUpdateService
-    : public BinderService<MediaExtractorUpdateService>, public BnMediaExtractorUpdateService
+    : public BinderService<MediaExtractorUpdateService>, public BnMediaUpdateService
 {
     friend class BinderService<MediaExtractorUpdateService>;
 public:
-    MediaExtractorUpdateService() : BnMediaExtractorUpdateService() { }
+    MediaExtractorUpdateService() : BnMediaUpdateService() { }
     virtual ~MediaExtractorUpdateService() { }
     static const char* getServiceName() { return "media.extractor.update"; }
     binder::Status loadPlugins(const ::std::string& apkPath);