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