Merge "Test NdkMediaDataSource"
diff --git a/tests/tests/media/libmediandkjni/native-media-jni.cpp b/tests/tests/media/libmediandkjni/native-media-jni.cpp
index 9439ed1..9c4d6f2 100644
--- a/tests/tests/media/libmediandkjni/native-media-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-media-jni.cpp
@@ -35,6 +35,7 @@
 #include "media/NdkMediaExtractor.h"
 #include "media/NdkMediaCodec.h"
 #include "media/NdkMediaCrypto.h"
+#include "media/NdkMediaDataSource.h"
 #include "media/NdkMediaFormat.h"
 #include "media/NdkMediaMuxer.h"
 
@@ -76,6 +77,49 @@
     }
 };
 
+struct FdDataSource {
+
+    FdDataSource(int fd, jlong offset, jlong size)
+        : mFd(fd),
+          mOffset(offset),
+          mSize(size) {
+    }
+
+    ssize_t readAt(off64_t offset, void *data, size_t size) {
+        ssize_t ssize = size;
+        if (!data || offset < 0 || offset >= mSize || offset + ssize < offset) {
+            return -1;
+        }
+        if (offset + ssize > mSize) {
+            ssize = mSize - offset;
+        }
+        if (lseek(mFd, mOffset + offset, SEEK_SET) < 0) {
+            return -1;
+        }
+        return read(mFd, data, ssize);
+    }
+
+    ssize_t getSize() {
+        return mSize;
+    }
+
+private:
+
+    int mFd;
+    off64_t mOffset;
+    int64_t mSize;
+
+};
+
+static ssize_t FdSourceReadAt(void *userdata, off64_t offset, void *data, size_t size) {
+    FdDataSource *src = (FdDataSource*) userdata;
+    return src->readAt(offset, data, size);
+}
+
+static ssize_t FdSourceGetSize(void *userdata) {
+    FdDataSource *src = (FdDataSource*) userdata;
+    return src->getSize();
+}
 
 
 jobject testExtractor(AMediaExtractor *ex, JNIEnv *env) {
@@ -220,11 +264,22 @@
 }
 
 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getDecodedDataNative(JNIEnv *env,
-        jclass /*clazz*/, int fd, jlong offset, jlong size) {
+        jclass /*clazz*/, int fd, jlong offset, jlong size, jboolean wrapFd) {
     ALOGV("getDecodedDataNative");
 
+    FdDataSource fdSrc(fd, offset, size);
     AMediaExtractor *ex = AMediaExtractor_new();
-    int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
+    AMediaDataSource *ndkSrc = AMediaDataSource_new();
+
+    int err;
+    if (wrapFd) {
+        AMediaDataSource_setUserdata(ndkSrc, &fdSrc);
+        AMediaDataSource_setReadAt(ndkSrc, FdSourceReadAt);
+        AMediaDataSource_setGetSize(ndkSrc, FdSourceGetSize);
+        err = AMediaExtractor_setDataSourceCustom(ex, ndkSrc);
+    } else {
+        err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
+    }
     if (err != 0) {
         ALOGE("setDataSource error: %d", err);
         return NULL;
@@ -367,6 +422,7 @@
     delete[] format;
     delete[] codec;
     AMediaExtractor_delete(ex);
+    AMediaDataSource_delete(ndkSrc);
     return ret;
 }
 
diff --git a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java b/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
index 32cf661..f688e09 100644
--- a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
@@ -203,7 +203,18 @@
         }
     }
 
+    public void testDataSource() throws Exception {
+        int testsRun = testDecoder(R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_mono_24kbps_11025hz, true);
+        if (testsRun == 0) {
+            MediaUtils.skipTest("no decoders found");
+        }
+    }
+
     private int testDecoder(int res) throws Exception {
+        return testDecoder(res, /* wrapFd */ false);
+    }
+
+    private int testDecoder(int res, boolean wrapFd) throws Exception {
         if (!MediaUtils.hasCodecsForResource(mContext, res)) {
             return 0; // skip
         }
@@ -213,7 +224,7 @@
         int[] jdata = getDecodedData(
                 fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
         int[] ndata = getDecodedDataNative(
-                fd.getParcelFileDescriptor().getFd(), fd.getStartOffset(), fd.getLength());
+                fd.getParcelFileDescriptor().getFd(), fd.getStartOffset(), fd.getLength(), wrapFd);
 
         fd.close();
         Log.i("@@@", Arrays.toString(jdata));
@@ -384,7 +395,7 @@
         return ret;
     }
 
-    private static native int[] getDecodedDataNative(int fd, long offset, long size)
+    private static native int[] getDecodedDataNative(int fd, long offset, long size, boolean wrapFd)
             throws IOException;
 
     public void testVideoPlayback() throws Exception {