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