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