• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
simplevector()45     simplevector() {
46         capacity = 16;
47         numfilled = 0;
48         storage = new T[capacity];
49     }
~simplevector()50     ~simplevector() {
51         delete[] storage;
52     }
53 
add(T item)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 
size()68     int size() {
69         return numfilled;
70     }
71 
data()72     T* data() {
73         return storage;
74     }
75 };
76 
77 
78 
testExtractor(AMediaExtractor * ex,JNIEnv * env)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
Java_android_media_cts_NativeDecoderTest_getSampleSizesNative(JNIEnv * env,jclass,int fd,jlong offset,jlong size)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
Java_android_media_cts_NativeDecoderTest_getSampleSizesNativePath(JNIEnv * env,jclass,jstring jpath)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 
adler32(const uint8_t * input,int len)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 
checksum(const uint8_t * in,int len,AMediaFormat * format)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 
Java_android_media_cts_NativeDecoderTest_getDecodedDataNative(JNIEnv * env,jclass,int fd,jlong offset,jlong size)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 
Java_android_media_cts_NativeDecoderTest_testPlaybackNative(JNIEnv * env,jclass,jobject surface,int fd,jlong offset,jlong size)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 
Java_android_media_cts_NativeDecoderTest_testMuxerNative(JNIEnv *,jclass,int infd,jlong inoffset,jlong insize,int outfd,jboolean webm)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 
Java_android_media_cts_NativeDecoderTest_testFormatNative(JNIEnv *,jclass)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 
Java_android_media_cts_NativeDecoderTest_testPsshNative(JNIEnv *,jclass,int fd,jlong offset,jlong size)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 
Java_android_media_cts_NativeDecoderTest_testCryptoInfoNative(JNIEnv *,jclass)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