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 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 }; 60 61 static struct CryptoErrorCodes { 62 jint cryptoErrorNoKey; 63 jint cryptoErrorKeyExpired; 64 jint cryptoErrorResourceBusy; 65 jint cryptoErrorInsufficientOutputProtection; 66 } gCryptoErrorCodes; 67 68 static struct CodecActionCodes { 69 jint codecActionTransient; 70 jint codecActionRecoverable; 71 } gCodecActionCodes; 72 73 struct fields_t { 74 jfieldID context; 75 jmethodID postEventFromNativeID; 76 jfieldID cryptoInfoNumSubSamplesID; 77 jfieldID cryptoInfoNumBytesOfClearDataID; 78 jfieldID cryptoInfoNumBytesOfEncryptedDataID; 79 jfieldID cryptoInfoKeyID; 80 jfieldID cryptoInfoIVID; 81 jfieldID cryptoInfoModeID; 82 }; 83 84 static fields_t gFields; 85 86 //////////////////////////////////////////////////////////////////////////////// 87 88 JMediaCodec::JMediaCodec( 89 JNIEnv *env, jobject thiz, 90 const char *name, bool nameIsType, bool encoder) 91 : mClass(NULL), 92 mObject(NULL) { 93 jclass clazz = env->GetObjectClass(thiz); 94 CHECK(clazz != NULL); 95 96 mClass = (jclass)env->NewGlobalRef(clazz); 97 mObject = env->NewWeakGlobalRef(thiz); 98 99 cacheJavaObjects(env); 100 101 mLooper = new ALooper; 102 mLooper->setName("MediaCodec_looper"); 103 104 mLooper->start( 105 false, // runOnCallingThread 106 true, // canCallJava 107 PRIORITY_FOREGROUND); 108 109 if (nameIsType) { 110 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus); 111 } else { 112 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus); 113 } 114 CHECK((mCodec != NULL) != (mInitStatus != OK)); 115 } 116 117 void JMediaCodec::cacheJavaObjects(JNIEnv *env) { 118 jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer"); 119 mByteBufferClass = (jclass)env->NewGlobalRef(clazz); 120 CHECK(mByteBufferClass != NULL); 121 122 ScopedLocalRef<jclass> byteOrderClass( 123 env, env->FindClass("java/nio/ByteOrder")); 124 CHECK(byteOrderClass.get() != NULL); 125 126 jmethodID nativeOrderID = env->GetStaticMethodID( 127 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;"); 128 CHECK(nativeOrderID != NULL); 129 130 jobject nativeByteOrderObj = 131 env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID); 132 mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj); 133 CHECK(mNativeByteOrderObj != NULL); 134 env->DeleteLocalRef(nativeByteOrderObj); 135 nativeByteOrderObj = NULL; 136 137 mByteBufferOrderMethodID = env->GetMethodID( 138 mByteBufferClass, 139 "order", 140 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"); 141 CHECK(mByteBufferOrderMethodID != NULL); 142 143 mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID( 144 mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;"); 145 CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL); 146 147 mByteBufferPositionMethodID = env->GetMethodID( 148 mByteBufferClass, "position", "(I)Ljava/nio/Buffer;"); 149 CHECK(mByteBufferPositionMethodID != NULL); 150 151 mByteBufferLimitMethodID = env->GetMethodID( 152 mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;"); 153 CHECK(mByteBufferLimitMethodID != NULL); 154 } 155 156 status_t JMediaCodec::initCheck() const { 157 return mInitStatus; 158 } 159 160 void JMediaCodec::registerSelf() { 161 mLooper->registerHandler(this); 162 } 163 164 void JMediaCodec::release() { 165 if (mCodec != NULL) { 166 mCodec->release(); 167 mCodec.clear(); 168 mInitStatus = NO_INIT; 169 } 170 171 if (mLooper != NULL) { 172 mLooper->unregisterHandler(id()); 173 mLooper->stop(); 174 mLooper.clear(); 175 } 176 } 177 178 JMediaCodec::~JMediaCodec() { 179 if (mCodec != NULL || mLooper != NULL) { 180 /* MediaCodec and looper should have been released explicitly already 181 * in setMediaCodec() (see comments in setMediaCodec()). 182 * 183 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the 184 * message handler, doing release() there risks deadlock as MediaCodec:: 185 * release() post synchronous message to the same looper. 186 * 187 * Print a warning and try to proceed with releasing. 188 */ 189 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()..."); 190 release(); 191 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec()."); 192 } 193 194 JNIEnv *env = AndroidRuntime::getJNIEnv(); 195 196 env->DeleteWeakGlobalRef(mObject); 197 mObject = NULL; 198 env->DeleteGlobalRef(mClass); 199 mClass = NULL; 200 deleteJavaObjects(env); 201 } 202 203 void JMediaCodec::deleteJavaObjects(JNIEnv *env) { 204 env->DeleteGlobalRef(mByteBufferClass); 205 mByteBufferClass = NULL; 206 env->DeleteGlobalRef(mNativeByteOrderObj); 207 mNativeByteOrderObj = NULL; 208 209 mByteBufferOrderMethodID = NULL; 210 mByteBufferAsReadOnlyBufferMethodID = NULL; 211 mByteBufferPositionMethodID = NULL; 212 mByteBufferLimitMethodID = NULL; 213 } 214 215 status_t JMediaCodec::setCallback(jobject cb) { 216 if (cb != NULL) { 217 if (mCallbackNotification == NULL) { 218 mCallbackNotification = new AMessage(kWhatCallbackNotify, id()); 219 } 220 } else { 221 mCallbackNotification.clear(); 222 } 223 224 return mCodec->setCallback(mCallbackNotification); 225 } 226 227 status_t JMediaCodec::configure( 228 const sp<AMessage> &format, 229 const sp<IGraphicBufferProducer> &bufferProducer, 230 const sp<ICrypto> &crypto, 231 int flags) { 232 sp<Surface> client; 233 if (bufferProducer != NULL) { 234 mSurfaceTextureClient = 235 new Surface(bufferProducer, true /* controlledByApp */); 236 } else { 237 mSurfaceTextureClient.clear(); 238 } 239 240 return mCodec->configure(format, mSurfaceTextureClient, crypto, flags); 241 } 242 243 status_t JMediaCodec::createInputSurface( 244 sp<IGraphicBufferProducer>* bufferProducer) { 245 return mCodec->createInputSurface(bufferProducer); 246 } 247 248 status_t JMediaCodec::start() { 249 return mCodec->start(); 250 } 251 252 status_t JMediaCodec::stop() { 253 mSurfaceTextureClient.clear(); 254 255 return mCodec->stop(); 256 } 257 258 status_t JMediaCodec::flush() { 259 return mCodec->flush(); 260 } 261 262 status_t JMediaCodec::reset() { 263 return mCodec->reset(); 264 } 265 266 status_t JMediaCodec::queueInputBuffer( 267 size_t index, 268 size_t offset, size_t size, int64_t timeUs, uint32_t flags, 269 AString *errorDetailMsg) { 270 return mCodec->queueInputBuffer( 271 index, offset, size, timeUs, flags, errorDetailMsg); 272 } 273 274 status_t JMediaCodec::queueSecureInputBuffer( 275 size_t index, 276 size_t offset, 277 const CryptoPlugin::SubSample *subSamples, 278 size_t numSubSamples, 279 const uint8_t key[16], 280 const uint8_t iv[16], 281 CryptoPlugin::Mode mode, 282 int64_t presentationTimeUs, 283 uint32_t flags, 284 AString *errorDetailMsg) { 285 return mCodec->queueSecureInputBuffer( 286 index, offset, subSamples, numSubSamples, key, iv, mode, 287 presentationTimeUs, flags, errorDetailMsg); 288 } 289 290 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) { 291 return mCodec->dequeueInputBuffer(index, timeoutUs); 292 } 293 294 status_t JMediaCodec::dequeueOutputBuffer( 295 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) { 296 size_t size, offset; 297 int64_t timeUs; 298 uint32_t flags; 299 status_t err = mCodec->dequeueOutputBuffer( 300 index, &offset, &size, &timeUs, &flags, timeoutUs); 301 302 if (err != OK) { 303 return err; 304 } 305 306 ScopedLocalRef<jclass> clazz( 307 env, env->FindClass("android/media/MediaCodec$BufferInfo")); 308 309 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V"); 310 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags); 311 312 return OK; 313 } 314 315 status_t JMediaCodec::releaseOutputBuffer( 316 size_t index, bool render, bool updatePTS, int64_t timestampNs) { 317 if (updatePTS) { 318 return mCodec->renderOutputBufferAndRelease(index, timestampNs); 319 } 320 return render 321 ? mCodec->renderOutputBufferAndRelease(index) 322 : mCodec->releaseOutputBuffer(index); 323 } 324 325 status_t JMediaCodec::signalEndOfInputStream() { 326 return mCodec->signalEndOfInputStream(); 327 } 328 329 status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const { 330 sp<AMessage> msg; 331 status_t err; 332 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg); 333 if (err != OK) { 334 return err; 335 } 336 337 return ConvertMessageToMap(env, msg, format); 338 } 339 340 status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const { 341 sp<AMessage> msg; 342 status_t err; 343 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) { 344 return err; 345 } 346 347 return ConvertMessageToMap(env, msg, format); 348 } 349 350 status_t JMediaCodec::getBuffers( 351 JNIEnv *env, bool input, jobjectArray *bufArray) const { 352 Vector<sp<ABuffer> > buffers; 353 354 status_t err = 355 input 356 ? mCodec->getInputBuffers(&buffers) 357 : mCodec->getOutputBuffers(&buffers); 358 359 if (err != OK) { 360 return err; 361 } 362 363 *bufArray = (jobjectArray)env->NewObjectArray( 364 buffers.size(), mByteBufferClass, NULL); 365 if (*bufArray == NULL) { 366 return NO_MEMORY; 367 } 368 369 for (size_t i = 0; i < buffers.size(); ++i) { 370 const sp<ABuffer> &buffer = buffers.itemAt(i); 371 372 jobject byteBuffer = NULL; 373 err = createByteBufferFromABuffer( 374 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer); 375 if (err != OK) { 376 return err; 377 } 378 if (byteBuffer != NULL) { 379 env->SetObjectArrayElement( 380 *bufArray, i, byteBuffer); 381 382 env->DeleteLocalRef(byteBuffer); 383 byteBuffer = NULL; 384 } 385 } 386 387 return OK; 388 } 389 390 // static 391 status_t JMediaCodec::createByteBufferFromABuffer( 392 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer, 393 jobject *buf) const { 394 // if this is an ABuffer that doesn't actually hold any accessible memory, 395 // use a null ByteBuffer 396 *buf = NULL; 397 if (buffer->base() == NULL) { 398 return OK; 399 } 400 401 jobject byteBuffer = 402 env->NewDirectByteBuffer(buffer->base(), buffer->capacity()); 403 if (readOnly && byteBuffer != NULL) { 404 jobject readOnlyBuffer = env->CallObjectMethod( 405 byteBuffer, mByteBufferAsReadOnlyBufferMethodID); 406 env->DeleteLocalRef(byteBuffer); 407 byteBuffer = readOnlyBuffer; 408 } 409 if (byteBuffer == NULL) { 410 return NO_MEMORY; 411 } 412 jobject me = env->CallObjectMethod( 413 byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj); 414 env->DeleteLocalRef(me); 415 me = env->CallObjectMethod( 416 byteBuffer, mByteBufferLimitMethodID, 417 clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size())); 418 env->DeleteLocalRef(me); 419 me = env->CallObjectMethod( 420 byteBuffer, mByteBufferPositionMethodID, 421 clearBuffer ? 0 : buffer->offset()); 422 env->DeleteLocalRef(me); 423 me = NULL; 424 425 *buf = byteBuffer; 426 return OK; 427 } 428 429 status_t JMediaCodec::getBuffer( 430 JNIEnv *env, bool input, size_t index, jobject *buf) const { 431 sp<ABuffer> buffer; 432 433 status_t err = 434 input 435 ? mCodec->getInputBuffer(index, &buffer) 436 : mCodec->getOutputBuffer(index, &buffer); 437 438 if (err != OK) { 439 return err; 440 } 441 442 return createByteBufferFromABuffer( 443 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf); 444 } 445 446 status_t JMediaCodec::getImage( 447 JNIEnv *env, bool input, size_t index, jobject *buf) const { 448 sp<ABuffer> buffer; 449 450 status_t err = 451 input 452 ? mCodec->getInputBuffer(index, &buffer) 453 : mCodec->getOutputBuffer(index, &buffer); 454 455 if (err != OK) { 456 return err; 457 } 458 459 // if this is an ABuffer that doesn't actually hold any accessible memory, 460 // use a null ByteBuffer 461 *buf = NULL; 462 if (buffer->base() == NULL) { 463 return OK; 464 } 465 466 // check if buffer is an image 467 sp<ABuffer> imageData; 468 if (!buffer->meta()->findBuffer("image-data", &imageData)) { 469 return OK; 470 } 471 472 int64_t timestamp = 0; 473 if (!input && buffer->meta()->findInt64("timeUs", ×tamp)) { 474 timestamp *= 1000; // adjust to ns 475 } 476 477 jobject byteBuffer = NULL; 478 err = createByteBufferFromABuffer( 479 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer); 480 if (err != OK) { 481 return OK; 482 } 483 484 jobject infoBuffer = NULL; 485 err = createByteBufferFromABuffer( 486 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer); 487 if (err != OK) { 488 env->DeleteLocalRef(byteBuffer); 489 byteBuffer = NULL; 490 return OK; 491 } 492 493 jobject cropRect = NULL; 494 int32_t left, top, right, bottom; 495 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) { 496 ScopedLocalRef<jclass> rectClazz( 497 env, env->FindClass("android/graphics/Rect")); 498 CHECK(rectClazz.get() != NULL); 499 500 jmethodID rectConstructID = env->GetMethodID( 501 rectClazz.get(), "<init>", "(IIII)V"); 502 503 cropRect = env->NewObject( 504 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1); 505 } 506 507 ScopedLocalRef<jclass> imageClazz( 508 env, env->FindClass("android/media/MediaCodec$MediaImage")); 509 CHECK(imageClazz.get() != NULL); 510 511 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>", 512 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V"); 513 514 *buf = env->NewObject(imageClazz.get(), imageConstructID, 515 byteBuffer, infoBuffer, 516 (jboolean)!input /* readOnly */, 517 (jlong)timestamp, 518 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect); 519 520 // if MediaImage creation fails, return null 521 if (env->ExceptionCheck()) { 522 env->ExceptionDescribe(); 523 env->ExceptionClear(); 524 *buf = NULL; 525 } 526 527 if (cropRect != NULL) { 528 env->DeleteLocalRef(cropRect); 529 cropRect = NULL; 530 } 531 532 env->DeleteLocalRef(byteBuffer); 533 byteBuffer = NULL; 534 535 env->DeleteLocalRef(infoBuffer); 536 infoBuffer = NULL; 537 538 return OK; 539 } 540 541 status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const { 542 AString name; 543 544 status_t err = mCodec->getName(&name); 545 546 if (err != OK) { 547 return err; 548 } 549 550 *nameStr = env->NewStringUTF(name.c_str()); 551 552 return OK; 553 } 554 555 status_t JMediaCodec::setParameters(const sp<AMessage> &msg) { 556 return mCodec->setParameters(msg); 557 } 558 559 void JMediaCodec::setVideoScalingMode(int mode) { 560 if (mSurfaceTextureClient != NULL) { 561 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode); 562 } 563 } 564 565 static jthrowable createCodecException( 566 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) { 567 ScopedLocalRef<jclass> clazz( 568 env, env->FindClass("android/media/MediaCodec$CodecException")); 569 CHECK(clazz.get() != NULL); 570 571 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V"); 572 CHECK(ctor != NULL); 573 574 ScopedLocalRef<jstring> msgObj( 575 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err))); 576 577 // translate action code to Java equivalent 578 switch (actionCode) { 579 case ACTION_CODE_TRANSIENT: 580 actionCode = gCodecActionCodes.codecActionTransient; 581 break; 582 case ACTION_CODE_RECOVERABLE: 583 actionCode = gCodecActionCodes.codecActionRecoverable; 584 break; 585 default: 586 actionCode = 0; // everything else is fatal 587 break; 588 } 589 590 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get()); 591 } 592 593 void JMediaCodec::handleCallback(const sp<AMessage> &msg) { 594 int32_t arg1, arg2 = 0; 595 jobject obj = NULL; 596 CHECK(msg->findInt32("callbackID", &arg1)); 597 JNIEnv *env = AndroidRuntime::getJNIEnv(); 598 599 switch (arg1) { 600 case MediaCodec::CB_INPUT_AVAILABLE: 601 { 602 CHECK(msg->findInt32("index", &arg2)); 603 break; 604 } 605 606 case MediaCodec::CB_OUTPUT_AVAILABLE: 607 { 608 CHECK(msg->findInt32("index", &arg2)); 609 610 size_t size, offset; 611 int64_t timeUs; 612 uint32_t flags; 613 CHECK(msg->findSize("size", &size)); 614 CHECK(msg->findSize("offset", &offset)); 615 CHECK(msg->findInt64("timeUs", &timeUs)); 616 CHECK(msg->findInt32("flags", (int32_t *)&flags)); 617 618 ScopedLocalRef<jclass> clazz( 619 env, env->FindClass("android/media/MediaCodec$BufferInfo")); 620 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V"); 621 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V"); 622 623 obj = env->NewObject(clazz.get(), ctor); 624 625 if (obj == NULL) { 626 if (env->ExceptionCheck()) { 627 ALOGE("Could not create MediaCodec.BufferInfo."); 628 env->ExceptionClear(); 629 } 630 jniThrowException(env, "java/lang/IllegalStateException", NULL); 631 return; 632 } 633 634 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags); 635 break; 636 } 637 638 case MediaCodec::CB_ERROR: 639 { 640 int32_t err, actionCode; 641 CHECK(msg->findInt32("err", &err)); 642 CHECK(msg->findInt32("actionCode", &actionCode)); 643 644 // note that DRM errors could conceivably alias into a CodecException 645 obj = (jobject)createCodecException(env, err, actionCode); 646 647 if (obj == NULL) { 648 if (env->ExceptionCheck()) { 649 ALOGE("Could not create CodecException object."); 650 env->ExceptionClear(); 651 } 652 jniThrowException(env, "java/lang/IllegalStateException", NULL); 653 return; 654 } 655 656 break; 657 } 658 659 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED: 660 { 661 sp<AMessage> format; 662 CHECK(msg->findMessage("format", &format)); 663 664 if (OK != ConvertMessageToMap(env, format, &obj)) { 665 jniThrowException(env, "java/lang/IllegalStateException", NULL); 666 return; 667 } 668 669 break; 670 } 671 672 default: 673 TRESPASS(); 674 } 675 676 env->CallVoidMethod( 677 mObject, 678 gFields.postEventFromNativeID, 679 EVENT_CALLBACK, 680 arg1, 681 arg2, 682 obj); 683 684 env->DeleteLocalRef(obj); 685 } 686 687 void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) { 688 switch (msg->what()) { 689 case kWhatCallbackNotify: 690 { 691 handleCallback(msg); 692 break; 693 } 694 default: 695 TRESPASS(); 696 } 697 } 698 699 } // namespace android 700 701 //////////////////////////////////////////////////////////////////////////////// 702 703 using namespace android; 704 705 static sp<JMediaCodec> setMediaCodec( 706 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) { 707 sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context); 708 if (codec != NULL) { 709 codec->incStrong(thiz); 710 } 711 if (old != NULL) { 712 /* release MediaCodec and stop the looper now before decStrong. 713 * otherwise JMediaCodec::~JMediaCodec() could be called from within 714 * its message handler, doing release() from there will deadlock 715 * (as MediaCodec::release() post synchronous message to the same looper) 716 */ 717 old->release(); 718 old->decStrong(thiz); 719 } 720 env->SetLongField(thiz, gFields.context, (jlong)codec.get()); 721 722 return old; 723 } 724 725 static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) { 726 return (JMediaCodec *)env->GetLongField(thiz, gFields.context); 727 } 728 729 static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) { 730 setMediaCodec(env, thiz, NULL); 731 } 732 733 static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) { 734 jthrowable exception = createCodecException(env, err, actionCode, msg); 735 env->Throw(exception); 736 } 737 738 static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) { 739 ScopedLocalRef<jclass> clazz( 740 env, env->FindClass("android/media/MediaCodec$CryptoException")); 741 CHECK(clazz.get() != NULL); 742 743 jmethodID constructID = 744 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V"); 745 CHECK(constructID != NULL); 746 747 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error"); 748 749 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */ 750 switch (err) { 751 case ERROR_DRM_NO_LICENSE: 752 err = gCryptoErrorCodes.cryptoErrorNoKey; 753 break; 754 case ERROR_DRM_LICENSE_EXPIRED: 755 err = gCryptoErrorCodes.cryptoErrorKeyExpired; 756 break; 757 case ERROR_DRM_RESOURCE_BUSY: 758 err = gCryptoErrorCodes.cryptoErrorResourceBusy; 759 break; 760 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION: 761 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection; 762 break; 763 default: /* Other negative DRM error codes go out as is. */ 764 break; 765 } 766 767 jthrowable exception = 768 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj); 769 770 env->Throw(exception); 771 } 772 773 static jint throwExceptionAsNecessary( 774 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL, 775 const char *msg = NULL) { 776 switch (err) { 777 case OK: 778 return 0; 779 780 case -EAGAIN: 781 return DEQUEUE_INFO_TRY_AGAIN_LATER; 782 783 case INFO_FORMAT_CHANGED: 784 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED; 785 786 case INFO_OUTPUT_BUFFERS_CHANGED: 787 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED; 788 789 case INVALID_OPERATION: 790 jniThrowException(env, "java/lang/IllegalStateException", msg); 791 return 0; 792 793 default: 794 if (isCryptoError(err)) { 795 throwCryptoException(env, err, msg); 796 return 0; 797 } 798 throwCodecException(env, err, actionCode, msg); 799 return 0; 800 } 801 } 802 803 static void android_media_MediaCodec_native_setCallback( 804 JNIEnv *env, 805 jobject thiz, 806 jobject cb) { 807 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 808 809 if (codec == NULL) { 810 throwExceptionAsNecessary(env, INVALID_OPERATION); 811 return; 812 } 813 814 status_t err = codec->setCallback(cb); 815 816 throwExceptionAsNecessary(env, err); 817 } 818 819 static void android_media_MediaCodec_native_configure( 820 JNIEnv *env, 821 jobject thiz, 822 jobjectArray keys, jobjectArray values, 823 jobject jsurface, 824 jobject jcrypto, 825 jint flags) { 826 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 827 828 if (codec == NULL) { 829 throwExceptionAsNecessary(env, INVALID_OPERATION); 830 return; 831 } 832 833 sp<AMessage> format; 834 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format); 835 836 if (err != OK) { 837 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 838 return; 839 } 840 841 sp<IGraphicBufferProducer> bufferProducer; 842 if (jsurface != NULL) { 843 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 844 if (surface != NULL) { 845 bufferProducer = surface->getIGraphicBufferProducer(); 846 } else { 847 jniThrowException( 848 env, 849 "java/lang/IllegalArgumentException", 850 "The surface has been released"); 851 return; 852 } 853 } 854 855 sp<ICrypto> crypto; 856 if (jcrypto != NULL) { 857 crypto = JCrypto::GetCrypto(env, jcrypto); 858 } 859 860 err = codec->configure(format, bufferProducer, crypto, flags); 861 862 throwExceptionAsNecessary(env, err); 863 } 864 865 static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env, 866 jobject thiz) { 867 ALOGV("android_media_MediaCodec_createInputSurface"); 868 869 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 870 if (codec == NULL) { 871 throwExceptionAsNecessary(env, INVALID_OPERATION); 872 return NULL; 873 } 874 875 // Tell the MediaCodec that we want to use a Surface as input. 876 sp<IGraphicBufferProducer> bufferProducer; 877 status_t err = codec->createInputSurface(&bufferProducer); 878 if (err != NO_ERROR) { 879 throwExceptionAsNecessary(env, err); 880 return NULL; 881 } 882 883 // Wrap the IGBP in a Java-language Surface. 884 return android_view_Surface_createFromIGraphicBufferProducer(env, 885 bufferProducer); 886 } 887 888 static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) { 889 ALOGV("android_media_MediaCodec_start"); 890 891 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 892 893 if (codec == NULL) { 894 throwExceptionAsNecessary(env, INVALID_OPERATION); 895 return; 896 } 897 898 status_t err = codec->start(); 899 900 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed"); 901 } 902 903 static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) { 904 ALOGV("android_media_MediaCodec_stop"); 905 906 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 907 908 if (codec == NULL) { 909 throwExceptionAsNecessary(env, INVALID_OPERATION); 910 return; 911 } 912 913 status_t err = codec->stop(); 914 915 throwExceptionAsNecessary(env, err); 916 } 917 918 static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) { 919 ALOGV("android_media_MediaCodec_reset"); 920 921 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 922 923 if (codec == NULL) { 924 throwExceptionAsNecessary(env, INVALID_OPERATION); 925 return; 926 } 927 928 status_t err = codec->reset(); 929 if (err != OK) { 930 // treat all errors as fatal for now, though resource not available 931 // errors could be treated as transient. 932 // we also should avoid sending INVALID_OPERATION here due to 933 // the transitory nature of reset(), it should not inadvertently 934 // trigger an IllegalStateException. 935 err = UNKNOWN_ERROR; 936 } 937 throwExceptionAsNecessary(env, err); 938 } 939 940 static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) { 941 ALOGV("android_media_MediaCodec_flush"); 942 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->flush(); 951 952 throwExceptionAsNecessary(env, err); 953 } 954 955 static void android_media_MediaCodec_queueInputBuffer( 956 JNIEnv *env, 957 jobject thiz, 958 jint index, 959 jint offset, 960 jint size, 961 jlong timestampUs, 962 jint flags) { 963 ALOGV("android_media_MediaCodec_queueInputBuffer"); 964 965 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 966 967 if (codec == NULL) { 968 throwExceptionAsNecessary(env, INVALID_OPERATION); 969 return; 970 } 971 972 AString errorDetailMsg; 973 974 status_t err = codec->queueInputBuffer( 975 index, offset, size, timestampUs, flags, &errorDetailMsg); 976 977 throwExceptionAsNecessary( 978 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 979 } 980 981 static void android_media_MediaCodec_queueSecureInputBuffer( 982 JNIEnv *env, 983 jobject thiz, 984 jint index, 985 jint offset, 986 jobject cryptoInfoObj, 987 jlong timestampUs, 988 jint flags) { 989 ALOGV("android_media_MediaCodec_queueSecureInputBuffer"); 990 991 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 992 993 if (codec == NULL) { 994 throwExceptionAsNecessary(env, INVALID_OPERATION); 995 return; 996 } 997 998 jint numSubSamples = 999 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID); 1000 1001 jintArray numBytesOfClearDataObj = 1002 (jintArray)env->GetObjectField( 1003 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID); 1004 1005 jintArray numBytesOfEncryptedDataObj = 1006 (jintArray)env->GetObjectField( 1007 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID); 1008 1009 jbyteArray keyObj = 1010 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID); 1011 1012 jbyteArray ivObj = 1013 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID); 1014 1015 jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID); 1016 1017 status_t err = OK; 1018 1019 CryptoPlugin::SubSample *subSamples = NULL; 1020 jbyte *key = NULL; 1021 jbyte *iv = NULL; 1022 1023 if (numSubSamples <= 0) { 1024 err = -EINVAL; 1025 } else if (numBytesOfClearDataObj == NULL 1026 && numBytesOfEncryptedDataObj == NULL) { 1027 err = -EINVAL; 1028 } else if (numBytesOfEncryptedDataObj != NULL 1029 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) { 1030 err = -ERANGE; 1031 } else if (numBytesOfClearDataObj != NULL 1032 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) { 1033 err = -ERANGE; 1034 // subSamples array may silently overflow if number of samples are too large. Use 1035 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms 1036 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) { 1037 err = -EINVAL; 1038 } else { 1039 jboolean isCopy; 1040 1041 jint *numBytesOfClearData = 1042 (numBytesOfClearDataObj == NULL) 1043 ? NULL 1044 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy); 1045 1046 jint *numBytesOfEncryptedData = 1047 (numBytesOfEncryptedDataObj == NULL) 1048 ? NULL 1049 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); 1050 1051 subSamples = new CryptoPlugin::SubSample[numSubSamples]; 1052 1053 for (jint i = 0; i < numSubSamples; ++i) { 1054 subSamples[i].mNumBytesOfClearData = 1055 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i]; 1056 1057 subSamples[i].mNumBytesOfEncryptedData = 1058 (numBytesOfEncryptedData == NULL) 1059 ? 0 : numBytesOfEncryptedData[i]; 1060 } 1061 1062 if (numBytesOfEncryptedData != NULL) { 1063 env->ReleaseIntArrayElements( 1064 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0); 1065 numBytesOfEncryptedData = NULL; 1066 } 1067 1068 if (numBytesOfClearData != NULL) { 1069 env->ReleaseIntArrayElements( 1070 numBytesOfClearDataObj, numBytesOfClearData, 0); 1071 numBytesOfClearData = NULL; 1072 } 1073 } 1074 1075 if (err == OK && keyObj != NULL) { 1076 if (env->GetArrayLength(keyObj) != 16) { 1077 err = -EINVAL; 1078 } else { 1079 jboolean isCopy; 1080 key = env->GetByteArrayElements(keyObj, &isCopy); 1081 } 1082 } 1083 1084 if (err == OK && ivObj != NULL) { 1085 if (env->GetArrayLength(ivObj) != 16) { 1086 err = -EINVAL; 1087 } else { 1088 jboolean isCopy; 1089 iv = env->GetByteArrayElements(ivObj, &isCopy); 1090 } 1091 } 1092 1093 AString errorDetailMsg; 1094 1095 if (err == OK) { 1096 err = codec->queueSecureInputBuffer( 1097 index, offset, 1098 subSamples, numSubSamples, 1099 (const uint8_t *)key, (const uint8_t *)iv, 1100 (CryptoPlugin::Mode)mode, 1101 timestampUs, 1102 flags, 1103 &errorDetailMsg); 1104 } 1105 1106 if (iv != NULL) { 1107 env->ReleaseByteArrayElements(ivObj, iv, 0); 1108 iv = NULL; 1109 } 1110 1111 if (key != NULL) { 1112 env->ReleaseByteArrayElements(keyObj, key, 0); 1113 key = NULL; 1114 } 1115 1116 delete[] subSamples; 1117 subSamples = NULL; 1118 1119 throwExceptionAsNecessary( 1120 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 1121 } 1122 1123 static jint android_media_MediaCodec_dequeueInputBuffer( 1124 JNIEnv *env, jobject thiz, jlong timeoutUs) { 1125 ALOGV("android_media_MediaCodec_dequeueInputBuffer"); 1126 1127 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1128 1129 if (codec == NULL) { 1130 throwExceptionAsNecessary(env, INVALID_OPERATION); 1131 return -1; 1132 } 1133 1134 size_t index; 1135 status_t err = codec->dequeueInputBuffer(&index, timeoutUs); 1136 1137 if (err == OK) { 1138 return (jint) index; 1139 } 1140 1141 return throwExceptionAsNecessary(env, err); 1142 } 1143 1144 static jint android_media_MediaCodec_dequeueOutputBuffer( 1145 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) { 1146 ALOGV("android_media_MediaCodec_dequeueOutputBuffer"); 1147 1148 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1149 1150 if (codec == NULL) { 1151 throwExceptionAsNecessary(env, INVALID_OPERATION); 1152 return 0; 1153 } 1154 1155 size_t index; 1156 status_t err = codec->dequeueOutputBuffer( 1157 env, bufferInfo, &index, timeoutUs); 1158 1159 if (err == OK) { 1160 return (jint) index; 1161 } 1162 1163 return throwExceptionAsNecessary(env, err); 1164 } 1165 1166 static void android_media_MediaCodec_releaseOutputBuffer( 1167 JNIEnv *env, jobject thiz, 1168 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) { 1169 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease"); 1170 1171 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1172 1173 if (codec == NULL) { 1174 throwExceptionAsNecessary(env, INVALID_OPERATION); 1175 return; 1176 } 1177 1178 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs); 1179 1180 throwExceptionAsNecessary(env, err); 1181 } 1182 1183 static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env, 1184 jobject thiz) { 1185 ALOGV("android_media_MediaCodec_signalEndOfInputStream"); 1186 1187 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1188 if (codec == NULL) { 1189 throwExceptionAsNecessary(env, INVALID_OPERATION); 1190 return; 1191 } 1192 1193 status_t err = codec->signalEndOfInputStream(); 1194 1195 throwExceptionAsNecessary(env, err); 1196 } 1197 1198 static jobject android_media_MediaCodec_getFormatNative( 1199 JNIEnv *env, jobject thiz, jboolean input) { 1200 ALOGV("android_media_MediaCodec_getFormatNative"); 1201 1202 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1203 1204 if (codec == NULL) { 1205 throwExceptionAsNecessary(env, INVALID_OPERATION); 1206 return NULL; 1207 } 1208 1209 jobject format; 1210 status_t err = codec->getFormat(env, input, &format); 1211 1212 if (err == OK) { 1213 return format; 1214 } 1215 1216 throwExceptionAsNecessary(env, err); 1217 1218 return NULL; 1219 } 1220 1221 static jobject android_media_MediaCodec_getOutputFormatForIndexNative( 1222 JNIEnv *env, jobject thiz, jint index) { 1223 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative"); 1224 1225 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1226 1227 if (codec == NULL) { 1228 throwExceptionAsNecessary(env, INVALID_OPERATION); 1229 return NULL; 1230 } 1231 1232 jobject format; 1233 status_t err = codec->getOutputFormat(env, index, &format); 1234 1235 if (err == OK) { 1236 return format; 1237 } 1238 1239 throwExceptionAsNecessary(env, err); 1240 1241 return NULL; 1242 } 1243 1244 static jobjectArray android_media_MediaCodec_getBuffers( 1245 JNIEnv *env, jobject thiz, jboolean input) { 1246 ALOGV("android_media_MediaCodec_getBuffers"); 1247 1248 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1249 1250 if (codec == NULL) { 1251 throwExceptionAsNecessary(env, INVALID_OPERATION); 1252 return NULL; 1253 } 1254 1255 jobjectArray buffers; 1256 status_t err = codec->getBuffers(env, input, &buffers); 1257 1258 if (err == OK) { 1259 return buffers; 1260 } 1261 1262 // if we're out of memory, an exception was already thrown 1263 if (err != NO_MEMORY) { 1264 throwExceptionAsNecessary(env, err); 1265 } 1266 1267 return NULL; 1268 } 1269 1270 static jobject android_media_MediaCodec_getBuffer( 1271 JNIEnv *env, jobject thiz, jboolean input, jint index) { 1272 ALOGV("android_media_MediaCodec_getBuffer"); 1273 1274 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1275 1276 if (codec == NULL) { 1277 throwExceptionAsNecessary(env, INVALID_OPERATION); 1278 return NULL; 1279 } 1280 1281 jobject buffer; 1282 status_t err = codec->getBuffer(env, input, index, &buffer); 1283 1284 if (err == OK) { 1285 return buffer; 1286 } 1287 1288 // if we're out of memory, an exception was already thrown 1289 if (err != NO_MEMORY) { 1290 throwExceptionAsNecessary(env, err); 1291 } 1292 1293 return NULL; 1294 } 1295 1296 static jobject android_media_MediaCodec_getImage( 1297 JNIEnv *env, jobject thiz, jboolean input, jint index) { 1298 ALOGV("android_media_MediaCodec_getImage"); 1299 1300 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1301 1302 if (codec == NULL) { 1303 throwExceptionAsNecessary(env, INVALID_OPERATION); 1304 return NULL; 1305 } 1306 1307 jobject image; 1308 status_t err = codec->getImage(env, input, index, &image); 1309 1310 if (err == OK) { 1311 return image; 1312 } 1313 1314 // if we're out of memory, an exception was already thrown 1315 if (err != NO_MEMORY) { 1316 throwExceptionAsNecessary(env, err); 1317 } 1318 1319 return NULL; 1320 } 1321 1322 static jobject android_media_MediaCodec_getName( 1323 JNIEnv *env, jobject thiz) { 1324 ALOGV("android_media_MediaCodec_getName"); 1325 1326 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1327 1328 if (codec == NULL) { 1329 throwExceptionAsNecessary(env, INVALID_OPERATION); 1330 return NULL; 1331 } 1332 1333 jstring name; 1334 status_t err = codec->getName(env, &name); 1335 1336 if (err == OK) { 1337 return name; 1338 } 1339 1340 throwExceptionAsNecessary(env, err); 1341 1342 return NULL; 1343 } 1344 1345 static void android_media_MediaCodec_setParameters( 1346 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) { 1347 ALOGV("android_media_MediaCodec_setParameters"); 1348 1349 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1350 1351 if (codec == NULL) { 1352 throwExceptionAsNecessary(env, INVALID_OPERATION); 1353 return; 1354 } 1355 1356 sp<AMessage> params; 1357 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, ¶ms); 1358 1359 if (err == OK) { 1360 err = codec->setParameters(params); 1361 } 1362 1363 throwExceptionAsNecessary(env, err); 1364 } 1365 1366 static void android_media_MediaCodec_setVideoScalingMode( 1367 JNIEnv *env, jobject thiz, jint mode) { 1368 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1369 1370 if (codec == NULL) { 1371 throwExceptionAsNecessary(env, INVALID_OPERATION); 1372 return; 1373 } 1374 1375 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW 1376 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { 1377 jniThrowException(env, "java/lang/InvalidArgumentException", NULL); 1378 return; 1379 } 1380 1381 codec->setVideoScalingMode(mode); 1382 } 1383 1384 static void android_media_MediaCodec_native_init(JNIEnv *env) { 1385 ScopedLocalRef<jclass> clazz( 1386 env, env->FindClass("android/media/MediaCodec")); 1387 CHECK(clazz.get() != NULL); 1388 1389 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J"); 1390 CHECK(gFields.context != NULL); 1391 1392 gFields.postEventFromNativeID = 1393 env->GetMethodID( 1394 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V"); 1395 1396 CHECK(gFields.postEventFromNativeID != NULL); 1397 1398 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo")); 1399 CHECK(clazz.get() != NULL); 1400 1401 gFields.cryptoInfoNumSubSamplesID = 1402 env->GetFieldID(clazz.get(), "numSubSamples", "I"); 1403 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL); 1404 1405 gFields.cryptoInfoNumBytesOfClearDataID = 1406 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I"); 1407 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL); 1408 1409 gFields.cryptoInfoNumBytesOfEncryptedDataID = 1410 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I"); 1411 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL); 1412 1413 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B"); 1414 CHECK(gFields.cryptoInfoKeyID != NULL); 1415 1416 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B"); 1417 CHECK(gFields.cryptoInfoIVID != NULL); 1418 1419 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I"); 1420 CHECK(gFields.cryptoInfoModeID != NULL); 1421 1422 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException")); 1423 CHECK(clazz.get() != NULL); 1424 1425 jfieldID field; 1426 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I"); 1427 CHECK(field != NULL); 1428 gCryptoErrorCodes.cryptoErrorNoKey = 1429 env->GetStaticIntField(clazz.get(), field); 1430 1431 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I"); 1432 CHECK(field != NULL); 1433 gCryptoErrorCodes.cryptoErrorKeyExpired = 1434 env->GetStaticIntField(clazz.get(), field); 1435 1436 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I"); 1437 CHECK(field != NULL); 1438 gCryptoErrorCodes.cryptoErrorResourceBusy = 1439 env->GetStaticIntField(clazz.get(), field); 1440 1441 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I"); 1442 CHECK(field != NULL); 1443 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection = 1444 env->GetStaticIntField(clazz.get(), field); 1445 1446 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException")); 1447 CHECK(clazz.get() != NULL); 1448 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I"); 1449 CHECK(field != NULL); 1450 gCodecActionCodes.codecActionTransient = 1451 env->GetStaticIntField(clazz.get(), field); 1452 1453 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I"); 1454 CHECK(field != NULL); 1455 gCodecActionCodes.codecActionRecoverable = 1456 env->GetStaticIntField(clazz.get(), field); 1457 } 1458 1459 static void android_media_MediaCodec_native_setup( 1460 JNIEnv *env, jobject thiz, 1461 jstring name, jboolean nameIsType, jboolean encoder) { 1462 if (name == NULL) { 1463 jniThrowException(env, "java/lang/NullPointerException", NULL); 1464 return; 1465 } 1466 1467 const char *tmp = env->GetStringUTFChars(name, NULL); 1468 1469 if (tmp == NULL) { 1470 return; 1471 } 1472 1473 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder); 1474 1475 const status_t err = codec->initCheck(); 1476 if (err == NAME_NOT_FOUND) { 1477 // fail and do not try again. 1478 jniThrowException(env, "java/lang/IllegalArgumentException", 1479 String8::format("Failed to initialize %s, error %#x", tmp, err)); 1480 env->ReleaseStringUTFChars(name, tmp); 1481 return; 1482 } else if (err != OK) { 1483 // believed possible to try again 1484 jniThrowException(env, "java/io/IOException", 1485 String8::format("Failed to find matching codec %s, error %#x", tmp, err)); 1486 env->ReleaseStringUTFChars(name, tmp); 1487 return; 1488 } 1489 1490 env->ReleaseStringUTFChars(name, tmp); 1491 1492 codec->registerSelf(); 1493 1494 setMediaCodec(env,thiz, codec); 1495 } 1496 1497 static void android_media_MediaCodec_native_finalize( 1498 JNIEnv *env, jobject thiz) { 1499 android_media_MediaCodec_release(env, thiz); 1500 } 1501 1502 static JNINativeMethod gMethods[] = { 1503 { "native_release", "()V", (void *)android_media_MediaCodec_release }, 1504 1505 { "native_reset", "()V", (void *)android_media_MediaCodec_reset }, 1506 1507 { "native_setCallback", 1508 "(Landroid/media/MediaCodec$Callback;)V", 1509 (void *)android_media_MediaCodec_native_setCallback }, 1510 1511 { "native_configure", 1512 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;" 1513 "Landroid/media/MediaCrypto;I)V", 1514 (void *)android_media_MediaCodec_native_configure }, 1515 1516 { "createInputSurface", "()Landroid/view/Surface;", 1517 (void *)android_media_MediaCodec_createInputSurface }, 1518 1519 { "native_start", "()V", (void *)android_media_MediaCodec_start }, 1520 { "native_stop", "()V", (void *)android_media_MediaCodec_stop }, 1521 { "native_flush", "()V", (void *)android_media_MediaCodec_flush }, 1522 1523 { "native_queueInputBuffer", "(IIIJI)V", 1524 (void *)android_media_MediaCodec_queueInputBuffer }, 1525 1526 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V", 1527 (void *)android_media_MediaCodec_queueSecureInputBuffer }, 1528 1529 { "native_dequeueInputBuffer", "(J)I", 1530 (void *)android_media_MediaCodec_dequeueInputBuffer }, 1531 1532 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", 1533 (void *)android_media_MediaCodec_dequeueOutputBuffer }, 1534 1535 { "releaseOutputBuffer", "(IZZJ)V", 1536 (void *)android_media_MediaCodec_releaseOutputBuffer }, 1537 1538 { "signalEndOfInputStream", "()V", 1539 (void *)android_media_MediaCodec_signalEndOfInputStream }, 1540 1541 { "getFormatNative", "(Z)Ljava/util/Map;", 1542 (void *)android_media_MediaCodec_getFormatNative }, 1543 1544 { "getOutputFormatNative", "(I)Ljava/util/Map;", 1545 (void *)android_media_MediaCodec_getOutputFormatForIndexNative }, 1546 1547 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;", 1548 (void *)android_media_MediaCodec_getBuffers }, 1549 1550 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;", 1551 (void *)android_media_MediaCodec_getBuffer }, 1552 1553 { "getImage", "(ZI)Landroid/media/Image;", 1554 (void *)android_media_MediaCodec_getImage }, 1555 1556 { "getName", "()Ljava/lang/String;", 1557 (void *)android_media_MediaCodec_getName }, 1558 1559 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V", 1560 (void *)android_media_MediaCodec_setParameters }, 1561 1562 { "setVideoScalingMode", "(I)V", 1563 (void *)android_media_MediaCodec_setVideoScalingMode }, 1564 1565 { "native_init", "()V", (void *)android_media_MediaCodec_native_init }, 1566 1567 { "native_setup", "(Ljava/lang/String;ZZ)V", 1568 (void *)android_media_MediaCodec_native_setup }, 1569 1570 { "native_finalize", "()V", 1571 (void *)android_media_MediaCodec_native_finalize }, 1572 }; 1573 1574 int register_android_media_MediaCodec(JNIEnv *env) { 1575 return AndroidRuntime::registerNativeMethods(env, 1576 "android/media/MediaCodec", gMethods, NELEM(gMethods)); 1577 } 1578