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