1 /* 2 * Copyright 2012, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //#define LOG_NDEBUG 0 18 #define LOG_TAG "MediaCodec-JNI" 19 #include <utils/Log.h> 20 21 #include "android_media_MediaCodec.h" 22 23 #include "android_media_MediaCrypto.h" 24 #include "android_media_Utils.h" 25 #include "android_runtime/AndroidRuntime.h" 26 #include "android_runtime/android_view_Surface.h" 27 #include "jni.h" 28 #include "JNIHelp.h" 29 30 #include <gui/Surface.h> 31 32 #include <media/ICrypto.h> 33 #include <media/stagefright/MediaCodec.h> 34 #include <media/stagefright/foundation/ABuffer.h> 35 #include <media/stagefright/foundation/ADebug.h> 36 #include <media/stagefright/foundation/ALooper.h> 37 #include <media/stagefright/foundation/AMessage.h> 38 #include <media/stagefright/foundation/AString.h> 39 #include <media/stagefright/MediaErrors.h> 40 41 #include <nativehelper/ScopedLocalRef.h> 42 43 #include <system/window.h> 44 45 namespace android { 46 47 // Keep these in sync with their equivalents in MediaCodec.java !!! 48 enum { 49 DEQUEUE_INFO_TRY_AGAIN_LATER = -1, 50 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2, 51 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3, 52 }; 53 54 struct CryptoErrorCodes { 55 jint cryptoErrorNoKey; 56 jint cryptoErrorKeyExpired; 57 jint cryptoErrorResourceBusy; 58 } gCryptoErrorCodes; 59 60 struct fields_t { 61 jfieldID context; 62 jfieldID cryptoInfoNumSubSamplesID; 63 jfieldID cryptoInfoNumBytesOfClearDataID; 64 jfieldID cryptoInfoNumBytesOfEncryptedDataID; 65 jfieldID cryptoInfoKeyID; 66 jfieldID cryptoInfoIVID; 67 jfieldID cryptoInfoModeID; 68 }; 69 70 static fields_t gFields; 71 72 //////////////////////////////////////////////////////////////////////////////// 73 74 JMediaCodec::JMediaCodec( 75 JNIEnv *env, jobject thiz, 76 const char *name, bool nameIsType, bool encoder) 77 : mClass(NULL), 78 mObject(NULL) { 79 jclass clazz = env->GetObjectClass(thiz); 80 CHECK(clazz != NULL); 81 82 mClass = (jclass)env->NewGlobalRef(clazz); 83 mObject = env->NewWeakGlobalRef(thiz); 84 85 mLooper = new ALooper; 86 mLooper->setName("MediaCodec_looper"); 87 88 mLooper->start( 89 false, // runOnCallingThread 90 false, // canCallJava 91 PRIORITY_FOREGROUND); 92 93 if (nameIsType) { 94 mCodec = MediaCodec::CreateByType(mLooper, name, encoder); 95 } else { 96 mCodec = MediaCodec::CreateByComponentName(mLooper, name); 97 } 98 } 99 100 status_t JMediaCodec::initCheck() const { 101 return mCodec != NULL ? OK : NO_INIT; 102 } 103 104 JMediaCodec::~JMediaCodec() { 105 if (mCodec != NULL) { 106 mCodec->release(); 107 mCodec.clear(); 108 } 109 110 JNIEnv *env = AndroidRuntime::getJNIEnv(); 111 112 env->DeleteWeakGlobalRef(mObject); 113 mObject = NULL; 114 env->DeleteGlobalRef(mClass); 115 mClass = NULL; 116 } 117 118 status_t JMediaCodec::configure( 119 const sp<AMessage> &format, 120 const sp<IGraphicBufferProducer> &bufferProducer, 121 const sp<ICrypto> &crypto, 122 int flags) { 123 sp<Surface> client; 124 if (bufferProducer != NULL) { 125 mSurfaceTextureClient = new Surface(bufferProducer, true /* controlledByApp */); 126 } else { 127 mSurfaceTextureClient.clear(); 128 } 129 130 return mCodec->configure(format, mSurfaceTextureClient, crypto, flags); 131 } 132 133 status_t JMediaCodec::createInputSurface( 134 sp<IGraphicBufferProducer>* bufferProducer) { 135 return mCodec->createInputSurface(bufferProducer); 136 } 137 138 status_t JMediaCodec::start() { 139 return mCodec->start(); 140 } 141 142 status_t JMediaCodec::stop() { 143 mSurfaceTextureClient.clear(); 144 145 return mCodec->stop(); 146 } 147 148 status_t JMediaCodec::flush() { 149 return mCodec->flush(); 150 } 151 152 status_t JMediaCodec::queueInputBuffer( 153 size_t index, 154 size_t offset, size_t size, int64_t timeUs, uint32_t flags, 155 AString *errorDetailMsg) { 156 return mCodec->queueInputBuffer( 157 index, offset, size, timeUs, flags, errorDetailMsg); 158 } 159 160 status_t JMediaCodec::queueSecureInputBuffer( 161 size_t index, 162 size_t offset, 163 const CryptoPlugin::SubSample *subSamples, 164 size_t numSubSamples, 165 const uint8_t key[16], 166 const uint8_t iv[16], 167 CryptoPlugin::Mode mode, 168 int64_t presentationTimeUs, 169 uint32_t flags, 170 AString *errorDetailMsg) { 171 return mCodec->queueSecureInputBuffer( 172 index, offset, subSamples, numSubSamples, key, iv, mode, 173 presentationTimeUs, flags, errorDetailMsg); 174 } 175 176 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) { 177 return mCodec->dequeueInputBuffer(index, timeoutUs); 178 } 179 180 status_t JMediaCodec::dequeueOutputBuffer( 181 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) { 182 size_t size, offset; 183 int64_t timeUs; 184 uint32_t flags; 185 status_t err; 186 if ((err = mCodec->dequeueOutputBuffer( 187 index, &offset, &size, &timeUs, &flags, timeoutUs)) != OK) { 188 return err; 189 } 190 191 ScopedLocalRef<jclass> clazz( 192 env, env->FindClass("android/media/MediaCodec$BufferInfo")); 193 194 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V"); 195 env->CallVoidMethod(bufferInfo, method, offset, size, timeUs, flags); 196 197 return OK; 198 } 199 200 status_t JMediaCodec::releaseOutputBuffer(size_t index, bool render) { 201 return render 202 ? mCodec->renderOutputBufferAndRelease(index) 203 : mCodec->releaseOutputBuffer(index); 204 } 205 206 status_t JMediaCodec::signalEndOfInputStream() { 207 return mCodec->signalEndOfInputStream(); 208 } 209 210 status_t JMediaCodec::getOutputFormat(JNIEnv *env, jobject *format) const { 211 sp<AMessage> msg; 212 status_t err; 213 if ((err = mCodec->getOutputFormat(&msg)) != OK) { 214 return err; 215 } 216 217 return ConvertMessageToMap(env, msg, format); 218 } 219 220 status_t JMediaCodec::getBuffers( 221 JNIEnv *env, bool input, jobjectArray *bufArray) const { 222 Vector<sp<ABuffer> > buffers; 223 224 status_t err = 225 input 226 ? mCodec->getInputBuffers(&buffers) 227 : mCodec->getOutputBuffers(&buffers); 228 229 if (err != OK) { 230 return err; 231 } 232 233 ScopedLocalRef<jclass> byteBufferClass( 234 env, env->FindClass("java/nio/ByteBuffer")); 235 236 CHECK(byteBufferClass.get() != NULL); 237 238 jmethodID orderID = env->GetMethodID( 239 byteBufferClass.get(), 240 "order", 241 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"); 242 243 CHECK(orderID != NULL); 244 245 ScopedLocalRef<jclass> byteOrderClass( 246 env, env->FindClass("java/nio/ByteOrder")); 247 248 CHECK(byteOrderClass.get() != NULL); 249 250 jmethodID nativeOrderID = env->GetStaticMethodID( 251 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;"); 252 CHECK(nativeOrderID != NULL); 253 254 jobject nativeByteOrderObj = 255 env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID); 256 CHECK(nativeByteOrderObj != NULL); 257 258 *bufArray = (jobjectArray)env->NewObjectArray( 259 buffers.size(), byteBufferClass.get(), NULL); 260 if (*bufArray == NULL) { 261 env->DeleteLocalRef(nativeByteOrderObj); 262 return NO_MEMORY; 263 } 264 265 for (size_t i = 0; i < buffers.size(); ++i) { 266 const sp<ABuffer> &buffer = buffers.itemAt(i); 267 268 // if this is an ABuffer that doesn't actually hold any accessible memory, 269 // use a null ByteBuffer 270 if (buffer->base() == NULL) { 271 continue; 272 } 273 jobject byteBuffer = 274 env->NewDirectByteBuffer( 275 buffer->base(), 276 buffer->capacity()); 277 if (byteBuffer == NULL) { 278 env->DeleteLocalRef(nativeByteOrderObj); 279 return NO_MEMORY; 280 } 281 jobject me = env->CallObjectMethod( 282 byteBuffer, orderID, nativeByteOrderObj); 283 env->DeleteLocalRef(me); 284 me = NULL; 285 286 env->SetObjectArrayElement( 287 *bufArray, i, byteBuffer); 288 289 env->DeleteLocalRef(byteBuffer); 290 byteBuffer = NULL; 291 } 292 293 env->DeleteLocalRef(nativeByteOrderObj); 294 nativeByteOrderObj = NULL; 295 296 return OK; 297 } 298 299 status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const { 300 AString name; 301 302 status_t err = mCodec->getName(&name); 303 304 if (err != OK) { 305 return err; 306 } 307 308 *nameStr = env->NewStringUTF(name.c_str()); 309 310 return OK; 311 } 312 313 status_t JMediaCodec::setParameters(const sp<AMessage> &msg) { 314 return mCodec->setParameters(msg); 315 } 316 317 void JMediaCodec::setVideoScalingMode(int mode) { 318 if (mSurfaceTextureClient != NULL) { 319 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode); 320 } 321 } 322 323 } // namespace android 324 325 //////////////////////////////////////////////////////////////////////////////// 326 327 using namespace android; 328 329 static sp<JMediaCodec> setMediaCodec( 330 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) { 331 sp<JMediaCodec> old = (JMediaCodec *)env->GetIntField(thiz, gFields.context); 332 if (codec != NULL) { 333 codec->incStrong(thiz); 334 } 335 if (old != NULL) { 336 old->decStrong(thiz); 337 } 338 env->SetIntField(thiz, gFields.context, (int)codec.get()); 339 340 return old; 341 } 342 343 static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) { 344 return (JMediaCodec *)env->GetIntField(thiz, gFields.context); 345 } 346 347 static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) { 348 setMediaCodec(env, thiz, NULL); 349 } 350 351 static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) { 352 ScopedLocalRef<jclass> clazz( 353 env, env->FindClass("android/media/MediaCodec$CryptoException")); 354 CHECK(clazz.get() != NULL); 355 356 jmethodID constructID = 357 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V"); 358 CHECK(constructID != NULL); 359 360 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error"); 361 362 /* translate OS errors to Java API CryptoException errorCodes */ 363 switch (err) { 364 case ERROR_DRM_NO_LICENSE: 365 err = gCryptoErrorCodes.cryptoErrorNoKey; 366 break; 367 case ERROR_DRM_LICENSE_EXPIRED: 368 err = gCryptoErrorCodes.cryptoErrorKeyExpired; 369 break; 370 case ERROR_DRM_RESOURCE_BUSY: 371 err = gCryptoErrorCodes.cryptoErrorResourceBusy; 372 break; 373 default: 374 break; 375 } 376 377 jthrowable exception = 378 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj); 379 380 env->Throw(exception); 381 } 382 383 static jint throwExceptionAsNecessary( 384 JNIEnv *env, status_t err, const char *msg = NULL) { 385 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) { 386 // We'll throw our custom MediaCodec.CryptoException 387 throwCryptoException(env, err, msg); 388 return 0; 389 } 390 391 switch (err) { 392 case OK: 393 return 0; 394 395 case -EAGAIN: 396 return DEQUEUE_INFO_TRY_AGAIN_LATER; 397 398 case INFO_FORMAT_CHANGED: 399 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED; 400 401 case INFO_OUTPUT_BUFFERS_CHANGED: 402 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED; 403 404 case ERROR_DRM_NO_LICENSE: 405 case ERROR_DRM_LICENSE_EXPIRED: 406 case ERROR_DRM_RESOURCE_BUSY: 407 throwCryptoException(env, err, msg); 408 break; 409 410 default: 411 { 412 jniThrowException(env, "java/lang/IllegalStateException", msg); 413 break; 414 } 415 } 416 417 return 0; 418 } 419 420 static void android_media_MediaCodec_native_configure( 421 JNIEnv *env, 422 jobject thiz, 423 jobjectArray keys, jobjectArray values, 424 jobject jsurface, 425 jobject jcrypto, 426 jint flags) { 427 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 428 429 if (codec == NULL) { 430 jniThrowException(env, "java/lang/IllegalStateException", NULL); 431 return; 432 } 433 434 sp<AMessage> format; 435 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format); 436 437 if (err != OK) { 438 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 439 return; 440 } 441 442 sp<IGraphicBufferProducer> bufferProducer; 443 if (jsurface != NULL) { 444 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 445 if (surface != NULL) { 446 bufferProducer = surface->getIGraphicBufferProducer(); 447 } else { 448 jniThrowException( 449 env, 450 "java/lang/IllegalArgumentException", 451 "The surface has been released"); 452 return; 453 } 454 } 455 456 sp<ICrypto> crypto; 457 if (jcrypto != NULL) { 458 crypto = JCrypto::GetCrypto(env, jcrypto); 459 } 460 461 err = codec->configure(format, bufferProducer, crypto, flags); 462 463 throwExceptionAsNecessary(env, err); 464 } 465 466 static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env, 467 jobject thiz) { 468 ALOGV("android_media_MediaCodec_createInputSurface"); 469 470 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 471 if (codec == NULL) { 472 jniThrowException(env, "java/lang/IllegalStateException", NULL); 473 return NULL; 474 } 475 476 // Tell the MediaCodec that we want to use a Surface as input. 477 sp<IGraphicBufferProducer> bufferProducer; 478 status_t err = codec->createInputSurface(&bufferProducer); 479 if (err != NO_ERROR) { 480 throwExceptionAsNecessary(env, err); 481 return NULL; 482 } 483 484 // Wrap the IGBP in a Java-language Surface. 485 return android_view_Surface_createFromIGraphicBufferProducer(env, 486 bufferProducer); 487 } 488 489 static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) { 490 ALOGV("android_media_MediaCodec_start"); 491 492 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 493 494 if (codec == NULL) { 495 jniThrowException(env, "java/lang/IllegalStateException", "no codec found"); 496 return; 497 } 498 499 status_t err = codec->start(); 500 501 throwExceptionAsNecessary(env, err, "start failed"); 502 } 503 504 static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) { 505 ALOGV("android_media_MediaCodec_stop"); 506 507 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 508 509 if (codec == NULL) { 510 jniThrowException(env, "java/lang/IllegalStateException", NULL); 511 return; 512 } 513 514 status_t err = codec->stop(); 515 516 throwExceptionAsNecessary(env, err); 517 } 518 519 static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) { 520 ALOGV("android_media_MediaCodec_flush"); 521 522 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 523 524 if (codec == NULL) { 525 jniThrowException(env, "java/lang/IllegalStateException", NULL); 526 return; 527 } 528 529 status_t err = codec->flush(); 530 531 throwExceptionAsNecessary(env, err); 532 } 533 534 static void android_media_MediaCodec_queueInputBuffer( 535 JNIEnv *env, 536 jobject thiz, 537 jint index, 538 jint offset, 539 jint size, 540 jlong timestampUs, 541 jint flags) { 542 ALOGV("android_media_MediaCodec_queueInputBuffer"); 543 544 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 545 546 if (codec == NULL) { 547 jniThrowException(env, "java/lang/IllegalStateException", NULL); 548 return; 549 } 550 551 AString errorDetailMsg; 552 553 status_t err = codec->queueInputBuffer( 554 index, offset, size, timestampUs, flags, &errorDetailMsg); 555 556 throwExceptionAsNecessary( 557 env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 558 } 559 560 static void android_media_MediaCodec_queueSecureInputBuffer( 561 JNIEnv *env, 562 jobject thiz, 563 jint index, 564 jint offset, 565 jobject cryptoInfoObj, 566 jlong timestampUs, 567 jint flags) { 568 ALOGV("android_media_MediaCodec_queueSecureInputBuffer"); 569 570 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 571 572 if (codec == NULL) { 573 jniThrowException(env, "java/lang/IllegalStateException", NULL); 574 return; 575 } 576 577 jint numSubSamples = 578 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID); 579 580 jintArray numBytesOfClearDataObj = 581 (jintArray)env->GetObjectField( 582 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID); 583 584 jintArray numBytesOfEncryptedDataObj = 585 (jintArray)env->GetObjectField( 586 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID); 587 588 jbyteArray keyObj = 589 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID); 590 591 jbyteArray ivObj = 592 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID); 593 594 jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID); 595 596 status_t err = OK; 597 598 CryptoPlugin::SubSample *subSamples = NULL; 599 jbyte *key = NULL; 600 jbyte *iv = NULL; 601 602 if (numSubSamples <= 0) { 603 err = -EINVAL; 604 } else if (numBytesOfClearDataObj == NULL 605 && numBytesOfEncryptedDataObj == NULL) { 606 err = -EINVAL; 607 } else if (numBytesOfEncryptedDataObj != NULL 608 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) { 609 err = -ERANGE; 610 } else if (numBytesOfClearDataObj != NULL 611 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) { 612 err = -ERANGE; 613 } else { 614 jboolean isCopy; 615 616 jint *numBytesOfClearData = 617 (numBytesOfClearDataObj == NULL) 618 ? NULL 619 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy); 620 621 jint *numBytesOfEncryptedData = 622 (numBytesOfEncryptedDataObj == NULL) 623 ? NULL 624 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); 625 626 subSamples = new CryptoPlugin::SubSample[numSubSamples]; 627 628 for (jint i = 0; i < numSubSamples; ++i) { 629 subSamples[i].mNumBytesOfClearData = 630 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i]; 631 632 subSamples[i].mNumBytesOfEncryptedData = 633 (numBytesOfEncryptedData == NULL) 634 ? 0 : numBytesOfEncryptedData[i]; 635 } 636 637 if (numBytesOfEncryptedData != NULL) { 638 env->ReleaseIntArrayElements( 639 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0); 640 numBytesOfEncryptedData = NULL; 641 } 642 643 if (numBytesOfClearData != NULL) { 644 env->ReleaseIntArrayElements( 645 numBytesOfClearDataObj, numBytesOfClearData, 0); 646 numBytesOfClearData = NULL; 647 } 648 } 649 650 if (err == OK && keyObj != NULL) { 651 if (env->GetArrayLength(keyObj) != 16) { 652 err = -EINVAL; 653 } else { 654 jboolean isCopy; 655 key = env->GetByteArrayElements(keyObj, &isCopy); 656 } 657 } 658 659 if (err == OK && ivObj != NULL) { 660 if (env->GetArrayLength(ivObj) != 16) { 661 err = -EINVAL; 662 } else { 663 jboolean isCopy; 664 iv = env->GetByteArrayElements(ivObj, &isCopy); 665 } 666 } 667 668 AString errorDetailMsg; 669 670 if (err == OK) { 671 err = codec->queueSecureInputBuffer( 672 index, offset, 673 subSamples, numSubSamples, 674 (const uint8_t *)key, (const uint8_t *)iv, 675 (CryptoPlugin::Mode)mode, 676 timestampUs, 677 flags, 678 &errorDetailMsg); 679 } 680 681 if (iv != NULL) { 682 env->ReleaseByteArrayElements(ivObj, iv, 0); 683 iv = NULL; 684 } 685 686 if (key != NULL) { 687 env->ReleaseByteArrayElements(keyObj, key, 0); 688 key = NULL; 689 } 690 691 delete[] subSamples; 692 subSamples = NULL; 693 694 throwExceptionAsNecessary( 695 env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 696 } 697 698 static jint android_media_MediaCodec_dequeueInputBuffer( 699 JNIEnv *env, jobject thiz, jlong timeoutUs) { 700 ALOGV("android_media_MediaCodec_dequeueInputBuffer"); 701 702 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 703 704 if (codec == NULL) { 705 jniThrowException(env, "java/lang/IllegalStateException", NULL); 706 return -1; 707 } 708 709 size_t index; 710 status_t err = codec->dequeueInputBuffer(&index, timeoutUs); 711 712 if (err == OK) { 713 return index; 714 } 715 716 return throwExceptionAsNecessary(env, err); 717 } 718 719 static jint android_media_MediaCodec_dequeueOutputBuffer( 720 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) { 721 ALOGV("android_media_MediaCodec_dequeueOutputBuffer"); 722 723 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 724 725 if (codec == NULL) { 726 jniThrowException(env, "java/lang/IllegalStateException", NULL); 727 return 0; 728 } 729 730 size_t index; 731 status_t err = codec->dequeueOutputBuffer( 732 env, bufferInfo, &index, timeoutUs); 733 734 if (err == OK) { 735 return index; 736 } 737 738 return throwExceptionAsNecessary(env, err); 739 } 740 741 static void android_media_MediaCodec_releaseOutputBuffer( 742 JNIEnv *env, jobject thiz, jint index, jboolean render) { 743 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease"); 744 745 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 746 747 if (codec == NULL) { 748 jniThrowException(env, "java/lang/IllegalStateException", NULL); 749 return; 750 } 751 752 status_t err = codec->releaseOutputBuffer(index, render); 753 754 throwExceptionAsNecessary(env, err); 755 } 756 757 static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env, 758 jobject thiz) { 759 ALOGV("android_media_MediaCodec_signalEndOfInputStream"); 760 761 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 762 if (codec == NULL) { 763 jniThrowException(env, "java/lang/IllegalStateException", NULL); 764 return; 765 } 766 767 status_t err = codec->signalEndOfInputStream(); 768 769 throwExceptionAsNecessary(env, err); 770 } 771 772 static jobject android_media_MediaCodec_getOutputFormatNative( 773 JNIEnv *env, jobject thiz) { 774 ALOGV("android_media_MediaCodec_getOutputFormatNative"); 775 776 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 777 778 if (codec == NULL) { 779 jniThrowException(env, "java/lang/IllegalStateException", NULL); 780 return NULL; 781 } 782 783 jobject format; 784 status_t err = codec->getOutputFormat(env, &format); 785 786 if (err == OK) { 787 return format; 788 } 789 790 throwExceptionAsNecessary(env, err); 791 792 return NULL; 793 } 794 795 static jobjectArray android_media_MediaCodec_getBuffers( 796 JNIEnv *env, jobject thiz, jboolean input) { 797 ALOGV("android_media_MediaCodec_getBuffers"); 798 799 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 800 801 if (codec == NULL) { 802 jniThrowException(env, "java/lang/IllegalStateException", NULL); 803 return NULL; 804 } 805 806 jobjectArray buffers; 807 status_t err = codec->getBuffers(env, input, &buffers); 808 809 if (err == OK) { 810 return buffers; 811 } 812 813 // if we're out of memory, an exception was already thrown 814 if (err != NO_MEMORY) { 815 throwExceptionAsNecessary(env, err); 816 } 817 818 return NULL; 819 } 820 821 static jobject android_media_MediaCodec_getName( 822 JNIEnv *env, jobject thiz) { 823 ALOGV("android_media_MediaCodec_getName"); 824 825 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 826 827 if (codec == NULL) { 828 jniThrowException(env, "java/lang/IllegalStateException", NULL); 829 return NULL; 830 } 831 832 jstring name; 833 status_t err = codec->getName(env, &name); 834 835 if (err == OK) { 836 return name; 837 } 838 839 throwExceptionAsNecessary(env, err); 840 841 return NULL; 842 } 843 844 static void android_media_MediaCodec_setParameters( 845 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) { 846 ALOGV("android_media_MediaCodec_setParameters"); 847 848 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 849 850 if (codec == NULL) { 851 jniThrowException(env, "java/lang/IllegalStateException", NULL); 852 return; 853 } 854 855 sp<AMessage> params; 856 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, ¶ms); 857 858 if (err == OK) { 859 err = codec->setParameters(params); 860 } 861 862 throwExceptionAsNecessary(env, err); 863 } 864 865 static void android_media_MediaCodec_setVideoScalingMode( 866 JNIEnv *env, jobject thiz, jint mode) { 867 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 868 869 if (codec == NULL) { 870 jniThrowException(env, "java/lang/IllegalStateException", NULL); 871 return; 872 } 873 874 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW 875 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { 876 jniThrowException(env, "java/lang/InvalidArgumentException", NULL); 877 return; 878 } 879 880 codec->setVideoScalingMode(mode); 881 } 882 883 static void android_media_MediaCodec_native_init(JNIEnv *env) { 884 ScopedLocalRef<jclass> clazz( 885 env, env->FindClass("android/media/MediaCodec")); 886 CHECK(clazz.get() != NULL); 887 888 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "I"); 889 CHECK(gFields.context != NULL); 890 891 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo")); 892 CHECK(clazz.get() != NULL); 893 894 gFields.cryptoInfoNumSubSamplesID = 895 env->GetFieldID(clazz.get(), "numSubSamples", "I"); 896 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL); 897 898 gFields.cryptoInfoNumBytesOfClearDataID = 899 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I"); 900 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL); 901 902 gFields.cryptoInfoNumBytesOfEncryptedDataID = 903 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I"); 904 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL); 905 906 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B"); 907 CHECK(gFields.cryptoInfoKeyID != NULL); 908 909 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B"); 910 CHECK(gFields.cryptoInfoIVID != NULL); 911 912 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I"); 913 CHECK(gFields.cryptoInfoModeID != NULL); 914 915 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException")); 916 CHECK(clazz.get() != NULL); 917 918 jfieldID field; 919 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I"); 920 CHECK(field != NULL); 921 gCryptoErrorCodes.cryptoErrorNoKey = 922 env->GetStaticIntField(clazz.get(), field); 923 924 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I"); 925 CHECK(field != NULL); 926 gCryptoErrorCodes.cryptoErrorKeyExpired = 927 env->GetStaticIntField(clazz.get(), field); 928 929 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I"); 930 CHECK(field != NULL); 931 gCryptoErrorCodes.cryptoErrorResourceBusy = 932 env->GetStaticIntField(clazz.get(), field); 933 } 934 935 static void android_media_MediaCodec_native_setup( 936 JNIEnv *env, jobject thiz, 937 jstring name, jboolean nameIsType, jboolean encoder) { 938 if (name == NULL) { 939 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 940 return; 941 } 942 943 const char *tmp = env->GetStringUTFChars(name, NULL); 944 945 if (tmp == NULL) { 946 return; 947 } 948 949 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder); 950 951 status_t err = codec->initCheck(); 952 953 env->ReleaseStringUTFChars(name, tmp); 954 tmp = NULL; 955 956 if (err != OK) { 957 jniThrowException( 958 env, 959 "java/io/IOException", 960 "Failed to allocate component instance"); 961 return; 962 } 963 964 setMediaCodec(env,thiz, codec); 965 } 966 967 static void android_media_MediaCodec_native_finalize( 968 JNIEnv *env, jobject thiz) { 969 android_media_MediaCodec_release(env, thiz); 970 } 971 972 static JNINativeMethod gMethods[] = { 973 { "release", "()V", (void *)android_media_MediaCodec_release }, 974 975 { "native_configure", 976 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;" 977 "Landroid/media/MediaCrypto;I)V", 978 (void *)android_media_MediaCodec_native_configure }, 979 980 { "createInputSurface", "()Landroid/view/Surface;", 981 (void *)android_media_MediaCodec_createInputSurface }, 982 983 { "start", "()V", (void *)android_media_MediaCodec_start }, 984 { "stop", "()V", (void *)android_media_MediaCodec_stop }, 985 { "flush", "()V", (void *)android_media_MediaCodec_flush }, 986 987 { "queueInputBuffer", "(IIIJI)V", 988 (void *)android_media_MediaCodec_queueInputBuffer }, 989 990 { "queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V", 991 (void *)android_media_MediaCodec_queueSecureInputBuffer }, 992 993 { "dequeueInputBuffer", "(J)I", 994 (void *)android_media_MediaCodec_dequeueInputBuffer }, 995 996 { "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", 997 (void *)android_media_MediaCodec_dequeueOutputBuffer }, 998 999 { "releaseOutputBuffer", "(IZ)V", 1000 (void *)android_media_MediaCodec_releaseOutputBuffer }, 1001 1002 { "signalEndOfInputStream", "()V", 1003 (void *)android_media_MediaCodec_signalEndOfInputStream }, 1004 1005 { "getOutputFormatNative", "()Ljava/util/Map;", 1006 (void *)android_media_MediaCodec_getOutputFormatNative }, 1007 1008 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;", 1009 (void *)android_media_MediaCodec_getBuffers }, 1010 1011 { "getName", "()Ljava/lang/String;", 1012 (void *)android_media_MediaCodec_getName }, 1013 1014 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V", 1015 (void *)android_media_MediaCodec_setParameters }, 1016 1017 { "setVideoScalingMode", "(I)V", 1018 (void *)android_media_MediaCodec_setVideoScalingMode }, 1019 1020 { "native_init", "()V", (void *)android_media_MediaCodec_native_init }, 1021 1022 { "native_setup", "(Ljava/lang/String;ZZ)V", 1023 (void *)android_media_MediaCodec_native_setup }, 1024 1025 { "native_finalize", "()V", 1026 (void *)android_media_MediaCodec_native_finalize }, 1027 }; 1028 1029 int register_android_media_MediaCodec(JNIEnv *env) { 1030 return AndroidRuntime::registerNativeMethods(env, 1031 "android/media/MediaCodec", gMethods, NELEM(gMethods)); 1032 } 1033