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