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