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