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 <pthread.h>
     26 #include <stdio.h>
     27 #include <string.h>
     28 #include <unistd.h>
     29 #include <semaphore.h>
     30 
     31 #include <android/native_window_jni.h>
     32 #include <EGL/egl.h>
     33 #include <EGL/eglext.h>
     34 
     35 #include "media/NdkMediaExtractor.h"
     36 #include "media/NdkMediaCodec.h"
     37 #include "media/NdkMediaCrypto.h"
     38 #include "media/NdkMediaFormat.h"
     39 #include "media/NdkMediaMuxer.h"
     40 
     41 template <class T>
     42 class simplevector {
     43     T *storage;
     44     int capacity;
     45     int numfilled;
     46 public:
     47     simplevector() {
     48         capacity = 16;
     49         numfilled = 0;
     50         storage = new T[capacity];
     51     }
     52     ~simplevector() {
     53         delete[] storage;
     54     }
     55 
     56     void add(T item) {
     57         if (numfilled == capacity) {
     58             T *old = storage;
     59             capacity *= 2;
     60             storage = new T[capacity];
     61             for (int i = 0; i < numfilled; i++) {
     62                 storage[i] = old[i];
     63             }
     64             delete[] old;
     65         }
     66         storage[numfilled] = item;
     67         numfilled++;
     68     }
     69 
     70     int size() {
     71         return numfilled;
     72     }
     73 
     74     T* data() {
     75         return storage;
     76     }
     77 };
     78 
     79 
     80 
     81 jobject testExtractor(AMediaExtractor *ex, JNIEnv *env) {
     82 
     83     simplevector<int> sizes;
     84     int numtracks = AMediaExtractor_getTrackCount(ex);
     85     sizes.add(numtracks);
     86     for (int i = 0; i < numtracks; i++) {
     87         AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
     88         const char *s = AMediaFormat_toString(format);
     89         ALOGI("track %d format: %s", i, s);
     90         const char *mime;
     91         if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
     92             ALOGE("no mime type");
     93             return NULL;
     94         } else if (!strncmp(mime, "audio/", 6)) {
     95             sizes.add(0);
     96             int32_t val32;
     97             int64_t val64;
     98             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &val32);
     99             sizes.add(val32);
    100             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &val32);
    101             sizes.add(val32);
    102             AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &val64);
    103             sizes.add(val64);
    104         } else if (!strncmp(mime, "video/", 6)) {
    105             sizes.add(1);
    106             int32_t val32;
    107             int64_t val64;
    108             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &val32);
    109             sizes.add(val32);
    110             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &val32);
    111             sizes.add(val32);
    112             AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &val64);
    113             sizes.add(val64);
    114         } else {
    115             ALOGE("expected audio or video mime type, got %s", mime);
    116         }
    117         AMediaFormat_delete(format);
    118         AMediaExtractor_selectTrack(ex, i);
    119     }
    120     int bufsize = 1024*1024;
    121     uint8_t *buf = new uint8_t[bufsize];
    122     while(true) {
    123         int n = AMediaExtractor_readSampleData(ex, buf, bufsize);
    124         if (n < 0) {
    125             break;
    126         }
    127         sizes.add(n);
    128         sizes.add(AMediaExtractor_getSampleTrackIndex(ex));
    129         sizes.add(AMediaExtractor_getSampleFlags(ex));
    130         sizes.add(AMediaExtractor_getSampleTime(ex));
    131         AMediaExtractor_advance(ex);
    132     }
    133 
    134     // allocate java int array for result and return it
    135     int *data = sizes.data();
    136     int numsamples = sizes.size();
    137     jintArray ret = env->NewIntArray(numsamples);
    138     jboolean isCopy;
    139     jint *dst = env->GetIntArrayElements(ret, &isCopy);
    140     for (int i = 0; i < numsamples; ++i) {
    141         dst[i] = data[i];
    142     }
    143     env->ReleaseIntArrayElements(ret, dst, 0);
    144 
    145     delete[] buf;
    146     AMediaExtractor_delete(ex);
    147     return ret;
    148 }
    149 
    150 
    151 // get the sample sizes for the file
    152 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getSampleSizesNative(JNIEnv *env,
    153         jclass /*clazz*/, int fd, jlong offset, jlong size)
    154 {
    155     AMediaExtractor *ex = AMediaExtractor_new();
    156     int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
    157     if (err != 0) {
    158         ALOGE("setDataSource error: %d", err);
    159         return NULL;
    160     }
    161     return testExtractor(ex, env);
    162 }
    163 
    164 // get the sample sizes for the path
    165 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getSampleSizesNativePath(JNIEnv *env,
    166         jclass /*clazz*/, jstring jpath)
    167 {
    168     AMediaExtractor *ex = AMediaExtractor_new();
    169 
    170     const char *tmp = env->GetStringUTFChars(jpath, NULL);
    171     if (tmp == NULL) {  // Out of memory
    172         return NULL;
    173     }
    174 
    175     int err = AMediaExtractor_setDataSource(ex, tmp);
    176 
    177     env->ReleaseStringUTFChars(jpath, tmp);
    178 
    179     if (err != 0) {
    180         ALOGE("setDataSource error: %d", err);
    181         return NULL;
    182     }
    183     return testExtractor(ex, env);
    184 }
    185 
    186 static int adler32(const uint8_t *input, int len) {
    187 
    188     int a = 1;
    189     int b = 0;
    190     for (int i = 0; i < len; i++) {
    191         a += input[i];
    192         b += a;
    193     }
    194     a = a % 65521;
    195     b = b % 65521;
    196     int ret = b * 65536 + a;
    197     ALOGV("adler %d/%d", len, ret);
    198     return ret;
    199 }
    200 
    201 static int checksum(const uint8_t *in, int len, AMediaFormat *format) {
    202     int width, stride, height;
    203     if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width)) {
    204         width = len;
    205     }
    206     if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_STRIDE, &stride)) {
    207         stride = width;
    208     }
    209     if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height)) {
    210         height = 1;
    211     }
    212     uint8_t *bb = new uint8_t[width * height];
    213     for (int i = 0; i < height; i++) {
    214         memcpy(bb + i * width, in + i * stride, width);
    215     }
    216     // bb is filled with data
    217     int sum = adler32(bb, width * height);
    218     delete[] bb;
    219     return sum;
    220 }
    221 
    222 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getDecodedDataNative(JNIEnv *env,
    223         jclass /*clazz*/, int fd, jlong offset, jlong size) {
    224     ALOGV("getDecodedDataNative");
    225 
    226     AMediaExtractor *ex = AMediaExtractor_new();
    227     int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
    228     if (err != 0) {
    229         ALOGE("setDataSource error: %d", err);
    230         return NULL;
    231     }
    232 
    233     int numtracks = AMediaExtractor_getTrackCount(ex);
    234 
    235     AMediaCodec **codec = new AMediaCodec*[numtracks];
    236     AMediaFormat **format = new AMediaFormat*[numtracks];
    237     bool *sawInputEOS = new bool[numtracks];
    238     bool *sawOutputEOS = new bool[numtracks];
    239     simplevector<int> *sizes = new simplevector<int>[numtracks];
    240 
    241     ALOGV("input has %d tracks", numtracks);
    242     for (int i = 0; i < numtracks; i++) {
    243         AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
    244         const char *s = AMediaFormat_toString(format);
    245         ALOGI("track %d format: %s", i, s);
    246         const char *mime;
    247         if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
    248             ALOGE("no mime type");
    249             return NULL;
    250         } else if (!strncmp(mime, "audio/", 6) || !strncmp(mime, "video/", 6)) {
    251             codec[i] = AMediaCodec_createDecoderByType(mime);
    252             AMediaCodec_configure(codec[i], format, NULL /* surface */, NULL /* crypto */, 0);
    253             AMediaCodec_start(codec[i]);
    254             sawInputEOS[i] = false;
    255             sawOutputEOS[i] = false;
    256         } else {
    257             ALOGE("expected audio or video mime type, got %s", mime);
    258             return NULL;
    259         }
    260         AMediaFormat_delete(format);
    261         AMediaExtractor_selectTrack(ex, i);
    262     }
    263     int eosCount = 0;
    264     while(eosCount < numtracks) {
    265         int t = AMediaExtractor_getSampleTrackIndex(ex);
    266         if (t >=0) {
    267             ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec[t], 5000);
    268             ALOGV("track %d, input buffer %zd", t, bufidx);
    269             if (bufidx >= 0) {
    270                 size_t bufsize;
    271                 uint8_t *buf = AMediaCodec_getInputBuffer(codec[t], bufidx, &bufsize);
    272                 int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
    273                 ALOGV("read %d", sampleSize);
    274                 if (sampleSize < 0) {
    275                     sampleSize = 0;
    276                     sawInputEOS[t] = true;
    277                     ALOGV("EOS");
    278                     //break;
    279                 }
    280                 int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
    281 
    282                 AMediaCodec_queueInputBuffer(codec[t], bufidx, 0, sampleSize, presentationTimeUs,
    283                         sawInputEOS[t] ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
    284                 AMediaExtractor_advance(ex);
    285             }
    286         } else {
    287             ALOGV("@@@@ no more input samples");
    288             for (int tt = 0; tt < numtracks; tt++) {
    289                 if (!sawInputEOS[tt]) {
    290                     // we ran out of samples without ever signaling EOS to the codec,
    291                     // so do that now
    292                     int bufidx = AMediaCodec_dequeueInputBuffer(codec[tt], 5000);
    293                     if (bufidx >= 0) {
    294                         AMediaCodec_queueInputBuffer(codec[tt], bufidx, 0, 0, 0,
    295                                 AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
    296                         sawInputEOS[tt] = true;
    297                     }
    298                 }
    299             }
    300         }
    301 
    302         // check all codecs for available data
    303         AMediaCodecBufferInfo info;
    304         for (int tt = 0; tt < numtracks; tt++) {
    305             if (!sawOutputEOS[tt]) {
    306                 int status = AMediaCodec_dequeueOutputBuffer(codec[tt], &info, 1);
    307                 ALOGV("dequeueoutput on track %d: %d", tt, status);
    308                 if (status >= 0) {
    309                     if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
    310                         ALOGV("EOS on track %d", tt);
    311                         sawOutputEOS[tt] = true;
    312                         eosCount++;
    313                     }
    314                     ALOGV("got decoded buffer for track %d, size %d", tt, info.size);
    315                     if (info.size > 0) {
    316                         size_t bufsize;
    317                         uint8_t *buf = AMediaCodec_getOutputBuffer(codec[tt], status, &bufsize);
    318                         int adler = checksum(buf, info.size, format[tt]);
    319                         sizes[tt].add(adler);
    320                     }
    321                     AMediaCodec_releaseOutputBuffer(codec[tt], status, false);
    322                 } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
    323                     ALOGV("output buffers changed for track %d", tt);
    324                 } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
    325                     format[tt] = AMediaCodec_getOutputFormat(codec[tt]);
    326                     ALOGV("format changed for track %d: %s", tt, AMediaFormat_toString(format[tt]));
    327                 } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
    328                     ALOGV("no output buffer right now for track %d", tt);
    329                 } else {
    330                     ALOGV("unexpected info code for track %d : %d", tt, status);
    331                 }
    332             } else {
    333                 ALOGV("already at EOS on track %d", tt);
    334             }
    335         }
    336     }
    337     ALOGV("decoding loop done");
    338 
    339     // allocate java int array for result and return it
    340     int numsamples = 0;
    341     for (int i = 0; i < numtracks; i++) {
    342         numsamples += sizes[i].size();
    343     }
    344     ALOGV("checksums: %d", numsamples);
    345     jintArray ret = env->NewIntArray(numsamples);
    346     jboolean isCopy;
    347     jint *org = env->GetIntArrayElements(ret, &isCopy);
    348     jint *dst = org;
    349     for (int i = 0; i < numtracks; i++) {
    350         int *data = sizes[i].data();
    351         int len = sizes[i].size();
    352         ALOGV("copying %d", len);
    353         for (int j = 0; j < len; j++) {
    354             *dst++ = data[j];
    355         }
    356     }
    357     env->ReleaseIntArrayElements(ret, org, 0);
    358 
    359     delete[] sizes;
    360     delete[] sawOutputEOS;
    361     delete[] sawInputEOS;
    362     for (int i = 0; i < numtracks; i++) {
    363         AMediaFormat_delete(format[i]);
    364         AMediaCodec_stop(codec[i]);
    365         AMediaCodec_delete(codec[i]);
    366     }
    367     delete[] format;
    368     delete[] codec;
    369     AMediaExtractor_delete(ex);
    370     return ret;
    371 }
    372 
    373 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testPlaybackNative(JNIEnv *env,
    374         jclass /*clazz*/, jobject surface, int fd, jlong offset, jlong size) {
    375 
    376     ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
    377     ALOGI("@@@@ native window: %p", window);
    378 
    379     AMediaExtractor *ex = AMediaExtractor_new();
    380     int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
    381     if (err != 0) {
    382         ALOGE("setDataSource error: %d", err);
    383         return false;
    384     }
    385 
    386     int numtracks = AMediaExtractor_getTrackCount(ex);
    387 
    388     AMediaCodec *codec = NULL;
    389     AMediaFormat *format = NULL;
    390     bool sawInputEOS = false;
    391     bool sawOutputEOS = false;
    392 
    393     ALOGV("input has %d tracks", numtracks);
    394     for (int i = 0; i < numtracks; i++) {
    395         AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
    396         const char *s = AMediaFormat_toString(format);
    397         ALOGI("track %d format: %s", i, s);
    398         const char *mime;
    399         if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
    400             ALOGE("no mime type");
    401             return false;
    402         } else if (!strncmp(mime, "video/", 6)) {
    403             codec = AMediaCodec_createDecoderByType(mime);
    404             AMediaCodec_configure(codec, format, window, NULL, 0);
    405             AMediaCodec_start(codec);
    406             AMediaExtractor_selectTrack(ex, i);
    407         }
    408         AMediaFormat_delete(format);
    409     }
    410 
    411     while (!sawOutputEOS) {
    412         ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec, 5000);
    413         ALOGV("input buffer %zd", bufidx);
    414         if (bufidx >= 0) {
    415             size_t bufsize;
    416             uint8_t *buf = AMediaCodec_getInputBuffer(codec, bufidx, &bufsize);
    417             int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
    418             ALOGV("read %d", sampleSize);
    419             if (sampleSize < 0) {
    420                 sampleSize = 0;
    421                 sawInputEOS = true;
    422                 ALOGV("EOS");
    423             }
    424             int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
    425 
    426             AMediaCodec_queueInputBuffer(codec, bufidx, 0, sampleSize, presentationTimeUs,
    427                     sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
    428             AMediaExtractor_advance(ex);
    429         }
    430 
    431         AMediaCodecBufferInfo info;
    432         int status = AMediaCodec_dequeueOutputBuffer(codec, &info, 1);
    433         ALOGV("dequeueoutput returned: %d", status);
    434         if (status >= 0) {
    435             if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
    436                 ALOGV("output EOS");
    437                 sawOutputEOS = true;
    438             }
    439             ALOGV("got decoded buffer size %d", info.size);
    440             AMediaCodec_releaseOutputBuffer(codec, status, true);
    441             usleep(20000);
    442         } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
    443             ALOGV("output buffers changed");
    444         } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
    445             format = AMediaCodec_getOutputFormat(codec);
    446             ALOGV("format changed to: %s", AMediaFormat_toString(format));
    447         } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
    448             ALOGV("no output buffer right now");
    449         } else {
    450             ALOGV("unexpected info code: %d", status);
    451         }
    452     }
    453 
    454     AMediaCodec_stop(codec);
    455     AMediaCodec_delete(codec);
    456     AMediaExtractor_delete(ex);
    457     return true;
    458 }
    459 
    460 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testMuxerNative(JNIEnv */*env*/,
    461         jclass /*clazz*/, int infd, jlong inoffset, jlong insize, int outfd, jboolean webm) {
    462 
    463 
    464     AMediaMuxer *muxer = AMediaMuxer_new(outfd,
    465             webm ? AMEDIAMUXER_OUTPUT_FORMAT_WEBM : AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
    466 
    467     AMediaExtractor *ex = AMediaExtractor_new();
    468     int err = AMediaExtractor_setDataSourceFd(ex, infd, inoffset, insize);
    469     if (err != 0) {
    470         ALOGE("setDataSource error: %d", err);
    471         return false;
    472     }
    473 
    474     int numtracks = AMediaExtractor_getTrackCount(ex);
    475     ALOGI("input tracks: %d", numtracks);
    476     for (int i = 0; i < numtracks; i++) {
    477         AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
    478         const char *s = AMediaFormat_toString(format);
    479         ALOGI("track %d format: %s", i, s);
    480         const char *mime;
    481         if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
    482             ALOGE("no mime type");
    483             return false;
    484         } else if (!strncmp(mime, "audio/", 6) || !strncmp(mime, "video/", 6)) {
    485             ssize_t tidx = AMediaMuxer_addTrack(muxer, format);
    486             ALOGI("track %d -> %zd format %s", i, tidx, s);
    487             AMediaExtractor_selectTrack(ex, i);
    488         } else {
    489             ALOGE("expected audio or video mime type, got %s", mime);
    490             return false;
    491         }
    492         AMediaFormat_delete(format);
    493         AMediaExtractor_selectTrack(ex, i);
    494     }
    495     AMediaMuxer_start(muxer);
    496 
    497     int bufsize = 1024*1024;
    498     uint8_t *buf = new uint8_t[bufsize];
    499     AMediaCodecBufferInfo info;
    500     while(true) {
    501         int n = AMediaExtractor_readSampleData(ex, buf, bufsize);
    502         if (n < 0) {
    503             break;
    504         }
    505         info.offset = 0;
    506         info.size = n;
    507         info.presentationTimeUs = AMediaExtractor_getSampleTime(ex);
    508         info.flags = AMediaExtractor_getSampleFlags(ex);
    509 
    510         size_t idx = (size_t) AMediaExtractor_getSampleTrackIndex(ex);
    511         AMediaMuxer_writeSampleData(muxer, idx, buf, &info);
    512 
    513         AMediaExtractor_advance(ex);
    514     }
    515 
    516     AMediaExtractor_delete(ex);
    517     AMediaMuxer_stop(muxer);
    518     AMediaMuxer_delete(muxer);
    519     return true;
    520 
    521 }
    522 
    523 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testFormatNative(JNIEnv * /*env*/,
    524         jclass /*clazz*/) {
    525     AMediaFormat* format = AMediaFormat_new();
    526     if (!format) {
    527         return false;
    528     }
    529 
    530     AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, 8000);
    531     int32_t bitrate = 0;
    532     if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate) || bitrate != 8000) {
    533         ALOGE("AMediaFormat_getInt32 fail: %d", bitrate);
    534         return false;
    535     }
    536 
    537     AMediaFormat_setInt64(format, AMEDIAFORMAT_KEY_DURATION, 123456789123456789ll);
    538     int64_t duration = 0;
    539     if (!AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &duration)
    540             || duration != 123456789123456789ll) {
    541         ALOGE("AMediaFormat_getInt64 fail: %lld", (long long) duration);
    542         return false;
    543     }
    544 
    545     AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_FRAME_RATE, 25.0f);
    546     float framerate = 0.0f;
    547     if (!AMediaFormat_getFloat(format, AMEDIAFORMAT_KEY_FRAME_RATE, &framerate)
    548             || framerate != 25.0f) {
    549         ALOGE("AMediaFormat_getFloat fail: %f", framerate);
    550         return false;
    551     }
    552 
    553     const char* value = "audio/mpeg";
    554     AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, value);
    555     const char* readback = NULL;
    556     if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &readback)
    557             || strcmp(value, readback) || value == readback) {
    558         ALOGE("AMediaFormat_getString fail");
    559         return false;
    560     }
    561 
    562     uint32_t foo = 0xdeadbeef;
    563     AMediaFormat_setBuffer(format, "csd-0", &foo, sizeof(foo));
    564     foo = 0xabadcafe;
    565     void *bytes;
    566     size_t bytesize = 0;
    567     if(!AMediaFormat_getBuffer(format, "csd-0", &bytes, &bytesize)
    568             || bytesize != sizeof(foo) || *((uint32_t*)bytes) != 0xdeadbeef) {
    569         ALOGE("AMediaFormat_getBuffer fail");
    570         return false;
    571     }
    572 
    573     return true;
    574 }
    575 
    576 
    577 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testPsshNative(JNIEnv * /*env*/,
    578         jclass /*clazz*/, int fd, jlong offset, jlong size) {
    579 
    580     AMediaExtractor *ex = AMediaExtractor_new();
    581     int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
    582     if (err != 0) {
    583         ALOGE("setDataSource error: %d", err);
    584         return false;
    585     }
    586 
    587     PsshInfo* info = AMediaExtractor_getPsshInfo(ex);
    588     if (info == NULL) {
    589         ALOGI("null pssh");
    590         return false;
    591     }
    592 
    593     ALOGI("pssh has %zd entries", info->numentries);
    594     if (info->numentries != 2) {
    595         return false;
    596     }
    597 
    598     for (size_t i = 0; i < info->numentries; i++) {
    599         PsshEntry *entry = &info->entries[i];
    600         ALOGI("entry uuid %02x%02x..%02x%02x, data size %zd",
    601                 entry->uuid[0],
    602                 entry->uuid[1],
    603                 entry->uuid[14],
    604                 entry->uuid[15],
    605                 entry->datalen);
    606 
    607         AMediaCrypto *crypto = AMediaCrypto_new(entry->uuid, entry->data, entry->datalen);
    608         if (crypto) {
    609             ALOGI("got crypto");
    610             AMediaCrypto_delete(crypto);
    611         } else {
    612             ALOGI("no crypto");
    613         }
    614     }
    615     return true;
    616 }
    617 
    618 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testCryptoInfoNative(JNIEnv * /*env*/,
    619         jclass /*clazz*/) {
    620 
    621     size_t numsubsamples = 4;
    622     uint8_t key[16] = { 1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4 };
    623     uint8_t iv[16] = { 4,3,2,1,4,3,2,1,4,3,2,1,4,3,2,1 };
    624     size_t clearbytes[4] = { 5, 6, 7, 8 };
    625     size_t encryptedbytes[4] = { 8, 7, 6, 5 };
    626 
    627     AMediaCodecCryptoInfo *ci =
    628             AMediaCodecCryptoInfo_new(numsubsamples, key, iv, AMEDIACODECRYPTOINFO_MODE_CLEAR, clearbytes, encryptedbytes);
    629 
    630     if (AMediaCodecCryptoInfo_getNumSubSamples(ci) != 4) {
    631         ALOGE("numsubsamples mismatch");
    632         return false;
    633     }
    634     uint8_t bytes[16];
    635     AMediaCodecCryptoInfo_getKey(ci, bytes);
    636     if (memcmp(key, bytes, 16) != 0) {
    637         ALOGE("key mismatch");
    638         return false;
    639     }
    640     AMediaCodecCryptoInfo_getIV(ci, bytes);
    641     if (memcmp(iv, bytes, 16) != 0) {
    642         ALOGE("IV mismatch");
    643         return false;
    644     }
    645     if (AMediaCodecCryptoInfo_getMode(ci) != AMEDIACODECRYPTOINFO_MODE_CLEAR) {
    646         ALOGE("mode mismatch");
    647         return false;
    648     }
    649     size_t sizes[numsubsamples];
    650     AMediaCodecCryptoInfo_getClearBytes(ci, sizes);
    651     if (memcmp(clearbytes, sizes, sizeof(size_t) * numsubsamples)) {
    652         ALOGE("clear size mismatch");
    653         return false;
    654     }
    655     AMediaCodecCryptoInfo_getEncryptedBytes(ci, sizes);
    656     if (memcmp(encryptedbytes, sizes, sizeof(size_t) * numsubsamples)) {
    657         ALOGE("encrypted size mismatch");
    658         return false;
    659     }
    660     return true;
    661 }
    662 
    663 // === NdkMediaCodec
    664 
    665 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateCodecByName(
    666         JNIEnv *env, jclass /*clazz*/, jstring name) {
    667 
    668     if (name == NULL) {
    669         return 0;
    670     }
    671 
    672     const char *tmp = env->GetStringUTFChars(name, NULL);
    673     if (tmp == NULL) {
    674         return 0;
    675     }
    676 
    677     AMediaCodec *codec = AMediaCodec_createCodecByName(tmp);
    678     if (codec == NULL) {
    679         env->ReleaseStringUTFChars(name, tmp);
    680         return 0;
    681     }
    682 
    683     env->ReleaseStringUTFChars(name, tmp);
    684     return reinterpret_cast<jlong>(codec);
    685 
    686 }
    687 
    688 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecDelete(
    689         JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) {
    690     media_status_t err = AMediaCodec_delete(reinterpret_cast<AMediaCodec *>(codec));
    691     return err == AMEDIA_OK;
    692 }
    693 
    694 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecStart(
    695         JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) {
    696     media_status_t err = AMediaCodec_start(reinterpret_cast<AMediaCodec *>(codec));
    697     return err == AMEDIA_OK;
    698 }
    699 
    700 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecStop(
    701         JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) {
    702     media_status_t err = AMediaCodec_stop(reinterpret_cast<AMediaCodec *>(codec));
    703     return err == AMEDIA_OK;
    704 }
    705 
    706 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecConfigure(
    707         JNIEnv *env,
    708         jclass /*clazz*/,
    709         jlong codec,
    710         jstring mime,
    711         jint width,
    712         jint height,
    713         jint colorFormat,
    714         jint bitRate,
    715         jint frameRate,
    716         jint iFrameInterval,
    717         jobject csd,
    718         jint flags) {
    719 
    720     AMediaFormat* format = AMediaFormat_new();
    721     if (format == NULL) {
    722         return false;
    723     }
    724 
    725     const char *tmp = env->GetStringUTFChars(mime, NULL);
    726     if (tmp == NULL) {
    727         AMediaFormat_delete(format);
    728         return false;
    729     }
    730 
    731     AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, tmp);
    732     env->ReleaseStringUTFChars(mime, tmp);
    733 
    734     const char *keys[] = {
    735             AMEDIAFORMAT_KEY_WIDTH,
    736             AMEDIAFORMAT_KEY_HEIGHT,
    737             AMEDIAFORMAT_KEY_COLOR_FORMAT,
    738             AMEDIAFORMAT_KEY_BIT_RATE,
    739             AMEDIAFORMAT_KEY_FRAME_RATE,
    740             AMEDIAFORMAT_KEY_I_FRAME_INTERVAL
    741     };
    742 
    743     jint values[] = {width, height, colorFormat, bitRate, frameRate, iFrameInterval};
    744     for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
    745         if (values[i] >= 0) {
    746             AMediaFormat_setInt32(format, keys[i], values[i]);
    747         }
    748     }
    749 
    750     if (csd != NULL) {
    751         void *csdPtr = env->GetDirectBufferAddress(csd);
    752         jlong csdSize = env->GetDirectBufferCapacity(csd);
    753         AMediaFormat_setBuffer(format, "csd-0", csdPtr, csdSize);
    754     }
    755 
    756     media_status_t err = AMediaCodec_configure(
    757             reinterpret_cast<AMediaCodec *>(codec),
    758             format,
    759             NULL,
    760             NULL,
    761             flags);
    762 
    763     AMediaFormat_delete(format);
    764     return err == AMEDIA_OK;
    765 
    766 }
    767 
    768 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetInputSurface(
    769         JNIEnv* env, jclass /*clazz*/, jlong codec, jobject surface) {
    770 
    771     media_status_t err = AMediaCodec_setInputSurface(
    772             reinterpret_cast<AMediaCodec *>(codec),
    773             ANativeWindow_fromSurface(env, surface));
    774 
    775     return err == AMEDIA_OK;
    776 
    777 }
    778 
    779 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetNativeInputSurface(
    780         JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jlong nativeWindow) {
    781 
    782     media_status_t err = AMediaCodec_setInputSurface(
    783             reinterpret_cast<AMediaCodec *>(codec),
    784             reinterpret_cast<ANativeWindow *>(nativeWindow));
    785 
    786     return err == AMEDIA_OK;
    787 
    788 }
    789 
    790 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateInputSurface(
    791         JNIEnv* /*env*/, jclass /*clazz*/, jlong codec) {
    792 
    793     ANativeWindow *nativeWindow;
    794     media_status_t err = AMediaCodec_createInputSurface(
    795             reinterpret_cast<AMediaCodec *>(codec),
    796             &nativeWindow);
    797 
    798      if (err == AMEDIA_OK) {
    799          return reinterpret_cast<jlong>(nativeWindow);
    800      }
    801 
    802      return 0;
    803 
    804 }
    805 
    806 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreatePersistentInputSurface(
    807         JNIEnv* /*env*/, jclass /*clazz*/) {
    808 
    809     ANativeWindow *nativeWindow;
    810     media_status_t err = AMediaCodec_createPersistentInputSurface(&nativeWindow);
    811 
    812      if (err == AMEDIA_OK) {
    813          return reinterpret_cast<jlong>(nativeWindow);
    814      }
    815 
    816      return 0;
    817 
    818 }
    819 
    820 extern "C" jstring Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputFormatString(
    821         JNIEnv* env, jclass /*clazz*/, jlong codec) {
    822 
    823     AMediaFormat *format = AMediaCodec_getOutputFormat(reinterpret_cast<AMediaCodec *>(codec));
    824     const char *str = AMediaFormat_toString(format);
    825     jstring jstr = env->NewStringUTF(str);
    826     AMediaFormat_delete(format);
    827     return jstr;
    828 
    829 }
    830 
    831 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSignalEndOfInputStream(
    832         JNIEnv* /*env*/, jclass /*clazz*/, jlong codec) {
    833 
    834     media_status_t err = AMediaCodec_signalEndOfInputStream(reinterpret_cast<AMediaCodec *>(codec));
    835     return err == AMEDIA_OK;
    836 
    837 }
    838 
    839 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecReleaseOutputBuffer(
    840         JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jint index, jboolean render) {
    841 
    842     media_status_t err = AMediaCodec_releaseOutputBuffer(
    843             reinterpret_cast<AMediaCodec *>(codec),
    844             index,
    845             render);
    846 
    847     return err == AMEDIA_OK;
    848 
    849 }
    850 
    851 static jobject AMediaCodecGetBuffer(
    852         JNIEnv* env,
    853         jlong codec,
    854         jint index,
    855         uint8_t *(*getBuffer)(AMediaCodec*, size_t, size_t*)) {
    856 
    857     size_t bufsize;
    858     uint8_t *buf = getBuffer(
    859             reinterpret_cast<AMediaCodec *>(codec),
    860             index,
    861             &bufsize);
    862 
    863     return env->NewDirectByteBuffer(buf, bufsize);
    864 
    865 }
    866 
    867 extern "C" jobject Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputBuffer(
    868         JNIEnv* env, jclass /*clazz*/, jlong codec, jint index) {
    869 
    870     return AMediaCodecGetBuffer(env, codec, index, AMediaCodec_getOutputBuffer);
    871 
    872 }
    873 
    874 extern "C" jlongArray Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueOutputBuffer(
    875         JNIEnv* env, jclass /*clazz*/, jlong codec, jlong timeoutUs) {
    876 
    877     AMediaCodecBufferInfo info;
    878     memset(&info, 0, sizeof(info));
    879     int status = AMediaCodec_dequeueOutputBuffer(
    880         reinterpret_cast<AMediaCodec *>(codec),
    881         &info,
    882         timeoutUs);
    883 
    884     jlong ret[5] = {0};
    885     ret[0] = status;
    886     ret[1] = 0; // NdkMediaCodec calls ABuffer::data, which already adds offset
    887     ret[2] = info.size;
    888     ret[3] = info.presentationTimeUs;
    889     ret[4] = info.flags;
    890 
    891     jlongArray jret = env->NewLongArray(5);
    892     env->SetLongArrayRegion(jret, 0, 5, ret);
    893     return jret;
    894 
    895 }
    896 
    897 extern "C" jobject Java_android_media_cts_NdkMediaCodec_AMediaCodecGetInputBuffer(
    898         JNIEnv* env, jclass /*clazz*/, jlong codec, jint index) {
    899 
    900     return AMediaCodecGetBuffer(env, codec, index, AMediaCodec_getInputBuffer);
    901 
    902 }
    903 
    904 extern "C" jint Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueInputBuffer(
    905         JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jlong timeoutUs) {
    906 
    907     return AMediaCodec_dequeueInputBuffer(
    908             reinterpret_cast<AMediaCodec *>(codec),
    909             timeoutUs);
    910 
    911 }
    912 
    913 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecQueueInputBuffer(
    914         JNIEnv* /*env*/,
    915         jclass /*clazz*/,
    916         jlong codec,
    917         jint index,
    918         jint offset,
    919         jint size,
    920         jlong presentationTimeUs,
    921         jint flags) {
    922 
    923     media_status_t err = AMediaCodec_queueInputBuffer(
    924             reinterpret_cast<AMediaCodec *>(codec),
    925             index,
    926             offset,
    927             size,
    928             presentationTimeUs,
    929             flags);
    930 
    931     return err == AMEDIA_OK;
    932 
    933 }
    934 
    935 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetParameter(
    936         JNIEnv* env, jclass /*clazz*/, jlong codec, jstring jkey, jint value) {
    937 
    938     AMediaFormat* params = AMediaFormat_new();
    939     if (params == NULL) {
    940         return false;
    941     }
    942 
    943     const char *key = env->GetStringUTFChars(jkey, NULL);
    944     if (key == NULL) {
    945         AMediaFormat_delete(params);
    946         return false;
    947     }
    948 
    949     AMediaFormat_setInt32(params, key, value);
    950     media_status_t err = AMediaCodec_setParameters(
    951             reinterpret_cast<AMediaCodec *>(codec),
    952             params);
    953     env->ReleaseStringUTFChars(jkey, key);
    954     AMediaFormat_delete(params);
    955     return err == AMEDIA_OK;
    956 
    957 }
    958 
    959 // === NdkInputSurface
    960 
    961 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglGetDisplay(JNIEnv * /*env*/, jclass /*clazz*/) {
    962 
    963     EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    964     if (eglDisplay == EGL_NO_DISPLAY) {
    965         return 0;
    966     }
    967 
    968     EGLint major, minor;
    969     if (!eglInitialize(eglDisplay, &major, &minor)) {
    970         return 0;
    971     }
    972 
    973     return reinterpret_cast<jlong>(eglDisplay);
    974 
    975 }
    976 
    977 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglChooseConfig(
    978         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay) {
    979 
    980     // Configure EGL for recordable and OpenGL ES 2.0.  We want enough RGB bits
    981     // to minimize artifacts from possible YUV conversion.
    982     EGLint attribList[] = {
    983             EGL_RED_SIZE, 8,
    984             EGL_GREEN_SIZE, 8,
    985             EGL_BLUE_SIZE, 8,
    986             EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    987             EGL_RECORDABLE_ANDROID, 1,
    988             EGL_NONE
    989     };
    990 
    991     EGLConfig configs[1];
    992     EGLint numConfigs[1];
    993     if (!eglChooseConfig(reinterpret_cast<EGLDisplay>(eglDisplay), attribList, configs, 1, numConfigs)) {
    994         return 0;
    995     }
    996     return reinterpret_cast<jlong>(configs[0]);
    997 
    998 }
    999 
   1000 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglCreateContext(
   1001         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglConfig) {
   1002 
   1003     // Configure context for OpenGL ES 2.0.
   1004     int attrib_list[] = {
   1005             EGL_CONTEXT_CLIENT_VERSION, 2,
   1006             EGL_NONE
   1007     };
   1008 
   1009     EGLConfig eglContext = eglCreateContext(
   1010             reinterpret_cast<EGLDisplay>(eglDisplay),
   1011             reinterpret_cast<EGLConfig>(eglConfig),
   1012             EGL_NO_CONTEXT,
   1013             attrib_list);
   1014 
   1015     if (eglGetError() != EGL_SUCCESS) {
   1016         return 0;
   1017     }
   1018 
   1019     return reinterpret_cast<jlong>(eglContext);
   1020 
   1021 }
   1022 
   1023 extern "C" jlong Java_android_media_cts_NdkInputSurface_createEGLSurface(
   1024         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglConfig, jlong nativeWindow) {
   1025 
   1026     int surfaceAttribs[] = {EGL_NONE};
   1027     EGLSurface eglSurface = eglCreateWindowSurface(
   1028             reinterpret_cast<EGLDisplay>(eglDisplay),
   1029             reinterpret_cast<EGLConfig>(eglConfig),
   1030             reinterpret_cast<EGLNativeWindowType>(nativeWindow),
   1031             surfaceAttribs);
   1032 
   1033     if (eglGetError() != EGL_SUCCESS) {
   1034         return 0;
   1035     }
   1036 
   1037     return reinterpret_cast<jlong>(eglSurface);
   1038 
   1039 }
   1040 
   1041 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglMakeCurrent(
   1042         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong eglContext) {
   1043 
   1044     return eglMakeCurrent(
   1045             reinterpret_cast<EGLDisplay>(eglDisplay),
   1046             reinterpret_cast<EGLSurface>(eglSurface),
   1047             reinterpret_cast<EGLSurface>(eglSurface),
   1048             reinterpret_cast<EGLContext>(eglContext));
   1049 
   1050 }
   1051 
   1052 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglSwapBuffers(
   1053         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
   1054 
   1055     return eglSwapBuffers(
   1056             reinterpret_cast<EGLDisplay>(eglDisplay),
   1057             reinterpret_cast<EGLSurface>(eglSurface));
   1058 
   1059 }
   1060 
   1061 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglPresentationTimeANDROID(
   1062         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong nsecs) {
   1063 
   1064     return eglPresentationTimeANDROID(
   1065             reinterpret_cast<EGLDisplay>(eglDisplay),
   1066             reinterpret_cast<EGLSurface>(eglSurface),
   1067             reinterpret_cast<EGLnsecsANDROID>(nsecs));
   1068 
   1069 }
   1070 
   1071 extern "C" jint Java_android_media_cts_NdkInputSurface_eglGetWidth(
   1072         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
   1073 
   1074     EGLint width;
   1075     eglQuerySurface(
   1076             reinterpret_cast<EGLDisplay>(eglDisplay),
   1077             reinterpret_cast<EGLSurface>(eglSurface),
   1078             EGL_WIDTH,
   1079             &width);
   1080 
   1081     return width;
   1082 
   1083 }
   1084 
   1085 extern "C" jint Java_android_media_cts_NdkInputSurface_eglGetHeight(
   1086         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
   1087 
   1088     EGLint height;
   1089     eglQuerySurface(
   1090             reinterpret_cast<EGLDisplay>(eglDisplay),
   1091             reinterpret_cast<EGLSurface>(eglSurface),
   1092             EGL_HEIGHT,
   1093             &height);
   1094 
   1095     return height;
   1096 
   1097 }
   1098 
   1099 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglDestroySurface(
   1100         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
   1101 
   1102     return eglDestroySurface(
   1103             reinterpret_cast<EGLDisplay>(eglDisplay),
   1104             reinterpret_cast<EGLSurface>(eglSurface));
   1105 
   1106 }
   1107 
   1108 extern "C" void Java_android_media_cts_NdkInputSurface_nativeRelease(
   1109         JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong eglContext, jlong nativeWindow) {
   1110 
   1111     if (eglDisplay != 0) {
   1112 
   1113         EGLDisplay _eglDisplay = reinterpret_cast<EGLDisplay>(eglDisplay);
   1114         EGLSurface _eglSurface = reinterpret_cast<EGLSurface>(eglSurface);
   1115         EGLContext _eglContext = reinterpret_cast<EGLContext>(eglContext);
   1116 
   1117         eglDestroySurface(_eglDisplay, _eglSurface);
   1118         eglDestroyContext(_eglDisplay, _eglContext);
   1119         eglReleaseThread();
   1120         eglTerminate(_eglDisplay);
   1121 
   1122     }
   1123 
   1124     ANativeWindow_release(reinterpret_cast<ANativeWindow *>(nativeWindow));
   1125 
   1126 }
   1127