1 /* 2 * Copyright 2012, 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 //#define LOG_NDEBUG 0 18 #define LOG_TAG "MediaCodec-JNI" 19 #include <utils/Log.h> 20 21 #include "android_media_MediaCodec.h" 22 23 #include "android_media_MediaCrypto.h" 24 #include "android_media_Utils.h" 25 #include "android_runtime/AndroidRuntime.h" 26 #include "android_runtime/android_view_Surface.h" 27 #include "jni.h" 28 #include "JNIHelp.h" 29 30 #include <cutils/compiler.h> 31 32 #include <gui/Surface.h> 33 34 #include <media/ICrypto.h> 35 #include <media/stagefright/MediaCodec.h> 36 #include <media/stagefright/foundation/ABuffer.h> 37 #include <media/stagefright/foundation/ADebug.h> 38 #include <media/stagefright/foundation/ALooper.h> 39 #include <media/stagefright/foundation/AMessage.h> 40 #include <media/stagefright/foundation/AString.h> 41 #include <media/stagefright/MediaErrors.h> 42 #include <media/stagefright/PersistentSurface.h> 43 #include <nativehelper/ScopedLocalRef.h> 44 45 #include <system/window.h> 46 47 namespace android { 48 49 // Keep these in sync with their equivalents in MediaCodec.java !!! 50 enum { 51 DEQUEUE_INFO_TRY_AGAIN_LATER = -1, 52 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2, 53 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3, 54 }; 55 56 enum { 57 EVENT_CALLBACK = 1, 58 EVENT_SET_CALLBACK = 2, 59 EVENT_FRAME_RENDERED = 3, 60 }; 61 62 static struct CryptoErrorCodes { 63 jint cryptoErrorNoKey; 64 jint cryptoErrorKeyExpired; 65 jint cryptoErrorResourceBusy; 66 jint cryptoErrorInsufficientOutputProtection; 67 jint cryptoErrorSessionNotOpened; 68 jint cryptoErrorUnsupportedOperation; 69 } gCryptoErrorCodes; 70 71 static struct CodecActionCodes { 72 jint codecActionTransient; 73 jint codecActionRecoverable; 74 } gCodecActionCodes; 75 76 static struct CodecErrorCodes { 77 jint errorInsufficientResource; 78 jint errorReclaimed; 79 } gCodecErrorCodes; 80 81 static struct { 82 jclass clazz; 83 jfieldID mLock; 84 jfieldID mPersistentObject; 85 jmethodID ctor; 86 jmethodID setNativeObjectLocked; 87 } gPersistentSurfaceClassInfo; 88 89 static struct { 90 jint Unencrypted; 91 jint AesCtr; 92 jint AesCbc; 93 } gCryptoModes; 94 95 96 struct fields_t { 97 jfieldID context; 98 jmethodID postEventFromNativeID; 99 jfieldID cryptoInfoNumSubSamplesID; 100 jfieldID cryptoInfoNumBytesOfClearDataID; 101 jfieldID cryptoInfoNumBytesOfEncryptedDataID; 102 jfieldID cryptoInfoKeyID; 103 jfieldID cryptoInfoIVID; 104 jfieldID cryptoInfoModeID; 105 jfieldID cryptoInfoPatternID; 106 jfieldID patternEncryptBlocksID; 107 jfieldID patternSkipBlocksID; 108 }; 109 110 static fields_t gFields; 111 static const void *sRefBaseOwner; 112 113 //////////////////////////////////////////////////////////////////////////////// 114 115 JMediaCodec::JMediaCodec( 116 JNIEnv *env, jobject thiz, 117 const char *name, bool nameIsType, bool encoder) 118 : mClass(NULL), 119 mObject(NULL) { 120 jclass clazz = env->GetObjectClass(thiz); 121 CHECK(clazz != NULL); 122 123 mClass = (jclass)env->NewGlobalRef(clazz); 124 mObject = env->NewWeakGlobalRef(thiz); 125 126 cacheJavaObjects(env); 127 128 mLooper = new ALooper; 129 mLooper->setName("MediaCodec_looper"); 130 131 mLooper->start( 132 false, // runOnCallingThread 133 true, // canCallJava 134 PRIORITY_FOREGROUND); 135 136 if (nameIsType) { 137 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus); 138 } else { 139 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus); 140 } 141 CHECK((mCodec != NULL) != (mInitStatus != OK)); 142 } 143 144 void JMediaCodec::cacheJavaObjects(JNIEnv *env) { 145 jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer"); 146 mByteBufferClass = (jclass)env->NewGlobalRef(clazz); 147 CHECK(mByteBufferClass != NULL); 148 149 ScopedLocalRef<jclass> byteOrderClass( 150 env, env->FindClass("java/nio/ByteOrder")); 151 CHECK(byteOrderClass.get() != NULL); 152 153 jmethodID nativeOrderID = env->GetStaticMethodID( 154 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;"); 155 CHECK(nativeOrderID != NULL); 156 157 jobject nativeByteOrderObj = 158 env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID); 159 mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj); 160 CHECK(mNativeByteOrderObj != NULL); 161 env->DeleteLocalRef(nativeByteOrderObj); 162 nativeByteOrderObj = NULL; 163 164 mByteBufferOrderMethodID = env->GetMethodID( 165 mByteBufferClass, 166 "order", 167 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"); 168 CHECK(mByteBufferOrderMethodID != NULL); 169 170 mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID( 171 mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;"); 172 CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL); 173 174 mByteBufferPositionMethodID = env->GetMethodID( 175 mByteBufferClass, "position", "(I)Ljava/nio/Buffer;"); 176 CHECK(mByteBufferPositionMethodID != NULL); 177 178 mByteBufferLimitMethodID = env->GetMethodID( 179 mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;"); 180 CHECK(mByteBufferLimitMethodID != NULL); 181 } 182 183 status_t JMediaCodec::initCheck() const { 184 return mInitStatus; 185 } 186 187 void JMediaCodec::registerSelf() { 188 mLooper->registerHandler(this); 189 } 190 191 void JMediaCodec::release() { 192 if (mCodec != NULL) { 193 mCodec->release(); 194 mCodec.clear(); 195 mInitStatus = NO_INIT; 196 } 197 198 if (mLooper != NULL) { 199 mLooper->unregisterHandler(id()); 200 mLooper->stop(); 201 mLooper.clear(); 202 } 203 } 204 205 JMediaCodec::~JMediaCodec() { 206 if (mCodec != NULL || mLooper != NULL) { 207 /* MediaCodec and looper should have been released explicitly already 208 * in setMediaCodec() (see comments in setMediaCodec()). 209 * 210 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the 211 * message handler, doing release() there risks deadlock as MediaCodec:: 212 * release() post synchronous message to the same looper. 213 * 214 * Print a warning and try to proceed with releasing. 215 */ 216 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()..."); 217 release(); 218 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec()."); 219 } 220 221 JNIEnv *env = AndroidRuntime::getJNIEnv(); 222 223 env->DeleteWeakGlobalRef(mObject); 224 mObject = NULL; 225 env->DeleteGlobalRef(mClass); 226 mClass = NULL; 227 deleteJavaObjects(env); 228 } 229 230 void JMediaCodec::deleteJavaObjects(JNIEnv *env) { 231 env->DeleteGlobalRef(mByteBufferClass); 232 mByteBufferClass = NULL; 233 env->DeleteGlobalRef(mNativeByteOrderObj); 234 mNativeByteOrderObj = NULL; 235 236 mByteBufferOrderMethodID = NULL; 237 mByteBufferAsReadOnlyBufferMethodID = NULL; 238 mByteBufferPositionMethodID = NULL; 239 mByteBufferLimitMethodID = NULL; 240 } 241 242 status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) { 243 if (enable) { 244 if (mOnFrameRenderedNotification == NULL) { 245 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this); 246 } 247 } else { 248 mOnFrameRenderedNotification.clear(); 249 } 250 251 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification); 252 } 253 254 status_t JMediaCodec::setCallback(jobject cb) { 255 if (cb != NULL) { 256 if (mCallbackNotification == NULL) { 257 mCallbackNotification = new AMessage(kWhatCallbackNotify, this); 258 } 259 } else { 260 mCallbackNotification.clear(); 261 } 262 263 return mCodec->setCallback(mCallbackNotification); 264 } 265 266 status_t JMediaCodec::configure( 267 const sp<AMessage> &format, 268 const sp<IGraphicBufferProducer> &bufferProducer, 269 const sp<ICrypto> &crypto, 270 int flags) { 271 sp<Surface> client; 272 if (bufferProducer != NULL) { 273 mSurfaceTextureClient = 274 new Surface(bufferProducer, true /* controlledByApp */); 275 } else { 276 mSurfaceTextureClient.clear(); 277 } 278 279 return mCodec->configure(format, mSurfaceTextureClient, crypto, flags); 280 } 281 282 status_t JMediaCodec::setSurface( 283 const sp<IGraphicBufferProducer> &bufferProducer) { 284 sp<Surface> client; 285 if (bufferProducer != NULL) { 286 client = new Surface(bufferProducer, true /* controlledByApp */); 287 } 288 status_t err = mCodec->setSurface(client); 289 if (err == OK) { 290 mSurfaceTextureClient = client; 291 } 292 return err; 293 } 294 295 status_t JMediaCodec::createInputSurface( 296 sp<IGraphicBufferProducer>* bufferProducer) { 297 return mCodec->createInputSurface(bufferProducer); 298 } 299 300 status_t JMediaCodec::setInputSurface( 301 const sp<PersistentSurface> &surface) { 302 return mCodec->setInputSurface(surface); 303 } 304 305 status_t JMediaCodec::start() { 306 return mCodec->start(); 307 } 308 309 status_t JMediaCodec::stop() { 310 mSurfaceTextureClient.clear(); 311 312 return mCodec->stop(); 313 } 314 315 status_t JMediaCodec::flush() { 316 return mCodec->flush(); 317 } 318 319 status_t JMediaCodec::reset() { 320 return mCodec->reset(); 321 } 322 323 status_t JMediaCodec::queueInputBuffer( 324 size_t index, 325 size_t offset, size_t size, int64_t timeUs, uint32_t flags, 326 AString *errorDetailMsg) { 327 return mCodec->queueInputBuffer( 328 index, offset, size, timeUs, flags, errorDetailMsg); 329 } 330 331 status_t JMediaCodec::queueSecureInputBuffer( 332 size_t index, 333 size_t offset, 334 const CryptoPlugin::SubSample *subSamples, 335 size_t numSubSamples, 336 const uint8_t key[16], 337 const uint8_t iv[16], 338 CryptoPlugin::Mode mode, 339 const CryptoPlugin::Pattern &pattern, 340 int64_t presentationTimeUs, 341 uint32_t flags, 342 AString *errorDetailMsg) { 343 return mCodec->queueSecureInputBuffer( 344 index, offset, subSamples, numSubSamples, key, iv, mode, pattern, 345 presentationTimeUs, flags, errorDetailMsg); 346 } 347 348 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) { 349 return mCodec->dequeueInputBuffer(index, timeoutUs); 350 } 351 352 status_t JMediaCodec::dequeueOutputBuffer( 353 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) { 354 size_t size, offset; 355 int64_t timeUs; 356 uint32_t flags; 357 status_t err = mCodec->dequeueOutputBuffer( 358 index, &offset, &size, &timeUs, &flags, timeoutUs); 359 360 if (err != OK) { 361 return err; 362 } 363 364 ScopedLocalRef<jclass> clazz( 365 env, env->FindClass("android/media/MediaCodec$BufferInfo")); 366 367 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V"); 368 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags); 369 370 return OK; 371 } 372 373 status_t JMediaCodec::releaseOutputBuffer( 374 size_t index, bool render, bool updatePTS, int64_t timestampNs) { 375 if (updatePTS) { 376 return mCodec->renderOutputBufferAndRelease(index, timestampNs); 377 } 378 return render 379 ? mCodec->renderOutputBufferAndRelease(index) 380 : mCodec->releaseOutputBuffer(index); 381 } 382 383 status_t JMediaCodec::signalEndOfInputStream() { 384 return mCodec->signalEndOfInputStream(); 385 } 386 387 status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const { 388 sp<AMessage> msg; 389 status_t err; 390 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg); 391 if (err != OK) { 392 return err; 393 } 394 395 return ConvertMessageToMap(env, msg, format); 396 } 397 398 status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const { 399 sp<AMessage> msg; 400 status_t err; 401 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) { 402 return err; 403 } 404 405 return ConvertMessageToMap(env, msg, format); 406 } 407 408 status_t JMediaCodec::getBuffers( 409 JNIEnv *env, bool input, jobjectArray *bufArray) const { 410 Vector<sp<ABuffer> > buffers; 411 412 status_t err = 413 input 414 ? mCodec->getInputBuffers(&buffers) 415 : mCodec->getOutputBuffers(&buffers); 416 417 if (err != OK) { 418 return err; 419 } 420 421 *bufArray = (jobjectArray)env->NewObjectArray( 422 buffers.size(), mByteBufferClass, NULL); 423 if (*bufArray == NULL) { 424 return NO_MEMORY; 425 } 426 427 for (size_t i = 0; i < buffers.size(); ++i) { 428 const sp<ABuffer> &buffer = buffers.itemAt(i); 429 430 jobject byteBuffer = NULL; 431 err = createByteBufferFromABuffer( 432 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer); 433 if (err != OK) { 434 return err; 435 } 436 if (byteBuffer != NULL) { 437 env->SetObjectArrayElement( 438 *bufArray, i, byteBuffer); 439 440 env->DeleteLocalRef(byteBuffer); 441 byteBuffer = NULL; 442 } 443 } 444 445 return OK; 446 } 447 448 // static 449 status_t JMediaCodec::createByteBufferFromABuffer( 450 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer, 451 jobject *buf) const { 452 // if this is an ABuffer that doesn't actually hold any accessible memory, 453 // use a null ByteBuffer 454 *buf = NULL; 455 456 if (buffer == NULL) { 457 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL"); 458 return OK; 459 } 460 461 if (buffer->base() == NULL) { 462 return OK; 463 } 464 465 jobject byteBuffer = 466 env->NewDirectByteBuffer(buffer->base(), buffer->capacity()); 467 if (readOnly && byteBuffer != NULL) { 468 jobject readOnlyBuffer = env->CallObjectMethod( 469 byteBuffer, mByteBufferAsReadOnlyBufferMethodID); 470 env->DeleteLocalRef(byteBuffer); 471 byteBuffer = readOnlyBuffer; 472 } 473 if (byteBuffer == NULL) { 474 return NO_MEMORY; 475 } 476 jobject me = env->CallObjectMethod( 477 byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj); 478 env->DeleteLocalRef(me); 479 me = env->CallObjectMethod( 480 byteBuffer, mByteBufferLimitMethodID, 481 clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size())); 482 env->DeleteLocalRef(me); 483 me = env->CallObjectMethod( 484 byteBuffer, mByteBufferPositionMethodID, 485 clearBuffer ? 0 : buffer->offset()); 486 env->DeleteLocalRef(me); 487 me = NULL; 488 489 *buf = byteBuffer; 490 return OK; 491 } 492 493 status_t JMediaCodec::getBuffer( 494 JNIEnv *env, bool input, size_t index, jobject *buf) const { 495 sp<ABuffer> buffer; 496 497 status_t err = 498 input 499 ? mCodec->getInputBuffer(index, &buffer) 500 : mCodec->getOutputBuffer(index, &buffer); 501 502 if (err != OK) { 503 return err; 504 } 505 506 return createByteBufferFromABuffer( 507 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf); 508 } 509 510 status_t JMediaCodec::getImage( 511 JNIEnv *env, bool input, size_t index, jobject *buf) const { 512 sp<ABuffer> buffer; 513 514 status_t err = 515 input 516 ? mCodec->getInputBuffer(index, &buffer) 517 : mCodec->getOutputBuffer(index, &buffer); 518 519 if (err != OK) { 520 return err; 521 } 522 523 // if this is an ABuffer that doesn't actually hold any accessible memory, 524 // use a null ByteBuffer 525 *buf = NULL; 526 if (buffer->base() == NULL) { 527 return OK; 528 } 529 530 // check if buffer is an image 531 sp<ABuffer> imageData; 532 if (!buffer->meta()->findBuffer("image-data", &imageData)) { 533 return OK; 534 } 535 536 int64_t timestamp = 0; 537 if (!input && buffer->meta()->findInt64("timeUs", ×tamp)) { 538 timestamp *= 1000; // adjust to ns 539 } 540 541 jobject byteBuffer = NULL; 542 err = createByteBufferFromABuffer( 543 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer); 544 if (err != OK) { 545 return OK; 546 } 547 548 jobject infoBuffer = NULL; 549 err = createByteBufferFromABuffer( 550 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer); 551 if (err != OK) { 552 env->DeleteLocalRef(byteBuffer); 553 byteBuffer = NULL; 554 return OK; 555 } 556 557 jobject cropRect = NULL; 558 int32_t left, top, right, bottom; 559 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) { 560 ScopedLocalRef<jclass> rectClazz( 561 env, env->FindClass("android/graphics/Rect")); 562 CHECK(rectClazz.get() != NULL); 563 564 jmethodID rectConstructID = env->GetMethodID( 565 rectClazz.get(), "<init>", "(IIII)V"); 566 567 cropRect = env->NewObject( 568 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1); 569 } 570 571 ScopedLocalRef<jclass> imageClazz( 572 env, env->FindClass("android/media/MediaCodec$MediaImage")); 573 CHECK(imageClazz.get() != NULL); 574 575 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>", 576 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V"); 577 578 *buf = env->NewObject(imageClazz.get(), imageConstructID, 579 byteBuffer, infoBuffer, 580 (jboolean)!input /* readOnly */, 581 (jlong)timestamp, 582 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect); 583 584 // if MediaImage creation fails, return null 585 if (env->ExceptionCheck()) { 586 env->ExceptionDescribe(); 587 env->ExceptionClear(); 588 *buf = NULL; 589 } 590 591 if (cropRect != NULL) { 592 env->DeleteLocalRef(cropRect); 593 cropRect = NULL; 594 } 595 596 env->DeleteLocalRef(byteBuffer); 597 byteBuffer = NULL; 598 599 env->DeleteLocalRef(infoBuffer); 600 infoBuffer = NULL; 601 602 return OK; 603 } 604 605 status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const { 606 AString name; 607 608 status_t err = mCodec->getName(&name); 609 610 if (err != OK) { 611 return err; 612 } 613 614 *nameStr = env->NewStringUTF(name.c_str()); 615 616 return OK; 617 } 618 619 status_t JMediaCodec::setParameters(const sp<AMessage> &msg) { 620 return mCodec->setParameters(msg); 621 } 622 623 void JMediaCodec::setVideoScalingMode(int mode) { 624 if (mSurfaceTextureClient != NULL) { 625 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode); 626 } 627 } 628 629 static jthrowable createCodecException( 630 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) { 631 ScopedLocalRef<jclass> clazz( 632 env, env->FindClass("android/media/MediaCodec$CodecException")); 633 CHECK(clazz.get() != NULL); 634 635 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V"); 636 CHECK(ctor != NULL); 637 638 ScopedLocalRef<jstring> msgObj( 639 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err))); 640 641 // translate action code to Java equivalent 642 switch (actionCode) { 643 case ACTION_CODE_TRANSIENT: 644 actionCode = gCodecActionCodes.codecActionTransient; 645 break; 646 case ACTION_CODE_RECOVERABLE: 647 actionCode = gCodecActionCodes.codecActionRecoverable; 648 break; 649 default: 650 actionCode = 0; // everything else is fatal 651 break; 652 } 653 654 /* translate OS errors to Java API CodecException errorCodes */ 655 switch (err) { 656 case NO_MEMORY: 657 err = gCodecErrorCodes.errorInsufficientResource; 658 break; 659 case DEAD_OBJECT: 660 err = gCodecErrorCodes.errorReclaimed; 661 break; 662 default: /* Other error codes go out as is. */ 663 break; 664 } 665 666 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get()); 667 } 668 669 void JMediaCodec::handleCallback(const sp<AMessage> &msg) { 670 int32_t arg1, arg2 = 0; 671 jobject obj = NULL; 672 CHECK(msg->findInt32("callbackID", &arg1)); 673 JNIEnv *env = AndroidRuntime::getJNIEnv(); 674 675 switch (arg1) { 676 case MediaCodec::CB_INPUT_AVAILABLE: 677 { 678 CHECK(msg->findInt32("index", &arg2)); 679 break; 680 } 681 682 case MediaCodec::CB_OUTPUT_AVAILABLE: 683 { 684 CHECK(msg->findInt32("index", &arg2)); 685 686 size_t size, offset; 687 int64_t timeUs; 688 uint32_t flags; 689 CHECK(msg->findSize("size", &size)); 690 CHECK(msg->findSize("offset", &offset)); 691 CHECK(msg->findInt64("timeUs", &timeUs)); 692 CHECK(msg->findInt32("flags", (int32_t *)&flags)); 693 694 ScopedLocalRef<jclass> clazz( 695 env, env->FindClass("android/media/MediaCodec$BufferInfo")); 696 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V"); 697 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V"); 698 699 obj = env->NewObject(clazz.get(), ctor); 700 701 if (obj == NULL) { 702 if (env->ExceptionCheck()) { 703 ALOGE("Could not create MediaCodec.BufferInfo."); 704 env->ExceptionClear(); 705 } 706 jniThrowException(env, "java/lang/IllegalStateException", NULL); 707 return; 708 } 709 710 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags); 711 break; 712 } 713 714 case MediaCodec::CB_ERROR: 715 { 716 int32_t err, actionCode; 717 CHECK(msg->findInt32("err", &err)); 718 CHECK(msg->findInt32("actionCode", &actionCode)); 719 720 // note that DRM errors could conceivably alias into a CodecException 721 obj = (jobject)createCodecException(env, err, actionCode); 722 723 if (obj == NULL) { 724 if (env->ExceptionCheck()) { 725 ALOGE("Could not create CodecException object."); 726 env->ExceptionClear(); 727 } 728 jniThrowException(env, "java/lang/IllegalStateException", NULL); 729 return; 730 } 731 732 break; 733 } 734 735 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED: 736 { 737 sp<AMessage> format; 738 CHECK(msg->findMessage("format", &format)); 739 740 if (OK != ConvertMessageToMap(env, format, &obj)) { 741 jniThrowException(env, "java/lang/IllegalStateException", NULL); 742 return; 743 } 744 745 break; 746 } 747 748 default: 749 TRESPASS(); 750 } 751 752 env->CallVoidMethod( 753 mObject, 754 gFields.postEventFromNativeID, 755 EVENT_CALLBACK, 756 arg1, 757 arg2, 758 obj); 759 760 env->DeleteLocalRef(obj); 761 } 762 763 void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) { 764 int32_t arg1 = 0, arg2 = 0; 765 jobject obj = NULL; 766 JNIEnv *env = AndroidRuntime::getJNIEnv(); 767 768 sp<AMessage> data; 769 CHECK(msg->findMessage("data", &data)); 770 771 status_t err = ConvertMessageToMap(env, data, &obj); 772 if (err != OK) { 773 jniThrowException(env, "java/lang/IllegalStateException", NULL); 774 return; 775 } 776 777 env->CallVoidMethod( 778 mObject, gFields.postEventFromNativeID, 779 EVENT_FRAME_RENDERED, arg1, arg2, obj); 780 781 env->DeleteLocalRef(obj); 782 } 783 784 void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) { 785 switch (msg->what()) { 786 case kWhatCallbackNotify: 787 { 788 handleCallback(msg); 789 break; 790 } 791 case kWhatFrameRendered: 792 { 793 handleFrameRenderedNotification(msg); 794 break; 795 } 796 default: 797 TRESPASS(); 798 } 799 } 800 801 } // namespace android 802 803 //////////////////////////////////////////////////////////////////////////////// 804 805 using namespace android; 806 807 static sp<JMediaCodec> setMediaCodec( 808 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) { 809 sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context); 810 if (codec != NULL) { 811 codec->incStrong(thiz); 812 } 813 if (old != NULL) { 814 /* release MediaCodec and stop the looper now before decStrong. 815 * otherwise JMediaCodec::~JMediaCodec() could be called from within 816 * its message handler, doing release() from there will deadlock 817 * (as MediaCodec::release() post synchronous message to the same looper) 818 */ 819 old->release(); 820 old->decStrong(thiz); 821 } 822 env->SetLongField(thiz, gFields.context, (jlong)codec.get()); 823 824 return old; 825 } 826 827 static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) { 828 return (JMediaCodec *)env->GetLongField(thiz, gFields.context); 829 } 830 831 static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) { 832 setMediaCodec(env, thiz, NULL); 833 } 834 835 static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) { 836 jthrowable exception = createCodecException(env, err, actionCode, msg); 837 env->Throw(exception); 838 } 839 840 static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) { 841 ScopedLocalRef<jclass> clazz( 842 env, env->FindClass("android/media/MediaCodec$CryptoException")); 843 CHECK(clazz.get() != NULL); 844 845 jmethodID constructID = 846 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V"); 847 CHECK(constructID != NULL); 848 849 const char *defaultMsg = "Unknown Error"; 850 851 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */ 852 switch (err) { 853 case ERROR_DRM_NO_LICENSE: 854 err = gCryptoErrorCodes.cryptoErrorNoKey; 855 defaultMsg = "Crypto key not available"; 856 break; 857 case ERROR_DRM_LICENSE_EXPIRED: 858 err = gCryptoErrorCodes.cryptoErrorKeyExpired; 859 defaultMsg = "License expired"; 860 break; 861 case ERROR_DRM_RESOURCE_BUSY: 862 err = gCryptoErrorCodes.cryptoErrorResourceBusy; 863 defaultMsg = "Resource busy or unavailable"; 864 break; 865 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION: 866 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection; 867 defaultMsg = "Required output protections are not active"; 868 break; 869 case ERROR_DRM_SESSION_NOT_OPENED: 870 err = gCryptoErrorCodes.cryptoErrorSessionNotOpened; 871 defaultMsg = "Attempted to use a closed session"; 872 break; 873 case ERROR_DRM_CANNOT_HANDLE: 874 err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation; 875 defaultMsg = "Operation not supported in this configuration"; 876 break; 877 default: /* Other negative DRM error codes go out as is. */ 878 break; 879 } 880 881 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : defaultMsg); 882 883 jthrowable exception = 884 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj); 885 886 env->Throw(exception); 887 } 888 889 static jint throwExceptionAsNecessary( 890 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL, 891 const char *msg = NULL) { 892 switch (err) { 893 case OK: 894 return 0; 895 896 case -EAGAIN: 897 return DEQUEUE_INFO_TRY_AGAIN_LATER; 898 899 case INFO_FORMAT_CHANGED: 900 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED; 901 902 case INFO_OUTPUT_BUFFERS_CHANGED: 903 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED; 904 905 case INVALID_OPERATION: 906 jniThrowException(env, "java/lang/IllegalStateException", msg); 907 return 0; 908 909 case BAD_VALUE: 910 jniThrowException(env, "java/lang/IllegalArgumentException", msg); 911 return 0; 912 913 default: 914 if (isCryptoError(err)) { 915 throwCryptoException(env, err, msg); 916 return 0; 917 } 918 throwCodecException(env, err, actionCode, msg); 919 return 0; 920 } 921 } 922 923 static void android_media_MediaCodec_native_enableOnFrameRenderedListener( 924 JNIEnv *env, 925 jobject thiz, 926 jboolean enabled) { 927 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 928 929 if (codec == NULL) { 930 throwExceptionAsNecessary(env, INVALID_OPERATION); 931 return; 932 } 933 934 status_t err = codec->enableOnFrameRenderedListener(enabled); 935 936 throwExceptionAsNecessary(env, err); 937 } 938 939 static void android_media_MediaCodec_native_setCallback( 940 JNIEnv *env, 941 jobject thiz, 942 jobject cb) { 943 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 944 945 if (codec == NULL) { 946 throwExceptionAsNecessary(env, INVALID_OPERATION); 947 return; 948 } 949 950 status_t err = codec->setCallback(cb); 951 952 throwExceptionAsNecessary(env, err); 953 } 954 955 static void android_media_MediaCodec_native_configure( 956 JNIEnv *env, 957 jobject thiz, 958 jobjectArray keys, jobjectArray values, 959 jobject jsurface, 960 jobject jcrypto, 961 jint flags) { 962 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 963 964 if (codec == NULL) { 965 throwExceptionAsNecessary(env, INVALID_OPERATION); 966 return; 967 } 968 969 sp<AMessage> format; 970 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format); 971 972 if (err != OK) { 973 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 974 return; 975 } 976 977 sp<IGraphicBufferProducer> bufferProducer; 978 if (jsurface != NULL) { 979 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 980 if (surface != NULL) { 981 bufferProducer = surface->getIGraphicBufferProducer(); 982 } else { 983 jniThrowException( 984 env, 985 "java/lang/IllegalArgumentException", 986 "The surface has been released"); 987 return; 988 } 989 } 990 991 sp<ICrypto> crypto; 992 if (jcrypto != NULL) { 993 crypto = JCrypto::GetCrypto(env, jcrypto); 994 } 995 996 err = codec->configure(format, bufferProducer, crypto, flags); 997 998 throwExceptionAsNecessary(env, err); 999 } 1000 1001 static void android_media_MediaCodec_native_setSurface( 1002 JNIEnv *env, 1003 jobject thiz, 1004 jobject jsurface) { 1005 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1006 1007 if (codec == NULL) { 1008 throwExceptionAsNecessary(env, INVALID_OPERATION); 1009 return; 1010 } 1011 1012 sp<IGraphicBufferProducer> bufferProducer; 1013 if (jsurface != NULL) { 1014 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 1015 if (surface != NULL) { 1016 bufferProducer = surface->getIGraphicBufferProducer(); 1017 } else { 1018 jniThrowException( 1019 env, 1020 "java/lang/IllegalArgumentException", 1021 "The surface has been released"); 1022 return; 1023 } 1024 } 1025 1026 status_t err = codec->setSurface(bufferProducer); 1027 throwExceptionAsNecessary(env, err); 1028 } 1029 1030 sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface( 1031 JNIEnv* env, jobject object) { 1032 sp<PersistentSurface> persistentSurface; 1033 1034 jobject lock = env->GetObjectField( 1035 object, gPersistentSurfaceClassInfo.mLock); 1036 if (env->MonitorEnter(lock) == JNI_OK) { 1037 persistentSurface = reinterpret_cast<PersistentSurface *>( 1038 env->GetLongField(object, 1039 gPersistentSurfaceClassInfo.mPersistentObject)); 1040 env->MonitorExit(lock); 1041 } 1042 env->DeleteLocalRef(lock); 1043 1044 return persistentSurface; 1045 } 1046 1047 static jobject android_media_MediaCodec_createPersistentInputSurface( 1048 JNIEnv* env, jclass /* clazz */) { 1049 ALOGV("android_media_MediaCodec_createPersistentInputSurface"); 1050 sp<PersistentSurface> persistentSurface = 1051 MediaCodec::CreatePersistentInputSurface(); 1052 1053 if (persistentSurface == NULL) { 1054 return NULL; 1055 } 1056 1057 sp<Surface> surface = new Surface( 1058 persistentSurface->getBufferProducer(), true); 1059 if (surface == NULL) { 1060 return NULL; 1061 } 1062 1063 jobject object = env->NewObject( 1064 gPersistentSurfaceClassInfo.clazz, 1065 gPersistentSurfaceClassInfo.ctor); 1066 1067 if (object == NULL) { 1068 if (env->ExceptionCheck()) { 1069 ALOGE("Could not create PersistentSurface."); 1070 env->ExceptionClear(); 1071 } 1072 return NULL; 1073 } 1074 1075 jobject lock = env->GetObjectField( 1076 object, gPersistentSurfaceClassInfo.mLock); 1077 if (env->MonitorEnter(lock) == JNI_OK) { 1078 env->CallVoidMethod( 1079 object, 1080 gPersistentSurfaceClassInfo.setNativeObjectLocked, 1081 (jlong)surface.get()); 1082 env->SetLongField( 1083 object, 1084 gPersistentSurfaceClassInfo.mPersistentObject, 1085 (jlong)persistentSurface.get()); 1086 env->MonitorExit(lock); 1087 } else { 1088 env->DeleteLocalRef(object); 1089 object = NULL; 1090 } 1091 env->DeleteLocalRef(lock); 1092 1093 if (object != NULL) { 1094 surface->incStrong(&sRefBaseOwner); 1095 persistentSurface->incStrong(&sRefBaseOwner); 1096 } 1097 1098 return object; 1099 } 1100 1101 static void android_media_MediaCodec_releasePersistentInputSurface( 1102 JNIEnv* env, jclass /* clazz */, jobject object) { 1103 sp<PersistentSurface> persistentSurface; 1104 1105 jobject lock = env->GetObjectField( 1106 object, gPersistentSurfaceClassInfo.mLock); 1107 if (env->MonitorEnter(lock) == JNI_OK) { 1108 persistentSurface = reinterpret_cast<PersistentSurface *>( 1109 env->GetLongField( 1110 object, gPersistentSurfaceClassInfo.mPersistentObject)); 1111 env->SetLongField( 1112 object, 1113 gPersistentSurfaceClassInfo.mPersistentObject, 1114 (jlong)0); 1115 env->MonitorExit(lock); 1116 } 1117 env->DeleteLocalRef(lock); 1118 1119 if (persistentSurface != NULL) { 1120 persistentSurface->decStrong(&sRefBaseOwner); 1121 } 1122 // no need to release surface as it will be released by Surface's jni 1123 } 1124 1125 static void android_media_MediaCodec_setInputSurface( 1126 JNIEnv* env, jobject thiz, jobject object) { 1127 ALOGV("android_media_MediaCodec_setInputSurface"); 1128 1129 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1130 if (codec == NULL) { 1131 throwExceptionAsNecessary(env, INVALID_OPERATION); 1132 return; 1133 } 1134 1135 sp<PersistentSurface> persistentSurface = 1136 android_media_MediaCodec_getPersistentInputSurface(env, object); 1137 1138 status_t err = codec->setInputSurface(persistentSurface); 1139 if (err != NO_ERROR) { 1140 throwExceptionAsNecessary(env, err); 1141 } 1142 } 1143 1144 static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env, 1145 jobject thiz) { 1146 ALOGV("android_media_MediaCodec_createInputSurface"); 1147 1148 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1149 if (codec == NULL) { 1150 throwExceptionAsNecessary(env, INVALID_OPERATION); 1151 return NULL; 1152 } 1153 1154 // Tell the MediaCodec that we want to use a Surface as input. 1155 sp<IGraphicBufferProducer> bufferProducer; 1156 status_t err = codec->createInputSurface(&bufferProducer); 1157 if (err != NO_ERROR) { 1158 throwExceptionAsNecessary(env, err); 1159 return NULL; 1160 } 1161 1162 // Wrap the IGBP in a Java-language Surface. 1163 return android_view_Surface_createFromIGraphicBufferProducer(env, 1164 bufferProducer); 1165 } 1166 1167 static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) { 1168 ALOGV("android_media_MediaCodec_start"); 1169 1170 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1171 1172 if (codec == NULL) { 1173 throwExceptionAsNecessary(env, INVALID_OPERATION); 1174 return; 1175 } 1176 1177 status_t err = codec->start(); 1178 1179 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed"); 1180 } 1181 1182 static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) { 1183 ALOGV("android_media_MediaCodec_stop"); 1184 1185 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1186 1187 if (codec == NULL) { 1188 throwExceptionAsNecessary(env, INVALID_OPERATION); 1189 return; 1190 } 1191 1192 status_t err = codec->stop(); 1193 1194 throwExceptionAsNecessary(env, err); 1195 } 1196 1197 static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) { 1198 ALOGV("android_media_MediaCodec_reset"); 1199 1200 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1201 1202 if (codec == NULL) { 1203 throwExceptionAsNecessary(env, INVALID_OPERATION); 1204 return; 1205 } 1206 1207 status_t err = codec->reset(); 1208 if (err != OK) { 1209 // treat all errors as fatal for now, though resource not available 1210 // errors could be treated as transient. 1211 // we also should avoid sending INVALID_OPERATION here due to 1212 // the transitory nature of reset(), it should not inadvertently 1213 // trigger an IllegalStateException. 1214 err = UNKNOWN_ERROR; 1215 } 1216 throwExceptionAsNecessary(env, err); 1217 } 1218 1219 static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) { 1220 ALOGV("android_media_MediaCodec_flush"); 1221 1222 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1223 1224 if (codec == NULL) { 1225 throwExceptionAsNecessary(env, INVALID_OPERATION); 1226 return; 1227 } 1228 1229 status_t err = codec->flush(); 1230 1231 throwExceptionAsNecessary(env, err); 1232 } 1233 1234 static void android_media_MediaCodec_queueInputBuffer( 1235 JNIEnv *env, 1236 jobject thiz, 1237 jint index, 1238 jint offset, 1239 jint size, 1240 jlong timestampUs, 1241 jint flags) { 1242 ALOGV("android_media_MediaCodec_queueInputBuffer"); 1243 1244 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1245 1246 if (codec == NULL) { 1247 throwExceptionAsNecessary(env, INVALID_OPERATION); 1248 return; 1249 } 1250 1251 AString errorDetailMsg; 1252 1253 status_t err = codec->queueInputBuffer( 1254 index, offset, size, timestampUs, flags, &errorDetailMsg); 1255 1256 throwExceptionAsNecessary( 1257 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 1258 } 1259 1260 static void android_media_MediaCodec_queueSecureInputBuffer( 1261 JNIEnv *env, 1262 jobject thiz, 1263 jint index, 1264 jint offset, 1265 jobject cryptoInfoObj, 1266 jlong timestampUs, 1267 jint flags) { 1268 ALOGV("android_media_MediaCodec_queueSecureInputBuffer"); 1269 1270 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1271 1272 if (codec == NULL) { 1273 throwExceptionAsNecessary(env, INVALID_OPERATION); 1274 return; 1275 } 1276 1277 jint numSubSamples = 1278 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID); 1279 1280 jintArray numBytesOfClearDataObj = 1281 (jintArray)env->GetObjectField( 1282 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID); 1283 1284 jintArray numBytesOfEncryptedDataObj = 1285 (jintArray)env->GetObjectField( 1286 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID); 1287 1288 jbyteArray keyObj = 1289 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID); 1290 1291 jbyteArray ivObj = 1292 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID); 1293 1294 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID); 1295 enum CryptoPlugin::Mode mode; 1296 if (jmode == gCryptoModes.Unencrypted) { 1297 mode = CryptoPlugin::kMode_Unencrypted; 1298 } else if (jmode == gCryptoModes.AesCtr) { 1299 mode = CryptoPlugin::kMode_AES_CTR; 1300 } else if (jmode == gCryptoModes.AesCbc) { 1301 mode = CryptoPlugin::kMode_AES_CBC; 1302 } else { 1303 throwExceptionAsNecessary(env, INVALID_OPERATION); 1304 return; 1305 } 1306 1307 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID); 1308 1309 CryptoPlugin::Pattern pattern; 1310 if (patternObj == NULL) { 1311 pattern.mEncryptBlocks = 0; 1312 pattern.mSkipBlocks = 0; 1313 } else { 1314 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID); 1315 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID); 1316 } 1317 1318 status_t err = OK; 1319 1320 CryptoPlugin::SubSample *subSamples = NULL; 1321 jbyte *key = NULL; 1322 jbyte *iv = NULL; 1323 1324 if (numSubSamples <= 0) { 1325 err = -EINVAL; 1326 } else if (numBytesOfClearDataObj == NULL 1327 && numBytesOfEncryptedDataObj == NULL) { 1328 err = -EINVAL; 1329 } else if (numBytesOfEncryptedDataObj != NULL 1330 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) { 1331 err = -ERANGE; 1332 } else if (numBytesOfClearDataObj != NULL 1333 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) { 1334 err = -ERANGE; 1335 // subSamples array may silently overflow if number of samples are too large. Use 1336 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms 1337 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) { 1338 err = -EINVAL; 1339 } else { 1340 jboolean isCopy; 1341 1342 jint *numBytesOfClearData = 1343 (numBytesOfClearDataObj == NULL) 1344 ? NULL 1345 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy); 1346 1347 jint *numBytesOfEncryptedData = 1348 (numBytesOfEncryptedDataObj == NULL) 1349 ? NULL 1350 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); 1351 1352 subSamples = new CryptoPlugin::SubSample[numSubSamples]; 1353 1354 for (jint i = 0; i < numSubSamples; ++i) { 1355 subSamples[i].mNumBytesOfClearData = 1356 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i]; 1357 1358 subSamples[i].mNumBytesOfEncryptedData = 1359 (numBytesOfEncryptedData == NULL) 1360 ? 0 : numBytesOfEncryptedData[i]; 1361 } 1362 1363 if (numBytesOfEncryptedData != NULL) { 1364 env->ReleaseIntArrayElements( 1365 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0); 1366 numBytesOfEncryptedData = NULL; 1367 } 1368 1369 if (numBytesOfClearData != NULL) { 1370 env->ReleaseIntArrayElements( 1371 numBytesOfClearDataObj, numBytesOfClearData, 0); 1372 numBytesOfClearData = NULL; 1373 } 1374 } 1375 1376 if (err == OK && keyObj != NULL) { 1377 if (env->GetArrayLength(keyObj) != 16) { 1378 err = -EINVAL; 1379 } else { 1380 jboolean isCopy; 1381 key = env->GetByteArrayElements(keyObj, &isCopy); 1382 } 1383 } 1384 1385 if (err == OK && ivObj != NULL) { 1386 if (env->GetArrayLength(ivObj) != 16) { 1387 err = -EINVAL; 1388 } else { 1389 jboolean isCopy; 1390 iv = env->GetByteArrayElements(ivObj, &isCopy); 1391 } 1392 } 1393 1394 AString errorDetailMsg; 1395 1396 if (err == OK) { 1397 err = codec->queueSecureInputBuffer( 1398 index, offset, 1399 subSamples, numSubSamples, 1400 (const uint8_t *)key, (const uint8_t *)iv, 1401 mode, 1402 pattern, 1403 timestampUs, 1404 flags, 1405 &errorDetailMsg); 1406 } 1407 1408 if (iv != NULL) { 1409 env->ReleaseByteArrayElements(ivObj, iv, 0); 1410 iv = NULL; 1411 } 1412 1413 if (key != NULL) { 1414 env->ReleaseByteArrayElements(keyObj, key, 0); 1415 key = NULL; 1416 } 1417 1418 delete[] subSamples; 1419 subSamples = NULL; 1420 1421 throwExceptionAsNecessary( 1422 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 1423 } 1424 1425 static jint android_media_MediaCodec_dequeueInputBuffer( 1426 JNIEnv *env, jobject thiz, jlong timeoutUs) { 1427 ALOGV("android_media_MediaCodec_dequeueInputBuffer"); 1428 1429 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1430 1431 if (codec == NULL) { 1432 throwExceptionAsNecessary(env, INVALID_OPERATION); 1433 return -1; 1434 } 1435 1436 size_t index; 1437 status_t err = codec->dequeueInputBuffer(&index, timeoutUs); 1438 1439 if (err == OK) { 1440 return (jint) index; 1441 } 1442 1443 return throwExceptionAsNecessary(env, err); 1444 } 1445 1446 static jint android_media_MediaCodec_dequeueOutputBuffer( 1447 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) { 1448 ALOGV("android_media_MediaCodec_dequeueOutputBuffer"); 1449 1450 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1451 1452 if (codec == NULL) { 1453 throwExceptionAsNecessary(env, INVALID_OPERATION); 1454 return 0; 1455 } 1456 1457 size_t index; 1458 status_t err = codec->dequeueOutputBuffer( 1459 env, bufferInfo, &index, timeoutUs); 1460 1461 if (err == OK) { 1462 return (jint) index; 1463 } 1464 1465 return throwExceptionAsNecessary(env, err); 1466 } 1467 1468 static void android_media_MediaCodec_releaseOutputBuffer( 1469 JNIEnv *env, jobject thiz, 1470 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) { 1471 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease"); 1472 1473 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1474 1475 if (codec == NULL) { 1476 throwExceptionAsNecessary(env, INVALID_OPERATION); 1477 return; 1478 } 1479 1480 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs); 1481 1482 throwExceptionAsNecessary(env, err); 1483 } 1484 1485 static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env, 1486 jobject thiz) { 1487 ALOGV("android_media_MediaCodec_signalEndOfInputStream"); 1488 1489 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1490 if (codec == NULL) { 1491 throwExceptionAsNecessary(env, INVALID_OPERATION); 1492 return; 1493 } 1494 1495 status_t err = codec->signalEndOfInputStream(); 1496 1497 throwExceptionAsNecessary(env, err); 1498 } 1499 1500 static jobject android_media_MediaCodec_getFormatNative( 1501 JNIEnv *env, jobject thiz, jboolean input) { 1502 ALOGV("android_media_MediaCodec_getFormatNative"); 1503 1504 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1505 1506 if (codec == NULL) { 1507 throwExceptionAsNecessary(env, INVALID_OPERATION); 1508 return NULL; 1509 } 1510 1511 jobject format; 1512 status_t err = codec->getFormat(env, input, &format); 1513 1514 if (err == OK) { 1515 return format; 1516 } 1517 1518 throwExceptionAsNecessary(env, err); 1519 1520 return NULL; 1521 } 1522 1523 static jobject android_media_MediaCodec_getOutputFormatForIndexNative( 1524 JNIEnv *env, jobject thiz, jint index) { 1525 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative"); 1526 1527 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1528 1529 if (codec == NULL) { 1530 throwExceptionAsNecessary(env, INVALID_OPERATION); 1531 return NULL; 1532 } 1533 1534 jobject format; 1535 status_t err = codec->getOutputFormat(env, index, &format); 1536 1537 if (err == OK) { 1538 return format; 1539 } 1540 1541 throwExceptionAsNecessary(env, err); 1542 1543 return NULL; 1544 } 1545 1546 static jobjectArray android_media_MediaCodec_getBuffers( 1547 JNIEnv *env, jobject thiz, jboolean input) { 1548 ALOGV("android_media_MediaCodec_getBuffers"); 1549 1550 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1551 1552 if (codec == NULL) { 1553 throwExceptionAsNecessary(env, INVALID_OPERATION); 1554 return NULL; 1555 } 1556 1557 jobjectArray buffers; 1558 status_t err = codec->getBuffers(env, input, &buffers); 1559 1560 if (err == OK) { 1561 return buffers; 1562 } 1563 1564 // if we're out of memory, an exception was already thrown 1565 if (err != NO_MEMORY) { 1566 throwExceptionAsNecessary(env, err); 1567 } 1568 1569 return NULL; 1570 } 1571 1572 static jobject android_media_MediaCodec_getBuffer( 1573 JNIEnv *env, jobject thiz, jboolean input, jint index) { 1574 ALOGV("android_media_MediaCodec_getBuffer"); 1575 1576 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1577 1578 if (codec == NULL) { 1579 throwExceptionAsNecessary(env, INVALID_OPERATION); 1580 return NULL; 1581 } 1582 1583 jobject buffer; 1584 status_t err = codec->getBuffer(env, input, index, &buffer); 1585 1586 if (err == OK) { 1587 return buffer; 1588 } 1589 1590 // if we're out of memory, an exception was already thrown 1591 if (err != NO_MEMORY) { 1592 throwExceptionAsNecessary(env, err); 1593 } 1594 1595 return NULL; 1596 } 1597 1598 static jobject android_media_MediaCodec_getImage( 1599 JNIEnv *env, jobject thiz, jboolean input, jint index) { 1600 ALOGV("android_media_MediaCodec_getImage"); 1601 1602 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1603 1604 if (codec == NULL) { 1605 throwExceptionAsNecessary(env, INVALID_OPERATION); 1606 return NULL; 1607 } 1608 1609 jobject image; 1610 status_t err = codec->getImage(env, input, index, &image); 1611 1612 if (err == OK) { 1613 return image; 1614 } 1615 1616 // if we're out of memory, an exception was already thrown 1617 if (err != NO_MEMORY) { 1618 throwExceptionAsNecessary(env, err); 1619 } 1620 1621 return NULL; 1622 } 1623 1624 static jobject android_media_MediaCodec_getName( 1625 JNIEnv *env, jobject thiz) { 1626 ALOGV("android_media_MediaCodec_getName"); 1627 1628 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1629 1630 if (codec == NULL) { 1631 throwExceptionAsNecessary(env, INVALID_OPERATION); 1632 return NULL; 1633 } 1634 1635 jstring name; 1636 status_t err = codec->getName(env, &name); 1637 1638 if (err == OK) { 1639 return name; 1640 } 1641 1642 throwExceptionAsNecessary(env, err); 1643 1644 return NULL; 1645 } 1646 1647 static void android_media_MediaCodec_setParameters( 1648 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) { 1649 ALOGV("android_media_MediaCodec_setParameters"); 1650 1651 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1652 1653 if (codec == NULL) { 1654 throwExceptionAsNecessary(env, INVALID_OPERATION); 1655 return; 1656 } 1657 1658 sp<AMessage> params; 1659 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, ¶ms); 1660 1661 if (err == OK) { 1662 err = codec->setParameters(params); 1663 } 1664 1665 throwExceptionAsNecessary(env, err); 1666 } 1667 1668 static void android_media_MediaCodec_setVideoScalingMode( 1669 JNIEnv *env, jobject thiz, jint mode) { 1670 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1671 1672 if (codec == NULL) { 1673 throwExceptionAsNecessary(env, INVALID_OPERATION); 1674 return; 1675 } 1676 1677 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW 1678 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { 1679 jniThrowException(env, "java/lang/InvalidArgumentException", NULL); 1680 return; 1681 } 1682 1683 codec->setVideoScalingMode(mode); 1684 } 1685 1686 static void android_media_MediaCodec_native_init(JNIEnv *env) { 1687 ScopedLocalRef<jclass> clazz( 1688 env, env->FindClass("android/media/MediaCodec")); 1689 CHECK(clazz.get() != NULL); 1690 1691 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J"); 1692 CHECK(gFields.context != NULL); 1693 1694 gFields.postEventFromNativeID = 1695 env->GetMethodID( 1696 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V"); 1697 1698 CHECK(gFields.postEventFromNativeID != NULL); 1699 1700 jfieldID field; 1701 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I"); 1702 CHECK(field != NULL); 1703 gCryptoModes.Unencrypted = 1704 env->GetStaticIntField(clazz.get(), field); 1705 1706 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I"); 1707 CHECK(field != NULL); 1708 gCryptoModes.AesCtr = 1709 env->GetStaticIntField(clazz.get(), field); 1710 1711 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I"); 1712 CHECK(field != NULL); 1713 gCryptoModes.AesCbc = 1714 env->GetStaticIntField(clazz.get(), field); 1715 1716 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo")); 1717 CHECK(clazz.get() != NULL); 1718 1719 gFields.cryptoInfoNumSubSamplesID = 1720 env->GetFieldID(clazz.get(), "numSubSamples", "I"); 1721 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL); 1722 1723 gFields.cryptoInfoNumBytesOfClearDataID = 1724 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I"); 1725 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL); 1726 1727 gFields.cryptoInfoNumBytesOfEncryptedDataID = 1728 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I"); 1729 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL); 1730 1731 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B"); 1732 CHECK(gFields.cryptoInfoKeyID != NULL); 1733 1734 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B"); 1735 CHECK(gFields.cryptoInfoIVID != NULL); 1736 1737 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I"); 1738 CHECK(gFields.cryptoInfoModeID != NULL); 1739 1740 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "pattern", 1741 "Landroid/media/MediaCodec$CryptoInfo$Pattern;"); 1742 CHECK(gFields.cryptoInfoPatternID != NULL); 1743 1744 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern")); 1745 CHECK(clazz.get() != NULL); 1746 1747 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I"); 1748 CHECK(gFields.patternEncryptBlocksID != NULL); 1749 1750 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I"); 1751 CHECK(gFields.patternSkipBlocksID != NULL); 1752 1753 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException")); 1754 CHECK(clazz.get() != NULL); 1755 1756 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I"); 1757 CHECK(field != NULL); 1758 gCryptoErrorCodes.cryptoErrorNoKey = 1759 env->GetStaticIntField(clazz.get(), field); 1760 1761 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I"); 1762 CHECK(field != NULL); 1763 gCryptoErrorCodes.cryptoErrorKeyExpired = 1764 env->GetStaticIntField(clazz.get(), field); 1765 1766 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I"); 1767 CHECK(field != NULL); 1768 gCryptoErrorCodes.cryptoErrorResourceBusy = 1769 env->GetStaticIntField(clazz.get(), field); 1770 1771 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I"); 1772 CHECK(field != NULL); 1773 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection = 1774 env->GetStaticIntField(clazz.get(), field); 1775 1776 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I"); 1777 CHECK(field != NULL); 1778 gCryptoErrorCodes.cryptoErrorSessionNotOpened = 1779 env->GetStaticIntField(clazz.get(), field); 1780 1781 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I"); 1782 CHECK(field != NULL); 1783 gCryptoErrorCodes.cryptoErrorUnsupportedOperation = 1784 env->GetStaticIntField(clazz.get(), field); 1785 1786 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException")); 1787 CHECK(clazz.get() != NULL); 1788 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I"); 1789 CHECK(field != NULL); 1790 gCodecActionCodes.codecActionTransient = 1791 env->GetStaticIntField(clazz.get(), field); 1792 1793 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I"); 1794 CHECK(field != NULL); 1795 gCodecActionCodes.codecActionRecoverable = 1796 env->GetStaticIntField(clazz.get(), field); 1797 1798 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I"); 1799 CHECK(field != NULL); 1800 gCodecErrorCodes.errorInsufficientResource = 1801 env->GetStaticIntField(clazz.get(), field); 1802 1803 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I"); 1804 CHECK(field != NULL); 1805 gCodecErrorCodes.errorReclaimed = 1806 env->GetStaticIntField(clazz.get(), field); 1807 1808 clazz.reset(env->FindClass("android/view/Surface")); 1809 CHECK(clazz.get() != NULL); 1810 1811 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;"); 1812 CHECK(field != NULL); 1813 gPersistentSurfaceClassInfo.mLock = field; 1814 1815 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V"); 1816 CHECK(method != NULL); 1817 gPersistentSurfaceClassInfo.setNativeObjectLocked = method; 1818 1819 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface")); 1820 CHECK(clazz.get() != NULL); 1821 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get()); 1822 1823 method = env->GetMethodID(clazz.get(), "<init>", "()V"); 1824 CHECK(method != NULL); 1825 gPersistentSurfaceClassInfo.ctor = method; 1826 1827 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J"); 1828 CHECK(field != NULL); 1829 gPersistentSurfaceClassInfo.mPersistentObject = field; 1830 } 1831 1832 static void android_media_MediaCodec_native_setup( 1833 JNIEnv *env, jobject thiz, 1834 jstring name, jboolean nameIsType, jboolean encoder) { 1835 if (name == NULL) { 1836 jniThrowException(env, "java/lang/NullPointerException", NULL); 1837 return; 1838 } 1839 1840 const char *tmp = env->GetStringUTFChars(name, NULL); 1841 1842 if (tmp == NULL) { 1843 return; 1844 } 1845 1846 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder); 1847 1848 const status_t err = codec->initCheck(); 1849 if (err == NAME_NOT_FOUND) { 1850 // fail and do not try again. 1851 jniThrowException(env, "java/lang/IllegalArgumentException", 1852 String8::format("Failed to initialize %s, error %#x", tmp, err)); 1853 env->ReleaseStringUTFChars(name, tmp); 1854 return; 1855 } if (err == NO_MEMORY) { 1856 throwCodecException(env, err, ACTION_CODE_TRANSIENT, 1857 String8::format("Failed to initialize %s, error %#x", tmp, err)); 1858 env->ReleaseStringUTFChars(name, tmp); 1859 return; 1860 } else if (err != OK) { 1861 // believed possible to try again 1862 jniThrowException(env, "java/io/IOException", 1863 String8::format("Failed to find matching codec %s, error %#x", tmp, err)); 1864 env->ReleaseStringUTFChars(name, tmp); 1865 return; 1866 } 1867 1868 env->ReleaseStringUTFChars(name, tmp); 1869 1870 codec->registerSelf(); 1871 1872 setMediaCodec(env,thiz, codec); 1873 } 1874 1875 static void android_media_MediaCodec_native_finalize( 1876 JNIEnv *env, jobject thiz) { 1877 android_media_MediaCodec_release(env, thiz); 1878 } 1879 1880 static const JNINativeMethod gMethods[] = { 1881 { "native_release", "()V", (void *)android_media_MediaCodec_release }, 1882 1883 { "native_reset", "()V", (void *)android_media_MediaCodec_reset }, 1884 1885 { "native_releasePersistentInputSurface", 1886 "(Landroid/view/Surface;)V", 1887 (void *)android_media_MediaCodec_releasePersistentInputSurface}, 1888 1889 { "native_createPersistentInputSurface", 1890 "()Landroid/media/MediaCodec$PersistentSurface;", 1891 (void *)android_media_MediaCodec_createPersistentInputSurface }, 1892 1893 { "native_setInputSurface", "(Landroid/view/Surface;)V", 1894 (void *)android_media_MediaCodec_setInputSurface }, 1895 1896 { "native_enableOnFrameRenderedListener", "(Z)V", 1897 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener }, 1898 1899 { "native_setCallback", 1900 "(Landroid/media/MediaCodec$Callback;)V", 1901 (void *)android_media_MediaCodec_native_setCallback }, 1902 1903 { "native_configure", 1904 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;" 1905 "Landroid/media/MediaCrypto;I)V", 1906 (void *)android_media_MediaCodec_native_configure }, 1907 1908 { "native_setSurface", 1909 "(Landroid/view/Surface;)V", 1910 (void *)android_media_MediaCodec_native_setSurface }, 1911 1912 { "createInputSurface", "()Landroid/view/Surface;", 1913 (void *)android_media_MediaCodec_createInputSurface }, 1914 1915 { "native_start", "()V", (void *)android_media_MediaCodec_start }, 1916 { "native_stop", "()V", (void *)android_media_MediaCodec_stop }, 1917 { "native_flush", "()V", (void *)android_media_MediaCodec_flush }, 1918 1919 { "native_queueInputBuffer", "(IIIJI)V", 1920 (void *)android_media_MediaCodec_queueInputBuffer }, 1921 1922 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V", 1923 (void *)android_media_MediaCodec_queueSecureInputBuffer }, 1924 1925 { "native_dequeueInputBuffer", "(J)I", 1926 (void *)android_media_MediaCodec_dequeueInputBuffer }, 1927 1928 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", 1929 (void *)android_media_MediaCodec_dequeueOutputBuffer }, 1930 1931 { "releaseOutputBuffer", "(IZZJ)V", 1932 (void *)android_media_MediaCodec_releaseOutputBuffer }, 1933 1934 { "signalEndOfInputStream", "()V", 1935 (void *)android_media_MediaCodec_signalEndOfInputStream }, 1936 1937 { "getFormatNative", "(Z)Ljava/util/Map;", 1938 (void *)android_media_MediaCodec_getFormatNative }, 1939 1940 { "getOutputFormatNative", "(I)Ljava/util/Map;", 1941 (void *)android_media_MediaCodec_getOutputFormatForIndexNative }, 1942 1943 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;", 1944 (void *)android_media_MediaCodec_getBuffers }, 1945 1946 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;", 1947 (void *)android_media_MediaCodec_getBuffer }, 1948 1949 { "getImage", "(ZI)Landroid/media/Image;", 1950 (void *)android_media_MediaCodec_getImage }, 1951 1952 { "getName", "()Ljava/lang/String;", 1953 (void *)android_media_MediaCodec_getName }, 1954 1955 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V", 1956 (void *)android_media_MediaCodec_setParameters }, 1957 1958 { "setVideoScalingMode", "(I)V", 1959 (void *)android_media_MediaCodec_setVideoScalingMode }, 1960 1961 { "native_init", "()V", (void *)android_media_MediaCodec_native_init }, 1962 1963 { "native_setup", "(Ljava/lang/String;ZZ)V", 1964 (void *)android_media_MediaCodec_native_setup }, 1965 1966 { "native_finalize", "()V", 1967 (void *)android_media_MediaCodec_native_finalize }, 1968 }; 1969 1970 int register_android_media_MediaCodec(JNIEnv *env) { 1971 return AndroidRuntime::registerNativeMethods(env, 1972 "android/media/MediaCodec", gMethods, NELEM(gMethods)); 1973 } 1974