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