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 csd0,jobject csd1,jint flags,jint lowLatency,jobject surface,jint range,jint standard,jint transfer)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 csd0,
1064 jobject csd1,
1065 jint flags,
1066 jint lowLatency,
1067 jobject surface,
1068 jint range,
1069 jint standard,
1070 jint transfer) {
1071
1072 AMediaFormat* format = AMediaFormat_new();
1073 if (format == NULL) {
1074 return false;
1075 }
1076
1077 const char *tmp = env->GetStringUTFChars(mime, NULL);
1078 if (tmp == NULL) {
1079 AMediaFormat_delete(format);
1080 return false;
1081 }
1082
1083 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, tmp);
1084 env->ReleaseStringUTFChars(mime, tmp);
1085
1086 const char *keys[] = {
1087 AMEDIAFORMAT_KEY_WIDTH,
1088 AMEDIAFORMAT_KEY_HEIGHT,
1089 AMEDIAFORMAT_KEY_COLOR_FORMAT,
1090 AMEDIAFORMAT_KEY_BIT_RATE,
1091 AMEDIAFORMAT_KEY_FRAME_RATE,
1092 AMEDIAFORMAT_KEY_I_FRAME_INTERVAL,
1093 // need to specify the actual string, since this test needs
1094 // to run on API 29, where the symbol doesn't exist
1095 "low-latency", // AMEDIAFORMAT_KEY_LOW_LATENCY
1096 AMEDIAFORMAT_KEY_COLOR_RANGE,
1097 AMEDIAFORMAT_KEY_COLOR_STANDARD,
1098 AMEDIAFORMAT_KEY_COLOR_TRANSFER,
1099 };
1100
1101 jint values[] = {width, height, colorFormat, bitRate, frameRate, iFrameInterval, lowLatency,
1102 range, standard, transfer};
1103 for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
1104 if (values[i] >= 0) {
1105 AMediaFormat_setInt32(format, keys[i], values[i]);
1106 }
1107 }
1108
1109 if (csd0 != NULL) {
1110 void *csd0Ptr = env->GetDirectBufferAddress(csd0);
1111 jlong csd0Size = env->GetDirectBufferCapacity(csd0);
1112 AMediaFormat_setBuffer(format, "csd-0", csd0Ptr, csd0Size);
1113 }
1114
1115 if (csd1 != NULL) {
1116 void *csd1Ptr = env->GetDirectBufferAddress(csd1);
1117 jlong csd1Size = env->GetDirectBufferCapacity(csd1);
1118 AMediaFormat_setBuffer(format, "csd-1", csd1Ptr, csd1Size);
1119 }
1120
1121 media_status_t err = AMediaCodec_configure(
1122 reinterpret_cast<AMediaCodec *>(codec),
1123 format,
1124 surface == NULL ? NULL : ANativeWindow_fromSurface(env, surface),
1125 NULL,
1126 flags);
1127
1128 AMediaFormat_delete(format);
1129 return err == AMEDIA_OK;
1130
1131 }
1132
Java_android_media_cts_NdkMediaCodec_AMediaCodecSetInputSurface(JNIEnv * env,jclass,jlong codec,jobject surface)1133 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetInputSurface(
1134 JNIEnv* env, jclass /*clazz*/, jlong codec, jobject surface) {
1135
1136 media_status_t err = AMediaCodec_setInputSurface(
1137 reinterpret_cast<AMediaCodec *>(codec),
1138 ANativeWindow_fromSurface(env, surface));
1139
1140 return err == AMEDIA_OK;
1141
1142 }
1143
Java_android_media_cts_NdkMediaCodec_AMediaCodecSetNativeInputSurface(JNIEnv *,jclass,jlong codec,jlong nativeWindow)1144 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetNativeInputSurface(
1145 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jlong nativeWindow) {
1146
1147 media_status_t err = AMediaCodec_setInputSurface(
1148 reinterpret_cast<AMediaCodec *>(codec),
1149 reinterpret_cast<ANativeWindow *>(nativeWindow));
1150
1151 return err == AMEDIA_OK;
1152
1153 }
1154
Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateInputSurface(JNIEnv *,jclass,jlong codec)1155 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreateInputSurface(
1156 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec) {
1157
1158 ANativeWindow *nativeWindow;
1159 media_status_t err = AMediaCodec_createInputSurface(
1160 reinterpret_cast<AMediaCodec *>(codec),
1161 &nativeWindow);
1162
1163 if (err == AMEDIA_OK) {
1164 return reinterpret_cast<jlong>(nativeWindow);
1165 }
1166
1167 return 0;
1168
1169 }
1170
Java_android_media_cts_NdkMediaCodec_AMediaCodecCreatePersistentInputSurface(JNIEnv *,jclass)1171 extern "C" jlong Java_android_media_cts_NdkMediaCodec_AMediaCodecCreatePersistentInputSurface(
1172 JNIEnv* /*env*/, jclass /*clazz*/) {
1173
1174 ANativeWindow *nativeWindow;
1175 media_status_t err = AMediaCodec_createPersistentInputSurface(&nativeWindow);
1176
1177 if (err == AMEDIA_OK) {
1178 return reinterpret_cast<jlong>(nativeWindow);
1179 }
1180
1181 return 0;
1182
1183 }
1184
Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputFormatString(JNIEnv * env,jclass,jlong codec)1185 extern "C" jstring Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputFormatString(
1186 JNIEnv* env, jclass /*clazz*/, jlong codec) {
1187
1188 AMediaFormat *format = AMediaCodec_getOutputFormat(reinterpret_cast<AMediaCodec *>(codec));
1189 const char *str = AMediaFormat_toString(format);
1190 jstring jstr = env->NewStringUTF(str);
1191 AMediaFormat_delete(format);
1192 return jstr;
1193
1194 }
1195
Java_android_media_cts_NdkMediaCodec_AMediaCodecSignalEndOfInputStream(JNIEnv *,jclass,jlong codec)1196 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSignalEndOfInputStream(
1197 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec) {
1198
1199 media_status_t err = AMediaCodec_signalEndOfInputStream(reinterpret_cast<AMediaCodec *>(codec));
1200 return err == AMEDIA_OK;
1201
1202 }
1203
Java_android_media_cts_NdkMediaCodec_AMediaCodecReleaseOutputBuffer(JNIEnv *,jclass,jlong codec,jint index,jboolean render)1204 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecReleaseOutputBuffer(
1205 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jint index, jboolean render) {
1206
1207 media_status_t err = AMediaCodec_releaseOutputBuffer(
1208 reinterpret_cast<AMediaCodec *>(codec),
1209 index,
1210 render);
1211
1212 return err == AMEDIA_OK;
1213
1214 }
1215
AMediaCodecGetBuffer(JNIEnv * env,jlong codec,jint index,uint8_t * (* getBuffer)(AMediaCodec *,size_t,size_t *))1216 static jobject AMediaCodecGetBuffer(
1217 JNIEnv* env,
1218 jlong codec,
1219 jint index,
1220 uint8_t *(*getBuffer)(AMediaCodec*, size_t, size_t*)) {
1221
1222 size_t bufsize;
1223 uint8_t *buf = getBuffer(
1224 reinterpret_cast<AMediaCodec *>(codec),
1225 index,
1226 &bufsize);
1227
1228 return env->NewDirectByteBuffer(buf, bufsize);
1229
1230 }
1231
Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputBuffer(JNIEnv * env,jclass,jlong codec,jint index)1232 extern "C" jobject Java_android_media_cts_NdkMediaCodec_AMediaCodecGetOutputBuffer(
1233 JNIEnv* env, jclass /*clazz*/, jlong codec, jint index) {
1234
1235 return AMediaCodecGetBuffer(env, codec, index, AMediaCodec_getOutputBuffer);
1236
1237 }
1238
Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueOutputBuffer(JNIEnv * env,jclass,jlong codec,jlong timeoutUs)1239 extern "C" jlongArray Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueOutputBuffer(
1240 JNIEnv* env, jclass /*clazz*/, jlong codec, jlong timeoutUs) {
1241
1242 AMediaCodecBufferInfo info;
1243 memset(&info, 0, sizeof(info));
1244 int status = AMediaCodec_dequeueOutputBuffer(
1245 reinterpret_cast<AMediaCodec *>(codec),
1246 &info,
1247 timeoutUs);
1248
1249 jlong ret[5] = {0};
1250 ret[0] = status;
1251 ret[1] = 0; // NdkMediaCodec calls ABuffer::data, which already adds offset
1252 ret[2] = info.size;
1253 ret[3] = info.presentationTimeUs;
1254 ret[4] = info.flags;
1255
1256 jlongArray jret = env->NewLongArray(5);
1257 env->SetLongArrayRegion(jret, 0, 5, ret);
1258 return jret;
1259
1260 }
1261
Java_android_media_cts_NdkMediaCodec_AMediaCodecGetInputBuffer(JNIEnv * env,jclass,jlong codec,jint index)1262 extern "C" jobject Java_android_media_cts_NdkMediaCodec_AMediaCodecGetInputBuffer(
1263 JNIEnv* env, jclass /*clazz*/, jlong codec, jint index) {
1264
1265 return AMediaCodecGetBuffer(env, codec, index, AMediaCodec_getInputBuffer);
1266
1267 }
1268
Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueInputBuffer(JNIEnv *,jclass,jlong codec,jlong timeoutUs)1269 extern "C" jint Java_android_media_cts_NdkMediaCodec_AMediaCodecDequeueInputBuffer(
1270 JNIEnv* /*env*/, jclass /*clazz*/, jlong codec, jlong timeoutUs) {
1271
1272 return AMediaCodec_dequeueInputBuffer(
1273 reinterpret_cast<AMediaCodec *>(codec),
1274 timeoutUs);
1275
1276 }
1277
Java_android_media_cts_NdkMediaCodec_AMediaCodecQueueInputBuffer(JNIEnv *,jclass,jlong codec,jint index,jint offset,jint size,jlong presentationTimeUs,jint flags)1278 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecQueueInputBuffer(
1279 JNIEnv* /*env*/,
1280 jclass /*clazz*/,
1281 jlong codec,
1282 jint index,
1283 jint offset,
1284 jint size,
1285 jlong presentationTimeUs,
1286 jint flags) {
1287
1288 media_status_t err = AMediaCodec_queueInputBuffer(
1289 reinterpret_cast<AMediaCodec *>(codec),
1290 index,
1291 offset,
1292 size,
1293 presentationTimeUs,
1294 flags);
1295
1296 return err == AMEDIA_OK;
1297
1298 }
1299
Java_android_media_cts_NdkMediaCodec_AMediaCodecSetParameter(JNIEnv * env,jclass,jlong codec,jstring jkey,jint value)1300 extern "C" jboolean Java_android_media_cts_NdkMediaCodec_AMediaCodecSetParameter(
1301 JNIEnv* env, jclass /*clazz*/, jlong codec, jstring jkey, jint value) {
1302
1303 AMediaFormat* params = AMediaFormat_new();
1304 if (params == NULL) {
1305 return false;
1306 }
1307
1308 const char *key = env->GetStringUTFChars(jkey, NULL);
1309 if (key == NULL) {
1310 AMediaFormat_delete(params);
1311 return false;
1312 }
1313
1314 AMediaFormat_setInt32(params, key, value);
1315 media_status_t err = AMediaCodec_setParameters(
1316 reinterpret_cast<AMediaCodec *>(codec),
1317 params);
1318 env->ReleaseStringUTFChars(jkey, key);
1319 AMediaFormat_delete(params);
1320 return err == AMEDIA_OK;
1321
1322 }
1323
1324 // === NdkInputSurface
1325
Java_android_media_cts_NdkInputSurface_eglGetDisplay(JNIEnv *,jclass)1326 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglGetDisplay(JNIEnv * /*env*/, jclass /*clazz*/) {
1327
1328 EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
1329 if (eglDisplay == EGL_NO_DISPLAY) {
1330 return 0;
1331 }
1332
1333 EGLint major, minor;
1334 if (!eglInitialize(eglDisplay, &major, &minor)) {
1335 return 0;
1336 }
1337
1338 return reinterpret_cast<jlong>(eglDisplay);
1339
1340 }
1341
Java_android_media_cts_NdkInputSurface_eglChooseConfig(JNIEnv *,jclass,jlong eglDisplay)1342 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglChooseConfig(
1343 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay) {
1344
1345 // Configure EGL for recordable and OpenGL ES 2.0. We want enough RGB bits
1346 // to minimize artifacts from possible YUV conversion.
1347 EGLint attribList[] = {
1348 EGL_RED_SIZE, 8,
1349 EGL_GREEN_SIZE, 8,
1350 EGL_BLUE_SIZE, 8,
1351 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1352 EGL_RECORDABLE_ANDROID, 1,
1353 EGL_NONE
1354 };
1355
1356 EGLConfig configs[1];
1357 EGLint numConfigs[1];
1358 if (!eglChooseConfig(reinterpret_cast<EGLDisplay>(eglDisplay), attribList, configs, 1, numConfigs)) {
1359 return 0;
1360 }
1361 return reinterpret_cast<jlong>(configs[0]);
1362
1363 }
1364
Java_android_media_cts_NdkInputSurface_eglCreateContext(JNIEnv *,jclass,jlong eglDisplay,jlong eglConfig)1365 extern "C" jlong Java_android_media_cts_NdkInputSurface_eglCreateContext(
1366 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglConfig) {
1367
1368 // Configure context for OpenGL ES 2.0.
1369 int attrib_list[] = {
1370 EGL_CONTEXT_CLIENT_VERSION, 2,
1371 EGL_NONE
1372 };
1373
1374 EGLConfig eglContext = eglCreateContext(
1375 reinterpret_cast<EGLDisplay>(eglDisplay),
1376 reinterpret_cast<EGLConfig>(eglConfig),
1377 EGL_NO_CONTEXT,
1378 attrib_list);
1379
1380 if (eglGetError() != EGL_SUCCESS) {
1381 return 0;
1382 }
1383
1384 return reinterpret_cast<jlong>(eglContext);
1385
1386 }
1387
Java_android_media_cts_NdkInputSurface_createEGLSurface(JNIEnv *,jclass,jlong eglDisplay,jlong eglConfig,jlong nativeWindow)1388 extern "C" jlong Java_android_media_cts_NdkInputSurface_createEGLSurface(
1389 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglConfig, jlong nativeWindow) {
1390
1391 int surfaceAttribs[] = {EGL_NONE};
1392 EGLSurface eglSurface = eglCreateWindowSurface(
1393 reinterpret_cast<EGLDisplay>(eglDisplay),
1394 reinterpret_cast<EGLConfig>(eglConfig),
1395 reinterpret_cast<EGLNativeWindowType>(nativeWindow),
1396 surfaceAttribs);
1397
1398 if (eglGetError() != EGL_SUCCESS) {
1399 return 0;
1400 }
1401
1402 return reinterpret_cast<jlong>(eglSurface);
1403
1404 }
1405
Java_android_media_cts_NdkInputSurface_eglMakeCurrent(JNIEnv *,jclass,jlong eglDisplay,jlong eglSurface,jlong eglContext)1406 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglMakeCurrent(
1407 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong eglContext) {
1408
1409 return eglMakeCurrent(
1410 reinterpret_cast<EGLDisplay>(eglDisplay),
1411 reinterpret_cast<EGLSurface>(eglSurface),
1412 reinterpret_cast<EGLSurface>(eglSurface),
1413 reinterpret_cast<EGLContext>(eglContext));
1414
1415 }
1416
Java_android_media_cts_NdkInputSurface_eglSwapBuffers(JNIEnv *,jclass,jlong eglDisplay,jlong eglSurface)1417 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglSwapBuffers(
1418 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
1419
1420 return eglSwapBuffers(
1421 reinterpret_cast<EGLDisplay>(eglDisplay),
1422 reinterpret_cast<EGLSurface>(eglSurface));
1423
1424 }
1425
Java_android_media_cts_NdkInputSurface_eglPresentationTimeANDROID(JNIEnv *,jclass,jlong eglDisplay,jlong eglSurface,jlong nsecs)1426 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglPresentationTimeANDROID(
1427 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong nsecs) {
1428
1429 return eglPresentationTimeANDROID(
1430 reinterpret_cast<EGLDisplay>(eglDisplay),
1431 reinterpret_cast<EGLSurface>(eglSurface),
1432 reinterpret_cast<EGLnsecsANDROID>(nsecs));
1433
1434 }
1435
Java_android_media_cts_NdkInputSurface_eglGetWidth(JNIEnv *,jclass,jlong eglDisplay,jlong eglSurface)1436 extern "C" jint Java_android_media_cts_NdkInputSurface_eglGetWidth(
1437 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
1438
1439 EGLint width;
1440 eglQuerySurface(
1441 reinterpret_cast<EGLDisplay>(eglDisplay),
1442 reinterpret_cast<EGLSurface>(eglSurface),
1443 EGL_WIDTH,
1444 &width);
1445
1446 return width;
1447
1448 }
1449
Java_android_media_cts_NdkInputSurface_eglGetHeight(JNIEnv *,jclass,jlong eglDisplay,jlong eglSurface)1450 extern "C" jint Java_android_media_cts_NdkInputSurface_eglGetHeight(
1451 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
1452
1453 EGLint height;
1454 eglQuerySurface(
1455 reinterpret_cast<EGLDisplay>(eglDisplay),
1456 reinterpret_cast<EGLSurface>(eglSurface),
1457 EGL_HEIGHT,
1458 &height);
1459
1460 return height;
1461
1462 }
1463
Java_android_media_cts_NdkInputSurface_eglDestroySurface(JNIEnv *,jclass,jlong eglDisplay,jlong eglSurface)1464 extern "C" jboolean Java_android_media_cts_NdkInputSurface_eglDestroySurface(
1465 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface) {
1466
1467 return eglDestroySurface(
1468 reinterpret_cast<EGLDisplay>(eglDisplay),
1469 reinterpret_cast<EGLSurface>(eglSurface));
1470
1471 }
1472
Java_android_media_cts_NdkInputSurface_nativeRelease(JNIEnv *,jclass,jlong eglDisplay,jlong eglSurface,jlong eglContext,jlong nativeWindow)1473 extern "C" void Java_android_media_cts_NdkInputSurface_nativeRelease(
1474 JNIEnv * /*env*/, jclass /*clazz*/, jlong eglDisplay, jlong eglSurface, jlong eglContext, jlong nativeWindow) {
1475
1476 if (eglDisplay != 0) {
1477
1478 EGLDisplay _eglDisplay = reinterpret_cast<EGLDisplay>(eglDisplay);
1479 EGLSurface _eglSurface = reinterpret_cast<EGLSurface>(eglSurface);
1480 EGLContext _eglContext = reinterpret_cast<EGLContext>(eglContext);
1481
1482 eglDestroySurface(_eglDisplay, _eglSurface);
1483 eglDestroyContext(_eglDisplay, _eglContext);
1484 eglReleaseThread();
1485 eglTerminate(_eglDisplay);
1486
1487 }
1488
1489 ANativeWindow_release(reinterpret_cast<ANativeWindow *>(nativeWindow));
1490
1491 }
1492
Java_android_media_cts_NativeDecoderTest_testMediaFormatNative(JNIEnv *,jclass)1493 extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testMediaFormatNative(
1494 JNIEnv * /*env*/, jclass /*clazz*/) {
1495
1496 AMediaFormat *original = AMediaFormat_new();
1497 AMediaFormat *copy = AMediaFormat_new();
1498 jboolean ret = false;
1499 while (true) {
1500 AMediaFormat_setInt64(original, AMEDIAFORMAT_KEY_DURATION, 1234ll);
1501 int64_t value = 0;
1502 if (!AMediaFormat_getInt64(original, AMEDIAFORMAT_KEY_DURATION, &value) || value != 1234) {
1503 ALOGE("format missing expected entry");
1504 break;
1505 }
1506 AMediaFormat_copy(copy, original);
1507 value = 0;
1508 if (!AMediaFormat_getInt64(copy, AMEDIAFORMAT_KEY_DURATION, &value) || value != 1234) {
1509 ALOGE("copied format missing expected entry");
1510 break;
1511 }
1512 AMediaFormat_clear(original);
1513 if (AMediaFormat_getInt64(original, AMEDIAFORMAT_KEY_DURATION, &value)) {
1514 ALOGE("format still has entry after clear");
1515 break;
1516 }
1517 value = 0;
1518 if (!AMediaFormat_getInt64(copy, AMEDIAFORMAT_KEY_DURATION, &value) || value != 1234) {
1519 ALOGE("copied format missing expected entry");
1520 break;
1521 }
1522 ret = true;
1523 break;
1524 }
1525 AMediaFormat_delete(original);
1526 AMediaFormat_delete(copy);
1527 return ret;
1528 }
1529