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 #undef NDEBUG
20 #include <assert.h>
21 #include <jni.h>
22 #include <pthread.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <semaphore.h>
27
28 #include <android/native_window_jni.h>
29
30 // for __android_log_print(ANDROID_LOG_INFO, "YourApp", "formatted message");
31 #include <android/log.h>
32 #define TAG "NativeMedia"
33 #define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
34 #define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
35 #define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
36
37 #include "ndk/NdkMediaExtractor.h"
38 #include "ndk/NdkMediaCodec.h"
39 #include "ndk/NdkMediaCrypto.h"
40 #include "ndk/NdkMediaFormat.h"
41 #include "ndk/NdkMediaMuxer.h"
42
43 template <class T>
44 class simplevector {
45 T *storage;
46 int capacity;
47 int numfilled;
48 public:
simplevector()49 simplevector() {
50 capacity = 16;
51 numfilled = 0;
52 storage = new T[capacity];
53 }
~simplevector()54 ~simplevector() {
55 delete[] storage;
56 }
57
add(T item)58 void add(T item) {
59 if (numfilled == capacity) {
60 T *old = storage;
61 capacity *= 2;
62 storage = new T[capacity];
63 for (int i = 0; i < numfilled; i++) {
64 storage[i] = old[i];
65 }
66 delete[] old;
67 }
68 storage[numfilled] = item;
69 numfilled++;
70 }
71
size()72 int size() {
73 return numfilled;
74 }
75
data()76 T* data() {
77 return storage;
78 }
79 };
80
81
82
testExtractor(AMediaExtractor * ex,JNIEnv * env)83 jobject testExtractor(AMediaExtractor *ex, JNIEnv *env) {
84
85 simplevector<int> sizes;
86 int numtracks = AMediaExtractor_getTrackCount(ex);
87 sizes.add(numtracks);
88 for (int i = 0; i < numtracks; i++) {
89 AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
90 const char *s = AMediaFormat_toString(format);
91 ALOGI("track %d format: %s", i, s);
92 const char *mime;
93 if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
94 ALOGE("no mime type");
95 return NULL;
96 } else if (!strncmp(mime, "audio/", 6)) {
97 sizes.add(0);
98 int32_t val32;
99 int64_t val64;
100 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &val32);
101 sizes.add(val32);
102 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &val32);
103 sizes.add(val32);
104 AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &val64);
105 sizes.add(val64);
106 } else if (!strncmp(mime, "video/", 6)) {
107 sizes.add(1);
108 int32_t val32;
109 int64_t val64;
110 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &val32);
111 sizes.add(val32);
112 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &val32);
113 sizes.add(val32);
114 AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &val64);
115 sizes.add(val64);
116 } else {
117 ALOGE("expected audio or video mime type, got %s", mime);
118 }
119 AMediaFormat_delete(format);
120 AMediaExtractor_selectTrack(ex, i);
121 }
122 int bufsize = 1024*1024;
123 uint8_t *buf = new uint8_t[bufsize];
124 while(true) {
125 int n = AMediaExtractor_readSampleData(ex, buf, bufsize);
126 if (n < 0) {
127 break;
128 }
129 sizes.add(n);
130 sizes.add(AMediaExtractor_getSampleTrackIndex(ex));
131 sizes.add(AMediaExtractor_getSampleFlags(ex));
132 sizes.add(AMediaExtractor_getSampleTime(ex));
133 AMediaExtractor_advance(ex);
134 }
135
136 // allocate java int array for result and return it
137 int *data = sizes.data();
138 int numsamples = sizes.size();
139 jintArray ret = env->NewIntArray(numsamples);
140 jboolean isCopy;
141 jint *dst = env->GetIntArrayElements(ret, &isCopy);
142 for (int i = 0; i < numsamples; ++i) {
143 dst[i] = data[i];
144 }
145 env->ReleaseIntArrayElements(ret, dst, 0);
146
147 delete[] buf;
148 AMediaExtractor_delete(ex);
149 return ret;
150 }
151
152
153 // get the sample sizes for the file
Java_android_media_cts_NativeDecoderTest_getSampleSizesNative(JNIEnv * env,jclass,int fd,jlong offset,jlong size)154 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getSampleSizesNative(JNIEnv *env,
155 jclass /*clazz*/, int fd, jlong offset, jlong size)
156 {
157 AMediaExtractor *ex = AMediaExtractor_new();
158 int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
159 if (err != 0) {
160 ALOGE("setDataSource error: %d", err);
161 return NULL;
162 }
163 return testExtractor(ex, env);
164 }
165
166 // get the sample sizes for the path
Java_android_media_cts_NativeDecoderTest_getSampleSizesNativePath(JNIEnv * env,jclass,jstring jpath)167 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getSampleSizesNativePath(JNIEnv *env,
168 jclass /*clazz*/, jstring jpath)
169 {
170 AMediaExtractor *ex = AMediaExtractor_new();
171
172 const char *tmp = env->GetStringUTFChars(jpath, NULL);
173 if (tmp == NULL) { // Out of memory
174 return NULL;
175 }
176
177 int err = AMediaExtractor_setDataSource(ex, tmp);
178
179 env->ReleaseStringUTFChars(jpath, tmp);
180
181 if (err != 0) {
182 ALOGE("setDataSource error: %d", err);
183 return NULL;
184 }
185 return testExtractor(ex, env);
186 }
187
adler32(const uint8_t * input,int len)188 static int adler32(const uint8_t *input, int len) {
189
190 int a = 1;
191 int b = 0;
192 for (int i = 0; i < len; i++) {
193 a += input[i];
194 b += a;
195 }
196 a = a % 65521;
197 b = b % 65521;
198 int ret = b * 65536 + a;
199 ALOGV("adler %d/%d", len, ret);
200 return ret;
201 }
202
checksum(const uint8_t * in,int len,AMediaFormat * format)203 static int checksum(const uint8_t *in, int len, AMediaFormat *format) {
204 int width, stride, height;
205 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width)) {
206 width = len;
207 }
208 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_STRIDE, &stride)) {
209 stride = width;
210 }
211 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height)) {
212 height = 1;
213 }
214 uint8_t *bb = new uint8_t[width * height];
215 for (int i = 0; i < height; i++) {
216 memcpy(bb + i * width, in + i * stride, width);
217 }
218 // bb is filled with data
219 int sum = adler32(bb, width * height);
220 delete[] bb;
221 return sum;
222 }
223
Java_android_media_cts_NativeDecoderTest_getDecodedDataNative(JNIEnv * env,jclass,int fd,jlong offset,jlong size)224 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getDecodedDataNative(JNIEnv *env,
225 jclass /*clazz*/, int fd, jlong offset, jlong size) {
226 ALOGV("getDecodedDataNative");
227
228 AMediaExtractor *ex = AMediaExtractor_new();
229 int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
230 if (err != 0) {
231 ALOGE("setDataSource error: %d", err);
232 return NULL;
233 }
234
235 int numtracks = AMediaExtractor_getTrackCount(ex);
236
237 AMediaCodec **codec = new AMediaCodec*[numtracks];
238 AMediaFormat **format = new AMediaFormat*[numtracks];
239 bool *sawInputEOS = new bool[numtracks];
240 bool *sawOutputEOS = new bool[numtracks];
241 simplevector<int> sizes[numtracks];
242
243 ALOGV("input has %d tracks", numtracks);
244 for (int i = 0; i < numtracks; i++) {
245 AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
246 const char *s = AMediaFormat_toString(format);
247 ALOGI("track %d format: %s", i, s);
248 const char *mime;
249 if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
250 ALOGE("no mime type");
251 return NULL;
252 } else if (!strncmp(mime, "audio/", 6) || !strncmp(mime, "video/", 6)) {
253 codec[i] = AMediaCodec_createDecoderByType(mime);
254 AMediaCodec_configure(codec[i], format, NULL /* surface */, NULL /* crypto */, 0);
255 AMediaCodec_start(codec[i]);
256 sawInputEOS[i] = false;
257 sawOutputEOS[i] = false;
258 } else {
259 ALOGE("expected audio or video mime type, got %s", mime);
260 return NULL;
261 }
262 AMediaFormat_delete(format);
263 AMediaExtractor_selectTrack(ex, i);
264 }
265 int eosCount = 0;
266 while(eosCount < numtracks) {
267 int t = AMediaExtractor_getSampleTrackIndex(ex);
268 if (t >=0) {
269 ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec[t], 5000);
270 ALOGV("track %d, input buffer %d", t, bufidx);
271 if (bufidx >= 0) {
272 size_t bufsize;
273 uint8_t *buf = AMediaCodec_getInputBuffer(codec[t], bufidx, &bufsize);
274 int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
275 ALOGV("read %d", sampleSize);
276 if (sampleSize < 0) {
277 sampleSize = 0;
278 sawInputEOS[t] = true;
279 ALOGV("EOS");
280 //break;
281 }
282 int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
283
284 AMediaCodec_queueInputBuffer(codec[t], bufidx, 0, sampleSize, presentationTimeUs,
285 sawInputEOS[t] ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
286 AMediaExtractor_advance(ex);
287 }
288 } else {
289 ALOGV("@@@@ no more input samples");
290 for (int tt = 0; tt < numtracks; tt++) {
291 if (!sawInputEOS[tt]) {
292 // we ran out of samples without ever signaling EOS to the codec,
293 // so do that now
294 int bufidx = AMediaCodec_dequeueInputBuffer(codec[tt], 5000);
295 if (bufidx >= 0) {
296 AMediaCodec_queueInputBuffer(codec[tt], bufidx, 0, 0, 0,
297 AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
298 sawInputEOS[tt] = true;
299 }
300 }
301 }
302 }
303
304 // check all codecs for available data
305 AMediaCodecBufferInfo info;
306 for (int tt = 0; tt < numtracks; tt++) {
307 if (!sawOutputEOS[tt]) {
308 int status = AMediaCodec_dequeueOutputBuffer(codec[tt], &info, 1);
309 ALOGV("dequeueoutput on track %d: %d", tt, status);
310 if (status >= 0) {
311 if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
312 ALOGV("EOS on track %d", tt);
313 sawOutputEOS[tt] = true;
314 eosCount++;
315 }
316 ALOGV("got decoded buffer for track %d, size %d", tt, info.size);
317 if (info.size > 0) {
318 size_t bufsize;
319 uint8_t *buf = AMediaCodec_getOutputBuffer(codec[tt], status, &bufsize);
320 int adler = checksum(buf, info.size, format[tt]);
321 sizes[tt].add(adler);
322 }
323 AMediaCodec_releaseOutputBuffer(codec[tt], status, false);
324 } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
325 ALOGV("output buffers changed for track %d", tt);
326 } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
327 format[tt] = AMediaCodec_getOutputFormat(codec[tt]);
328 ALOGV("format changed for track %d: %s", tt, AMediaFormat_toString(format[tt]));
329 } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
330 ALOGV("no output buffer right now for track %d", tt);
331 } else {
332 ALOGV("unexpected info code for track %d : %d", tt, status);
333 }
334 } else {
335 ALOGV("already at EOS on track %d", tt);
336 }
337 }
338 }
339 ALOGV("decoding loop done");
340
341 // allocate java int array for result and return it
342 int numsamples = 0;
343 for (int i = 0; i < numtracks; i++) {
344 numsamples += sizes[i].size();
345 }
346 ALOGV("checksums: %d", numsamples);
347 jintArray ret = env->NewIntArray(numsamples);
348 jboolean isCopy;
349 jint *org = env->GetIntArrayElements(ret, &isCopy);
350 jint *dst = org;
351 for (int i = 0; i < numtracks; i++) {
352 int *data = sizes[i].data();
353 int len = sizes[i].size();
354 ALOGV("copying %d", len);
355 for (int j = 0; j < len; j++) {
356 *dst++ = data[j];
357 }
358 }
359 env->ReleaseIntArrayElements(ret, org, 0);
360
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
Java_android_media_cts_NativeDecoderTest_testPlaybackNative(JNIEnv * env,jclass,jobject surface,int fd,jlong offset,jlong size)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 %d", 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
Java_android_media_cts_NativeDecoderTest_testMuxerNative(JNIEnv *,jclass,int infd,jlong inoffset,jlong insize,int outfd,jboolean webm)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 -> %d 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
Java_android_media_cts_NativeDecoderTest_testFormatNative(JNIEnv *,jclass)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", 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
Java_android_media_cts_NativeDecoderTest_testPsshNative(JNIEnv *,jclass,int fd,jlong offset,jlong size)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
Java_android_media_cts_NativeDecoderTest_testCryptoInfoNative(JNIEnv *,jclass)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