C-ify MediaBuffer

Bug: 111407253
Test: CTS, manual
Change-Id: Id20094f23d9d0dc0ec23127bbedc62c6e29944bd
diff --git a/include/media/MediaExtractorPluginApi.h b/include/media/MediaExtractorPluginApi.h
index 38962e5..b480bbe 100644
--- a/include/media/MediaExtractorPluginApi.h
+++ b/include/media/MediaExtractorPluginApi.h
@@ -69,6 +69,40 @@
     bool     (*supportsNonBlockingRead)(void *data);
 };
 
+/**
+ * only use CMediaBufferV3 allocated from the CMediaBufferGroupV3 that is
+ * provided to CMediaTrack::start()
+ */
+struct CMediaBufferV3 {
+    void *handle;
+    void (*release)(void *handle);
+    void* (*data)(void *handle);
+    size_t (*size)(void *handle);
+    size_t (*range_offset)(void *handle);
+    size_t (*range_length)(void *handle);
+    void (*set_range)(void *handle, size_t offset, size_t length);
+    AMediaFormat* (*meta_data)(void *handle);
+};
+
+struct CMediaBufferGroupV3 {
+    void *handle;
+    bool (*init)(void *handle, size_t buffers, size_t buffer_size, size_t growthLimit);
+    void (*add_buffer)(void *handle, size_t size);
+    media_status_t (*acquire_buffer)(void *handle,
+            CMediaBufferV3 **buffer, bool nonBlocking, size_t requestedSize);
+    bool (*has_buffers)(void *handle);
+};
+
+struct CMediaTrackV3 {
+    void *data;
+    void (*free)(void *data);
+
+    media_status_t (*start)(void *data, CMediaBufferGroupV3 *bufferGroup);
+    media_status_t (*stop)(void *data);
+    media_status_t (*getFormat)(void *data, AMediaFormat *format);
+    media_status_t (*read)(void *data, CMediaBufferV3 **buffer, uint32_t options, int64_t seekPosUs);
+    bool     (*supportsNonBlockingRead)(void *data);
+};
 
 struct CMediaExtractorV1 {
     void *data;
@@ -104,6 +138,23 @@
     const char * (*name)(void *data);
 };
 
+struct CMediaExtractorV3 {
+    void *data;
+
+    void (*free)(void *data);
+    size_t (*countTracks)(void *data);
+    CMediaTrackV3* (*getTrack)(void *data, size_t index);
+    media_status_t (*getTrackMetaData)(
+            void *data,
+            AMediaFormat *meta,
+            size_t index, uint32_t flags);
+
+    media_status_t (*getMetaData)(void *data, AMediaFormat *meta);
+    uint32_t (*flags)(void *data);
+    media_status_t (*setMediaCas)(void *data, const uint8_t* casToken, size_t size);
+    const char * (*name)(void *data);
+};
+
 typedef CMediaExtractorV1* (*CreatorFuncV1)(CDataSource *source, void *meta);
 typedef void (*FreeMetaFunc)(void *meta);
 
@@ -121,6 +172,12 @@
         CDataSource *source, float *confidence,
         void **meta, FreeMetaFunc *freeMeta);
 
+typedef CMediaExtractorV3* (*CreatorFuncV3)(CDataSource *source, void *meta);
+
+typedef CreatorFuncV3 (*SnifferFuncV3)(
+        CDataSource *source, float *confidence,
+        void **meta, FreeMetaFunc *freeMeta);
+
 typedef CMediaExtractorV1 CMediaExtractor;
 typedef CreatorFuncV1 CreatorFunc;
 
@@ -148,6 +205,7 @@
     union {
         SnifferFuncV1 v1;
         SnifferFuncV2 v2;
+        SnifferFuncV3 v3;
     } sniff;
 };
 
diff --git a/include/media/MediaExtractorPluginHelper.h b/include/media/MediaExtractorPluginHelper.h
index 858c575..292ec93 100644
--- a/include/media/MediaExtractorPluginHelper.h
+++ b/include/media/MediaExtractorPluginHelper.h
@@ -20,12 +20,13 @@
 
 #include <arpa/inet.h>
 #include <stdio.h>
-#include <vector>
+#include <map>
 
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/RefBase.h>
 #include <media/MediaExtractorPluginApi.h>
+#include <media/NdkMediaFormat.h>
 
 namespace android {
 
@@ -171,6 +172,176 @@
     return wrapper;
 }
 
+class MediaTrackHelperV3;
+
+class MediaBufferHelperV3 {
+private:
+    friend CMediaTrackV3 *wrapV3(MediaTrackHelperV3 *);
+    CMediaBufferV3 *mBuffer;
+public:
+    MediaBufferHelperV3(CMediaBufferV3 *buf) {
+        mBuffer = buf;
+    }
+
+    ~MediaBufferHelperV3() {}
+
+    void release() {
+        mBuffer->release(mBuffer->handle);
+    }
+
+    void* data() {
+        return mBuffer->data(mBuffer->handle);
+    }
+
+    size_t size() {
+        return mBuffer->size(mBuffer->handle);
+    }
+
+    size_t range_offset() {
+        return mBuffer->range_offset(mBuffer->handle);
+    }
+
+    size_t range_length() {
+        return mBuffer->range_length(mBuffer->handle);
+    }
+
+    void set_range(size_t offset, size_t length) {
+        mBuffer->set_range(mBuffer->handle, offset, length);
+    }
+    AMediaFormat *meta_data() {
+        return mBuffer->meta_data(mBuffer->handle);
+    }
+};
+
+class MediaBufferGroupHelperV3 {
+private:
+    CMediaBufferGroupV3 *mGroup;
+    std::map<CMediaBufferV3*, MediaBufferHelperV3*> mBufferHelpers;
+public:
+    MediaBufferGroupHelperV3(CMediaBufferGroupV3 *group) {
+        mGroup = group;
+    }
+    ~MediaBufferGroupHelperV3() {
+        // delete all entries in map
+        ALOGV("buffergroup %p map has %zu entries", this, mBufferHelpers.size());
+        for (auto it = mBufferHelpers.begin(); it != mBufferHelpers.end(); ++it) {
+            delete it->second;
+        }
+    }
+    bool init(size_t buffers, size_t buffer_size, size_t growthLimit = 0) {
+        return mGroup->init(mGroup->handle, buffers, buffer_size, growthLimit);
+    }
+    void add_buffer(size_t size) {
+        mGroup->add_buffer(mGroup->handle, size);
+    }
+    media_status_t acquire_buffer(
+            MediaBufferHelperV3 **buffer, bool nonBlocking = false, size_t requestedSize = 0) {
+        CMediaBufferV3 *buf = nullptr;
+        media_status_t ret =
+                mGroup->acquire_buffer(mGroup->handle, &buf, nonBlocking, requestedSize);
+        if (ret == AMEDIA_OK && buf != nullptr) {
+            auto helper = mBufferHelpers.find(buf);
+            if (helper == mBufferHelpers.end()) {
+                MediaBufferHelperV3* newHelper = new MediaBufferHelperV3(buf);
+                mBufferHelpers.insert(std::make_pair(buf, newHelper));
+                *buffer = newHelper;
+            } else {
+                *buffer = helper->second;
+            }
+        } else {
+            *buffer = nullptr;
+        }
+        return ret;
+    }
+    bool has_buffers() {
+        return mGroup->has_buffers(mGroup->handle);
+    }
+};
+
+class MediaTrackHelperV3 {
+public:
+    MediaTrackHelperV3() : mBufferGroup(nullptr) {
+    }
+    virtual ~MediaTrackHelperV3() {
+        delete mBufferGroup;
+    }
+    virtual media_status_t start() = 0;
+    virtual media_status_t stop() = 0;
+    virtual media_status_t getFormat(AMediaFormat *format) = 0;
+
+    class ReadOptions {
+    public:
+        enum SeekMode : int32_t {
+            SEEK_PREVIOUS_SYNC,
+            SEEK_NEXT_SYNC,
+            SEEK_CLOSEST_SYNC,
+            SEEK_CLOSEST,
+            SEEK_FRAME_INDEX,
+        };
+
+        ReadOptions(uint32_t options, int64_t seekPosUs) {
+            mOptions = options;
+            mSeekPosUs = seekPosUs;
+        }
+        bool getSeekTo(int64_t *time_us, SeekMode *mode) const {
+            if ((mOptions & CMediaTrackReadOptions::SEEK) == 0) {
+                return false;
+            }
+            *time_us = mSeekPosUs;
+            *mode = (SeekMode) (mOptions & 7);
+            return true;
+        }
+        bool getNonBlocking() const {
+            return mOptions & CMediaTrackReadOptions::NONBLOCKING;
+        }
+    private:
+        uint32_t mOptions;
+        int64_t mSeekPosUs;
+    };
+
+    virtual media_status_t read(
+            MediaBufferHelperV3 **buffer, const ReadOptions *options = NULL) = 0;
+    virtual bool supportsNonBlockingRead() { return false; }
+protected:
+    friend CMediaTrackV3 *wrapV3(MediaTrackHelperV3 *track);
+    MediaBufferGroupHelperV3 *mBufferGroup;
+};
+
+inline CMediaTrackV3 *wrapV3(MediaTrackHelperV3 *track) {
+    CMediaTrackV3 *wrapper = (CMediaTrackV3*) malloc(sizeof(CMediaTrackV3));
+    wrapper->data = track;
+    wrapper->free = [](void *data) -> void {
+        delete (MediaTrackHelperV3*)(data);
+    };
+    wrapper->start = [](void *data, CMediaBufferGroupV3 *bufferGroup) -> media_status_t {
+        if (((MediaTrackHelperV3*)data)->mBufferGroup) {
+            // this shouldn't happen, but handle it anyway
+            delete ((MediaTrackHelperV3*)data)->mBufferGroup;
+        }
+        ((MediaTrackHelperV3*)data)->mBufferGroup = new MediaBufferGroupHelperV3(bufferGroup);
+        return ((MediaTrackHelperV3*)data)->start();
+    };
+    wrapper->stop = [](void *data) -> media_status_t {
+        return ((MediaTrackHelperV3*)data)->stop();
+    };
+    wrapper->getFormat = [](void *data, AMediaFormat *meta) -> media_status_t {
+        return ((MediaTrackHelperV3*)data)->getFormat(meta);
+    };
+    wrapper->read = [](void *data, CMediaBufferV3 **buffer,  uint32_t options, int64_t seekPosUs)
+            -> media_status_t {
+        MediaTrackHelperV3::ReadOptions opts(options, seekPosUs);
+        MediaBufferHelperV3 *buf = NULL;
+        media_status_t ret = ((MediaTrackHelperV3*)data)->read(&buf, &opts);
+        if (ret == AMEDIA_OK && buf != nullptr) {
+            *buffer = buf->mBuffer;
+        }
+        return ret;
+    };
+    wrapper->supportsNonBlockingRead = [](void *data) -> bool {
+                return ((MediaTrackHelperV3*)data)->supportsNonBlockingRead();
+    };
+    return wrapper;
+}
 
 
 // extractor plugins can derive from this class which looks remarkably
@@ -341,6 +512,89 @@
     return wrapper;
 }
 
+class MediaExtractorPluginHelperV3
+{
+public:
+    virtual ~MediaExtractorPluginHelperV3() {}
+    virtual size_t countTracks() = 0;
+    virtual MediaTrackHelperV3 *getTrack(size_t index) = 0;
+
+    enum GetTrackMetaDataFlags {
+        kIncludeExtensiveMetaData = 1
+    };
+    virtual media_status_t getTrackMetaData(
+            AMediaFormat *meta,
+            size_t index, uint32_t flags = 0) = 0;
+
+    // Return container specific meta-data. The default implementation
+    // returns an empty metadata object.
+    virtual media_status_t getMetaData(AMediaFormat *meta) = 0;
+
+    enum Flags {
+        CAN_SEEK_BACKWARD  = 1,  // the "seek 10secs back button"
+        CAN_SEEK_FORWARD   = 2,  // the "seek 10secs forward button"
+        CAN_PAUSE          = 4,
+        CAN_SEEK           = 8,  // the "seek bar"
+    };
+
+    // If subclasses do _not_ override this, the default is
+    // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
+    virtual uint32_t flags() const {
+        return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE;
+    };
+
+    virtual media_status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
+        return AMEDIA_ERROR_INVALID_OPERATION;
+    }
+
+    virtual const char * name() { return "<unspecified>"; }
+
+protected:
+    MediaExtractorPluginHelperV3() {}
+
+private:
+    MediaExtractorPluginHelperV3(const MediaExtractorPluginHelperV2 &);
+    MediaExtractorPluginHelperV3 &operator=(const MediaExtractorPluginHelperV2 &);
+};
+
+inline CMediaExtractorV3 *wrapV3(MediaExtractorPluginHelperV3 *extractor) {
+    CMediaExtractorV3 *wrapper = (CMediaExtractorV3*) malloc(sizeof(CMediaExtractorV3));
+    wrapper->data = extractor;
+    wrapper->free = [](void *data) -> void {
+        delete (MediaExtractorPluginHelperV3*)(data);
+    };
+    wrapper->countTracks = [](void *data) -> size_t {
+        return ((MediaExtractorPluginHelperV3*)data)->countTracks();
+    };
+    wrapper->getTrack = [](void *data, size_t index) -> CMediaTrackV3* {
+        return wrapV3(((MediaExtractorPluginHelperV3*)data)->getTrack(index));
+    };
+    wrapper->getTrackMetaData = [](
+            void *data,
+            AMediaFormat *meta,
+            size_t index, uint32_t flags) -> media_status_t {
+        return ((MediaExtractorPluginHelperV3*)data)->getTrackMetaData(meta, index, flags);
+    };
+    wrapper->getMetaData = [](
+            void *data,
+            AMediaFormat *meta) -> media_status_t {
+        return ((MediaExtractorPluginHelperV3*)data)->getMetaData(meta);
+    };
+    wrapper->flags = [](
+            void *data) -> uint32_t {
+        return ((MediaExtractorPluginHelperV3*)data)->flags();
+    };
+    wrapper->setMediaCas = [](
+            void *data, const uint8_t *casToken, size_t size) -> media_status_t {
+        return ((MediaExtractorPluginHelperV3*)data)->setMediaCas(casToken, size);
+    };
+    wrapper->name = [](
+            void *data) -> const char * {
+        return ((MediaExtractorPluginHelperV3*)data)->name();
+    };
+    return wrapper;
+}
+
 /* adds some convience methods */
 class DataSourceHelper {
 public:
diff --git a/include/media/MediaTrack.h b/include/media/MediaTrack.h
index ee3591e..baa3410 100644
--- a/include/media/MediaTrack.h
+++ b/include/media/MediaTrack.h
@@ -23,6 +23,7 @@
 #include <binder/IMemory.h>
 #include <binder/MemoryDealer.h>
 #include <media/MediaExtractorPluginApi.h>
+#include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <media/MediaExtractorPluginApi.h>
@@ -175,6 +176,25 @@
     CMediaTrackV2 *wrapper;
 };
 
+class MediaTrackCUnwrapperV3 : public MediaTrack {
+public:
+    explicit MediaTrackCUnwrapperV3(CMediaTrackV3 *wrapper);
+
+    virtual status_t start();
+    virtual status_t stop();
+    virtual status_t getFormat(MetaDataBase& format);
+    virtual status_t read(MediaBufferBase **buffer, const ReadOptions *options = NULL);
+
+    virtual bool supportNonblockingRead();
+
+protected:
+    virtual ~MediaTrackCUnwrapperV3();
+
+private:
+    CMediaTrackV3 *wrapper;
+    MediaBufferGroup *bufferGroup;
+};
+
 }  // namespace android
 
 #endif  // MEDIA_SOURCE_BASE_H_
diff --git a/include/media/NdkMediaErrorPriv.h b/include/media/NdkMediaErrorPriv.h
index f5e2f02..3bbba79 100644
--- a/include/media/NdkMediaErrorPriv.h
+++ b/include/media/NdkMediaErrorPriv.h
@@ -20,10 +20,8 @@
 #include <media/NdkMediaError.h>
 #include <utils/Errors.h>
 
-using namespace android;
+media_status_t translate_error(android::status_t);
 
-media_status_t translate_error(status_t);
-
-status_t reverse_translate_error(media_status_t);
+android::status_t reverse_translate_error(media_status_t);
 
 #endif // _NDK_MEDIA_ERROR_PRIV_H
diff --git a/include/media/NdkMediaFormatPriv.h b/include/media/NdkMediaFormatPriv.h
index 6c452c3..1fda4a8 100644
--- a/include/media/NdkMediaFormatPriv.h
+++ b/include/media/NdkMediaFormatPriv.h
@@ -27,6 +27,7 @@
 #ifndef _NDK_MEDIA_FORMAT_PRIV_H
 #define _NDK_MEDIA_FORMAT_PRIV_H
 
+#include <utils/KeyedVector.h>
 #include <utils/String8.h>
 #include <utils/StrongPointer.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -35,20 +36,22 @@
 extern "C" {
 #endif
 
-using namespace android;
-
 struct AMediaFormat {
-    sp<AMessage> mFormat;
-    String8 mDebug;
-    KeyedVector<String8, String8> mStringCache;
+    android::sp<android::AMessage> mFormat;
+    android::String8 mDebug;
+    android::KeyedVector<android::String8, android::String8> mStringCache;
 };
 
-AMediaFormat* AMediaFormat_fromMsg(const void*);
-void AMediaFormat_getFormat(const AMediaFormat* mData, void* dest);
-
 #ifdef __cplusplus
 } // extern "C"
 #endif
 
+namespace android {
+
+AMediaFormat* AMediaFormat_fromMsg(sp<AMessage> *);
+void AMediaFormat_getFormat(const AMediaFormat* mData, sp<AMessage> *dest);
+
+} // namespace android
+
 #endif // _NDK_MEDIA_FORMAT_PRIV_H
 
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
index 185bb32..dcc73bb 100644
--- a/media/extractors/wav/Android.bp
+++ b/media/extractors/wav/Android.bp
@@ -9,7 +9,6 @@
     shared_libs: [
         "libbinder_ndk",
         "liblog",
-        "libmediaextractor",
         "libmediandk",
     ],
 
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index 86500ef..17b5f81 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -22,9 +22,7 @@
 
 #include <android/binder_ibinder.h> // for AIBinder_getCallingUid
 #include <audio_utils/primitives.h>
-#include <media/DataSourceBase.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
@@ -68,7 +66,7 @@
     return ptr[1] << 8 | ptr[0];
 }
 
-struct WAVSource : public MediaTrackHelperV2 {
+struct WAVSource : public MediaTrackHelperV3 {
     WAVSource(
             DataSourceHelper *dataSource,
             AMediaFormat *meta,
@@ -81,7 +79,7 @@
     virtual media_status_t getFormat(AMediaFormat *meta);
 
     virtual media_status_t read(
-            MediaBufferBase **buffer, const ReadOptions *options = NULL);
+            MediaBufferHelperV3 **buffer, const ReadOptions *options = NULL);
 
     virtual bool supportNonblockingRead() { return true; }
 
@@ -101,7 +99,6 @@
     off64_t mOffset;
     size_t mSize;
     bool mStarted;
-    MediaBufferGroup *mGroup;
     off64_t mCurrentPos;
 
     WAVSource(const WAVSource &);
@@ -134,7 +131,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-MediaTrackHelperV2 *WAVExtractor::getTrack(size_t index) {
+MediaTrackHelperV3 *WAVExtractor::getTrack(size_t index) {
     if (mInitCheck != OK || index > 0) {
         return NULL;
     }
@@ -379,14 +376,14 @@
       mOutputFloat(outputFloat),
       mOffset(offset),
       mSize(size),
-      mStarted(false),
-      mGroup(NULL) {
+      mStarted(false) {
     CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, &mSampleRate));
     CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &mNumChannels));
     CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, &mBitsPerSample));
 }
 
 WAVSource::~WAVSource() {
+    ALOGI("~WAVSource");
     if (mStarted) {
         stop();
     }
@@ -398,7 +395,9 @@
     CHECK(!mStarted);
 
     // some WAV files may have large audio buffers that use shared memory transfer.
-    mGroup = new MediaBufferGroup(4 /* buffers */, kMaxFrameSize);
+    if (!mBufferGroup->init(4 /* buffers */, kMaxFrameSize)) {
+        return AMEDIA_ERROR_UNKNOWN;
+    }
 
     mCurrentPos = mOffset;
 
@@ -412,9 +411,6 @@
 
     CHECK(mStarted);
 
-    delete mGroup;
-    mGroup = NULL;
-
     mStarted = false;
 
     return AMEDIA_OK;
@@ -433,10 +429,10 @@
 }
 
 media_status_t WAVSource::read(
-        MediaBufferBase **out, const ReadOptions *options) {
+        MediaBufferHelperV3 **out, const ReadOptions *options) {
     *out = NULL;
 
-    if (options != nullptr && options->getNonBlocking() && !mGroup->has_buffers()) {
+    if (options != nullptr && options->getNonBlocking() && !mBufferGroup->has_buffers()) {
         return AMEDIA_ERROR_WOULD_BLOCK;
     }
 
@@ -459,10 +455,10 @@
         mCurrentPos = pos + mOffset;
     }
 
-    MediaBufferBase *buffer;
-    status_t err = mGroup->acquire_buffer(&buffer);
+    MediaBufferHelperV3 *buffer;
+    media_status_t err = mBufferGroup->acquire_buffer(&buffer);
     if (err != OK) {
-        return AMEDIA_ERROR_UNKNOWN;
+        return err;
     }
 
     // maxBytesToRead may be reduced so that in-place data conversion will fit in buffer size.
@@ -573,9 +569,10 @@
                 / (mNumChannels * bytesPerSample) / mSampleRate;
     }
 
-    buffer->meta_data().setInt64(kKeyTime, timeStampUs);
+    AMediaFormat *meta = buffer->meta_data();
+    AMediaFormat_setInt64(meta, AMEDIAFORMAT_KEY_TIME_US, timeStampUs);
+    AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_IS_SYNC_FRAME, 1);
 
-    buffer->meta_data().setInt32(kKeyIsSyncFrame, 1);
     mCurrentPos += n;
 
     *out = buffer;
@@ -585,13 +582,13 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-static CMediaExtractorV2* CreateExtractor(
+static CMediaExtractorV3* CreateExtractor(
         CDataSource *source,
         void *) {
-    return wrapV2(new WAVExtractor(new DataSourceHelper(source)));
+    return wrapV3(new WAVExtractor(new DataSourceHelper(source)));
 }
 
-static CreatorFuncV2 Sniff(
+static CreatorFuncV3 Sniff(
         CDataSource *source,
         float *confidence,
         void **,
@@ -625,11 +622,11 @@
 __attribute__ ((visibility ("default")))
 ExtractorDef GETEXTRACTORDEF() {
     return {
-        EXTRACTORDEF_VERSION_CURRENT,
+        EXTRACTORDEF_VERSION_CURRENT + 1,
         UUID("7d613858-5837-4a38-84c5-332d1cddee27"),
         1, // version
         "WAV Extractor",
-        { .v2 = Sniff }
+        { .v3 = Sniff }
     };
 }
 
diff --git a/media/extractors/wav/WAVExtractor.h b/media/extractors/wav/WAVExtractor.h
index ce34881..9b7dfde 100644
--- a/media/extractors/wav/WAVExtractor.h
+++ b/media/extractors/wav/WAVExtractor.h
@@ -29,12 +29,12 @@
 struct CDataSource;
 class String8;
 
-class WAVExtractor : public MediaExtractorPluginHelperV2 {
+class WAVExtractor : public MediaExtractorPluginHelperV3 {
 public:
     explicit WAVExtractor(DataSourceHelper *source);
 
     virtual size_t countTracks();
-    virtual MediaTrackHelperV2 *getTrack(size_t index);
+    virtual MediaTrackHelperV3 *getTrack(size_t index);
     virtual media_status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
 
     virtual media_status_t getMetaData(AMediaFormat *meta);
diff --git a/media/libmedia/NdkMediaFormatPriv.cpp b/media/libmedia/NdkMediaFormatPriv.cpp
index 3c84d6a..3a9fb8b 100644
--- a/media/libmedia/NdkMediaFormatPriv.cpp
+++ b/media/libmedia/NdkMediaFormatPriv.cpp
@@ -19,27 +19,22 @@
 
 #include <inttypes.h>
 
-//#include <ndk/include/media/NdkMediaFormat.h>
-
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
 #include <media/NdkMediaFormatPriv.h>
-#include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
-//#include <android_runtime/AndroidRuntime.h>
-//#include <android_util_Binder.h>
 
 #include <jni.h>
 
 using namespace android;
 
-extern "C" {
+namespace android {
 
 // private functions for conversion to/from AMessage
-AMediaFormat* AMediaFormat_fromMsg(const void* data) {
+AMediaFormat* AMediaFormat_fromMsg(sp<AMessage> *data) {
     ALOGV("private ctor");
     AMediaFormat* mData = new AMediaFormat();
-    mData->mFormat = *((sp<AMessage>*)data);
+    mData->mFormat = *data;
     if (mData->mFormat == NULL) {
         ALOGW("got NULL format");
         mData->mFormat = new AMessage;
@@ -47,10 +42,10 @@
     return mData;
 }
 
-void AMediaFormat_getFormat(const AMediaFormat* mData, void* dest) {
-    *((sp<AMessage>*)dest) = mData->mFormat;
+void AMediaFormat_getFormat(const AMediaFormat* mData, sp<AMessage> *dest) {
+    *dest = mData->mFormat;
 }
 
-} // extern "C"
+} // namespace android
 
 
diff --git a/media/libmediaextractor/MediaBufferGroup.cpp b/media/libmediaextractor/MediaBufferGroup.cpp
index 62b83cc..4e6beca 100644
--- a/media/libmediaextractor/MediaBufferGroup.cpp
+++ b/media/libmediaextractor/MediaBufferGroup.cpp
@@ -44,12 +44,16 @@
 };
 
 MediaBufferGroup::MediaBufferGroup(size_t growthLimit)
-    : mInternal(new InternalData()) {
+    : mWrapper(nullptr), mInternal(new InternalData()) {
     mInternal->mGrowthLimit = growthLimit;
 }
 
 MediaBufferGroup::MediaBufferGroup(size_t buffers, size_t buffer_size, size_t growthLimit)
-    : mInternal(new InternalData()) {
+    : mWrapper(nullptr), mInternal(new InternalData()) {
+    init(buffers, buffer_size, growthLimit);
+}
+
+void MediaBufferGroup::init(size_t buffers, size_t buffer_size, size_t growthLimit) {
     mInternal->mGrowthLimit = growthLimit;
 
     if (mInternal->mGrowthLimit > 0 && buffers > mInternal->mGrowthLimit) {
diff --git a/media/libmediaextractor/include/media/DataSource.h b/media/libmediaextractor/include/media/DataSource.h
index cb96ff5..1f7a473 100644
--- a/media/libmediaextractor/include/media/DataSource.h
+++ b/media/libmediaextractor/include/media/DataSource.h
@@ -22,7 +22,7 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/DataSourceBase.h>
 #include <media/IDataSource.h>
-#include <media/MediaExtractorPluginHelper.h>
+#include <media/MediaExtractorPluginApi.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 #include <utils/threads.h>
diff --git a/media/libmediaextractor/include/media/stagefright/MediaBufferBase.h b/media/libmediaextractor/include/media/stagefright/MediaBufferBase.h
index 6c8d94a..d67ddbd 100644
--- a/media/libmediaextractor/include/media/stagefright/MediaBufferBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MediaBufferBase.h
@@ -18,6 +18,10 @@
 
 #define MEDIA_BUFFER_BASE_H_
 
+#include <media/MediaExtractorPluginApi.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/NdkMediaFormatPriv.h>
+
 namespace android {
 
 class MediaBufferBase;
@@ -77,6 +81,48 @@
     virtual int remoteRefcount() const = 0;
 
     virtual ~MediaBufferBase() {};
+
+    CMediaBufferV3 *wrap() {
+        if (mWrapper) {
+            return mWrapper;
+        }
+        mWrapper = new CMediaBufferV3;
+        mWrapper->handle = this;
+
+        mWrapper->release = [](void *handle) -> void {
+            ((MediaBufferBase*)handle)->release();
+        };
+
+        mWrapper->data = [](void *handle) -> void * {
+            return ((MediaBufferBase*)handle)->data();
+        };
+
+        mWrapper->size = [](void *handle) -> size_t {
+            return ((MediaBufferBase*)handle)->size();
+        };
+
+        mWrapper->set_range = [](void *handle, size_t offset, size_t length) -> void {
+            return ((MediaBufferBase*)handle)->set_range(offset, length);
+        };
+
+        mWrapper->meta_data = [](void *handle) -> AMediaFormat* {
+            if (((MediaBufferBase*)handle)->mFormat == nullptr) {
+                sp<AMessage> msg = new AMessage();
+                ((MediaBufferBase*)handle)->mFormat = AMediaFormat_fromMsg(&msg);
+            }
+            return ((MediaBufferBase*)handle)->mFormat;
+        };
+
+        return mWrapper;
+    }
+protected:
+    MediaBufferBase() {
+        mWrapper = nullptr;
+        mFormat = nullptr;
+    }
+private:
+    CMediaBufferV3 *mWrapper;
+    AMediaFormat *mFormat;
 };
 
 }  // namespace android
diff --git a/media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h b/media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h
index 75d5df7..dc04556 100644
--- a/media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h
+++ b/media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h
@@ -20,6 +20,8 @@
 
 #include <list>
 
+#include <media/MediaExtractorPluginApi.h>
+#include <media/NdkMediaErrorPriv.h>
 #include <media/stagefright/MediaBufferBase.h>
 #include <utils/Errors.h>
 #include <utils/threads.h>
@@ -57,12 +59,54 @@
     // If buffer is nullptr, have acquire_buffer() check for remote release.
     virtual void signalBufferReturned(MediaBufferBase *buffer);
 
+    CMediaBufferGroupV3 *wrap() {
+        if (mWrapper) {
+            return mWrapper;
+        }
+
+        mWrapper = new CMediaBufferGroupV3;
+        mWrapper->handle = this;
+
+        mWrapper->add_buffer = [](void *handle, size_t size) -> void {
+            MediaBufferBase *buf = MediaBufferBase::Create(size);
+            ((MediaBufferGroup*)handle)->add_buffer(buf);
+        };
+
+        mWrapper->init = [](void *handle,
+                size_t buffers, size_t buffer_size, size_t growthLimit) -> bool {
+            ((MediaBufferGroup*)handle)->init(buffers, buffer_size, growthLimit);
+          //  ((MediaBufferGroup*)handle)->mWrapper->init = nullptr; // enforce call-once
+            return true;
+        };
+
+        mWrapper->acquire_buffer = [](void *handle,
+                CMediaBufferV3 **buf, bool nonBlocking, size_t requestedSize) -> media_status_t {
+            MediaBufferBase *acquiredBuf = nullptr;
+            status_t err = ((MediaBufferGroup*)handle)->acquire_buffer(
+                    &acquiredBuf, nonBlocking, requestedSize);
+            if (err == OK && acquiredBuf != nullptr) {
+                *buf = acquiredBuf->wrap();
+            } else {
+                *buf = nullptr;
+            }
+            return translate_error(err);
+        };
+
+        mWrapper->has_buffers = [](void *handle) -> bool {
+            return ((MediaBufferGroup*)handle)->has_buffers();
+        };
+
+        return mWrapper;
+    }
+
 private:
+    CMediaBufferGroupV3 *mWrapper;
     struct InternalData;
     InternalData *mInternal;
 
     MediaBufferGroup(const MediaBufferGroup &);
     MediaBufferGroup &operator=(const MediaBufferGroup &);
+    void init(size_t buffers, size_t buffer_size, size_t growthLimit);
 };
 
 }  // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index ac9eb0b..ea818ff 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -134,4 +134,57 @@
     return plugin->setMediaCas(plugin->data, casToken, size);
 }
 
+// --------------------------------------------------------------------------------
+MediaExtractorCUnwrapperV3::MediaExtractorCUnwrapperV3(CMediaExtractorV3 *plugin) {
+    this->plugin = plugin;
+}
+
+MediaExtractorCUnwrapperV3::~MediaExtractorCUnwrapperV3() {
+    plugin->free(plugin->data);
+    free(plugin);
+}
+
+size_t MediaExtractorCUnwrapperV3::countTracks() {
+    return plugin->countTracks(plugin->data);
+}
+
+MediaTrack *MediaExtractorCUnwrapperV3::getTrack(size_t index) {
+    return new MediaTrackCUnwrapperV3(plugin->getTrack(plugin->data, index));
+}
+
+status_t MediaExtractorCUnwrapperV3::getTrackMetaData(
+        MetaDataBase& meta, size_t index, uint32_t flags) {
+    sp<AMessage> msg = new AMessage();
+    AMediaFormat *format =  AMediaFormat_fromMsg(&msg);
+    media_status_t ret = plugin->getTrackMetaData(plugin->data, format, index, flags);
+    sp<MetaData> newMeta = new MetaData();
+    convertMessageToMetaData(msg, newMeta);
+    delete format;
+    meta = *newMeta;
+    return reverse_translate_error(ret);
+}
+
+status_t MediaExtractorCUnwrapperV3::getMetaData(MetaDataBase& meta) {
+    sp<AMessage> msg = new AMessage();
+    AMediaFormat *format =  AMediaFormat_fromMsg(&msg);
+    media_status_t ret = plugin->getMetaData(plugin->data, format);
+    sp<MetaData> newMeta = new MetaData();
+    convertMessageToMetaData(msg, newMeta);
+    delete format;
+    meta = *newMeta;
+    return reverse_translate_error(ret);
+}
+
+const char * MediaExtractorCUnwrapperV3::name() {
+    return plugin->name(plugin->data);
+}
+
+uint32_t MediaExtractorCUnwrapperV3::flags() const {
+    return plugin->flags(plugin->data);
+}
+
+status_t MediaExtractorCUnwrapperV3::setMediaCas(const uint8_t* casToken, size_t size) {
+    return plugin->setMediaCas(plugin->data, casToken, size);
+}
+
 }  // namespace android
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 318c1eb..1f8ccb3 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -100,6 +100,12 @@
             freeMeta(meta);
         }
         ex = ret != nullptr ? new MediaExtractorCUnwrapperV2(ret) : nullptr;
+    } else if (creatorVersion == 3) {
+        CMediaExtractorV3 *ret = ((CreatorFuncV3)creator)(source->wrap(), meta);
+        if (meta != nullptr && freeMeta != nullptr) {
+            freeMeta(meta);
+        }
+        ex = ret != nullptr ? new MediaExtractorCUnwrapperV3(ret) : nullptr;
     }
 
     ALOGV("Created an extractor '%s' with confidence %.2f",
@@ -170,6 +176,9 @@
         } else if ((*it)->def.def_version == 2) {
             curCreator = (void*) (*it)->def.sniff.v2(
                     source->wrap(), &newConfidence, &newMeta, &newFreeMeta);
+        } else if ((*it)->def.def_version == 3) {
+            curCreator = (void*) (*it)->def.sniff.v3(
+                    source->wrap(), &newConfidence, &newMeta, &newFreeMeta);
         }
 
         if (curCreator) {
@@ -199,7 +208,7 @@
         std::list<sp<ExtractorPlugin>> &pluginList) {
     // sanity check check struct version, uuid, name
     if (plugin->def.def_version == 0
-            || plugin->def.def_version > EXTRACTORDEF_VERSION_CURRENT) {
+            || plugin->def.def_version > EXTRACTORDEF_VERSION_CURRENT + 1) {
         ALOGE("don't understand extractor format %u, ignoring.", plugin->def.def_version);
         return;
     }
diff --git a/media/libstagefright/MediaTrack.cpp b/media/libstagefright/MediaTrack.cpp
index 821605d..daed5a0 100644
--- a/media/libstagefright/MediaTrack.cpp
+++ b/media/libstagefright/MediaTrack.cpp
@@ -155,4 +155,76 @@
     return wrapper->supportsNonBlockingRead(wrapper->data);
 }
 
+/* -------------- unwrapper v3 --------------- */
+
+MediaTrackCUnwrapperV3::MediaTrackCUnwrapperV3(CMediaTrackV3 *cmediatrack3) {
+    wrapper = cmediatrack3;
+    bufferGroup = nullptr;
+}
+
+MediaTrackCUnwrapperV3::~MediaTrackCUnwrapperV3() {
+    wrapper->free(wrapper->data);
+    free(wrapper);
+}
+
+status_t MediaTrackCUnwrapperV3::start() {
+    if (bufferGroup == nullptr) {
+        bufferGroup = new MediaBufferGroup();
+    }
+    return reverse_translate_error(wrapper->start(wrapper->data, bufferGroup->wrap()));
+}
+
+status_t MediaTrackCUnwrapperV3::stop() {
+    return reverse_translate_error(wrapper->stop(wrapper->data));
+}
+
+status_t MediaTrackCUnwrapperV3::getFormat(MetaDataBase& format) {
+    sp<AMessage> msg = new AMessage();
+    AMediaFormat *tmpFormat =  AMediaFormat_fromMsg(&msg);
+    media_status_t ret = wrapper->getFormat(wrapper->data, tmpFormat);
+    sp<MetaData> newMeta = new MetaData();
+    convertMessageToMetaData(msg, newMeta);
+    delete tmpFormat;
+    format = *newMeta;
+    return reverse_translate_error(ret);
+}
+
+status_t MediaTrackCUnwrapperV3::read(MediaBufferBase **buffer, const ReadOptions *options) {
+
+    uint32_t opts = 0;
+
+    if (options && options->getNonBlocking()) {
+        opts |= CMediaTrackReadOptions::NONBLOCKING;
+    }
+
+    int64_t seekPosition = 0;
+    MediaTrack::ReadOptions::SeekMode seekMode;
+    if (options && options->getSeekTo(&seekPosition, &seekMode)) {
+        opts |= SEEK;
+        opts |= (uint32_t) seekMode;
+    }
+    CMediaBufferV3 *buf = nullptr;
+    media_status_t ret = wrapper->read(wrapper->data, &buf, opts, seekPosition);
+    if (ret == AMEDIA_OK && buf != nullptr) {
+        *buffer = (MediaBufferBase*)buf->handle;
+        MetaDataBase &meta = (*buffer)->meta_data();
+        AMediaFormat *format = buf->meta_data(buf->handle);
+        // only convert the keys we're actually expecting, as doing
+        // the full convertMessageToMetadata() for every buffer is
+        // too expensive
+        int64_t val;
+        if (format->mFormat->findInt64("timeUs", &val)) {
+            meta.setInt64(kKeyTime, val);
+        }
+    } else {
+        *buffer = nullptr;
+    }
+
+    return reverse_translate_error(ret);
+}
+
+bool MediaTrackCUnwrapperV3::supportNonblockingRead() {
+    return wrapper->supportsNonBlockingRead(wrapper->data);
+}
+
 }  // namespace android
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
index 00f2dd3..71e1170 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
@@ -17,7 +17,6 @@
 #ifndef SOFT_MPEG4_ENCODER_H_
 #define SOFT_MPEG4_ENCODER_H_
 
-#include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/omx/SoftVideoEncoderOMXComponent.h>
 #include "mp4enc_api.h"
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractor.h b/media/libstagefright/include/media/stagefright/MediaExtractor.h
index 71343d5..6f3e57e 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractor.h
@@ -135,6 +135,22 @@
     CMediaExtractorV2 *plugin;
 };
 
+class MediaExtractorCUnwrapperV3 : public MediaExtractorCUnwrapper {
+public:
+    explicit MediaExtractorCUnwrapperV3(CMediaExtractorV3 *plugin);
+    virtual size_t countTracks();
+    virtual MediaTrack *getTrack(size_t index);
+    virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags = 0);
+    virtual status_t getMetaData(MetaDataBase& meta);
+    virtual const char * name();
+    virtual uint32_t flags() const;
+    virtual status_t setMediaCas(const uint8_t* casToken, size_t size);
+protected:
+    virtual ~MediaExtractorCUnwrapperV3();
+private:
+    CMediaExtractorV3 *plugin;
+};
+
 }  // namespace android
 
 #endif  // MEDIA_EXTRACTOR_H_
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index bf9725c..bc140bf 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -327,6 +327,7 @@
 EXPORT const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT = "is-autoselect";
 EXPORT const char* AMEDIAFORMAT_KEY_IS_DEFAULT = "is-default";
 EXPORT const char* AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
+EXPORT const char* AMEDIAFORMAT_KEY_IS_SYNC_FRAME = "is-sync-frame";
 EXPORT const char* AMEDIAFORMAT_KEY_I_FRAME_INTERVAL = "i-frame-interval";
 EXPORT const char* AMEDIAFORMAT_KEY_LANGUAGE = "language";
 EXPORT const char* AMEDIAFORMAT_KEY_LATENCY = "latency";
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 658cbac..4be1928 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -209,6 +209,7 @@
 extern const char* AMEDIAFORMAT_KEY_GENRE __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_HDR_STATIC_INFO __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_ICC_PROFILE __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_IS_SYNC_FRAME __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_LOCATION __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_LOOP __INTRODUCED_IN(29);
 extern const char* AMEDIAFORMAT_KEY_LYRICIST __INTRODUCED_IN(29);