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