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