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 LOG_TAG "NativeMedia"
21 #include <log/log.h>
22
23 #include <assert.h>
24 #include <jni.h>
25 #include <mutex>
26 #include <pthread.h>
27 #include <queue>
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <semaphore.h>
32
33 #include <android/native_window_jni.h>
34 #include <EGL/egl.h>
35 #include <EGL/eglext.h>
36
37 #include "media/NdkMediaExtractor.h"
38 #include "media/NdkMediaCodec.h"
39 #include "media/NdkMediaCrypto.h"
40 #include "media/NdkMediaDataSource.h"
41 #include "media/NdkMediaFormat.h"
42 #include "media/NdkMediaMuxer.h"
43
44 template <class T>
45 class simplevector {
46 T *storage;
47 int capacity;
48 int numfilled;
49 public:
simplevector()50 simplevector() {
51 capacity = 16;
52 numfilled = 0;
53 storage = new T[capacity];
54 }
~simplevector()55 ~simplevector() {
56 delete[] storage;
57 }
58
add(T item)59 void add(T item) {
60 if (numfilled == capacity) {
61 T *old = storage;
62 capacity *= 2;
63 storage = new T[capacity];
64 for (int i = 0; i < numfilled; i++) {
65 storage[i] = old[i];
66 }
67 delete[] old;
68 }
69 storage[numfilled] = item;
70 numfilled++;
71 }
72
size()73 int size() {
74 return numfilled;
75 }
76
data()77 T* data() {
78 return storage;
79 }
80 };
81
82 struct FdDataSource {
83
FdDataSourceFdDataSource84 FdDataSource(int fd, jlong offset, jlong size)
85 : mFd(dup(fd)),
86 mOffset(offset),
87 mSize(size) {
88 }
89
readAtFdDataSource90 ssize_t readAt(off64_t offset, void *data, size_t size) {
91 ssize_t ssize = size;
92 if (!data || offset < 0 || offset + ssize < offset) {
93 return -1;
94 }
95 if (offset >= mSize) {
96 return 0; // EOS
97 }
98 if (offset + ssize > mSize) {
99 ssize = mSize - offset;
100 }
101 if (lseek(mFd, mOffset + offset, SEEK_SET) < 0) {
102 return -1;
103 }
104 return read(mFd, data, ssize);
105 }
106
getSizeFdDataSource107 ssize_t getSize() {
108 return mSize;
109 }
110
closeFdDataSource111 void close() {
112 ::close(mFd);
113 }
114
115 private:
116
117 int mFd;
118 off64_t mOffset;
119 int64_t mSize;
120
121 };
122
FdSourceReadAt(void * userdata,off64_t offset,void * data,size_t size)123 static ssize_t FdSourceReadAt(void *userdata, off64_t offset, void *data, size_t size) {
124 FdDataSource *src = (FdDataSource*) userdata;
125 return src->readAt(offset, data, size);
126 }
127
FdSourceGetSize(void * userdata)128 static ssize_t FdSourceGetSize(void *userdata) {
129 FdDataSource *src = (FdDataSource*) userdata;
130 return src->getSize();
131 }
132
FdSourceClose(void * userdata)133 static void FdSourceClose(void *userdata) {
134 FdDataSource *src = (FdDataSource*) userdata;
135 src->close();
136 }
137
138 class CallbackData {
139 std::mutex mMutex;
140 std::queue<int32_t> mInputBufferIds;
141 std::queue<int32_t> mOutputBufferIds;
142 std::queue<AMediaCodecBufferInfo> mOutputBufferInfos;
143 std::queue<AMediaFormat*> mFormats;
144
145 public:
CallbackData()146 CallbackData() { }
147
~CallbackData()148 ~CallbackData() {
149 mMutex.lock();
150 while (!mFormats.empty()) {
151 AMediaFormat* format = mFormats.front();
152 mFormats.pop();
153 AMediaFormat_delete(format);
154 }
155 mMutex.unlock();
156 }
157
addInputBufferId(int32_t index)158 void addInputBufferId(int32_t index) {
159 mMutex.lock();
160 mInputBufferIds.push(index);
161 mMutex.unlock();
162 }
163
getInputBufferId()164 int32_t getInputBufferId() {
165 int32_t id = -1;
166 mMutex.lock();
167 if (!mInputBufferIds.empty()) {
168 id = mInputBufferIds.front();
169 mInputBufferIds.pop();
170 }
171 mMutex.unlock();
172 return id;
173 }
174
addOutputBuffer(int32_t index,AMediaCodecBufferInfo * bufferInfo)175 void addOutputBuffer(int32_t index, AMediaCodecBufferInfo *bufferInfo) {
176 mMutex.lock();
177 mOutputBufferIds.push(index);
178 mOutputBufferInfos.push(*bufferInfo);
179 mMutex.unlock();
180 }
181
addOutputFormat(AMediaFormat * format)182 void addOutputFormat(AMediaFormat *format) {
183 mMutex.lock();
184 mOutputBufferIds.push(AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED);
185 mFormats.push(format);
186 mMutex.unlock();
187 }
188
getOutput(AMediaCodecBufferInfo * bufferInfo,AMediaFormat ** format)189 int32_t getOutput(AMediaCodecBufferInfo *bufferInfo, AMediaFormat **format) {
190 int32_t id = AMEDIACODEC_INFO_TRY_AGAIN_LATER;
191 mMutex.lock();
192 if (!mOutputBufferIds.empty()) {
193 id = mOutputBufferIds.front();
194 mOutputBufferIds.pop();
195
196 if (id >= 0) {
197 *bufferInfo = mOutputBufferInfos.front();
198 mOutputBufferInfos.pop();
199 } else { // AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED
200 *format = mFormats.front();
201 mFormats.pop();
202 }
203 }
204 mMutex.unlock();
205 return id;
206 }
207 };
208
OnInputAvailableCB(AMediaCodec *,void * userdata,int32_t index)209 static void OnInputAvailableCB(
210 AMediaCodec * /* aMediaCodec */,
211 void *userdata,
212 int32_t index) {
213 ALOGV("OnInputAvailableCB: index(%d)", index);
214 CallbackData *callbackData = (CallbackData *)userdata;
215 callbackData->addInputBufferId(index);
216 }
217
OnOutputAvailableCB(AMediaCodec *,void * userdata,int32_t index,AMediaCodecBufferInfo * bufferInfo)218 static void OnOutputAvailableCB(
219 AMediaCodec * /* aMediaCodec */,
220 void *userdata,
221 int32_t index,
222 AMediaCodecBufferInfo *bufferInfo) {
223 ALOGV("OnOutputAvailableCB: index(%d), (%d, %d, %lld, 0x%x)",
224 index, bufferInfo->offset, bufferInfo->size,
225 (long long)bufferInfo->presentationTimeUs, bufferInfo->flags);
226 CallbackData *callbackData = (CallbackData *)userdata;
227 callbackData->addOutputBuffer(index, bufferInfo);
228 }
229
OnFormatChangedCB(AMediaCodec *,void * userdata,AMediaFormat * format)230 static void OnFormatChangedCB(
231 AMediaCodec * /* aMediaCodec */,
232 void *userdata,
233 AMediaFormat *format) {
234 ALOGV("OnFormatChangedCB: format(%s)", AMediaFormat_toString(format));
235 CallbackData *callbackData = (CallbackData *)userdata;
236 callbackData->addOutputFormat(format);
237 }
238
OnErrorCB(AMediaCodec *,void *,media_status_t err,int32_t actionCode,const char * detail)239 static void OnErrorCB(
240 AMediaCodec * /* aMediaCodec */,
241 void * /* userdata */,
242 media_status_t err,
243 int32_t actionCode,
244 const char *detail) {
245 ALOGV("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail);
246 }
247
adler32(const uint8_t * input,int len)248 static int adler32(const uint8_t *input, int len) {
249
250 int a = 1;
251 int b = 0;
252 for (int i = 0; i < len; i++) {
253 a += input[i];
254 b += a;
255 a = a % 65521;
256 b = b % 65521;
257 }
258 int ret = b * 65536 + a;
259 ALOGV("adler %d/%d", len, ret);
260 return ret;
261 }
262
testExtractor(AMediaExtractor * ex,JNIEnv * env)263 jobject testExtractor(AMediaExtractor *ex, JNIEnv *env) {
264
265 simplevector<int> sizes;
266 int numtracks = AMediaExtractor_getTrackCount(ex);
267 sizes.add(numtracks);
268 for (int i = 0; i < numtracks; i++) {
269 AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
270 const char *s = AMediaFormat_toString(format);
271 ALOGI("track %d format: %s", i, s);
272 const char *mime;
273 if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
274 ALOGE("no mime type");
275 return NULL;
276 } else if (!strncmp(mime, "audio/", 6)) {
277 sizes.add(0);
278 int32_t val32;
279 int64_t val64;
280 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &val32);
281 sizes.add(val32);
282 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &val32);
283 sizes.add(val32);
284 AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &val64);
285 sizes.add(val64);
286 } else if (!strncmp(mime, "video/", 6)) {
287 sizes.add(1);
288 int32_t val32;
289 int64_t val64;
290 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &val32);
291 sizes.add(val32);
292 AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &val32);
293 sizes.add(val32);
294 AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &val64);
295 sizes.add(val64);
296 } else {
297 ALOGE("expected audio or video mime type, got %s", mime);
298 }
299 AMediaFormat_delete(format);
300 AMediaExtractor_selectTrack(ex, i);
301 }
302 int bufsize = 1024*1024;
303 uint8_t *buf = new uint8_t[bufsize];
304 while(true) {
305 int n = AMediaExtractor_readSampleData(ex, buf, bufsize);
306 ssize_t sampleSize = AMediaExtractor_getSampleSize(ex);
307 if (n < 0 || n != sampleSize) {
308 break;
309 }
310 sizes.add(n);
311 sizes.add(AMediaExtractor_getSampleTrackIndex(ex));
312 sizes.add(AMediaExtractor_getSampleFlags(ex));
313 sizes.add(AMediaExtractor_getSampleTime(ex));
314 sizes.add(adler32(buf, n));
315 AMediaExtractor_advance(ex);
316 }
317
318 // allocate java int array for result and return it
319 int *data = sizes.data();
320 int numsamples = sizes.size();
321 jintArray ret = env->NewIntArray(numsamples);
322 jboolean isCopy;
323 jint *dst = env->GetIntArrayElements(ret, &isCopy);
324 for (int i = 0; i < numsamples; ++i) {
325 dst[i] = data[i];
326 }
327 env->ReleaseIntArrayElements(ret, dst, 0);
328
329 delete[] buf;
330 AMediaExtractor_delete(ex);
331 return ret;
332 }
333
334
335 // get the sample sizes for the file
Java_android_media_cts_NativeDecoderTest_getSampleSizesNative(JNIEnv * env,jclass,int fd,jlong offset,jlong size)336 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getSampleSizesNative(JNIEnv *env,
337 jclass /*clazz*/, int fd, jlong offset, jlong size)
338 {
339 AMediaExtractor *ex = AMediaExtractor_new();
340 int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
341 if (err != 0) {
342 ALOGE("setDataSource error: %d", err);
343 return NULL;
344 }
345 return testExtractor(ex, env);
346 }
347
348 // get the sample sizes for the path
Java_android_media_cts_NativeDecoderTest_getSampleSizesNativePath(JNIEnv * env,jclass,jstring jpath,jobjectArray jkeys,jobjectArray jvalues,jboolean testNativeSource)349 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getSampleSizesNativePath(JNIEnv *env,
350 jclass /*clazz*/, jstring jpath, jobjectArray jkeys, jobjectArray jvalues,
351 jboolean testNativeSource)
352 {
353 AMediaExtractor *ex = AMediaExtractor_new();
354
355 const char *tmp = env->GetStringUTFChars(jpath, NULL);
356 if (tmp == NULL) { // Out of memory
357 return NULL;
358 }
359
360 int numkeys = jkeys ? env->GetArrayLength(jkeys) : 0;
361 int numvalues = jvalues ? env->GetArrayLength(jvalues) : 0;
362 int numheaders = numkeys < numvalues ? numkeys : numvalues;
363 const char **key_values = numheaders ? new const char *[numheaders * 2] : NULL;
364 for (int i = 0; i < numheaders; i++) {
365 jstring jkey = (jstring) (env->GetObjectArrayElement(jkeys, i));
366 jstring jvalue = (jstring) (env->GetObjectArrayElement(jvalues, i));
367 const char *key = env->GetStringUTFChars(jkey, NULL);
368 const char *value = env->GetStringUTFChars(jvalue, NULL);
369 key_values[i * 2] = key;
370 key_values[i * 2 + 1] = value;
371 }
372
373 int err;
374 AMediaDataSource *src = NULL;
375 if (testNativeSource) {
376 src = AMediaDataSource_newUri(tmp, numheaders, key_values);
377 err = src ? AMediaExtractor_setDataSourceCustom(ex, src) : -1;
378 } else {
379 err = AMediaExtractor_setDataSource(ex, tmp);
380 }
381
382 for (int i = 0; i < numheaders; i++) {
383 jstring jkey = (jstring) (env->GetObjectArrayElement(jkeys, i));
384 jstring jvalue = (jstring) (env->GetObjectArrayElement(jvalues, i));
385 env->ReleaseStringUTFChars(jkey, key_values[i * 2]);
386 env->ReleaseStringUTFChars(jvalue, key_values[i * 2 + 1]);
387 }
388
389 env->ReleaseStringUTFChars(jpath, tmp);
390 delete[] key_values;
391
392 if (err != 0) {
393 ALOGE("setDataSource error: %d", err);
394 AMediaExtractor_delete(ex);
395 AMediaDataSource_delete(src);
396 return NULL;
397 }
398
399 jobject ret = testExtractor(ex, env);
400 AMediaDataSource_delete(src);
401 return ret;
402 }
403
checksum(const uint8_t * in,int len,AMediaFormat * format)404 static int checksum(const uint8_t *in, int len, AMediaFormat *format) {
405 int width, stride, height;
406 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width)) {
407 width = len;
408 }
409 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_STRIDE, &stride)) {
410 stride = width;
411 }
412 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height)) {
413 height = 1;
414 }
415 uint8_t *bb = new uint8_t[width * height];
416 for (int i = 0; i < height; i++) {
417 memcpy(bb + i * width, in + i * stride, width);
418 }
419 // bb is filled with data
420 int sum = adler32(bb, width * height);
421 delete[] bb;
422 return sum;
423 }
424
Java_android_media_cts_NativeDecoderTest_getExtractorFileDurationNative(JNIEnv *,jclass,int fd,jlong offset,jlong size)425 extern "C" jlong Java_android_media_cts_NativeDecoderTest_getExtractorFileDurationNative(
426 JNIEnv * /*env*/, jclass /*clazz*/, int fd, jlong offset, jlong size)
427 {
428 AMediaExtractor *ex = AMediaExtractor_new();
429 int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
430 if (err != 0) {
431 ALOGE("setDataSource error: %d", err);
432 AMediaExtractor_delete(ex);
433 return -1;
434 }
435 int64_t durationUs = -1;
436 AMediaFormat *format = AMediaExtractor_getFileFormat(ex);
437 AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &durationUs);
438 AMediaFormat_delete(format);
439 AMediaExtractor_delete(ex);
440 return durationUs;
441 }
442
Java_android_media_cts_NativeDecoderTest_getExtractorCachedDurationNative(JNIEnv * env,jclass,jstring jpath,jboolean testNativeSource)443 extern "C" jlong Java_android_media_cts_NativeDecoderTest_getExtractorCachedDurationNative(
444 JNIEnv * env, jclass /*clazz*/, jstring jpath, jboolean testNativeSource)
445 {
446 AMediaExtractor *ex = AMediaExtractor_new();
447
448 const char *tmp = env->GetStringUTFChars(jpath, NULL);
449 if (tmp == NULL) { // Out of memory
450 AMediaExtractor_delete(ex);
451 return -1;
452 }
453
454 int err;
455 AMediaDataSource *src = NULL;
456 if (testNativeSource) {
457 src = AMediaDataSource_newUri(tmp, 0, NULL);
458 err = src ? AMediaExtractor_setDataSourceCustom(ex, src) : -1;
459 } else {
460 err = AMediaExtractor_setDataSource(ex, tmp);
461 }
462
463 env->ReleaseStringUTFChars(jpath, tmp);
464
465 if (err != 0) {
466 ALOGE("setDataSource error: %d", err);
467 AMediaExtractor_delete(ex);
468 AMediaDataSource_delete(src);
469 return -1;
470 }
471
472 int64_t cachedDurationUs = AMediaExtractor_getCachedDuration(ex);
473 AMediaExtractor_delete(ex);
474 AMediaDataSource_delete(src);
475 return cachedDurationUs;
476
477 }
478
Java_android_media_cts_NativeDecoderTest_getDecodedDataNative(JNIEnv * env,jclass,int fd,jlong offset,jlong size,jboolean wrapFd,jboolean useCallback)479 extern "C" jobject Java_android_media_cts_NativeDecoderTest_getDecodedDataNative(JNIEnv *env,
480 jclass /*clazz*/, int fd, jlong offset, jlong size, jboolean wrapFd, jboolean useCallback) {
481 ALOGV("getDecodedDataNative");
482
483 FdDataSource fdSrc(fd, offset, size);
484 AMediaExtractor *ex = AMediaExtractor_new();
485 AMediaDataSource *ndkSrc = AMediaDataSource_new();
486
487 int err;
488 if (wrapFd) {
489 AMediaDataSource_setUserdata(ndkSrc, &fdSrc);
490 AMediaDataSource_setReadAt(ndkSrc, FdSourceReadAt);
491 AMediaDataSource_setGetSize(ndkSrc, FdSourceGetSize);
492 AMediaDataSource_setClose(ndkSrc, FdSourceClose);
493 err = AMediaExtractor_setDataSourceCustom(ex, ndkSrc);
494 } else {
495 err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
496 }
497 if (err != 0) {
498 ALOGE("setDataSource error: %d", err);
499 return NULL;
500 }
501
502 int numtracks = AMediaExtractor_getTrackCount(ex);
503
504 AMediaCodec **codec = new AMediaCodec*[numtracks];
505 AMediaFormat **format = new AMediaFormat*[numtracks];
506 memset(format, 0, sizeof(AMediaFormat*) * numtracks);
507 bool *sawInputEOS = new bool[numtracks];
508 bool *sawOutputEOS = new bool[numtracks];
509 simplevector<int> *sizes = new simplevector<int>[numtracks];
510 CallbackData *callbackData = new CallbackData[numtracks];
511
512 ALOGV("input has %d tracks", numtracks);
513 for (int i = 0; i < numtracks; i++) {
514 AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
515 const char *s = AMediaFormat_toString(format);
516 ALOGI("track %d format: %s", i, s);
517 const char *mime;
518 if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
519 ALOGE("no mime type");
520 return NULL;
521 } else if (!strncmp(mime, "audio/", 6) || !strncmp(mime, "video/", 6)) {
522 codec[i] = AMediaCodec_createDecoderByType(mime);
523 AMediaCodec_configure(codec[i], format, NULL /* surface */, NULL /* crypto */, 0);
524 if (useCallback) {
525 AMediaCodecOnAsyncNotifyCallback aCB = {
526 OnInputAvailableCB,
527 OnOutputAvailableCB,
528 OnFormatChangedCB,
529 OnErrorCB
530 };
531 AMediaCodec_setAsyncNotifyCallback(codec[i], aCB, &callbackData[i]);
532 }
533 AMediaCodec_start(codec[i]);
534 sawInputEOS[i] = false;
535 sawOutputEOS[i] = false;
536 } else {
537 ALOGE("expected audio or video mime type, got %s", mime);
538 return NULL;
539 }
540 AMediaFormat_delete(format);
541 AMediaExtractor_selectTrack(ex, i);
542 }
543 int eosCount = 0;
544 while(eosCount < numtracks) {
545 int t = AMediaExtractor_getSampleTrackIndex(ex);
546 if (t >=0) {
547 ssize_t bufidx;
548 if (useCallback) {
549 bufidx = callbackData[t].getInputBufferId();
550 } else {
551 bufidx = AMediaCodec_dequeueInputBuffer(codec[t], 5000);
552 }
553 ALOGV("track %d, input buffer %zd", t, bufidx);
554 if (bufidx >= 0) {
555 size_t bufsize;
556 uint8_t *buf = AMediaCodec_getInputBuffer(codec[t], bufidx, &bufsize);
557 int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
558 ALOGV("read %d", sampleSize);
559 if (sampleSize < 0) {
560 sampleSize = 0;
561 sawInputEOS[t] = true;
562 ALOGV("EOS");
563 //break;
564 }
565 int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
566
567 AMediaCodec_queueInputBuffer(codec[t], bufidx, 0, sampleSize, presentationTimeUs,
568 sawInputEOS[t] ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
569 AMediaExtractor_advance(ex);
570 }
571 } else {
572 ALOGV("@@@@ no more input samples");
573 for (int tt = 0; tt < numtracks; tt++) {
574 if (!sawInputEOS[tt]) {
575 // we ran out of samples without ever signaling EOS to the codec,
576 // so do that now
577 int bufidx;
578 if (useCallback) {
579 bufidx = callbackData[tt].getInputBufferId();
580 } else {
581 bufidx = AMediaCodec_dequeueInputBuffer(codec[tt], 5000);
582 }
583 if (bufidx >= 0) {
584 AMediaCodec_queueInputBuffer(codec[tt], bufidx, 0, 0, 0,
585 AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
586 sawInputEOS[tt] = true;
587 }
588 }
589 }
590 }
591
592 // check all codecs for available data
593 AMediaCodecBufferInfo info;
594 AMediaFormat *outputFormat;
595 for (int tt = 0; tt < numtracks; tt++) {
596 if (!sawOutputEOS[tt]) {
597 int status;
598 if (useCallback) {
599 status = callbackData[tt].getOutput(&info, &outputFormat);
600 } else {
601 status = AMediaCodec_dequeueOutputBuffer(codec[tt], &info, 1);
602 }
603 ALOGV("dequeueoutput on track %d: %d", tt, status);
604 if (status >= 0) {
605 if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
606 ALOGV("EOS on track %d", tt);
607 sawOutputEOS[tt] = true;
608 eosCount++;
609 }
610 ALOGV("got decoded buffer for track %d, size %d", tt, info.size);
611 if (info.size > 0) {
612 size_t bufsize;
613 uint8_t *buf = AMediaCodec_getOutputBuffer(codec[tt], status, &bufsize);
614 int adler = checksum(buf, info.size, format[tt]);
615 sizes[tt].add(adler);
616 }
617 AMediaCodec_releaseOutputBuffer(codec[tt], status, false);
618 } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
619 ALOGV("output buffers changed for track %d", tt);
620 } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
621 if (format[tt] != NULL) {
622 AMediaFormat_delete(format[tt]);
623 }
624 if (useCallback) {
625 format[tt] = outputFormat;
626 } else {
627 format[tt] = AMediaCodec_getOutputFormat(codec[tt]);
628 }
629 ALOGV("format changed for track %d: %s", tt, AMediaFormat_toString(format[tt]));
630 } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
631 ALOGV("no output buffer right now for track %d", tt);
632 } else {
633 ALOGV("unexpected info code for track %d : %d", tt, status);
634 }
635 } else {
636 ALOGV("already at EOS on track %d", tt);
637 }
638 }
639 }
640 ALOGV("decoding loop done");
641
642 // allocate java int array for result and return it
643 int numsamples = 0;
644 for (int i = 0; i < numtracks; i++) {
645 numsamples += sizes[i].size();
646 }
647 ALOGV("checksums: %d", numsamples);
648 jintArray ret = env->NewIntArray(numsamples);
649 jboolean isCopy;
650 jint *org = env->GetIntArrayElements(ret, &isCopy);
651 jint *dst = org;
652 for (int i = 0; i < numtracks; i++) {
653 int *data = sizes[i].data();
654 int len = sizes[i].size();
655 ALOGV("copying %d", len);
656 for (int j = 0; j < len; j++) {
657 *dst++ = data[j];
658 }
659 }
660 env->ReleaseIntArrayElements(ret, org, 0);
661
662 delete[] callbackData;
663 delete[] sizes;
664 delete[] sawOutputEOS;
665 delete[] sawInputEOS;
666 for (int i = 0; i < numtracks; i++) {
667 AMediaFormat_delete(format[i]);
668 AMediaCodec_stop(codec[i]);
669 AMediaCodec_delete(codec[i]);
670 }
671 delete[] format;
672 delete[] codec;
673 AMediaExtractor_delete(ex);
674 AMediaDataSource_delete(ndkSrc);
675 return ret;
676 }
677
Java_android_media_cts_NativeDecoderTest_testPlaybackNative(JNIEnv * env,jclass,jobject surface,int fd,jlong offset,jlong size)678 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testPlaybackNative(JNIEnv *env,
679 jclass /*clazz*/, jobject surface, int fd, jlong offset, jlong size) {
680
681 ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
682 ALOGI("@@@@ native window: %p", window);
683
684 AMediaExtractor *ex = AMediaExtractor_new();
685 int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
686 if (err != 0) {
687 ALOGE("setDataSource error: %d", err);
688 return false;
689 }
690
691 int numtracks = AMediaExtractor_getTrackCount(ex);
692
693 AMediaCodec *codec = NULL;
694 AMediaFormat *format = NULL;
695 bool sawInputEOS = false;
696 bool sawOutputEOS = false;
697
698 ALOGV("input has %d tracks", numtracks);
699 for (int i = 0; i < numtracks; i++) {
700 AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
701 const char *s = AMediaFormat_toString(format);
702 ALOGI("track %d format: %s", i, s);
703 const char *mime;
704 if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
705 ALOGE("no mime type");
706 return false;
707 } else if (!strncmp(mime, "video/", 6)) {
708 codec = AMediaCodec_createDecoderByType(mime);
709 AMediaCodec_configure(codec, format, window, NULL, 0);
710 AMediaCodec_start(codec);
711 AMediaExtractor_selectTrack(ex, i);
712 }
713 AMediaFormat_delete(format);
714 }
715
716 while (!sawOutputEOS) {
717 ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec, 5000);
718 ALOGV("input buffer %zd", bufidx);
719 if (bufidx >= 0) {
720 size_t bufsize;
721 uint8_t *buf = AMediaCodec_getInputBuffer(codec, bufidx, &bufsize);
722 int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
723 ALOGV("read %d", sampleSize);
724 if (sampleSize < 0) {
725 sampleSize = 0;
726 sawInputEOS = true;
727 ALOGV("EOS");
728 }
729 int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
730
731 AMediaCodec_queueInputBuffer(codec, bufidx, 0, sampleSize, presentationTimeUs,
732 sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
733 AMediaExtractor_advance(ex);
734 }
735
736 AMediaCodecBufferInfo info;
737 int status = AMediaCodec_dequeueOutputBuffer(codec, &info, 1);
738 ALOGV("dequeueoutput returned: %d", status);
739 if (status >= 0) {
740 if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
741 ALOGV("output EOS");
742 sawOutputEOS = true;
743 }
744 ALOGV("got decoded buffer size %d", info.size);
745 AMediaCodec_releaseOutputBuffer(codec, status, true);
746 usleep(20000);
747 } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
748 ALOGV("output buffers changed");
749 } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
750 format = AMediaCodec_getOutputFormat(codec);
751 ALOGV("format changed to: %s", AMediaFormat_toString(format));
752 } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
753 ALOGV("no output buffer right now");
754 } else {
755 ALOGV("unexpected info code: %d", status);
756 }
757 }
758
759 AMediaCodec_stop(codec);
760 AMediaCodec_delete(codec);
761 AMediaExtractor_delete(ex);
762 return true;
763 }
764
Java_android_media_cts_NativeDecoderTest_testMuxerNative(JNIEnv *,jclass,int infd,jlong inoffset,jlong insize,int outfd,jboolean webm)765 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testMuxerNative(JNIEnv */*env*/,
766 jclass /*clazz*/, int infd, jlong inoffset, jlong insize, int outfd, jboolean webm) {
767
768
769 AMediaMuxer *muxer = AMediaMuxer_new(outfd,
770 webm ? AMEDIAMUXER_OUTPUT_FORMAT_WEBM : AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
771
772 AMediaExtractor *ex = AMediaExtractor_new();
773 int err = AMediaExtractor_setDataSourceFd(ex, infd, inoffset, insize);
774 if (err != 0) {
775 ALOGE("setDataSource error: %d", err);
776 return false;
777 }
778
779 int numtracks = AMediaExtractor_getTrackCount(ex);
780 ALOGI("input tracks: %d", numtracks);
781 for (int i = 0; i < numtracks; i++) {
782 AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
783 const char *s = AMediaFormat_toString(format);
784 ALOGI("track %d format: %s", i, s);
785 const char *mime;
786 if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
787 ALOGE("no mime type");
788 return false;
789 } else if (!strncmp(mime, "audio/", 6) || !strncmp(mime, "video/", 6)) {
790 ssize_t tidx = AMediaMuxer_addTrack(muxer, format);
791 ALOGI("track %d -> %zd format %s", i, tidx, s);
792 AMediaExtractor_selectTrack(ex, i);
793 } else {
794 ALOGE("expected audio or video mime type, got %s", mime);
795 return false;
796 }
797 AMediaFormat_delete(format);
798 AMediaExtractor_selectTrack(ex, i);
799 }
800 AMediaMuxer_start(muxer);
801
802 int bufsize = 1024*1024;
803 uint8_t *buf = new uint8_t[bufsize];
804 AMediaCodecBufferInfo info;
805 while(true) {
806 int n = AMediaExtractor_readSampleData(ex, buf, bufsize);
807 if (n < 0) {
808 break;
809 }
810 info.offset = 0;
811 info.size = n;
812 info.presentationTimeUs = AMediaExtractor_getSampleTime(ex);
813 info.flags = AMediaExtractor_getSampleFlags(ex);
814
815 size_t idx = (size_t) AMediaExtractor_getSampleTrackIndex(ex);
816 AMediaMuxer_writeSampleData(muxer, idx, buf, &info);
817
818 AMediaExtractor_advance(ex);
819 }
820
821 AMediaExtractor_delete(ex);
822 AMediaMuxer_stop(muxer);
823 AMediaMuxer_delete(muxer);
824 return true;
825
826 }
827
Java_android_media_cts_NativeDecoderTest_testFormatNative(JNIEnv *,jclass)828 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testFormatNative(JNIEnv * /*env*/,
829 jclass /*clazz*/) {
830 AMediaFormat* format = AMediaFormat_new();
831 if (!format) {
832 return false;
833 }
834
835 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, 8000);
836 int32_t bitrate = 0;
837 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate) || bitrate != 8000) {
838 ALOGE("AMediaFormat_getInt32 fail: %d", bitrate);
839 return false;
840 }
841
842 AMediaFormat_setInt64(format, AMEDIAFORMAT_KEY_DURATION, 123456789123456789LL);
843 int64_t duration = 0;
844 if (!AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &duration)
845 || duration != 123456789123456789LL) {
846 ALOGE("AMediaFormat_getInt64 fail: %lld", (long long) duration);
847 return false;
848 }
849
850 AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_FRAME_RATE, 25.0f);
851 float framerate = 0.0f;
852 if (!AMediaFormat_getFloat(format, AMEDIAFORMAT_KEY_FRAME_RATE, &framerate)
853 || framerate != 25.0f) {
854 ALOGE("AMediaFormat_getFloat fail: %f", framerate);
855 return false;
856 }
857
858 const char* value = "audio/mpeg";
859 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, value);
860 const char* readback = NULL;
861 if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &readback)
862 || strcmp(value, readback) || value == readback) {
863 ALOGE("AMediaFormat_getString fail");
864 return false;
865 }
866
867 uint32_t foo = 0xdeadbeef;
868 AMediaFormat_setBuffer(format, "csd-0", &foo, sizeof(foo));
869 foo = 0xabadcafe;
870 void *bytes;
871 size_t bytesize = 0;
872 if(!AMediaFormat_getBuffer(format, "csd-0", &bytes, &bytesize)
873 || bytesize != sizeof(foo) || *((uint32_t*)bytes) != 0xdeadbeef) {
874 ALOGE("AMediaFormat_getBuffer fail");
875 return false;
876 }
877
878 return true;
879 }
880
881
Java_android_media_cts_NativeDecoderTest_testPsshNative(JNIEnv *,jclass,int fd,jlong offset,jlong size)882 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testPsshNative(JNIEnv * /*env*/,
883 jclass /*clazz*/, int fd, jlong offset, jlong size) {
884
885 AMediaExtractor *ex = AMediaExtractor_new();
886 int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
887 if (err != 0) {
888 ALOGE("setDataSource error: %d", err);
889 return false;
890 }
891
892 PsshInfo* info = AMediaExtractor_getPsshInfo(ex);
893 if (info == NULL) {
894 ALOGI("null pssh");
895 return false;
896 }
897
898 ALOGI("pssh has %zd entries", info->numentries);
899 if (info->numentries != 2) {
900 return false;
901 }
902
903 for (size_t i = 0; i < info->numentries; i++) {
904 PsshEntry *entry = &info->entries[i];
905 ALOGI("entry uuid %02x%02x..%02x%02x, data size %zd",
906 entry->uuid[0],
907 entry->uuid[1],
908 entry->uuid[14],
909 entry->uuid[15],
910 entry->datalen);
911
912 AMediaCrypto *crypto = AMediaCrypto_new(entry->uuid, entry->data, entry->datalen);
913 if (crypto) {
914 ALOGI("got crypto");
915 AMediaCrypto_delete(crypto);
916 } else {
917 ALOGI("no crypto");
918 }
919 }
920 return true;
921 }
922
Java_android_media_cts_NativeDecoderTest_testCryptoInfoNative(JNIEnv *,jclass)923 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testCryptoInfoNative(JNIEnv * /*env*/,
924 jclass /*clazz*/) {
925
926 size_t numsubsamples = 4;
927 uint8_t key[16] = { 1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4 };
928 uint8_t iv[16] = { 4,3,2,1,4,3,2,1,4,3,2,1,4,3,2,1 };
929 size_t clearbytes[4] = { 5, 6, 7, 8 };
930 size_t encryptedbytes[4] = { 8, 7, 6, 5 };
931
932 AMediaCodecCryptoInfo *ci =
933 AMediaCodecCryptoInfo_new(numsubsamples, key, iv, AMEDIACODECRYPTOINFO_MODE_CLEAR, clearbytes, encryptedbytes);
934
935 if (AMediaCodecCryptoInfo_getNumSubSamples(ci) != 4) {
936 ALOGE("numsubsamples mismatch");
937 return false;
938 }
939 uint8_t bytes[16];
940 AMediaCodecCryptoInfo_getKey(ci, bytes);
941 if (memcmp(key, bytes, 16) != 0) {
942 ALOGE("key mismatch");
943 return false;
944 }
945 AMediaCodecCryptoInfo_getIV(ci, bytes);
946 if (memcmp(iv, bytes, 16) != 0) {
947 ALOGE("IV mismatch");
948 return false;
949 }
950 if (AMediaCodecCryptoInfo_getMode(ci) != AMEDIACODECRYPTOINFO_MODE_CLEAR) {
951 ALOGE("mode mismatch");
952 return false;
953 }
954 size_t sizes[numsubsamples];
955 AMediaCodecCryptoInfo_getClearBytes(ci, sizes);
956 if (memcmp(clearbytes, sizes, sizeof(size_t) * numsubsamples)) {
957 ALOGE("clear size mismatch");
958 return false;
959 }
960 AMediaCodecCryptoInfo_getEncryptedBytes(ci, sizes);
961 if (memcmp(encryptedbytes, sizes, sizeof(size_t) * numsubsamples)) {
962 ALOGE("encrypted size mismatch");
963 return false;
964 }
965 return true;
966 }
967
Java_android_media_cts_NativeDecoderTest_createAMediaExtractor(JNIEnv *,jclass)968 extern "C" jlong Java_android_media_cts_NativeDecoderTest_createAMediaExtractor(JNIEnv * /*env*/,
969 jclass /*clazz*/) {
970 AMediaExtractor *ex = AMediaExtractor_new();
971 return reinterpret_cast<jlong>(ex);
972 }
973
Java_android_media_cts_NativeDecoderTest_createAMediaDataSource(JNIEnv * env,jclass,jstring jurl)974 extern "C" jlong Java_android_media_cts_NativeDecoderTest_createAMediaDataSource(JNIEnv * env,
975 jclass /*clazz*/, jstring jurl) {
976 const char *url = env->GetStringUTFChars(jurl, NULL);
977 if (url == NULL) {
978 ALOGE("GetStringUTFChars error");
979 return 0;
980 }
981
982 AMediaDataSource *ds = AMediaDataSource_newUri(url, 0, NULL);
983 env->ReleaseStringUTFChars(jurl, url);
984 return reinterpret_cast<jlong>(ds);
985 }
986
Java_android_media_cts_NativeDecoderTest_setAMediaExtractorDataSource(JNIEnv *,jclass,jlong jex,jlong jds)987 extern "C" jint Java_android_media_cts_NativeDecoderTest_setAMediaExtractorDataSource(JNIEnv * /*env*/,
988 jclass /*clazz*/, jlong jex, jlong jds) {
989 AMediaExtractor *ex = reinterpret_cast<AMediaExtractor *>(jex);
990 AMediaDataSource *ds = reinterpret_cast<AMediaDataSource *>(jds);
991 return AMediaExtractor_setDataSourceCustom(ex, ds);
992 }
993
Java_android_media_cts_NativeDecoderTest_closeAMediaDataSource(JNIEnv *,jclass,jlong ds)994 extern "C" void Java_android_media_cts_NativeDecoderTest_closeAMediaDataSource(
995 JNIEnv * /*env*/, jclass /*clazz*/, jlong ds) {
996 AMediaDataSource_close(reinterpret_cast<AMediaDataSource *>(ds));
997 }
998
Java_android_media_cts_NativeDecoderTest_deleteAMediaExtractor(JNIEnv *,jclass,jlong ex)999 extern "C" void Java_android_media_cts_NativeDecoderTest_deleteAMediaExtractor(
1000 JNIEnv * /*env*/, jclass /*clazz*/, jlong ex) {
1001 AMediaExtractor_delete(reinterpret_cast<AMediaExtractor *>(ex));
1002 }
1003
Java_android_media_cts_NativeDecoderTest_deleteAMediaDataSource(JNIEnv *,jclass,jlong ds)1004 extern "C" void Java_android_media_cts_NativeDecoderTest_deleteAMediaDataSource(
1005 JNIEnv * /*env*/, jclass /*clazz*/, jlong ds) {
1006 AMediaDataSource_delete(reinterpret_cast<AMediaDataSource *>(ds));
1007 }
1008 //
1009 // === NdkMediaCodec
1010
Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateCodecByName(JNIEnv * env,jclass,jstring name)1011 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateCodecByName(
1012 JNIEnv *env, jclass /*clazz*/, jstring name) {
1013
1014 if (name == NULL) {
1015 return 0;
1016 }
1017
1018 const char *tmp = env->GetStringUTFChars(name, NULL);
1019 if (tmp == NULL) {
1020 return 0;
1021 }
1022
1023 AMediaCodec *codec = AMediaCodec_createCodecByName(tmp);
1024 if (codec == NULL) {
1025 env->ReleaseStringUTFChars(name, tmp);
1026 return 0;
1027 }
1028
1029 env->ReleaseStringUTFChars(name, tmp);
1030 return reinterpret_cast<jlong>(codec);
1031
1032 }
1033
Java_android_media_cts_NdkMediaCodec_AMediaCodecDelete(JNIEnv *,jclass,jlong codec)1034 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecDelete(
1035 JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) {
1036 media_status_t err = AMediaCodec_delete(reinterpret_cast<AMediaCodec *>(codec));
1037 return err == AMEDIA_OK;
1038 }
1039
Java_android_media_cts_NdkMediaCodec_AMediaCodecStart(JNIEnv *,jclass,jlong codec)1040 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecStart(
1041 JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) {
1042 media_status_t err = AMediaCodec_start(reinterpret_cast<AMediaCodec *>(codec));
1043 return err == AMEDIA_OK;
1044 }
1045
Java_android_media_cts_NdkMediaCodec_AMediaCodecStop(JNIEnv *,jclass,jlong codec)1046 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecStop(
1047 JNIEnv * /*env*/, jclass /*clazz*/, jlong codec) {
1048 media_status_t err = AMediaCodec_stop(reinterpret_cast<AMediaCodec *>(codec));
1049 return err == AMEDIA_OK;
1050 }
1051
Java_android_media_cts_NdkMediaCodec_AMediaCodecConfigure(JNIEnv * env,jclass,jlong codec,jstring mime,jint width,jint height,jint colorFormat,jint bitRate,jint frameRate,jint iFrameInterval,jobject csd,jint flags)1052 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecConfigure(
1053 JNIEnv *env,
1054 jclass /*clazz*/,
1055 jlong codec,
1056 jstring mime,
1057 jint width,
1058 jint height,
1059 jint colorFormat,
1060 jint bitRate,
1061 jint frameRate,
1062 jint iFrameInterval,
1063 jobject csd,
1064 jint flags) {
1065
1066 AMediaFormat* format = AMediaFormat_new();
1067 if (format == NULL) {
1068 return false;
1069 }
1070
1071 const char *tmp = env->GetStringUTFChars(mime, NULL);
1072 if (tmp == NULL) {
1073 AMediaFormat_delete(format);
1074 return false;
1075 }
1076
1077 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, tmp);
1078 env->ReleaseStringUTFChars(mime, tmp);
1079
1080 const char *keys[] = {
1081 AMEDIAFORMAT_KEY_WIDTH,
1082 AMEDIAFORMAT_KEY_HEIGHT,
1083 AMEDIAFORMAT_KEY_COLOR_FORMAT,
1084 AMEDIAFORMAT_KEY_BIT_RATE,
1085 AMEDIAFORMAT_KEY_FRAME_RATE,
1086 AMEDIAFORMAT_KEY_I_FRAME_INTERVAL
1087 };
1088
1089 jint values[] = {width, height, colorFormat, bitRate, frameRate, iFrameInterval};
1090 for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
1091 if (values[i] >= 0) {
1092 AMediaFormat_setInt32(format, keys[i], values[i]);
1093 }
1094 }
1095
1096 if (csd != NULL) {
1097 void *csdPtr = env->GetDirectBufferAddress(csd);
1098 jlong csdSize = env->GetDirectBufferCapacity(csd);
1099 AMediaFormat_setBuffer(format, "csd-0", csdPtr, csdSize);
1100 }
1101
1102 media_status_t err = AMediaCodec_configure(
1103 reinterpret_cast<AMediaCodec *>(codec),
1104 format,
1105 NULL,
1106 NULL,
1107 flags);
1108
1109 AMediaFormat_delete(format);
1110 return err == AMEDIA_OK;
1111
1112 }
1113
Java_android_media_cts_NdkMediaCodec_AMediaCodecSetInputSurface(JNIEnv * env,jclass,jlong codec,jobject surface)1114 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetInputSurface(
1115 JNIEnv* env, jclass /*clazz*/, jlong codec, jobject surface) {
1116
1117 media_status_t err = AMediaCodec_setInputSurface(
1118 reinterpret_cast<AMediaCodec *>(codec),
1119 ANativeWindow_fromSurface(env, surface));
1120
1121 return err == AMEDIA_OK;
1122
1123 }
1124
Java_android_media_cts_NdkMediaCodec_AMediaCodecSetNativeInputSurface(JNIEnv *,jclass,jlong codec,jlong nativeWindow)1125 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetNativeInputSurface(
1126 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jlong nativeWindow) {
1127
1128 media_status_t err = AMediaCodec_setInputSurface(
1129 reinterpret_cast<AMediaCodec *>(codec),
1130 reinterpret_cast<ANativeWindow *>(nativeWindow));
1131
1132 return err == AMEDIA_OK;
1133
1134 }
1135
Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateInputSurface(JNIEnv *,jclass,jlong codec)1136 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateInputSurface(
1137 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec) {
1138
1139 ANativeWindow *nativeWindow;
1140 media_status_t err = AMediaCodec_createInputSurface(
1141 reinterpret_cast<AMediaCodec *>(codec),
1142 &nativeWindow);
1143
1144 if (err == AMEDIA_OK) {
1145 return reinterpret_cast<jlong>(nativeWindow);
1146 }
1147
1148 return 0;
1149
1150 }
1151
Java_android_media_cts_NdkMediaCodec_AMediaCodecCreatePersistentInputSurface(JNIEnv *,jclass)1152 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreatePersistentInputSurface(
1153 JNIEnv* /*env*/, jclass /*clazz*/) {
1154
1155 ANativeWindow *nativeWindow;
1156 media_status_t err = AMediaCodec_createPersistentInputSurface(&nativeWindow);
1157
1158 if (err == AMEDIA_OK) {
1159 return reinterpret_cast<jlong>(nativeWindow);
1160 }
1161
1162 return 0;
1163
1164 }
1165
Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputFormatString(JNIEnv * env,jclass,jlong codec)1166 extern "C" jstring Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputFormatString(
1167 JNIEnv* env, jclass /*clazz*/, jlong codec) {
1168
1169 AMediaFormat *format = AMediaCodec_getOutputFormat(reinterpret_cast<AMediaCodec *>(codec));
1170 const char *str = AMediaFormat_toString(format);
1171 jstring jstr = env->NewStringUTF(str);
1172 AMediaFormat_delete(format);
1173 return jstr;
1174
1175 }
1176
Java_android_media_cts_NdkMediaCodec_AMediaCodecSignalEndOfInputStream(JNIEnv *,jclass,jlong codec)1177 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSignalEndOfInputStream(
1178 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec) {
1179
1180 media_status_t err = AMediaCodec_signalEndOfInputStream(reinterpret_cast<AMediaCodec *>(codec));
1181 return err == AMEDIA_OK;
1182
1183 }
1184
Java_android_media_cts_NdkMediaCodec_AMediaCodecReleaseOutputBuffer(JNIEnv *,jclass,jlong codec,jint index,jboolean render)1185 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecReleaseOutputBuffer(
1186 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jint index, jboolean render) {
1187
1188 media_status_t err = AMediaCodec_releaseOutputBuffer(
1189 reinterpret_cast<AMediaCodec *>(codec),
1190 index,
1191 render);
1192
1193 return err == AMEDIA_OK;
1194
1195 }
1196
AMediaCodecGetBuffer(JNIEnv * env,jlong codec,jint index,uint8_t * (* getBuffer)(AMediaCodec *,size_t,size_t *))1197 static jobject AMediaCodecGetBuffer(
1198 JNIEnv* env,
1199 jlong codec,
1200 jint index,
1201 uint8_t *(*getBuffer)(AMediaCodec*, size_t, size_t*)) {
1202
1203 size_t bufsize;
1204 uint8_t *buf = getBuffer(
1205 reinterpret_cast<AMediaCodec *>(codec),
1206 index,
1207 &bufsize);
1208
1209 return env->NewDirectByteBuffer(buf, bufsize);
1210
1211 }
1212
Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputBuffer(JNIEnv * env,jclass,jlong codec,jint index)1213 extern "C" jobject Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputBuffer(
1214 JNIEnv* env, jclass /*clazz*/, jlong codec, jint index) {
1215
1216 return AMediaCodecGetBuffer(env, codec, index, AMediaCodec_getOutputBuffer);
1217
1218 }
1219
Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueOutputBuffer(JNIEnv * env,jclass,jlong codec,jlong timeoutUs)1220 extern "C" jlongArray Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueOutputBuffer(
1221 JNIEnv* env, jclass /*clazz*/, jlong codec, jlong timeoutUs) {
1222
1223 AMediaCodecBufferInfo info;
1224 memset(&info, 0, sizeof(info));
1225 int status = AMediaCodec_dequeueOutputBuffer(
1226 reinterpret_cast<AMediaCodec *>(codec),
1227 &info,
1228 timeoutUs);
1229
1230 jlong ret[5] = {0};
1231 ret[0] = status;
1232 ret[1] = 0; // NdkMediaCodec calls ABuffer::data, which already adds offset
1233 ret[2] = info.size;
1234 ret[3] = info.presentationTimeUs;
1235 ret[4] = info.flags;
1236
1237 jlongArray jret = env->NewLongArray(5);
1238 env->SetLongArrayRegion(jret, 0, 5, ret);
1239 return jret;
1240
1241 }
1242
Java_android_media_cts_NdkMediaCodec_AMediaCodecGetInputBuffer(JNIEnv * env,jclass,jlong codec,jint index)1243 extern "C" jobject Java_android_media_cts_NdkMediaCodec_AMediaCodecGetInputBuffer(
1244 JNIEnv* env, jclass /*clazz*/, jlong codec, jint index) {
1245
1246 return AMediaCodecGetBuffer(env, codec, index, AMediaCodec_getInputBuffer);
1247
1248 }
1249
Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueInputBuffer(JNIEnv *,jclass,jlong codec,jlong timeoutUs)1250 extern "C" jint Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueInputBuffer(
1251 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jlong timeoutUs) {
1252
1253 return AMediaCodec_dequeueInputBuffer(
1254 reinterpret_cast<AMediaCodec *>(codec),
1255 timeoutUs);
1256
1257 }
1258
Java_android_media_cts_NdkMediaCodec_AMediaCodecQueueInputBuffer(JNIEnv *,jclass,jlong codec,jint index,jint offset,jint size,jlong presentationTimeUs,jint flags)1259 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecQueueInputBuffer(
1260 JNIEnv* /*env*/,
1261 jclass /*clazz*/,
1262 jlong codec,
1263 jint index,
1264 jint offset,
1265 jint size,
1266 jlong presentationTimeUs,
1267 jint flags) {
1268
1269 media_status_t err = AMediaCodec_queueInputBuffer(
1270 reinterpret_cast<AMediaCodec *>(codec),
1271 index,
1272 offset,
1273 size,
1274 presentationTimeUs,
1275 flags);
1276
1277 return err == AMEDIA_OK;
1278
1279 }
1280
Java_android_media_cts_NdkMediaCodec_AMediaCodecSetParameter(JNIEnv * env,jclass,jlong codec,jstring jkey,jint value)1281 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetParameter(
1282 JNIEnv* env, jclass /*clazz*/, jlong codec, jstring jkey, jint value) {
1283
1284 AMediaFormat* params = AMediaFormat_new();
1285 if (params == NULL) {
1286 return false;
1287 }
1288
1289 const char *key = env->GetStringUTFChars(jkey, NULL);
1290 if (key == NULL) {
1291 AMediaFormat_delete(params);
1292 return false;
1293 }
1294
1295 AMediaFormat_setInt32(params, key, value);
1296 media_status_t err = AMediaCodec_setParameters(
1297 reinterpret_cast<AMediaCodec *>(codec),
1298 params);
1299 env->ReleaseStringUTFChars(jkey, key);
1300 AMediaFormat_delete(params);
1301 return err == AMEDIA_OK;
1302
1303 }
1304
1305 // === NdkInputSurface
1306
Java_android_media_cts_NdkInputSurface_eglGetDisplay(JNIEnv *,jclass)1307 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglGetDisplay(JNIEnv * /*env*/, jclass /*clazz*/) {
1308
1309 EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
1310 if (eglDisplay == EGL_NO_DISPLAY) {
1311 return 0;
1312 }
1313
1314 EGLint major, minor;
1315 if (!eglInitialize(eglDisplay, &major, &minor)) {
1316 return 0;
1317 }
1318
1319 return reinterpret_cast<jlong>(eglDisplay);
1320
1321 }
1322
Java_android_media_cts_NdkInputSurface_eglChooseConfig(JNIEnv *,jclass,jlong eglDisplay)1323 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglChooseConfig(
1324 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay) {
1325
1326 // Configure EGL for recordable and OpenGL ES 2.0. We want enough RGB bits
1327 // to minimize artifacts from possible YUV conversion.
1328 EGLint attribList[] = {
1329 EGL_RED_SIZE, 8,
1330 EGL_GREEN_SIZE, 8,
1331 EGL_BLUE_SIZE, 8,
1332 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1333 EGL_RECORDABLE_ANDROID, 1,
1334 EGL_NONE
1335 };
1336
1337 EGLConfig configs[1];
1338 EGLint numConfigs[1];
1339 if (!eglChooseConfig(reinterpret_cast<EGLDisplay>(eglDisplay), attribList, configs, 1, numConfigs)) {
1340 return 0;
1341 }
1342 return reinterpret_cast<jlong>(configs[0]);
1343
1344 }
1345
Java_android_media_cts_NdkInputSurface_eglCreateContext(JNIEnv *,jclass,jlong eglDisplay,jlong eglConfig)1346 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglCreateContext(
1347 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglConfig) {
1348
1349 // Configure context for OpenGL ES 2.0.
1350 int attrib_list[] = {
1351 EGL_CONTEXT_CLIENT_VERSION, 2,
1352 EGL_NONE
1353 };
1354
1355 EGLConfig eglContext = eglCreateContext(
1356 reinterpret_cast<EGLDisplay>(eglDisplay),
1357 reinterpret_cast<EGLConfig>(eglConfig),
1358 EGL_NO_CONTEXT,
1359 attrib_list);
1360
1361 if (eglGetError() != EGL_SUCCESS) {
1362 return 0;
1363 }
1364
1365 return reinterpret_cast<jlong>(eglContext);
1366
1367 }
1368
Java_android_media_cts_NdkInputSurface_createEGLSurface(JNIEnv *,jclass,jlong eglDisplay,jlong eglConfig,jlong nativeWindow)1369 extern "C" jlong Java_android_media_cts_NdkInputSurface_createEGLSurface(
1370 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglConfig, jlong nativeWindow) {
1371
1372 int surfaceAttribs[] = {EGL_NONE};
1373 EGLSurface eglSurface = eglCreateWindowSurface(
1374 reinterpret_cast<EGLDisplay>(eglDisplay),
1375 reinterpret_cast<EGLConfig>(eglConfig),
1376 reinterpret_cast<EGLNativeWindowType>(nativeWindow),
1377 surfaceAttribs);
1378
1379 if (eglGetError() != EGL_SUCCESS) {
1380 return 0;
1381 }
1382
1383 return reinterpret_cast<jlong>(eglSurface);
1384
1385 }
1386
Java_android_media_cts_NdkInputSurface_eglMakeCurrent(JNIEnv *,jclass,jlong eglDisplay,jlong eglSurface,jlong eglContext)1387 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglMakeCurrent(
1388 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong eglContext) {
1389
1390 return eglMakeCurrent(
1391 reinterpret_cast<EGLDisplay>(eglDisplay),
1392 reinterpret_cast<EGLSurface>(eglSurface),
1393 reinterpret_cast<EGLSurface>(eglSurface),
1394 reinterpret_cast<EGLContext>(eglContext));
1395
1396 }
1397
Java_android_media_cts_NdkInputSurface_eglSwapBuffers(JNIEnv *,jclass,jlong eglDisplay,jlong eglSurface)1398 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglSwapBuffers(
1399 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
1400
1401 return eglSwapBuffers(
1402 reinterpret_cast<EGLDisplay>(eglDisplay),
1403 reinterpret_cast<EGLSurface>(eglSurface));
1404
1405 }
1406
Java_android_media_cts_NdkInputSurface_eglPresentationTimeANDROID(JNIEnv *,jclass,jlong eglDisplay,jlong eglSurface,jlong nsecs)1407 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglPresentationTimeANDROID(
1408 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong nsecs) {
1409
1410 return eglPresentationTimeANDROID(
1411 reinterpret_cast<EGLDisplay>(eglDisplay),
1412 reinterpret_cast<EGLSurface>(eglSurface),
1413 reinterpret_cast<EGLnsecsANDROID>(nsecs));
1414
1415 }
1416
Java_android_media_cts_NdkInputSurface_eglGetWidth(JNIEnv *,jclass,jlong eglDisplay,jlong eglSurface)1417 extern "C" jint Java_android_media_cts_NdkInputSurface_eglGetWidth(
1418 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
1419
1420 EGLint width;
1421 eglQuerySurface(
1422 reinterpret_cast<EGLDisplay>(eglDisplay),
1423 reinterpret_cast<EGLSurface>(eglSurface),
1424 EGL_WIDTH,
1425 &width);
1426
1427 return width;
1428
1429 }
1430
Java_android_media_cts_NdkInputSurface_eglGetHeight(JNIEnv *,jclass,jlong eglDisplay,jlong eglSurface)1431 extern "C" jint Java_android_media_cts_NdkInputSurface_eglGetHeight(
1432 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
1433
1434 EGLint height;
1435 eglQuerySurface(
1436 reinterpret_cast<EGLDisplay>(eglDisplay),
1437 reinterpret_cast<EGLSurface>(eglSurface),
1438 EGL_HEIGHT,
1439 &height);
1440
1441 return height;
1442
1443 }
1444
Java_android_media_cts_NdkInputSurface_eglDestroySurface(JNIEnv *,jclass,jlong eglDisplay,jlong eglSurface)1445 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglDestroySurface(
1446 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
1447
1448 return eglDestroySurface(
1449 reinterpret_cast<EGLDisplay>(eglDisplay),
1450 reinterpret_cast<EGLSurface>(eglSurface));
1451
1452 }
1453
Java_android_media_cts_NdkInputSurface_nativeRelease(JNIEnv *,jclass,jlong eglDisplay,jlong eglSurface,jlong eglContext,jlong nativeWindow)1454 extern "C" void Java_android_media_cts_NdkInputSurface_nativeRelease(
1455 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong eglContext, jlong nativeWindow) {
1456
1457 if (eglDisplay != 0) {
1458
1459 EGLDisplay _eglDisplay = reinterpret_cast<EGLDisplay>(eglDisplay);
1460 EGLSurface _eglSurface = reinterpret_cast<EGLSurface>(eglSurface);
1461 EGLContext _eglContext = reinterpret_cast<EGLContext>(eglContext);
1462
1463 eglDestroySurface(_eglDisplay, _eglSurface);
1464 eglDestroyContext(_eglDisplay, _eglContext);
1465 eglReleaseThread();
1466 eglTerminate(_eglDisplay);
1467
1468 }
1469
1470 ANativeWindow_release(reinterpret_cast<ANativeWindow *>(nativeWindow));
1471
1472 }
1473
Java_android_media_cts_NativeDecoderTest_testMediaFormatNative(JNIEnv *,jclass)1474 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testMediaFormatNative(
1475 JNIEnv * /*env*/, jclass /*clazz*/) {
1476
1477 AMediaFormat *original = AMediaFormat_new();
1478 AMediaFormat *copy = AMediaFormat_new();
1479 jboolean ret = false;
1480 while (true) {
1481 AMediaFormat_setInt64(original, AMEDIAFORMAT_KEY_DURATION, 1234ll);
1482 int64_t value = 0;
1483 if (!AMediaFormat_getInt64(original, AMEDIAFORMAT_KEY_DURATION, &value) || value != 1234) {
1484 ALOGE("format missing expected entry");
1485 break;
1486 }
1487 AMediaFormat_copy(copy, original);
1488 value = 0;
1489 if (!AMediaFormat_getInt64(copy, AMEDIAFORMAT_KEY_DURATION, &value) || value != 1234) {
1490 ALOGE("copied format missing expected entry");
1491 break;
1492 }
1493 AMediaFormat_clear(original);
1494 if (AMediaFormat_getInt64(original, AMEDIAFORMAT_KEY_DURATION, &value)) {
1495 ALOGE("format still has entry after clear");
1496 break;
1497 }
1498 value = 0;
1499 if (!AMediaFormat_getInt64(copy, AMEDIAFORMAT_KEY_DURATION, &value) || value != 1234) {
1500 ALOGE("copied format missing expected entry");
1501 break;
1502 }
1503 ret = true;
1504 break;
1505 }
1506 AMediaFormat_delete(original);
1507 AMediaFormat_delete(copy);
1508 return ret;
1509 }
1510