Home | History | Annotate | Download | only in libmediandkjni
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /* Original code copied from NDK Native-media sample code */
     18 
     19 //#define LOG_NDEBUG 0
     20 #define TAG "NativeMedia"
     21 #include <log/log.h>
     22 
     23 #include <assert.h>
     24 #include <jni.h>
     25 #include <mutex>
     26 #include <pthread.h>
     27 #include <queue>
     28 #include <stdio.h>
     29 #include <string.h>
     30 #include <unistd.h>
     31 #include <semaphore.h>
     32 
     33 #include <android/native_window_jni.h>
     34 #include <EGL/egl.h>
     35 #include <EGL/eglext.h>
     36 
     37 #include "media/NdkMediaExtractor.h"
     38 #include "media/NdkMediaCodec.h"
     39 #include "media/NdkMediaCrypto.h"
     40 #include "media/NdkMediaDataSource.h"
     41 #include "media/NdkMediaFormat.h"
     42 #include "media/NdkMediaMuxer.h"
     43 
     44 template <class T>
     45 class simplevector {
     46     T *storage;
     47     int capacity;
     48     int numfilled;
     49 public:
     50     simplevector() {
     51         capacity = 16;
     52         numfilled = 0;
     53         storage = new T[capacity];
     54     }
     55     ~simplevector() {
     56         delete[] storage;
     57     }
     58 
     59     void add(T item) {
     60         if (numfilled == capacity) {
     61             T *old = storage;
     62             capacity *= 2;
     63             storage = new T[capacity];
     64             for (int i = 0; i < numfilled; i++) {
     65                 storage[i] = old[i];
     66             }
     67             delete[] old;
     68         }
     69         storage[numfilled] = item;
     70         numfilled++;
     71     }
     72 
     73     int size() {
     74         return numfilled;
     75     }
     76 
     77     T* data() {
     78         return storage;
     79     }
     80 };
     81 
     82 struct FdDataSource {
     83 
     84     FdDataSource(int fd, jlong offset, jlong size)
     85         : mFd(fd),
     86           mOffset(offset),
     87           mSize(size) {
     88     }
     89 
     90     ssize_t readAt(off64_t offset, void *data, size_t size) {
     91         ssize_t ssize = size;
     92         if (!data || offset < 0 || offset >= mSize || offset + ssize < offset) {
     93             return -1;
     94         }
     95         if (offset + ssize > mSize) {
     96             ssize = mSize - offset;
     97         }
     98         if (lseek(mFd, mOffset + offset, SEEK_SET) < 0) {
     99             return -1;
    100         }
    101         return read(mFd, data, ssize);
    102     }
    103 
    104     ssize_t getSize() {
    105         return mSize;
    106     }
    107 
    108     void close() {
    109         ::close(mFd);
    110     }
    111 
    112 private:
    113 
    114     int mFd;
    115     off64_t mOffset;
    116     int64_t mSize;
    117 
    118 };
    119 
    120 static ssize_t FdSourceReadAt(void *userdata, off64_t offset, void *data, size_t size) {
    121     FdDataSource *src = (FdDataSource*) userdata;
    122     return src->readAt(offset, data, size);
    123 }
    124 
    125 static ssize_t FdSourceGetSize(void *userdata) {
    126     FdDataSource *src = (FdDataSource*) userdata;
    127     return src->getSize();
    128 }
    129 
    130 static void FdSourceClose(void *userdata) {
    131     FdDataSource *src = (FdDataSource*) userdata;
    132     src->close();
    133 }
    134 
    135 class CallbackData {
    136     std::mutex mMutex;
    137     std::queue<int32_t> mInputBufferIds;
    138     std::queue<int32_t> mOutputBufferIds;
    139     std::queue<AMediaCodecBufferInfo> mOutputBufferInfos;
    140     std::queue<AMediaFormat*> mFormats;
    141 
    142 public:
    143     CallbackData() { }
    144 
    145     ~CallbackData() {
    146         mMutex.lock();
    147         while (!mFormats.empty()) {
    148             AMediaFormat* format = mFormats.front();
    149             mFormats.pop();
    150             AMediaFormat_delete(format);
    151         }
    152         mMutex.unlock();
    153     }
    154 
    155     void addInputBufferId(int32_t index) {
    156         mMutex.lock();
    157         mInputBufferIds.push(index);
    158         mMutex.unlock();
    159     }
    160 
    161     int32_t getInputBufferId() {
    162         int32_t id = -1;
    163         mMutex.lock();
    164         if (!mInputBufferIds.empty()) {
    165             id = mInputBufferIds.front();
    166             mInputBufferIds.pop();
    167         }
    168         mMutex.unlock();
    169         return id;
    170     }
    171 
    172     void addOutputBuffer(int32_t index, AMediaCodecBufferInfo *bufferInfo) {
    173         mMutex.lock();
    174         mOutputBufferIds.push(index);
    175         mOutputBufferInfos.push(*bufferInfo);
    176         mMutex.unlock();
    177     }
    178 
    179     void addOutputFormat(AMediaFormat *format) {
    180         mMutex.lock();
    181         mOutputBufferIds.push(AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED);
    182         mFormats.push(format);
    183         mMutex.unlock();
    184     }
    185 
    186     int32_t getOutput(AMediaCodecBufferInfo *bufferInfo, AMediaFormat **format) {
    187         int32_t id = AMEDIACODEC_INFO_TRY_AGAIN_LATER;
    188         mMutex.lock();
    189         if (!mOutputBufferIds.empty()) {
    190             id = mOutputBufferIds.front();
    191             mOutputBufferIds.pop();
    192 
    193             if (id >= 0) {
    194                 *bufferInfo = mOutputBufferInfos.front();
    195                 mOutputBufferInfos.pop();
    196             } else {  // AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED
    197                 *format = mFormats.front();
    198                 mFormats.pop();
    199             }
    200         }
    201         mMutex.unlock();
    202         return id;
    203     }
    204 };
    205 
    206 static void OnInputAvailableCB(
    207         AMediaCodec * /* aMediaCodec */,
    208         void *userdata,
    209         int32_t index) {
    210     ALOGV("OnInputAvailableCB: index(%d)", index);
    211     CallbackData *callbackData = (CallbackData *)userdata;
    212     callbackData->addInputBufferId(index);
    213 }
    214 
    215 static void OnOutputAvailableCB(
    216         AMediaCodec * /* aMediaCodec */,
    217         void *userdata,
    218         int32_t index,
    219         AMediaCodecBufferInfo *bufferInfo) {
    220     ALOGV("OnOutputAvailableCB: index(%d), (%d, %d, %lld, 0x%x)",
    221           index, bufferInfo->offset, bufferInfo->size,
    222           (long long)bufferInfo->presentationTimeUs, bufferInfo->flags);
    223     CallbackData *callbackData = (CallbackData *)userdata;
    224     callbackData->addOutputBuffer(index, bufferInfo);
    225 }
    226 
    227 static void OnFormatChangedCB(
    228         AMediaCodec * /* aMediaCodec */,
    229         void *userdata,
    230         AMediaFormat *format) {
    231     ALOGV("OnFormatChangedCB: format(%s)", AMediaFormat_toString(format));
    232     CallbackData *callbackData = (CallbackData *)userdata;
    233     callbackData->addOutputFormat(format);
    234 }
    235 
    236 static void OnErrorCB(
    237         AMediaCodec * /* aMediaCodec */,
    238         void * /* userdata */,
    239         media_status_t err,
    240         int32_t actionCode,
    241         const char *detail) {
    242     ALOGV("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail);
    243 }
    244 
    245 jobject testExtractor(AMediaExtractor *ex, JNIEnv *env) {
    246 
    247     simplevector<int> sizes;
    248     int numtracks = AMediaExtractor_getTrackCount(ex);
    249     sizes.add(numtracks);
    250     for (int i = 0; i < numtracks; i++) {
    251         AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
    252         const char *s = AMediaFormat_toString(format);
    253         ALOGI("track %d format: %s", i, s);
    254         const char *mime;
    255         if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
    256             ALOGE("no mime type");
    257             return NULL;
    258         } else if (!strncmp(mime, "audio/", 6)) {
    259             sizes.add(0);
    260             int32_t val32;
    261             int64_t val64;
    262             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &val32);
    263             sizes.add(val32);
    264             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &val32);
    265             sizes.add(val32);
    266             AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &val64);
    267             sizes.add(val64);
    268         } else if (!strncmp(mime, "video/", 6)) {
    269             sizes.add(1);
    270             int32_t val32;
    271             int64_t val64;
    272             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &val32);
    273             sizes.add(val32);
    274             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &val32);
    275             sizes.add(val32);
    276             AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &val64);
    277             sizes.add(val64);
    278         } else {
    279             ALOGE("expected audio or video mime type, got %s", mime);
    280         }
    281         AMediaFormat_delete(format);
    282         AMediaExtractor_selectTrack(ex, i);
    283     }
    284     int bufsize = 1024*1024;
    285     uint8_t *buf = new uint8_t[bufsize];
    286     while(true) {
    287         int n = AMediaExtractor_readSampleData(ex, buf, bufsize);
    288         ssize_t sampleSize = AMediaExtractor_getSampleSize(ex);
    289         if (n < 0 || n != sampleSize) {
    290             break;
    291         }
    292         sizes.add(n);
    293         sizes.add(AMediaExtractor_getSampleTrackIndex(ex));
    294         sizes.add(AMediaExtractor_getSampleFlags(ex));
    295         sizes.add(AMediaExtractor_getSampleTime(ex));
    296         AMediaExtractor_advance(ex);
    297     }
    298 
    299     // allocate java int array for result and return it
    300     int *data = sizes.data();
    301     int numsamples = sizes.size();
    302     jintArray ret = env->NewIntArray(numsamples);
    303     jboolean isCopy;
    304     jint *dst = env->GetIntArrayElements(ret, &isCopy);
    305     for (int i = 0; i < numsamples; ++i) {
    306         dst[i] = data[i];
    307     }
    308     env->ReleaseIntArrayElements(ret, dst, 0);
    309 
    310     delete[] buf;
    311     AMediaExtractor_delete(ex);
    312     return ret;
    313 }
    314 
    315 
    316 // get the sample sizes for the file
    317 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getSampleSizesNative(JNIEnv *env,
    318         jclass /*clazz*/, int fd, jlong offset, jlong size)
    319 {
    320     AMediaExtractor *ex = AMediaExtractor_new();
    321     int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
    322     if (err != 0) {
    323         ALOGE("setDataSource error: %d", err);
    324         return NULL;
    325     }
    326     return testExtractor(ex, env);
    327 }
    328 
    329 // get the sample sizes for the path
    330 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getSampleSizesNativePath(JNIEnv *env,
    331         jclass /*clazz*/, jstring jpath)
    332 {
    333     AMediaExtractor *ex = AMediaExtractor_new();
    334 
    335     const char *tmp = env->GetStringUTFChars(jpath, NULL);
    336     if (tmp == NULL) {  // Out of memory
    337         return NULL;
    338     }
    339 
    340     int err = AMediaExtractor_setDataSource(ex, tmp);
    341 
    342     env->ReleaseStringUTFChars(jpath, tmp);
    343 
    344     if (err != 0) {
    345         ALOGE("setDataSource error: %d", err);
    346         return NULL;
    347     }
    348     return testExtractor(ex, env);
    349 }
    350 
    351 static int adler32(const uint8_t *input, int len) {
    352 
    353     int a = 1;
    354     int b = 0;
    355     for (int i = 0; i < len; i++) {
    356         a += input[i];
    357         b += a;
    358     }
    359     a = a % 65521;
    360     b = b % 65521;
    361     int ret = b * 65536 + a;
    362     ALOGV("adler %d/%d", len, ret);
    363     return ret;
    364 }
    365 
    366 static int checksum(const uint8_t *in, int len, AMediaFormat *format) {
    367     int width, stride, height;
    368     if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width)) {
    369         width = len;
    370     }
    371     if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_STRIDE, &stride)) {
    372         stride = width;
    373     }
    374     if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height)) {
    375         height = 1;
    376     }
    377     uint8_t *bb = new uint8_t[width * height];
    378     for (int i = 0; i < height; i++) {
    379         memcpy(bb + i * width, in + i * stride, width);
    380     }
    381     // bb is filled with data
    382     int sum = adler32(bb, width * height);
    383     delete[] bb;
    384     return sum;
    385 }
    386 
    387 extern "C" jlong Java_android_media_cts_NativeDecoderTest_getExtractorFileDurationNative(
    388         JNIEnv * /*env*/, jclass /*clazz*/, int fd, jlong offset, jlong size)
    389 {
    390     AMediaExtractor *ex = AMediaExtractor_new();
    391     int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
    392     if (err != 0) {
    393         ALOGE("setDataSource error: %d", err);
    394         AMediaExtractor_delete(ex);
    395         return -1;
    396     }
    397     int64_t durationUs = -1;
    398     AMediaFormat *format = AMediaExtractor_getFileFormat(ex);
    399     AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &durationUs);
    400     AMediaFormat_delete(format);
    401     AMediaExtractor_delete(ex);
    402     return durationUs;
    403 }
    404 
    405 extern "C" jlong Java_android_media_cts_NativeDecoderTest_getExtractorCachedDurationNative(
    406         JNIEnv * env, jclass /*clazz*/, jstring jpath)
    407 {
    408     AMediaExtractor *ex = AMediaExtractor_new();
    409 
    410     const char *tmp = env->GetStringUTFChars(jpath, NULL);
    411     if (tmp == NULL) {  // Out of memory
    412         AMediaExtractor_delete(ex);
    413         return -1;
    414     }
    415 
    416     int err = AMediaExtractor_setDataSource(ex, tmp);
    417 
    418     env->ReleaseStringUTFChars(jpath, tmp);
    419 
    420     if (err != 0) {
    421         ALOGE("setDataSource error: %d", err);
    422         AMediaExtractor_delete(ex);
    423         return -1;
    424     }
    425 
    426     int64_t cachedDurationUs = AMediaExtractor_getCachedDuration(ex);
    427     AMediaExtractor_delete(ex);
    428     return cachedDurationUs;
    429 
    430 }
    431 
    432 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getDecodedDataNative(JNIEnv *env,
    433         jclass /*clazz*/, int fd, jlong offset, jlong size, jboolean wrapFd, jboolean useCallback) {
    434     ALOGV("getDecodedDataNative");
    435 
    436     FdDataSource fdSrc(fd, offset, size);
    437     AMediaExtractor *ex = AMediaExtractor_new();
    438     AMediaDataSource *ndkSrc = AMediaDataSource_new();
    439 
    440     int err;
    441     if (wrapFd) {
    442         AMediaDataSource_setUserdata(ndkSrc, &fdSrc);
    443         AMediaDataSource_setReadAt(ndkSrc, FdSourceReadAt);
    444         AMediaDataSource_setGetSize(ndkSrc, FdSourceGetSize);
    445         AMediaDataSource_setClose(ndkSrc, FdSourceClose);
    446         err = AMediaExtractor_setDataSourceCustom(ex, ndkSrc);
    447     } else {
    448         err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
    449     }
    450     if (err != 0) {
    451         ALOGE("setDataSource error: %d", err);
    452         return NULL;
    453     }
    454 
    455     int numtracks = AMediaExtractor_getTrackCount(ex);
    456 
    457     AMediaCodec **codec = new AMediaCodec*[numtracks];
    458     AMediaFormat **format = new AMediaFormat*[numtracks];
    459     memset(format, 0, sizeof(AMediaFormat*) * numtracks);
    460     bool *sawInputEOS = new bool[numtracks];
    461     bool *sawOutputEOS = new bool[numtracks];
    462     simplevector<int> *sizes = new simplevector<int>[numtracks];
    463     CallbackData *callbackData = new CallbackData[numtracks];
    464 
    465     ALOGV("input has %d tracks", numtracks);
    466     for (int i = 0; i < numtracks; i++) {
    467         AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
    468         const char *s = AMediaFormat_toString(format);
    469         ALOGI("track %d format: %s", i, s);
    470         const char *mime;
    471         if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
    472             ALOGE("no mime type");
    473             return NULL;
    474         } else if (!strncmp(mime, "audio/", 6) || !strncmp(mime, "video/", 6)) {
    475             codec[i] = AMediaCodec_createDecoderByType(mime);
    476             AMediaCodec_configure(codec[i], format, NULL /* surface */, NULL /* crypto */, 0);
    477             if (useCallback) {
    478                 AMediaCodecOnAsyncNotifyCallback aCB = {
    479                     OnInputAvailableCB,
    480                     OnOutputAvailableCB,
    481                     OnFormatChangedCB,
    482                     OnErrorCB
    483                 };
    484                 AMediaCodec_setAsyncNotifyCallback(codec[i], aCB, &callbackData[i]);
    485             }
    486             AMediaCodec_start(codec[i]);
    487             sawInputEOS[i] = false;
    488             sawOutputEOS[i] = false;
    489         } else {
    490             ALOGE("expected audio or video mime type, got %s", mime);
    491             return NULL;
    492         }
    493         AMediaFormat_delete(format);
    494         AMediaExtractor_selectTrack(ex, i);
    495     }
    496     int eosCount = 0;
    497     while(eosCount < numtracks) {
    498         int t = AMediaExtractor_getSampleTrackIndex(ex);
    499         if (t >=0) {
    500             ssize_t bufidx;
    501             if (useCallback) {
    502                 bufidx = callbackData[t].getInputBufferId();
    503             } else {
    504                 bufidx = AMediaCodec_dequeueInputBuffer(codec[t], 5000);
    505             }
    506             ALOGV("track %d, input buffer %zd", t, bufidx);
    507             if (bufidx >= 0) {
    508                 size_t bufsize;
    509                 uint8_t *buf = AMediaCodec_getInputBuffer(codec[t], bufidx, &bufsize);
    510                 int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
    511                 ALOGV("read %d", sampleSize);
    512                 if (sampleSize < 0) {
    513                     sampleSize = 0;
    514                     sawInputEOS[t] = true;
    515                     ALOGV("EOS");
    516                     //break;
    517                 }
    518                 int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
    519 
    520                 AMediaCodec_queueInputBuffer(codec[t], bufidx, 0, sampleSize, presentationTimeUs,
    521                         sawInputEOS[t] ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
    522                 AMediaExtractor_advance(ex);
    523             }
    524         } else {
    525             ALOGV("@@@@ no more input samples");
    526             for (int tt = 0; tt < numtracks; tt++) {
    527                 if (!sawInputEOS[tt]) {
    528                     // we ran out of samples without ever signaling EOS to the codec,
    529                     // so do that now
    530                     int bufidx;
    531                     if (useCallback) {
    532                         bufidx = callbackData[tt].getInputBufferId();
    533                     } else {
    534                         bufidx = AMediaCodec_dequeueInputBuffer(codec[tt], 5000);
    535                     }
    536                     if (bufidx >= 0) {
    537                         AMediaCodec_queueInputBuffer(codec[tt], bufidx, 0, 0, 0,
    538                                 AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
    539                         sawInputEOS[tt] = true;
    540                     }
    541                 }
    542             }
    543         }
    544 
    545         // check all codecs for available data
    546         AMediaCodecBufferInfo info;
    547         AMediaFormat *outputFormat;
    548         for (int tt = 0; tt < numtracks; tt++) {
    549             if (!sawOutputEOS[tt]) {
    550                 int status;
    551                 if (useCallback) {
    552                     status = callbackData[tt].getOutput(&info, &outputFormat);
    553                 } else {
    554                     status = AMediaCodec_dequeueOutputBuffer(codec[tt], &info, 1);
    555                 }
    556                 ALOGV("dequeueoutput on track %d: %d", tt, status);
    557                 if (status >= 0) {
    558                     if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
    559                         ALOGV("EOS on track %d", tt);
    560                         sawOutputEOS[tt] = true;
    561                         eosCount++;
    562                     }
    563                     ALOGV("got decoded buffer for track %d, size %d", tt, info.size);
    564                     if (info.size > 0) {
    565                         size_t bufsize;
    566                         uint8_t *buf = AMediaCodec_getOutputBuffer(codec[tt], status, &bufsize);
    567                         int adler = checksum(buf, info.size, format[tt]);
    568                         sizes[tt].add(adler);
    569                     }
    570                     AMediaCodec_releaseOutputBuffer(codec[tt], status, false);
    571                 } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
    572                     ALOGV("output buffers changed for track %d", tt);
    573                 } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
    574                     if (format[tt] != NULL) {
    575                         AMediaFormat_delete(format[tt]);
    576                     }
    577                     if (useCallback) {
    578                         format[tt] = outputFormat;
    579                     } else {
    580                         format[tt] = AMediaCodec_getOutputFormat(codec[tt]);
    581                     }
    582                     ALOGV("format changed for track %d: %s", tt, AMediaFormat_toString(format[tt]));
    583                 } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
    584                     ALOGV("no output buffer right now for track %d", tt);
    585                 } else {
    586                     ALOGV("unexpected info code for track %d : %d", tt, status);
    587                 }
    588             } else {
    589                 ALOGV("already at EOS on track %d", tt);
    590             }
    591         }
    592     }
    593     ALOGV("decoding loop done");
    594 
    595     // allocate java int array for result and return it
    596     int numsamples = 0;
    597     for (int i = 0; i < numtracks; i++) {
    598         numsamples += sizes[i].size();
    599     }
    600     ALOGV("checksums: %d", numsamples);
    601     jintArray ret = env->NewIntArray(numsamples);
    602     jboolean isCopy;
    603     jint *org = env->GetIntArrayElements(ret, &isCopy);
    604     jint *dst = org;
    605     for (int i = 0; i < numtracks; i++) {
    606         int *data = sizes[i].data();
    607         int len = sizes[i].size();
    608         ALOGV("copying %d", len);
    609         for (int j = 0; j < len; j++) {
    610             *dst++ = data[j];
    611         }
    612     }
    613     env->ReleaseIntArrayElements(ret, org, 0);
    614 
    615     delete[] callbackData;
    616     delete[] sizes;
    617     delete[] sawOutputEOS;
    618     delete[] sawInputEOS;
    619     for (int i = 0; i < numtracks; i++) {
    620         AMediaFormat_delete(format[i]);
    621         AMediaCodec_stop(codec[i]);
    622         AMediaCodec_delete(codec[i]);
    623     }
    624     delete[] format;
    625     delete[] codec;
    626     AMediaExtractor_delete(ex);
    627     AMediaDataSource_delete(ndkSrc);
    628     return ret;
    629 }
    630 
    631 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testPlaybackNative(JNIEnv *env,
    632         jclass /*clazz*/, jobject surface, int fd, jlong offset, jlong size) {
    633 
    634     ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
    635     ALOGI("@@@@ native window: %p", window);
    636 
    637     AMediaExtractor *ex = AMediaExtractor_new();
    638     int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
    639     if (err != 0) {
    640         ALOGE("setDataSource error: %d", err);
    641         return false;
    642     }
    643 
    644     int numtracks = AMediaExtractor_getTrackCount(ex);
    645 
    646     AMediaCodec *codec = NULL;
    647     AMediaFormat *format = NULL;
    648     bool sawInputEOS = false;
    649     bool sawOutputEOS = false;
    650 
    651     ALOGV("input has %d tracks", numtracks);
    652     for (int i = 0; i < numtracks; i++) {
    653         AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
    654         const char *s = AMediaFormat_toString(format);
    655         ALOGI("track %d format: %s", i, s);
    656         const char *mime;
    657         if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
    658             ALOGE("no mime type");
    659             return false;
    660         } else if (!strncmp(mime, "video/", 6)) {
    661             codec = AMediaCodec_createDecoderByType(mime);
    662             AMediaCodec_configure(codec, format, window, NULL, 0);
    663             AMediaCodec_start(codec);
    664             AMediaExtractor_selectTrack(ex, i);
    665         }
    666         AMediaFormat_delete(format);
    667     }
    668 
    669     while (!sawOutputEOS) {
    670         ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec, 5000);
    671         ALOGV("input buffer %zd", bufidx);
    672         if (bufidx >= 0) {
    673             size_t bufsize;
    674             uint8_t *buf = AMediaCodec_getInputBuffer(codec, bufidx, &bufsize);
    675             int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
    676             ALOGV("read %d", sampleSize);
    677             if (sampleSize < 0) {
    678                 sampleSize = 0;
    679                 sawInputEOS = true;
    680                 ALOGV("EOS");
    681             }
    682             int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
    683 
    684             AMediaCodec_queueInputBuffer(codec, bufidx, 0, sampleSize, presentationTimeUs,
    685                     sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
    686             AMediaExtractor_advance(ex);
    687         }
    688 
    689         AMediaCodecBufferInfo info;
    690         int status = AMediaCodec_dequeueOutputBuffer(codec, &info, 1);
    691         ALOGV("dequeueoutput returned: %d", status);
    692         if (status >= 0) {
    693             if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
    694                 ALOGV("output EOS");
    695                 sawOutputEOS = true;
    696             }
    697             ALOGV("got decoded buffer size %d", info.size);
    698             AMediaCodec_releaseOutputBuffer(codec, status, true);
    699             usleep(20000);
    700         } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
    701             ALOGV("output buffers changed");
    702         } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
    703             format = AMediaCodec_getOutputFormat(codec);
    704             ALOGV("format changed to: %s", AMediaFormat_toString(format));
    705         } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
    706             ALOGV("no output buffer right now");
    707         } else {
    708             ALOGV("unexpected info code: %d", status);
    709         }
    710     }
    711 
    712     AMediaCodec_stop(codec);
    713     AMediaCodec_delete(codec);
    714     AMediaExtractor_delete(ex);
    715     return true;
    716 }
    717 
    718 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testMuxerNative(JNIEnv */*env*/,
    719         jclass /*clazz*/, int infd, jlong inoffset, jlong insize, int outfd, jboolean webm) {
    720 
    721 
    722     AMediaMuxer *muxer = AMediaMuxer_new(outfd,
    723             webm ? AMEDIAMUXER_OUTPUT_FORMAT_WEBM : AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
    724 
    725     AMediaExtractor *ex = AMediaExtractor_new();
    726     int err = AMediaExtractor_setDataSourceFd(ex, infd, inoffset, insize);
    727     if (err != 0) {
    728         ALOGE("setDataSource error: %d", err);
    729         return false;
    730     }
    731 
    732     int numtracks = AMediaExtractor_getTrackCount(ex);
    733     ALOGI("input tracks: %d", numtracks);
    734     for (int i = 0; i < numtracks; i++) {
    735         AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
    736         const char *s = AMediaFormat_toString(format);
    737         ALOGI("track %d format: %s", i, s);
    738         const char *mime;
    739         if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
    740             ALOGE("no mime type");
    741             return false;
    742         } else if (!strncmp(mime, "audio/", 6) || !strncmp(mime, "video/", 6)) {
    743             ssize_t tidx = AMediaMuxer_addTrack(muxer, format);
    744             ALOGI("track %d -> %zd format %s", i, tidx, s);
    745             AMediaExtractor_selectTrack(ex, i);
    746         } else {
    747             ALOGE("expected audio or video mime type, got %s", mime);
    748             return false;
    749         }
    750         AMediaFormat_delete(format);
    751         AMediaExtractor_selectTrack(ex, i);
    752     }
    753     AMediaMuxer_start(muxer);
    754 
    755     int bufsize = 1024*1024;
    756     uint8_t *buf = new uint8_t[bufsize];
    757     AMediaCodecBufferInfo info;
    758     while(true) {
    759         int n = AMediaExtractor_readSampleData(ex, buf, bufsize);
    760         if (n < 0) {
    761             break;
    762         }
    763         info.offset = 0;
    764         info.size = n;
    765         info.presentationTimeUs = AMediaExtractor_getSampleTime(ex);
    766         info.flags = AMediaExtractor_getSampleFlags(ex);
    767 
    768         size_t idx = (size_t) AMediaExtractor_getSampleTrackIndex(ex);
    769         AMediaMuxer_writeSampleData(muxer, idx, buf, &info);
    770 
    771         AMediaExtractor_advance(ex);
    772     }
    773 
    774     AMediaExtractor_delete(ex);
    775     AMediaMuxer_stop(muxer);
    776     AMediaMuxer_delete(muxer);
    777     return true;
    778 
    779 }
    780 
    781 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testFormatNative(JNIEnv * /*env*/,
    782         jclass /*clazz*/) {
    783     AMediaFormat* format = AMediaFormat_new();
    784     if (!format) {
    785         return false;
    786     }
    787 
    788     AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, 8000);
    789     int32_t bitrate = 0;
    790     if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate) || bitrate != 8000) {
    791         ALOGE("AMediaFormat_getInt32 fail: %d", bitrate);
    792         return false;
    793     }
    794 
    795     AMediaFormat_setInt64(format, AMEDIAFORMAT_KEY_DURATION, 123456789123456789ll);
    796     int64_t duration = 0;
    797     if (!AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &duration)
    798             || duration != 123456789123456789ll) {
    799         ALOGE("AMediaFormat_getInt64 fail: %lld", (long long) duration);
    800         return false;
    801     }
    802 
    803     AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_FRAME_RATE, 25.0f);
    804     float framerate = 0.0f;
    805     if (!AMediaFormat_getFloat(format, AMEDIAFORMAT_KEY_FRAME_RATE, &framerate)
    806             || framerate != 25.0f) {
    807         ALOGE("AMediaFormat_getFloat fail: %f", framerate);
    808         return false;
    809     }
    810 
    811     const char* value = "audio/mpeg";
    812     AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, value);
    813     const char* readback = NULL;
    814     if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &readback)
    815             || strcmp(value, readback) || value == readback) {
    816         ALOGE("AMediaFormat_getString fail");
    817         return false;
    818     }
    819 
    820     uint32_t foo = 0xdeadbeef;
    821     AMediaFormat_setBuffer(format, "csd-0", &foo, sizeof(foo));
    822     foo = 0xabadcafe;
    823     void *bytes;
    824     size_t bytesize = 0;
    825     if(!AMediaFormat_getBuffer(format, "csd-0", &bytes, &bytesize)
    826             || bytesize != sizeof(foo) || *((uint32_t*)bytes) != 0xdeadbeef) {
    827         ALOGE("AMediaFormat_getBuffer fail");
    828         return false;
    829     }
    830 
    831     return true;
    832 }
    833 
    834 
    835 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testPsshNative(JNIEnv * /*env*/,
    836         jclass /*clazz*/, int fd, jlong offset, jlong size) {
    837 
    838     AMediaExtractor *ex = AMediaExtractor_new();
    839     int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
    840     if (err != 0) {
    841         ALOGE("setDataSource error: %d", err);
    842         return false;
    843     }
    844 
    845     PsshInfo* info = AMediaExtractor_getPsshInfo(ex);
    846     if (info == NULL) {
    847         ALOGI("null pssh");
    848         return false;
    849     }
    850 
    851     ALOGI("pssh has %zd entries", info->numentries);
    852     if (info->numentries != 2) {
    853         return false;
    854     }
    855 
    856     for (size_t i = 0; i < info->numentries; i++) {
    857         PsshEntry *entry = &info->entries[i];
    858         ALOGI("entry uuid %02x%02x..%02x%02x, data size %zd",
    859                 entry->uuid[0],
    860                 entry->uuid[1],
    861                 entry->uuid[14],
    862                 entry->uuid[15],
    863                 entry->datalen);
    864 
    865         AMediaCrypto *crypto = AMediaCrypto_new(entry->uuid, entry->data, entry->datalen);
    866         if (crypto) {
    867             ALOGI("got crypto");
    868             AMediaCrypto_delete(crypto);
    869         } else {
    870             ALOGI("no crypto");
    871         }
    872     }
    873     return true;
    874 }
    875 
    876 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testCryptoInfoNative(JNIEnv * /*env*/,
    877         jclass /*clazz*/) {
    878 
    879     size_t numsubsamples = 4;
    880     uint8_t key[16] = { 1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4 };
    881     uint8_t iv[16] = { 4,3,2,1,4,3,2,1,4,3,2,1,4,3,2,1 };
    882     size_t clearbytes[4] = { 5, 6, 7, 8 };
    883     size_t encryptedbytes[4] = { 8, 7, 6, 5 };
    884 
    885     AMediaCodecCryptoInfo *ci =
    886             AMediaCodecCryptoInfo_new(numsubsamples, key, iv, AMEDIACODECRYPTOINFO_MODE_CLEAR, clearbytes, encryptedbytes);
    887 
    888     if (AMediaCodecCryptoInfo_getNumSubSamples(ci) != 4) {
    889         ALOGE("numsubsamples mismatch");
    890         return false;
    891     }
    892     uint8_t bytes[16];
    893     AMediaCodecCryptoInfo_getKey(ci, bytes);
    894     if (memcmp(key, bytes, 16) != 0) {
    895         ALOGE("key mismatch");
    896         return false;
    897     }
    898     AMediaCodecCryptoInfo_getIV(ci, bytes);
    899     if (memcmp(iv, bytes, 16) != 0) {
    900         ALOGE("IV mismatch");
    901         return false;
    902     }
    903     if (AMediaCodecCryptoInfo_getMode(ci) != AMEDIACODECRYPTOINFO_MODE_CLEAR) {
    904         ALOGE("mode mismatch");
    905         return false;
    906     }
    907     size_t sizes[numsubsamples];
    908     AMediaCodecCryptoInfo_getClearBytes(ci, sizes);
    909     if (memcmp(clearbytes, sizes, sizeof(size_t) * numsubsamples)) {
    910         ALOGE("clear size mismatch");
    911         return false;
    912     }
    913     AMediaCodecCryptoInfo_getEncryptedBytes(ci, sizes);
    914     if (memcmp(encryptedbytes, sizes, sizeof(size_t) * numsubsamples)) {
    915         ALOGE("encrypted size mismatch");
    916         return false;
    917     }
    918     return true;
    919 }
    920 
    921 // === NdkMediaCodec
    922 
    923 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateCodecByName(
    924         JNIEnv *env, jclass /*clazz*/, jstring name) {
    925 
    926     if (name == NULL) {
    927         return 0;
    928     }
    929 
    930     const char *tmp = env->GetStringUTFChars(name, NULL);
    931     if (tmp == NULL) {
    932         return 0;
    933     }
    934 
    935     AMediaCodec *codec = AMediaCodec_createCodecByName(tmp);
    936     if (codec == NULL) {
    937         env->ReleaseStringUTFChars(name, tmp);
    938         return 0;
    939     }
    940 
    941     env->ReleaseStringUTFChars(name, tmp);
    942     return reinterpret_cast<jlong>(codec);
    943 
    944 }
    945 
    946 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecDelete(
    947         JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) {
    948     media_status_t err = AMediaCodec_delete(reinterpret_cast<AMediaCodec *>(codec));
    949     return err == AMEDIA_OK;
    950 }
    951 
    952 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecStart(
    953         JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) {
    954     media_status_t err = AMediaCodec_start(reinterpret_cast<AMediaCodec *>(codec));
    955     return err == AMEDIA_OK;
    956 }
    957 
    958 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecStop(
    959         JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) {
    960     media_status_t err = AMediaCodec_stop(reinterpret_cast<AMediaCodec *>(codec));
    961     return err == AMEDIA_OK;
    962 }
    963 
    964 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecConfigure(
    965         JNIEnv *env,
    966         jclass /*clazz*/,
    967         jlong codec,
    968         jstring mime,
    969         jint width,
    970         jint height,
    971         jint colorFormat,
    972         jint bitRate,
    973         jint frameRate,
    974         jint iFrameInterval,
    975         jobject csd,
    976         jint flags) {
    977 
    978     AMediaFormat* format = AMediaFormat_new();
    979     if (format == NULL) {
    980         return false;
    981     }
    982 
    983     const char *tmp = env->GetStringUTFChars(mime, NULL);
    984     if (tmp == NULL) {
    985         AMediaFormat_delete(format);
    986         return false;
    987     }
    988 
    989     AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, tmp);
    990     env->ReleaseStringUTFChars(mime, tmp);
    991 
    992     const char *keys[] = {
    993             AMEDIAFORMAT_KEY_WIDTH,
    994             AMEDIAFORMAT_KEY_HEIGHT,
    995             AMEDIAFORMAT_KEY_COLOR_FORMAT,
    996             AMEDIAFORMAT_KEY_BIT_RATE,
    997             AMEDIAFORMAT_KEY_FRAME_RATE,
    998             AMEDIAFORMAT_KEY_I_FRAME_INTERVAL
    999     };
   1000 
   1001     jint values[] = {width, height, colorFormat, bitRate, frameRate, iFrameInterval};
   1002     for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
   1003         if (values[i] >= 0) {
   1004             AMediaFormat_setInt32(format, keys[i], values[i]);
   1005         }
   1006     }
   1007 
   1008     if (csd != NULL) {
   1009         void *csdPtr = env->GetDirectBufferAddress(csd);
   1010         jlong csdSize = env->GetDirectBufferCapacity(csd);
   1011         AMediaFormat_setBuffer(format, "csd-0", csdPtr, csdSize);
   1012     }
   1013 
   1014     media_status_t err = AMediaCodec_configure(
   1015             reinterpret_cast<AMediaCodec *>(codec),
   1016             format,
   1017             NULL,
   1018             NULL,
   1019             flags);
   1020 
   1021     AMediaFormat_delete(format);
   1022     return err == AMEDIA_OK;
   1023 
   1024 }
   1025 
   1026 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetInputSurface(
   1027         JNIEnv* env, jclass /*clazz*/, jlong codec, jobject surface) {
   1028 
   1029     media_status_t err = AMediaCodec_setInputSurface(
   1030             reinterpret_cast<AMediaCodec *>(codec),
   1031             ANativeWindow_fromSurface(env, surface));
   1032 
   1033     return err == AMEDIA_OK;
   1034 
   1035 }
   1036 
   1037 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetNativeInputSurface(
   1038         JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jlong nativeWindow) {
   1039 
   1040     media_status_t err = AMediaCodec_setInputSurface(
   1041             reinterpret_cast<AMediaCodec *>(codec),
   1042             reinterpret_cast<ANativeWindow *>(nativeWindow));
   1043 
   1044     return err == AMEDIA_OK;
   1045 
   1046 }
   1047 
   1048 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateInputSurface(
   1049         JNIEnv* /*env*/, jclass /*clazz*/, jlong codec) {
   1050 
   1051     ANativeWindow *nativeWindow;
   1052     media_status_t err = AMediaCodec_createInputSurface(
   1053             reinterpret_cast<AMediaCodec *>(codec),
   1054             &nativeWindow);
   1055 
   1056      if (err == AMEDIA_OK) {
   1057          return reinterpret_cast<jlong>(nativeWindow);
   1058      }
   1059 
   1060      return 0;
   1061 
   1062 }
   1063 
   1064 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreatePersistentInputSurface(
   1065         JNIEnv* /*env*/, jclass /*clazz*/) {
   1066 
   1067     ANativeWindow *nativeWindow;
   1068     media_status_t err = AMediaCodec_createPersistentInputSurface(&nativeWindow);
   1069 
   1070      if (err == AMEDIA_OK) {
   1071          return reinterpret_cast<jlong>(nativeWindow);
   1072      }
   1073 
   1074      return 0;
   1075 
   1076 }
   1077 
   1078 extern "C" jstring Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputFormatString(
   1079         JNIEnv* env, jclass /*clazz*/, jlong codec) {
   1080 
   1081     AMediaFormat *format = AMediaCodec_getOutputFormat(reinterpret_cast<AMediaCodec *>(codec));
   1082     const char *str = AMediaFormat_toString(format);
   1083     jstring jstr = env->NewStringUTF(str);
   1084     AMediaFormat_delete(format);
   1085     return jstr;
   1086 
   1087 }
   1088 
   1089 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSignalEndOfInputStream(
   1090         JNIEnv* /*env*/, jclass /*clazz*/, jlong codec) {
   1091 
   1092     media_status_t err = AMediaCodec_signalEndOfInputStream(reinterpret_cast<AMediaCodec *>(codec));
   1093     return err == AMEDIA_OK;
   1094 
   1095 }
   1096 
   1097 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecReleaseOutputBuffer(
   1098         JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jint index, jboolean render) {
   1099 
   1100     media_status_t err = AMediaCodec_releaseOutputBuffer(
   1101             reinterpret_cast<AMediaCodec *>(codec),
   1102             index,
   1103             render);
   1104 
   1105     return err == AMEDIA_OK;
   1106 
   1107 }
   1108 
   1109 static jobject AMediaCodecGetBuffer(
   1110         JNIEnv* env,
   1111         jlong codec,
   1112         jint index,
   1113         uint8_t *(*getBuffer)(AMediaCodec*, size_t, size_t*)) {
   1114 
   1115     size_t bufsize;
   1116     uint8_t *buf = getBuffer(
   1117             reinterpret_cast<AMediaCodec *>(codec),
   1118             index,
   1119             &bufsize);
   1120 
   1121     return env->NewDirectByteBuffer(buf, bufsize);
   1122 
   1123 }
   1124 
   1125 extern "C" jobject Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputBuffer(
   1126         JNIEnv* env, jclass /*clazz*/, jlong codec, jint index) {
   1127 
   1128     return AMediaCodecGetBuffer(env, codec, index, AMediaCodec_getOutputBuffer);
   1129 
   1130 }
   1131 
   1132 extern "C" jlongArray Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueOutputBuffer(
   1133         JNIEnv* env, jclass /*clazz*/, jlong codec, jlong timeoutUs) {
   1134 
   1135     AMediaCodecBufferInfo info;
   1136     memset(&info, 0, sizeof(info));
   1137     int status = AMediaCodec_dequeueOutputBuffer(
   1138         reinterpret_cast<AMediaCodec *>(codec),
   1139         &info,
   1140         timeoutUs);
   1141 
   1142     jlong ret[5] = {0};
   1143     ret[0] = status;
   1144     ret[1] = 0; // NdkMediaCodec calls ABuffer::data, which already adds offset
   1145     ret[2] = info.size;
   1146     ret[3] = info.presentationTimeUs;
   1147     ret[4] = info.flags;
   1148 
   1149     jlongArray jret = env->NewLongArray(5);
   1150     env->SetLongArrayRegion(jret, 0, 5, ret);
   1151     return jret;
   1152 
   1153 }
   1154 
   1155 extern "C" jobject Java_android_media_cts_NdkMediaCodec_AMediaCodecGetInputBuffer(
   1156         JNIEnv* env, jclass /*clazz*/, jlong codec, jint index) {
   1157 
   1158     return AMediaCodecGetBuffer(env, codec, index, AMediaCodec_getInputBuffer);
   1159 
   1160 }
   1161 
   1162 extern "C" jint Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueInputBuffer(
   1163         JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jlong timeoutUs) {
   1164 
   1165     return AMediaCodec_dequeueInputBuffer(
   1166             reinterpret_cast<AMediaCodec *>(codec),
   1167             timeoutUs);
   1168 
   1169 }
   1170 
   1171 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecQueueInputBuffer(
   1172         JNIEnv* /*env*/,
   1173         jclass /*clazz*/,
   1174         jlong codec,
   1175         jint index,
   1176         jint offset,
   1177         jint size,
   1178         jlong presentationTimeUs,
   1179         jint flags) {
   1180 
   1181     media_status_t err = AMediaCodec_queueInputBuffer(
   1182             reinterpret_cast<AMediaCodec *>(codec),
   1183             index,
   1184             offset,
   1185             size,
   1186             presentationTimeUs,
   1187             flags);
   1188 
   1189     return err == AMEDIA_OK;
   1190 
   1191 }
   1192 
   1193 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetParameter(
   1194         JNIEnv* env, jclass /*clazz*/, jlong codec, jstring jkey, jint value) {
   1195 
   1196     AMediaFormat* params = AMediaFormat_new();
   1197     if (params == NULL) {
   1198         return false;
   1199     }
   1200 
   1201     const char *key = env->GetStringUTFChars(jkey, NULL);
   1202     if (key == NULL) {
   1203         AMediaFormat_delete(params);
   1204         return false;
   1205     }
   1206 
   1207     AMediaFormat_setInt32(params, key, value);
   1208     media_status_t err = AMediaCodec_setParameters(
   1209             reinterpret_cast<AMediaCodec *>(codec),
   1210             params);
   1211     env->ReleaseStringUTFChars(jkey, key);
   1212     AMediaFormat_delete(params);
   1213     return err == AMEDIA_OK;
   1214 
   1215 }
   1216 
   1217 // === NdkInputSurface
   1218 
   1219 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglGetDisplay(JNIEnv * /*env*/, jclass /*clazz*/) {
   1220 
   1221     EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
   1222     if (eglDisplay == EGL_NO_DISPLAY) {
   1223         return 0;
   1224     }
   1225 
   1226     EGLint major, minor;
   1227     if (!eglInitialize(eglDisplay, &major, &minor)) {
   1228         return 0;
   1229     }
   1230 
   1231     return reinterpret_cast<jlong>(eglDisplay);
   1232 
   1233 }
   1234 
   1235 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglChooseConfig(
   1236         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay) {
   1237 
   1238     // Configure EGL for recordable and OpenGL ES 2.0.  We want enough RGB bits
   1239     // to minimize artifacts from possible YUV conversion.
   1240     EGLint attribList[] = {
   1241             EGL_RED_SIZE, 8,
   1242             EGL_GREEN_SIZE, 8,
   1243             EGL_BLUE_SIZE, 8,
   1244             EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
   1245             EGL_RECORDABLE_ANDROID, 1,
   1246             EGL_NONE
   1247     };
   1248 
   1249     EGLConfig configs[1];
   1250     EGLint numConfigs[1];
   1251     if (!eglChooseConfig(reinterpret_cast<EGLDisplay>(eglDisplay), attribList, configs, 1, numConfigs)) {
   1252         return 0;
   1253     }
   1254     return reinterpret_cast<jlong>(configs[0]);
   1255 
   1256 }
   1257 
   1258 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglCreateContext(
   1259         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglConfig) {
   1260 
   1261     // Configure context for OpenGL ES 2.0.
   1262     int attrib_list[] = {
   1263             EGL_CONTEXT_CLIENT_VERSION, 2,
   1264             EGL_NONE
   1265     };
   1266 
   1267     EGLConfig eglContext = eglCreateContext(
   1268             reinterpret_cast<EGLDisplay>(eglDisplay),
   1269             reinterpret_cast<EGLConfig>(eglConfig),
   1270             EGL_NO_CONTEXT,
   1271             attrib_list);
   1272 
   1273     if (eglGetError() != EGL_SUCCESS) {
   1274         return 0;
   1275     }
   1276 
   1277     return reinterpret_cast<jlong>(eglContext);
   1278 
   1279 }
   1280 
   1281 extern "C" jlong Java_android_media_cts_NdkInputSurface_createEGLSurface(
   1282         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglConfig, jlong nativeWindow) {
   1283 
   1284     int surfaceAttribs[] = {EGL_NONE};
   1285     EGLSurface eglSurface = eglCreateWindowSurface(
   1286             reinterpret_cast<EGLDisplay>(eglDisplay),
   1287             reinterpret_cast<EGLConfig>(eglConfig),
   1288             reinterpret_cast<EGLNativeWindowType>(nativeWindow),
   1289             surfaceAttribs);
   1290 
   1291     if (eglGetError() != EGL_SUCCESS) {
   1292         return 0;
   1293     }
   1294 
   1295     return reinterpret_cast<jlong>(eglSurface);
   1296 
   1297 }
   1298 
   1299 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglMakeCurrent(
   1300         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong eglContext) {
   1301 
   1302     return eglMakeCurrent(
   1303             reinterpret_cast<EGLDisplay>(eglDisplay),
   1304             reinterpret_cast<EGLSurface>(eglSurface),
   1305             reinterpret_cast<EGLSurface>(eglSurface),
   1306             reinterpret_cast<EGLContext>(eglContext));
   1307 
   1308 }
   1309 
   1310 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglSwapBuffers(
   1311         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
   1312 
   1313     return eglSwapBuffers(
   1314             reinterpret_cast<EGLDisplay>(eglDisplay),
   1315             reinterpret_cast<EGLSurface>(eglSurface));
   1316 
   1317 }
   1318 
   1319 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglPresentationTimeANDROID(
   1320         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong nsecs) {
   1321 
   1322     return eglPresentationTimeANDROID(
   1323             reinterpret_cast<EGLDisplay>(eglDisplay),
   1324             reinterpret_cast<EGLSurface>(eglSurface),
   1325             reinterpret_cast<EGLnsecsANDROID>(nsecs));
   1326 
   1327 }
   1328 
   1329 extern "C" jint Java_android_media_cts_NdkInputSurface_eglGetWidth(
   1330         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
   1331 
   1332     EGLint width;
   1333     eglQuerySurface(
   1334             reinterpret_cast<EGLDisplay>(eglDisplay),
   1335             reinterpret_cast<EGLSurface>(eglSurface),
   1336             EGL_WIDTH,
   1337             &width);
   1338 
   1339     return width;
   1340 
   1341 }
   1342 
   1343 extern "C" jint Java_android_media_cts_NdkInputSurface_eglGetHeight(
   1344         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
   1345 
   1346     EGLint height;
   1347     eglQuerySurface(
   1348             reinterpret_cast<EGLDisplay>(eglDisplay),
   1349             reinterpret_cast<EGLSurface>(eglSurface),
   1350             EGL_HEIGHT,
   1351             &height);
   1352 
   1353     return height;
   1354 
   1355 }
   1356 
   1357 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglDestroySurface(
   1358         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
   1359 
   1360     return eglDestroySurface(
   1361             reinterpret_cast<EGLDisplay>(eglDisplay),
   1362             reinterpret_cast<EGLSurface>(eglSurface));
   1363 
   1364 }
   1365 
   1366 extern "C" void Java_android_media_cts_NdkInputSurface_nativeRelease(
   1367         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong eglContext, jlong nativeWindow) {
   1368 
   1369     if (eglDisplay != 0) {
   1370 
   1371         EGLDisplay _eglDisplay = reinterpret_cast<EGLDisplay>(eglDisplay);
   1372         EGLSurface _eglSurface = reinterpret_cast<EGLSurface>(eglSurface);
   1373         EGLContext _eglContext = reinterpret_cast<EGLContext>(eglContext);
   1374 
   1375         eglDestroySurface(_eglDisplay, _eglSurface);
   1376         eglDestroyContext(_eglDisplay, _eglContext);
   1377         eglReleaseThread();
   1378         eglTerminate(_eglDisplay);
   1379 
   1380     }
   1381 
   1382     ANativeWindow_release(reinterpret_cast<ANativeWindow *>(nativeWindow));
   1383 
   1384 }
   1385