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