1 /*
2 * Copyright (C) 2022 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 <queue>
27 #include <stdio.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31
32 #include <android/native_window_jni.h>
33
34 #include "media/NdkMediaExtractor.h"
35 #include "media/NdkMediaCodec.h"
36 #include "media/NdkMediaDataSource.h"
37 #include "media/NdkMediaFormat.h"
38 template <class T>
39 class simplevector {
40 T *storage;
41 int capacity;
42 int numfilled;
43 public:
simplevector()44 simplevector() {
45 capacity = 16;
46 numfilled = 0;
47 storage = new T[capacity];
48 }
~simplevector()49 ~simplevector() {
50 delete[] storage;
51 }
52
add(T item)53 void add(T item) {
54 if (numfilled == capacity) {
55 T *old = storage;
56 capacity *= 2;
57 storage = new T[capacity];
58 for (int i = 0; i < numfilled; i++) {
59 storage[i] = old[i];
60 }
61 delete[] old;
62 }
63 storage[numfilled] = item;
64 numfilled++;
65 }
66
size()67 int size() {
68 return numfilled;
69 }
70
data()71 T* data() {
72 return storage;
73 }
74 };
75
76 struct FdDataSource {
77
FdDataSourceFdDataSource78 FdDataSource(int fd, jlong offset, jlong size)
79 : mFd(dup(fd)),
80 mOffset(offset),
81 mSize(size) {
82 }
83
readAtFdDataSource84 ssize_t readAt(off64_t offset, void *data, size_t size) {
85 ssize_t ssize = size;
86 if (!data || offset < 0 || offset + ssize < offset) {
87 return -1;
88 }
89 if (offset >= mSize) {
90 return 0; // EOS
91 }
92 if (offset + ssize > mSize) {
93 ssize = mSize - offset;
94 }
95 if (lseek(mFd, mOffset + offset, SEEK_SET) < 0) {
96 return -1;
97 }
98 return read(mFd, data, ssize);
99 }
100
getSizeFdDataSource101 ssize_t getSize() {
102 return mSize;
103 }
104
closeFdDataSource105 void close() {
106 ::close(mFd);
107 }
108
109 private:
110
111 int mFd;
112 off64_t mOffset;
113 int64_t mSize;
114
115 };
116
FdSourceReadAt(void * userdata,off64_t offset,void * data,size_t size)117 static ssize_t FdSourceReadAt(void *userdata, off64_t offset, void *data, size_t size) {
118 FdDataSource *src = (FdDataSource*) userdata;
119 return src->readAt(offset, data, size);
120 }
121
FdSourceGetSize(void * userdata)122 static ssize_t FdSourceGetSize(void *userdata) {
123 FdDataSource *src = (FdDataSource*) userdata;
124 return src->getSize();
125 }
126
FdSourceClose(void * userdata)127 static void FdSourceClose(void *userdata) {
128 FdDataSource *src = (FdDataSource*) userdata;
129 src->close();
130 }
131
132 class CallbackData {
133 std::mutex mMutex;
134 std::queue<int32_t> mInputBufferIds;
135 std::queue<int32_t> mOutputBufferIds;
136 std::queue<AMediaCodecBufferInfo> mOutputBufferInfos;
137 std::queue<AMediaFormat*> mFormats;
138
139 public:
CallbackData()140 CallbackData() { }
141
~CallbackData()142 ~CallbackData() {
143 mMutex.lock();
144 while (!mFormats.empty()) {
145 AMediaFormat* format = mFormats.front();
146 mFormats.pop();
147 AMediaFormat_delete(format);
148 }
149 mMutex.unlock();
150 }
151
addInputBufferId(int32_t index)152 void addInputBufferId(int32_t index) {
153 mMutex.lock();
154 mInputBufferIds.push(index);
155 mMutex.unlock();
156 }
157
getInputBufferId()158 int32_t getInputBufferId() {
159 int32_t id = -1;
160 mMutex.lock();
161 if (!mInputBufferIds.empty()) {
162 id = mInputBufferIds.front();
163 mInputBufferIds.pop();
164 }
165 mMutex.unlock();
166 return id;
167 }
168
addOutputBuffer(int32_t index,AMediaCodecBufferInfo * bufferInfo)169 void addOutputBuffer(int32_t index, AMediaCodecBufferInfo *bufferInfo) {
170 mMutex.lock();
171 mOutputBufferIds.push(index);
172 mOutputBufferInfos.push(*bufferInfo);
173 mMutex.unlock();
174 }
175
addOutputFormat(AMediaFormat * format)176 void addOutputFormat(AMediaFormat *format) {
177 mMutex.lock();
178 mOutputBufferIds.push(AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED);
179 mFormats.push(format);
180 mMutex.unlock();
181 }
182
getOutput(AMediaCodecBufferInfo * bufferInfo,AMediaFormat ** format)183 int32_t getOutput(AMediaCodecBufferInfo *bufferInfo, AMediaFormat **format) {
184 int32_t id = AMEDIACODEC_INFO_TRY_AGAIN_LATER;
185 mMutex.lock();
186 if (!mOutputBufferIds.empty()) {
187 id = mOutputBufferIds.front();
188 mOutputBufferIds.pop();
189
190 if (id >= 0) {
191 *bufferInfo = mOutputBufferInfos.front();
192 mOutputBufferInfos.pop();
193 } else { // AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED
194 *format = mFormats.front();
195 mFormats.pop();
196 }
197 }
198 mMutex.unlock();
199 return id;
200 }
201 };
202
OnInputAvailableCB(AMediaCodec *,void * userdata,int32_t index)203 static void OnInputAvailableCB(
204 AMediaCodec * /* aMediaCodec */,
205 void *userdata,
206 int32_t index) {
207 ALOGV("OnInputAvailableCB: index(%d)", index);
208 CallbackData *callbackData = (CallbackData *)userdata;
209 callbackData->addInputBufferId(index);
210 }
211
OnOutputAvailableCB(AMediaCodec *,void * userdata,int32_t index,AMediaCodecBufferInfo * bufferInfo)212 static void OnOutputAvailableCB(
213 AMediaCodec * /* aMediaCodec */,
214 void *userdata,
215 int32_t index,
216 AMediaCodecBufferInfo *bufferInfo) {
217 ALOGV("OnOutputAvailableCB: index(%d), (%d, %d, %lld, 0x%x)",
218 index, bufferInfo->offset, bufferInfo->size,
219 (long long)bufferInfo->presentationTimeUs, bufferInfo->flags);
220 CallbackData *callbackData = (CallbackData *)userdata;
221 callbackData->addOutputBuffer(index, bufferInfo);
222 }
223
OnFormatChangedCB(AMediaCodec *,void * userdata,AMediaFormat * format)224 static void OnFormatChangedCB(
225 AMediaCodec * /* aMediaCodec */,
226 void *userdata,
227 AMediaFormat *format) {
228 ALOGV("OnFormatChangedCB: format(%s)", AMediaFormat_toString(format));
229 CallbackData *callbackData = (CallbackData *)userdata;
230 callbackData->addOutputFormat(format);
231 }
232
OnErrorCB(AMediaCodec *,void *,media_status_t err,int32_t actionCode,const char * detail)233 static void OnErrorCB(
234 AMediaCodec * /* aMediaCodec */,
235 void * /* userdata */,
236 media_status_t err,
237 int32_t actionCode,
238 const char *detail) {
239 ALOGV("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail);
240 }
241
adler32(const uint8_t * input,int len)242 static int adler32(const uint8_t *input, int len) {
243
244 int a = 1;
245 int b = 0;
246 for (int i = 0; i < len; i++) {
247 a += input[i];
248 b += a;
249 a = a % 65521;
250 b = b % 65521;
251 }
252 int ret = b * 65536 + a;
253 ALOGV("adler %d/%d", len, ret);
254 return ret;
255 }
256
checksum(const uint8_t * in,int len,AMediaFormat * format)257 static int checksum(const uint8_t *in, int len, AMediaFormat *format) {
258 int width, stride, height;
259 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width)) {
260 width = len;
261 }
262 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_STRIDE, &stride)) {
263 stride = width;
264 }
265 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height)) {
266 height = 1;
267 }
268 uint8_t *bb = new uint8_t[width * height];
269 for (int i = 0; i < height; i++) {
270 memcpy(bb + i * width, in + i * stride, width);
271 }
272 // bb is filled with data
273 int sum = adler32(bb, width * height);
274 delete[] bb;
275 return sum;
276 }
277
Java_android_media_decoder_cts_NativeDecoderTest_getDecodedDataNative(JNIEnv * env,jclass,int fd,jlong offset,jlong size,jboolean wrapFd,jboolean useCallback)278 extern "C" jobject Java_android_media_decoder_cts_NativeDecoderTest_getDecodedDataNative(
279 JNIEnv *env, jclass /*clazz*/, int fd, jlong offset, jlong size, jboolean wrapFd,
280 jboolean useCallback) {
281 ALOGV("getDecodedDataNative");
282
283 FdDataSource fdSrc(fd, offset, size);
284 AMediaExtractor *ex = AMediaExtractor_new();
285 AMediaDataSource *ndkSrc = AMediaDataSource_new();
286
287 int err;
288 if (wrapFd) {
289 AMediaDataSource_setUserdata(ndkSrc, &fdSrc);
290 AMediaDataSource_setReadAt(ndkSrc, FdSourceReadAt);
291 AMediaDataSource_setGetSize(ndkSrc, FdSourceGetSize);
292 AMediaDataSource_setClose(ndkSrc, FdSourceClose);
293 err = AMediaExtractor_setDataSourceCustom(ex, ndkSrc);
294 } else {
295 err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
296 }
297 if (err != 0) {
298 ALOGE("setDataSource error: %d", err);
299 return NULL;
300 }
301
302 int numtracks = AMediaExtractor_getTrackCount(ex);
303
304 std::unique_ptr<AMediaCodec*[]> codec(new AMediaCodec*[numtracks]());
305 std::unique_ptr<AMediaFormat*[]> format(new AMediaFormat*[numtracks]());
306 std::unique_ptr<bool[]> sawInputEOS(new bool[numtracks]);
307 std::unique_ptr<bool[]> sawOutputEOS(new bool[numtracks]);
308 std::unique_ptr<simplevector<int>[]> sizes(new simplevector<int>[numtracks]);
309 std::unique_ptr<CallbackData[]> callbackData(new CallbackData[numtracks]);
310
311 ALOGV("input has %d tracks", numtracks);
312 for (int i = 0; i < numtracks; i++) {
313 AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
314 const char *s = AMediaFormat_toString(format);
315 ALOGI("track %d format: %s", i, s);
316 const char *mime;
317 if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
318 ALOGE("no mime type");
319 return NULL;
320 } else if (!strncmp(mime, "audio/", 6) || !strncmp(mime, "video/", 6)) {
321 codec[i] = AMediaCodec_createDecoderByType(mime);
322 AMediaCodec_configure(codec[i], format, NULL /* surface */, NULL /* crypto */, 0);
323 if (useCallback) {
324 AMediaCodecOnAsyncNotifyCallback aCB = {
325 OnInputAvailableCB,
326 OnOutputAvailableCB,
327 OnFormatChangedCB,
328 OnErrorCB
329 };
330 AMediaCodec_setAsyncNotifyCallback(codec[i], aCB, &callbackData[i]);
331 }
332 AMediaCodec_start(codec[i]);
333 sawInputEOS[i] = false;
334 sawOutputEOS[i] = false;
335 } else {
336 ALOGE("expected audio or video mime type, got %s", mime);
337 return NULL;
338 }
339 AMediaFormat_delete(format);
340 AMediaExtractor_selectTrack(ex, i);
341 }
342 int eosCount = 0;
343 while(eosCount < numtracks) {
344 int t = AMediaExtractor_getSampleTrackIndex(ex);
345 if (t >=0) {
346 ssize_t bufidx;
347 if (useCallback) {
348 bufidx = callbackData[t].getInputBufferId();
349 } else {
350 bufidx = AMediaCodec_dequeueInputBuffer(codec[t], 5000);
351 }
352 ALOGV("track %d, input buffer %zd", t, bufidx);
353 if (bufidx >= 0) {
354 size_t bufsize;
355 uint8_t *buf = AMediaCodec_getInputBuffer(codec[t], bufidx, &bufsize);
356 int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
357 ALOGV("read %d", sampleSize);
358 if (sampleSize < 0) {
359 sampleSize = 0;
360 sawInputEOS[t] = true;
361 ALOGV("EOS");
362 //break;
363 }
364 int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
365
366 AMediaCodec_queueInputBuffer(codec[t], bufidx, 0, sampleSize, presentationTimeUs,
367 sawInputEOS[t] ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
368 AMediaExtractor_advance(ex);
369 }
370 } else {
371 ALOGV("@@@@ no more input samples");
372 for (int tt = 0; tt < numtracks; tt++) {
373 if (!sawInputEOS[tt]) {
374 // we ran out of samples without ever signaling EOS to the codec,
375 // so do that now
376 int bufidx;
377 if (useCallback) {
378 bufidx = callbackData[tt].getInputBufferId();
379 } else {
380 bufidx = AMediaCodec_dequeueInputBuffer(codec[tt], 5000);
381 }
382 if (bufidx >= 0) {
383 AMediaCodec_queueInputBuffer(codec[tt], bufidx, 0, 0, 0,
384 AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
385 sawInputEOS[tt] = true;
386 }
387 }
388 }
389 }
390
391 // check all codecs for available data
392 AMediaCodecBufferInfo info;
393 AMediaFormat *outputFormat;
394 for (int tt = 0; tt < numtracks; tt++) {
395 if (!sawOutputEOS[tt]) {
396 int status;
397 if (useCallback) {
398 status = callbackData[tt].getOutput(&info, &outputFormat);
399 } else {
400 status = AMediaCodec_dequeueOutputBuffer(codec[tt], &info, 1);
401 }
402 ALOGV("dequeueoutput on track %d: %d", tt, status);
403 if (status >= 0) {
404 if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
405 ALOGV("EOS on track %d", tt);
406 sawOutputEOS[tt] = true;
407 eosCount++;
408 }
409 ALOGV("got decoded buffer for track %d, size %d", tt, info.size);
410 if (info.size > 0) {
411 size_t bufsize;
412 uint8_t *buf = AMediaCodec_getOutputBuffer(codec[tt], status, &bufsize);
413 int adler = checksum(buf, info.size, format[tt]);
414 sizes[tt].add(adler);
415 }
416 AMediaCodec_releaseOutputBuffer(codec[tt], status, false);
417 } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
418 ALOGV("output buffers changed for track %d", tt);
419 } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
420 if (format[tt] != NULL) {
421 AMediaFormat_delete(format[tt]);
422 }
423 if (useCallback) {
424 format[tt] = outputFormat;
425 } else {
426 format[tt] = AMediaCodec_getOutputFormat(codec[tt]);
427 }
428 ALOGV("format changed for track %d: %s", tt, AMediaFormat_toString(format[tt]));
429 } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
430 ALOGV("no output buffer right now for track %d", tt);
431 } else {
432 ALOGV("unexpected info code for track %d : %d", tt, status);
433 }
434 } else {
435 ALOGV("already at EOS on track %d", tt);
436 }
437 }
438 }
439 ALOGV("decoding loop done");
440
441 // allocate java int array for result and return it
442 int numsamples = 0;
443 for (int i = 0; i < numtracks; i++) {
444 numsamples += sizes[i].size();
445 }
446 ALOGV("checksums: %d", numsamples);
447 jintArray ret = env->NewIntArray(numsamples);
448 jboolean isCopy;
449 jint *org = env->GetIntArrayElements(ret, &isCopy);
450 jint *dst = org;
451 for (int i = 0; i < numtracks; i++) {
452 int *data = sizes[i].data();
453 int len = sizes[i].size();
454 ALOGV("copying %d", len);
455 for (int j = 0; j < len; j++) {
456 *dst++ = data[j];
457 }
458 }
459 env->ReleaseIntArrayElements(ret, org, 0);
460
461 for (int i = 0; i < numtracks; i++) {
462 AMediaFormat_delete(format[i]);
463 AMediaCodec_stop(codec[i]);
464 AMediaCodec_delete(codec[i]);
465 }
466 AMediaExtractor_delete(ex);
467 AMediaDataSource_delete(ndkSrc);
468 return ret;
469 }
470
arePtsListsIdentical(const std::vector<u_long> & refArray,const std::vector<u_long> & testArray)471 static bool arePtsListsIdentical(const std::vector<u_long>& refArray,
472 const std::vector<u_long>& testArray) {
473 bool isEqual = true;
474 u_long i;
475 if (refArray.size() != testArray.size()) {
476 ALOGE("Expected and received timestamps list sizes are not identical");
477 ALOGE("Expected pts list size is %zu", refArray.size());
478 ALOGE("Received pts list size is %zu", testArray.size());
479 isEqual = false;
480 } else {
481 for (i = 0; i < refArray.size(); i++) {
482 if (refArray[i] != testArray[i]) {
483 isEqual = false;
484 }
485 }
486 }
487
488 if (!isEqual) {
489 for (i = 0; i < std::min(refArray.size(), testArray.size()); i++) {
490 ALOGE("Frame idx %3lu, expected pts %9luus, received pts %9luus", i, refArray[i],
491 testArray[i]);
492 }
493 if (refArray.size() < testArray.size()) {
494 for (i = refArray.size(); i < testArray.size(); i++) {
495 ALOGE("Frame idx %3lu, expected pts %11s, received pts %9luus", i, "EMPTY",
496 testArray[i]);
497 }
498 } else if (refArray.size() > testArray.size()) {
499 for (i = testArray.size(); i < refArray.size(); i++) {
500 ALOGE("Frame idx %3lu, expected pts %9luus, received pts %11s", i, refArray[i],
501 "EMPTY");
502 }
503 }
504 }
505
506 return isEqual;
507 }
508
testNonTunneledTrickPlay(const char * fileName,ANativeWindow * pWindow,bool isAsync)509 bool testNonTunneledTrickPlay(const char *fileName, ANativeWindow *pWindow, bool isAsync) {
510 FILE *fp = fopen(fileName, "rbe");
511 if (fp == nullptr) {
512 ALOGE("Unable to open input file: %s", fileName);
513 return false;
514 }
515
516 struct stat buf {};
517 AMediaExtractor *extractor = AMediaExtractor_new();
518 if (!fstat(fileno(fp), &buf)) {
519 media_status_t res = AMediaExtractor_setDataSourceFd(extractor, fileno(fp), 0, buf.st_size);
520 if (res != AMEDIA_OK) {
521 ALOGE("AMediaExtractor_setDataSourceFd failed with error %d", res);
522 AMediaExtractor_delete(extractor);
523 return false;
524 }
525 }
526
527 int trackIndex = -1;
528 for (size_t trackID = 0; trackID < AMediaExtractor_getTrackCount(extractor); trackID++) {
529 AMediaFormat *format = AMediaExtractor_getTrackFormat(extractor, trackID);
530 const char *mediaType = nullptr;
531 AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mediaType);
532 bool isVideo = strncmp(mediaType, "video/", strlen("video/")) == 0;
533 AMediaFormat_delete(format);
534 if (isVideo) {
535 trackIndex = trackID;
536 ALOGV("mediaType = %s, prefix = \"video/\", trackId = %zu", mediaType, trackID);
537 break;
538 }
539 }
540
541 if (trackIndex < 0) {
542 ALOGE("No video track found for track index: %d", trackIndex);
543 AMediaExtractor_delete(extractor);
544 return false;
545 }
546
547 AMediaExtractor_selectTrack(extractor, trackIndex);
548 AMediaFormat *format = AMediaExtractor_getTrackFormat(extractor, trackIndex);
549 const char *mediaType = nullptr;
550 AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mediaType);
551 AMediaCodec *codec = AMediaCodec_createDecoderByType(mediaType);
552 CallbackData *callbackData = new CallbackData();
553
554 if (isAsync) {
555 AMediaCodecOnAsyncNotifyCallback callBack = {OnInputAvailableCB, OnOutputAvailableCB,
556 OnFormatChangedCB, OnErrorCB};
557 auto status = AMediaCodec_setAsyncNotifyCallback(codec, callBack, callbackData);
558 if (status != AMEDIA_OK) {
559 ALOGE("failed to set async callback");
560 delete callbackData;
561 AMediaFormat_delete(format);
562 AMediaCodec_delete(codec);
563 AMediaExtractor_delete(extractor);
564 return false;
565 }
566 }
567 AMediaCodec_configure(codec, format, pWindow, nullptr, 0);
568 AMediaCodec_start(codec);
569
570 std::atomic<bool> done(false);
571 std::vector<u_long> expectedPresentationTimes;
572 std::vector<u_long> receivedPresentationTimes;
573 bool mEosQueued = false;
574 int mDecodeOnlyCounter = 0;
575 // keep looping until the codec receives the EOS frame
576 while (!done.load()) {
577 // enqueue
578 if (!mEosQueued) {
579 size_t inBufSize;
580 int32_t id;
581 if (isAsync) {
582 id = callbackData->getInputBufferId();
583 } else {
584 id = AMediaCodec_dequeueInputBuffer(codec, 5000);
585 }
586 if (id >= 0) {
587 uint8_t *inBuf = AMediaCodec_getInputBuffer(codec, id, &inBufSize);
588 if (inBuf == nullptr) {
589 ALOGE("AMediaCodec_getInputBuffer returned nullptr");
590 delete callbackData;
591 AMediaFormat_delete(format);
592 AMediaCodec_stop(codec);
593 AMediaCodec_delete(codec);
594 AMediaExtractor_delete(extractor);
595 return false;
596 }
597 ssize_t sampleSize = AMediaExtractor_readSampleData(extractor, inBuf, inBufSize);
598 int64_t presentationTime = AMediaExtractor_getSampleTime(extractor);
599 uint32_t flags = 0;
600 if (sampleSize < 0) {
601 flags = AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
602 sampleSize = 0;
603 mEosQueued = true;
604 } else if (mDecodeOnlyCounter % 2 == 0) {
605 flags = AMEDIACODEC_BUFFER_FLAG_DECODE_ONLY;
606 } else {
607 expectedPresentationTimes.push_back(presentationTime);
608 }
609 mDecodeOnlyCounter++;
610 AMediaCodec_queueInputBuffer(codec, id, 0, sampleSize, presentationTime, flags);
611 AMediaExtractor_advance(extractor);
612 }
613 }
614
615 // dequeue
616 AMediaCodecBufferInfo bufferInfo;
617 AMediaFormat *outputFormat;
618 int id;
619 if (isAsync) {
620 id = callbackData->getOutput(&bufferInfo, &outputFormat);
621 } else {
622 id = AMediaCodec_dequeueOutputBuffer(codec, &bufferInfo, 1);
623 }
624 if (id >= 0) {
625 AMediaCodec_releaseOutputBuffer(codec, id, false);
626 if ((bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) != 0) {
627 done.store(true);
628 } else {
629 receivedPresentationTimes.push_back(bufferInfo.presentationTimeUs);
630 }
631 }
632 }
633
634 delete callbackData;
635 AMediaFormat_delete(format);
636 AMediaCodec_stop(codec);
637 AMediaCodec_delete(codec);
638 AMediaExtractor_delete(extractor);
639 std::sort(expectedPresentationTimes.begin(), expectedPresentationTimes.end());
640 return arePtsListsIdentical(expectedPresentationTimes, receivedPresentationTimes);
641 }
642
Java_android_media_decoder_cts_DecodeOnlyTest_nativeTestNonTunneledTrickPlay(JNIEnv * env,jclass,jstring jFileName,jobject surface,jboolean isAsync)643 extern "C" jboolean Java_android_media_decoder_cts_DecodeOnlyTest_nativeTestNonTunneledTrickPlay(
644 JNIEnv *env, jclass /*clazz*/, jstring jFileName, jobject surface, jboolean isAsync) {
645 ALOGD("nativeTestNonTunneledTrickPlay");
646 const char *cFileName = env->GetStringUTFChars(jFileName, nullptr);
647 ANativeWindow *window = surface ? ANativeWindow_fromSurface(env, surface) : nullptr;
648 bool isPass = testNonTunneledTrickPlay(cFileName, window, isAsync);
649 env->ReleaseStringUTFChars(jFileName, cFileName);
650 return static_cast<jboolean>(isPass);
651 }
652