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 
     33 #include "media/NdkMediaExtractor.h"
     34 #include "media/NdkMediaCodec.h"
     35 #include "media/NdkMediaCrypto.h"
     36 #include "media/NdkMediaFormat.h"
     37 #include "media/NdkMediaMuxer.h"
     38 
     39 template <class T>
     40 class simplevector {
     41     T *storage;
     42     int capacity;
     43     int numfilled;
     44 public:
     45     simplevector() {
     46         capacity = 16;
     47         numfilled = 0;
     48         storage = new T[capacity];
     49     }
     50     ~simplevector() {
     51         delete[] storage;
     52     }
     53 
     54     void add(T item) {
     55         if (numfilled == capacity) {
     56             T *old = storage;
     57             capacity *= 2;
     58             storage = new T[capacity];
     59             for (int i = 0; i < numfilled; i++) {
     60                 storage[i] = old[i];
     61             }
     62             delete[] old;
     63         }
     64         storage[numfilled] = item;
     65         numfilled++;
     66     }
     67 
     68     int size() {
     69         return numfilled;
     70     }
     71 
     72     T* data() {
     73         return storage;
     74     }
     75 };
     76 
     77 
     78 
     79 jobject testExtractor(AMediaExtractor *ex, JNIEnv *env) {
     80 
     81     simplevector<int> sizes;
     82     int numtracks = AMediaExtractor_getTrackCount(ex);
     83     sizes.add(numtracks);
     84     for (int i = 0; i < numtracks; i++) {
     85         AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
     86         const char *s = AMediaFormat_toString(format);
     87         ALOGI("track %d format: %s", i, s);
     88         const char *mime;
     89         if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
     90             ALOGE("no mime type");
     91             return NULL;
     92         } else if (!strncmp(mime, "audio/", 6)) {
     93             sizes.add(0);
     94             int32_t val32;
     95             int64_t val64;
     96             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &val32);
     97             sizes.add(val32);
     98             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &val32);
     99             sizes.add(val32);
    100             AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &val64);
    101             sizes.add(val64);
    102         } else if (!strncmp(mime, "video/", 6)) {
    103             sizes.add(1);
    104             int32_t val32;
    105             int64_t val64;
    106             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &val32);
    107             sizes.add(val32);
    108             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &val32);
    109             sizes.add(val32);
    110             AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &val64);
    111             sizes.add(val64);
    112         } else {
    113             ALOGE("expected audio or video mime type, got %s", mime);
    114         }
    115         AMediaFormat_delete(format);
    116         AMediaExtractor_selectTrack(ex, i);
    117     }
    118     int bufsize = 1024*1024;
    119     uint8_t *buf = new uint8_t[bufsize];
    120     while(true) {
    121         int n = AMediaExtractor_readSampleData(ex, buf, bufsize);
    122         if (n < 0) {
    123             break;
    124         }
    125         sizes.add(n);
    126         sizes.add(AMediaExtractor_getSampleTrackIndex(ex));
    127         sizes.add(AMediaExtractor_getSampleFlags(ex));
    128         sizes.add(AMediaExtractor_getSampleTime(ex));
    129         AMediaExtractor_advance(ex);
    130     }
    131 
    132     // allocate java int array for result and return it
    133     int *data = sizes.data();
    134     int numsamples = sizes.size();
    135     jintArray ret = env->NewIntArray(numsamples);
    136     jboolean isCopy;
    137     jint *dst = env->GetIntArrayElements(ret, &isCopy);
    138     for (int i = 0; i < numsamples; ++i) {
    139         dst[i] = data[i];
    140     }
    141     env->ReleaseIntArrayElements(ret, dst, 0);
    142 
    143     delete[] buf;
    144     AMediaExtractor_delete(ex);
    145     return ret;
    146 }
    147 
    148 
    149 // get the sample sizes for the file
    150 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getSampleSizesNative(JNIEnv *env,
    151         jclass /*clazz*/, int fd, jlong offset, jlong size)
    152 {
    153     AMediaExtractor *ex = AMediaExtractor_new();
    154     int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
    155     if (err != 0) {
    156         ALOGE("setDataSource error: %d", err);
    157         return NULL;
    158     }
    159     return testExtractor(ex, env);
    160 }
    161 
    162 // get the sample sizes for the path
    163 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getSampleSizesNativePath(JNIEnv *env,
    164         jclass /*clazz*/, jstring jpath)
    165 {
    166     AMediaExtractor *ex = AMediaExtractor_new();
    167 
    168     const char *tmp = env->GetStringUTFChars(jpath, NULL);
    169     if (tmp == NULL) {  // Out of memory
    170         return NULL;
    171     }
    172 
    173     int err = AMediaExtractor_setDataSource(ex, tmp);
    174 
    175     env->ReleaseStringUTFChars(jpath, tmp);
    176 
    177     if (err != 0) {
    178         ALOGE("setDataSource error: %d", err);
    179         return NULL;
    180     }
    181     return testExtractor(ex, env);
    182 }
    183 
    184 static int adler32(const uint8_t *input, int len) {
    185 
    186     int a = 1;
    187     int b = 0;
    188     for (int i = 0; i < len; i++) {
    189         a += input[i];
    190         b += a;
    191     }
    192     a = a % 65521;
    193     b = b % 65521;
    194     int ret = b * 65536 + a;
    195     ALOGV("adler %d/%d", len, ret);
    196     return ret;
    197 }
    198 
    199 static int checksum(const uint8_t *in, int len, AMediaFormat *format) {
    200     int width, stride, height;
    201     if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width)) {
    202         width = len;
    203     }
    204     if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_STRIDE, &stride)) {
    205         stride = width;
    206     }
    207     if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height)) {
    208         height = 1;
    209     }
    210     uint8_t *bb = new uint8_t[width * height];
    211     for (int i = 0; i < height; i++) {
    212         memcpy(bb + i * width, in + i * stride, width);
    213     }
    214     // bb is filled with data
    215     int sum = adler32(bb, width * height);
    216     delete[] bb;
    217     return sum;
    218 }
    219 
    220 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getDecodedDataNative(JNIEnv *env,
    221         jclass /*clazz*/, int fd, jlong offset, jlong size) {
    222     ALOGV("getDecodedDataNative");
    223 
    224     AMediaExtractor *ex = AMediaExtractor_new();
    225     int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
    226     if (err != 0) {
    227         ALOGE("setDataSource error: %d", err);
    228         return NULL;
    229     }
    230 
    231     int numtracks = AMediaExtractor_getTrackCount(ex);
    232 
    233     AMediaCodec **codec = new AMediaCodec*[numtracks];
    234     AMediaFormat **format = new AMediaFormat*[numtracks];
    235     bool *sawInputEOS = new bool[numtracks];
    236     bool *sawOutputEOS = new bool[numtracks];
    237     simplevector<int> *sizes = new simplevector<int>[numtracks];
    238 
    239     ALOGV("input has %d tracks", numtracks);
    240     for (int i = 0; i < numtracks; i++) {
    241         AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
    242         const char *s = AMediaFormat_toString(format);
    243         ALOGI("track %d format: %s", i, s);
    244         const char *mime;
    245         if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
    246             ALOGE("no mime type");
    247             return NULL;
    248         } else if (!strncmp(mime, "audio/", 6) || !strncmp(mime, "video/", 6)) {
    249             codec[i] = AMediaCodec_createDecoderByType(mime);
    250             AMediaCodec_configure(codec[i], format, NULL /* surface */, NULL /* crypto */, 0);
    251             AMediaCodec_start(codec[i]);
    252             sawInputEOS[i] = false;
    253             sawOutputEOS[i] = false;
    254         } else {
    255             ALOGE("expected audio or video mime type, got %s", mime);
    256             return NULL;
    257         }
    258         AMediaFormat_delete(format);
    259         AMediaExtractor_selectTrack(ex, i);
    260     }
    261     int eosCount = 0;
    262     while(eosCount < numtracks) {
    263         int t = AMediaExtractor_getSampleTrackIndex(ex);
    264         if (t >=0) {
    265             ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec[t], 5000);
    266             ALOGV("track %d, input buffer %zd", t, bufidx);
    267             if (bufidx >= 0) {
    268                 size_t bufsize;
    269                 uint8_t *buf = AMediaCodec_getInputBuffer(codec[t], bufidx, &bufsize);
    270                 int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
    271                 ALOGV("read %d", sampleSize);
    272                 if (sampleSize < 0) {
    273                     sampleSize = 0;
    274                     sawInputEOS[t] = true;
    275                     ALOGV("EOS");
    276                     //break;
    277                 }
    278                 int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
    279 
    280                 AMediaCodec_queueInputBuffer(codec[t], bufidx, 0, sampleSize, presentationTimeUs,
    281                         sawInputEOS[t] ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
    282                 AMediaExtractor_advance(ex);
    283             }
    284         } else {
    285             ALOGV("@@@@ no more input samples");
    286             for (int tt = 0; tt < numtracks; tt++) {
    287                 if (!sawInputEOS[tt]) {
    288                     // we ran out of samples without ever signaling EOS to the codec,
    289                     // so do that now
    290                     int bufidx = AMediaCodec_dequeueInputBuffer(codec[tt], 5000);
    291                     if (bufidx >= 0) {
    292                         AMediaCodec_queueInputBuffer(codec[tt], bufidx, 0, 0, 0,
    293                                 AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
    294                         sawInputEOS[tt] = true;
    295                     }
    296                 }
    297             }
    298         }
    299 
    300         // check all codecs for available data
    301         AMediaCodecBufferInfo info;
    302         for (int tt = 0; tt < numtracks; tt++) {
    303             if (!sawOutputEOS[tt]) {
    304                 int status = AMediaCodec_dequeueOutputBuffer(codec[tt], &info, 1);
    305                 ALOGV("dequeueoutput on track %d: %d", tt, status);
    306                 if (status >= 0) {
    307                     if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
    308                         ALOGV("EOS on track %d", tt);
    309                         sawOutputEOS[tt] = true;
    310                         eosCount++;
    311                     }
    312                     ALOGV("got decoded buffer for track %d, size %d", tt, info.size);
    313                     if (info.size > 0) {
    314                         size_t bufsize;
    315                         uint8_t *buf = AMediaCodec_getOutputBuffer(codec[tt], status, &bufsize);
    316                         int adler = checksum(buf, info.size, format[tt]);
    317                         sizes[tt].add(adler);
    318                     }
    319                     AMediaCodec_releaseOutputBuffer(codec[tt], status, false);
    320                 } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
    321                     ALOGV("output buffers changed for track %d", tt);
    322                 } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
    323                     format[tt] = AMediaCodec_getOutputFormat(codec[tt]);
    324                     ALOGV("format changed for track %d: %s", tt, AMediaFormat_toString(format[tt]));
    325                 } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
    326                     ALOGV("no output buffer right now for track %d", tt);
    327                 } else {
    328                     ALOGV("unexpected info code for track %d : %d", tt, status);
    329                 }
    330             } else {
    331                 ALOGV("already at EOS on track %d", tt);
    332             }
    333         }
    334     }
    335     ALOGV("decoding loop done");
    336 
    337     // allocate java int array for result and return it
    338     int numsamples = 0;
    339     for (int i = 0; i < numtracks; i++) {
    340         numsamples += sizes[i].size();
    341     }
    342     ALOGV("checksums: %d", numsamples);
    343     jintArray ret = env->NewIntArray(numsamples);
    344     jboolean isCopy;
    345     jint *org = env->GetIntArrayElements(ret, &isCopy);
    346     jint *dst = org;
    347     for (int i = 0; i < numtracks; i++) {
    348         int *data = sizes[i].data();
    349         int len = sizes[i].size();
    350         ALOGV("copying %d", len);
    351         for (int j = 0; j < len; j++) {
    352             *dst++ = data[j];
    353         }
    354     }
    355     env->ReleaseIntArrayElements(ret, org, 0);
    356 
    357     delete[] sizes;
    358     delete[] sawOutputEOS;
    359     delete[] sawInputEOS;
    360     for (int i = 0; i < numtracks; i++) {
    361         AMediaFormat_delete(format[i]);
    362         AMediaCodec_stop(codec[i]);
    363         AMediaCodec_delete(codec[i]);
    364     }
    365     delete[] format;
    366     delete[] codec;
    367     AMediaExtractor_delete(ex);
    368     return ret;
    369 }
    370 
    371 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testPlaybackNative(JNIEnv *env,
    372         jclass /*clazz*/, jobject surface, int fd, jlong offset, jlong size) {
    373 
    374     ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
    375     ALOGI("@@@@ native window: %p", window);
    376 
    377     AMediaExtractor *ex = AMediaExtractor_new();
    378     int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
    379     if (err != 0) {
    380         ALOGE("setDataSource error: %d", err);
    381         return false;
    382     }
    383 
    384     int numtracks = AMediaExtractor_getTrackCount(ex);
    385 
    386     AMediaCodec *codec = NULL;
    387     AMediaFormat *format = NULL;
    388     bool sawInputEOS = false;
    389     bool sawOutputEOS = false;
    390 
    391     ALOGV("input has %d tracks", numtracks);
    392     for (int i = 0; i < numtracks; i++) {
    393         AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
    394         const char *s = AMediaFormat_toString(format);
    395         ALOGI("track %d format: %s", i, s);
    396         const char *mime;
    397         if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
    398             ALOGE("no mime type");
    399             return false;
    400         } else if (!strncmp(mime, "video/", 6)) {
    401             codec = AMediaCodec_createDecoderByType(mime);
    402             AMediaCodec_configure(codec, format, window, NULL, 0);
    403             AMediaCodec_start(codec);
    404             AMediaExtractor_selectTrack(ex, i);
    405         }
    406         AMediaFormat_delete(format);
    407     }
    408 
    409     while (!sawOutputEOS) {
    410         ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec, 5000);
    411         ALOGV("input buffer %zd", bufidx);
    412         if (bufidx >= 0) {
    413             size_t bufsize;
    414             uint8_t *buf = AMediaCodec_getInputBuffer(codec, bufidx, &bufsize);
    415             int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
    416             ALOGV("read %d", sampleSize);
    417             if (sampleSize < 0) {
    418                 sampleSize = 0;
    419                 sawInputEOS = true;
    420                 ALOGV("EOS");
    421             }
    422             int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
    423 
    424             AMediaCodec_queueInputBuffer(codec, bufidx, 0, sampleSize, presentationTimeUs,
    425                     sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
    426             AMediaExtractor_advance(ex);
    427         }
    428 
    429         AMediaCodecBufferInfo info;
    430         int status = AMediaCodec_dequeueOutputBuffer(codec, &info, 1);
    431         ALOGV("dequeueoutput returned: %d", status);
    432         if (status >= 0) {
    433             if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
    434                 ALOGV("output EOS");
    435                 sawOutputEOS = true;
    436             }
    437             ALOGV("got decoded buffer size %d", info.size);
    438             AMediaCodec_releaseOutputBuffer(codec, status, true);
    439             usleep(20000);
    440         } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
    441             ALOGV("output buffers changed");
    442         } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
    443             format = AMediaCodec_getOutputFormat(codec);
    444             ALOGV("format changed to: %s", AMediaFormat_toString(format));
    445         } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
    446             ALOGV("no output buffer right now");
    447         } else {
    448             ALOGV("unexpected info code: %d", status);
    449         }
    450     }
    451 
    452     AMediaCodec_stop(codec);
    453     AMediaCodec_delete(codec);
    454     AMediaExtractor_delete(ex);
    455     return true;
    456 }
    457 
    458 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testMuxerNative(JNIEnv */*env*/,
    459         jclass /*clazz*/, int infd, jlong inoffset, jlong insize, int outfd, jboolean webm) {
    460 
    461 
    462     AMediaMuxer *muxer = AMediaMuxer_new(outfd,
    463             webm ? AMEDIAMUXER_OUTPUT_FORMAT_WEBM : AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
    464 
    465     AMediaExtractor *ex = AMediaExtractor_new();
    466     int err = AMediaExtractor_setDataSourceFd(ex, infd, inoffset, insize);
    467     if (err != 0) {
    468         ALOGE("setDataSource error: %d", err);
    469         return false;
    470     }
    471 
    472     int numtracks = AMediaExtractor_getTrackCount(ex);
    473     ALOGI("input tracks: %d", numtracks);
    474     for (int i = 0; i < numtracks; i++) {
    475         AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
    476         const char *s = AMediaFormat_toString(format);
    477         ALOGI("track %d format: %s", i, s);
    478         const char *mime;
    479         if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
    480             ALOGE("no mime type");
    481             return false;
    482         } else if (!strncmp(mime, "audio/", 6) || !strncmp(mime, "video/", 6)) {
    483             ssize_t tidx = AMediaMuxer_addTrack(muxer, format);
    484             ALOGI("track %d -> %zd format %s", i, tidx, s);
    485             AMediaExtractor_selectTrack(ex, i);
    486         } else {
    487             ALOGE("expected audio or video mime type, got %s", mime);
    488             return false;
    489         }
    490         AMediaFormat_delete(format);
    491         AMediaExtractor_selectTrack(ex, i);
    492     }
    493     AMediaMuxer_start(muxer);
    494 
    495     int bufsize = 1024*1024;
    496     uint8_t *buf = new uint8_t[bufsize];
    497     AMediaCodecBufferInfo info;
    498     while(true) {
    499         int n = AMediaExtractor_readSampleData(ex, buf, bufsize);
    500         if (n < 0) {
    501             break;
    502         }
    503         info.offset = 0;
    504         info.size = n;
    505         info.presentationTimeUs = AMediaExtractor_getSampleTime(ex);
    506         info.flags = AMediaExtractor_getSampleFlags(ex);
    507 
    508         size_t idx = (size_t) AMediaExtractor_getSampleTrackIndex(ex);
    509         AMediaMuxer_writeSampleData(muxer, idx, buf, &info);
    510 
    511         AMediaExtractor_advance(ex);
    512     }
    513 
    514     AMediaExtractor_delete(ex);
    515     AMediaMuxer_stop(muxer);
    516     AMediaMuxer_delete(muxer);
    517     return true;
    518 
    519 }
    520 
    521 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testFormatNative(JNIEnv * /*env*/,
    522         jclass /*clazz*/) {
    523     AMediaFormat* format = AMediaFormat_new();
    524     if (!format) {
    525         return false;
    526     }
    527 
    528     AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, 8000);
    529     int32_t bitrate = 0;
    530     if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate) || bitrate != 8000) {
    531         ALOGE("AMediaFormat_getInt32 fail: %d", bitrate);
    532         return false;
    533     }
    534 
    535     AMediaFormat_setInt64(format, AMEDIAFORMAT_KEY_DURATION, 123456789123456789ll);
    536     int64_t duration = 0;
    537     if (!AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &duration)
    538             || duration != 123456789123456789ll) {
    539         ALOGE("AMediaFormat_getInt64 fail: %lld", (long long) duration);
    540         return false;
    541     }
    542 
    543     AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_FRAME_RATE, 25.0f);
    544     float framerate = 0.0f;
    545     if (!AMediaFormat_getFloat(format, AMEDIAFORMAT_KEY_FRAME_RATE, &framerate)
    546             || framerate != 25.0f) {
    547         ALOGE("AMediaFormat_getFloat fail: %f", framerate);
    548         return false;
    549     }
    550 
    551     const char* value = "audio/mpeg";
    552     AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, value);
    553     const char* readback = NULL;
    554     if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &readback)
    555             || strcmp(value, readback) || value == readback) {
    556         ALOGE("AMediaFormat_getString fail");
    557         return false;
    558     }
    559 
    560     uint32_t foo = 0xdeadbeef;
    561     AMediaFormat_setBuffer(format, "csd-0", &foo, sizeof(foo));
    562     foo = 0xabadcafe;
    563     void *bytes;
    564     size_t bytesize = 0;
    565     if(!AMediaFormat_getBuffer(format, "csd-0", &bytes, &bytesize)
    566             || bytesize != sizeof(foo) || *((uint32_t*)bytes) != 0xdeadbeef) {
    567         ALOGE("AMediaFormat_getBuffer fail");
    568         return false;
    569     }
    570 
    571     return true;
    572 }
    573 
    574 
    575 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testPsshNative(JNIEnv * /*env*/,
    576         jclass /*clazz*/, int fd, jlong offset, jlong size) {
    577 
    578     AMediaExtractor *ex = AMediaExtractor_new();
    579     int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
    580     if (err != 0) {
    581         ALOGE("setDataSource error: %d", err);
    582         return false;
    583     }
    584 
    585     PsshInfo* info = AMediaExtractor_getPsshInfo(ex);
    586     if (info == NULL) {
    587         ALOGI("null pssh");
    588         return false;
    589     }
    590 
    591     ALOGI("pssh has %zd entries", info->numentries);
    592     if (info->numentries != 2) {
    593         return false;
    594     }
    595 
    596     for (size_t i = 0; i < info->numentries; i++) {
    597         PsshEntry *entry = &info->entries[i];
    598         ALOGI("entry uuid %02x%02x..%02x%02x, data size %zd",
    599                 entry->uuid[0],
    600                 entry->uuid[1],
    601                 entry->uuid[14],
    602                 entry->uuid[15],
    603                 entry->datalen);
    604 
    605         AMediaCrypto *crypto = AMediaCrypto_new(entry->uuid, entry->data, entry->datalen);
    606         if (crypto) {
    607             ALOGI("got crypto");
    608             AMediaCrypto_delete(crypto);
    609         } else {
    610             ALOGI("no crypto");
    611         }
    612     }
    613     return true;
    614 }
    615 
    616 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testCryptoInfoNative(JNIEnv * /*env*/,
    617         jclass /*clazz*/) {
    618 
    619     size_t numsubsamples = 4;
    620     uint8_t key[16] = { 1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4 };
    621     uint8_t iv[16] = { 4,3,2,1,4,3,2,1,4,3,2,1,4,3,2,1 };
    622     size_t clearbytes[4] = { 5, 6, 7, 8 };
    623     size_t encryptedbytes[4] = { 8, 7, 6, 5 };
    624 
    625     AMediaCodecCryptoInfo *ci =
    626             AMediaCodecCryptoInfo_new(numsubsamples, key, iv, AMEDIACODECRYPTOINFO_MODE_CLEAR, clearbytes, encryptedbytes);
    627 
    628     if (AMediaCodecCryptoInfo_getNumSubSamples(ci) != 4) {
    629         ALOGE("numsubsamples mismatch");
    630         return false;
    631     }
    632     uint8_t bytes[16];
    633     AMediaCodecCryptoInfo_getKey(ci, bytes);
    634     if (memcmp(key, bytes, 16) != 0) {
    635         ALOGE("key mismatch");
    636         return false;
    637     }
    638     AMediaCodecCryptoInfo_getIV(ci, bytes);
    639     if (memcmp(iv, bytes, 16) != 0) {
    640         ALOGE("IV mismatch");
    641         return false;
    642     }
    643     if (AMediaCodecCryptoInfo_getMode(ci) != AMEDIACODECRYPTOINFO_MODE_CLEAR) {
    644         ALOGE("mode mismatch");
    645         return false;
    646     }
    647     size_t sizes[numsubsamples];
    648     AMediaCodecCryptoInfo_getClearBytes(ci, sizes);
    649     if (memcmp(clearbytes, sizes, sizeof(size_t) * numsubsamples)) {
    650         ALOGE("clear size mismatch");
    651         return false;
    652     }
    653     AMediaCodecCryptoInfo_getEncryptedBytes(ci, sizes);
    654     if (memcmp(encryptedbytes, sizes, sizeof(size_t) * numsubsamples)) {
    655         ALOGE("encrypted size mismatch");
    656         return false;
    657     }
    658     return true;
    659 }
    660 
    661