android_media_MediaCodec.cpp revision 64a55af0ac700baecb0877235eb42caac59a3560
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<ISurfaceTexture> &surfaceTexture, 115 const sp<ICrypto> &crypto, 116 int flags) { 117 sp<SurfaceTextureClient> client; 118 if (surfaceTexture != NULL) { 119 mSurfaceTextureClient = new SurfaceTextureClient(surfaceTexture); 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 267void JMediaCodec::setVideoScalingMode(int mode) { 268 if (mSurfaceTextureClient != NULL) { 269 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode); 270 } 271} 272 273} // namespace android 274 275//////////////////////////////////////////////////////////////////////////////// 276 277using namespace android; 278 279static sp<JMediaCodec> setMediaCodec( 280 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) { 281 sp<JMediaCodec> old = (JMediaCodec *)env->GetIntField(thiz, gFields.context); 282 if (codec != NULL) { 283 codec->incStrong(thiz); 284 } 285 if (old != NULL) { 286 old->decStrong(thiz); 287 } 288 env->SetIntField(thiz, gFields.context, (int)codec.get()); 289 290 return old; 291} 292 293static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) { 294 return (JMediaCodec *)env->GetIntField(thiz, gFields.context); 295} 296 297static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) { 298 setMediaCodec(env, thiz, NULL); 299} 300 301static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) { 302 jclass clazz = env->FindClass("android/media/MediaCodec$CryptoException"); 303 CHECK(clazz != NULL); 304 305 jmethodID constructID = 306 env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;)V"); 307 CHECK(constructID != NULL); 308 309 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error"); 310 311 jthrowable exception = 312 (jthrowable)env->NewObject(clazz, constructID, err, msgObj); 313 314 env->Throw(exception); 315} 316 317static jint throwExceptionAsNecessary( 318 JNIEnv *env, status_t err, const char *msg = NULL) { 319 if (err >= ERROR_DRM_WV_VENDOR_MIN && err <= ERROR_DRM_WV_VENDOR_MAX) { 320 // We'll throw our custom MediaCodec.CryptoException 321 322 throwCryptoException(env, err, msg); 323 return 0; 324 } 325 326 switch (err) { 327 case OK: 328 return 0; 329 330 case -EAGAIN: 331 return DEQUEUE_INFO_TRY_AGAIN_LATER; 332 333 case INFO_FORMAT_CHANGED: 334 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED; 335 336 case INFO_OUTPUT_BUFFERS_CHANGED: 337 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED; 338 339 default: 340 { 341 jniThrowException(env, "java/lang/IllegalStateException", NULL); 342 break; 343 } 344 } 345 346 return 0; 347} 348 349static void android_media_MediaCodec_native_configure( 350 JNIEnv *env, 351 jobject thiz, 352 jobjectArray keys, jobjectArray values, 353 jobject jsurface, 354 jobject jcrypto, 355 jint flags) { 356 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 357 358 if (codec == NULL) { 359 jniThrowException(env, "java/lang/IllegalStateException", NULL); 360 return; 361 } 362 363 sp<AMessage> format; 364 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format); 365 366 if (err != OK) { 367 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 368 return; 369 } 370 371 sp<ISurfaceTexture> surfaceTexture; 372 if (jsurface != NULL) { 373 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 374 if (surface != NULL) { 375 surfaceTexture = surface->getSurfaceTexture(); 376 } else { 377 jniThrowException( 378 env, 379 "java/lang/IllegalArgumentException", 380 "The surface has been released"); 381 return; 382 } 383 } 384 385 sp<ICrypto> crypto; 386 if (jcrypto != NULL) { 387 crypto = JCrypto::GetCrypto(env, jcrypto); 388 } 389 390 err = codec->configure(format, surfaceTexture, crypto, flags); 391 392 throwExceptionAsNecessary(env, err); 393} 394 395static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) { 396 ALOGV("android_media_MediaCodec_start"); 397 398 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 399 400 if (codec == NULL) { 401 jniThrowException(env, "java/lang/IllegalStateException", NULL); 402 return; 403 } 404 405 status_t err = codec->start(); 406 407 throwExceptionAsNecessary(env, err); 408} 409 410static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) { 411 ALOGV("android_media_MediaCodec_stop"); 412 413 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 414 415 if (codec == NULL) { 416 jniThrowException(env, "java/lang/IllegalStateException", NULL); 417 return; 418 } 419 420 status_t err = codec->stop(); 421 422 throwExceptionAsNecessary(env, err); 423} 424 425static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) { 426 ALOGV("android_media_MediaCodec_flush"); 427 428 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 429 430 if (codec == NULL) { 431 jniThrowException(env, "java/lang/IllegalStateException", NULL); 432 return; 433 } 434 435 status_t err = codec->flush(); 436 437 throwExceptionAsNecessary(env, err); 438} 439 440static void android_media_MediaCodec_queueInputBuffer( 441 JNIEnv *env, 442 jobject thiz, 443 jint index, 444 jint offset, 445 jint size, 446 jlong timestampUs, 447 jint flags) { 448 ALOGV("android_media_MediaCodec_queueInputBuffer"); 449 450 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 451 452 if (codec == NULL) { 453 jniThrowException(env, "java/lang/IllegalStateException", NULL); 454 return; 455 } 456 457 AString errorDetailMsg; 458 459 status_t err = codec->queueInputBuffer( 460 index, offset, size, timestampUs, flags, &errorDetailMsg); 461 462 throwExceptionAsNecessary( 463 env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 464} 465 466static void android_media_MediaCodec_queueSecureInputBuffer( 467 JNIEnv *env, 468 jobject thiz, 469 jint index, 470 jint offset, 471 jobject cryptoInfoObj, 472 jlong timestampUs, 473 jint flags) { 474 ALOGV("android_media_MediaCodec_queueSecureInputBuffer"); 475 476 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 477 478 if (codec == NULL) { 479 jniThrowException(env, "java/lang/IllegalStateException", NULL); 480 return; 481 } 482 483 jint numSubSamples = 484 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID); 485 486 jintArray numBytesOfClearDataObj = 487 (jintArray)env->GetObjectField( 488 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID); 489 490 jintArray numBytesOfEncryptedDataObj = 491 (jintArray)env->GetObjectField( 492 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID); 493 494 jbyteArray keyObj = 495 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID); 496 497 jbyteArray ivObj = 498 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID); 499 500 jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID); 501 502 status_t err = OK; 503 504 CryptoPlugin::SubSample *subSamples = NULL; 505 jbyte *key = NULL; 506 jbyte *iv = NULL; 507 508 if (numSubSamples <= 0) { 509 err = -EINVAL; 510 } else if (numBytesOfClearDataObj == NULL 511 && numBytesOfEncryptedDataObj == NULL) { 512 err = -EINVAL; 513 } else if (numBytesOfEncryptedDataObj != NULL 514 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) { 515 err = -ERANGE; 516 } else if (numBytesOfClearDataObj != NULL 517 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) { 518 err = -ERANGE; 519 } else { 520 jboolean isCopy; 521 522 jint *numBytesOfClearData = 523 (numBytesOfClearDataObj == NULL) 524 ? NULL 525 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy); 526 527 jint *numBytesOfEncryptedData = 528 (numBytesOfEncryptedDataObj == NULL) 529 ? NULL 530 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); 531 532 subSamples = new CryptoPlugin::SubSample[numSubSamples]; 533 534 for (jint i = 0; i < numSubSamples; ++i) { 535 subSamples[i].mNumBytesOfClearData = 536 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i]; 537 538 subSamples[i].mNumBytesOfEncryptedData = 539 (numBytesOfEncryptedData == NULL) 540 ? 0 : numBytesOfEncryptedData[i]; 541 } 542 543 if (numBytesOfEncryptedData != NULL) { 544 env->ReleaseIntArrayElements( 545 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0); 546 numBytesOfEncryptedData = NULL; 547 } 548 549 if (numBytesOfClearData != NULL) { 550 env->ReleaseIntArrayElements( 551 numBytesOfClearDataObj, numBytesOfClearData, 0); 552 numBytesOfClearData = NULL; 553 } 554 } 555 556 if (err == OK && keyObj != NULL) { 557 if (env->GetArrayLength(keyObj) != 16) { 558 err = -EINVAL; 559 } else { 560 jboolean isCopy; 561 key = env->GetByteArrayElements(keyObj, &isCopy); 562 } 563 } 564 565 if (err == OK && ivObj != NULL) { 566 if (env->GetArrayLength(ivObj) != 16) { 567 err = -EINVAL; 568 } else { 569 jboolean isCopy; 570 iv = env->GetByteArrayElements(ivObj, &isCopy); 571 } 572 } 573 574 AString errorDetailMsg; 575 576 if (err == OK) { 577 err = codec->queueSecureInputBuffer( 578 index, offset, 579 subSamples, numSubSamples, 580 (const uint8_t *)key, (const uint8_t *)iv, 581 (CryptoPlugin::Mode)mode, 582 timestampUs, 583 flags, 584 &errorDetailMsg); 585 } 586 587 if (iv != NULL) { 588 env->ReleaseByteArrayElements(ivObj, iv, 0); 589 iv = NULL; 590 } 591 592 if (key != NULL) { 593 env->ReleaseByteArrayElements(keyObj, key, 0); 594 key = NULL; 595 } 596 597 delete[] subSamples; 598 subSamples = NULL; 599 600 throwExceptionAsNecessary( 601 env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 602} 603 604static jint android_media_MediaCodec_dequeueInputBuffer( 605 JNIEnv *env, jobject thiz, jlong timeoutUs) { 606 ALOGV("android_media_MediaCodec_dequeueInputBuffer"); 607 608 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 609 610 if (codec == NULL) { 611 jniThrowException(env, "java/lang/IllegalStateException", NULL); 612 return -1; 613 } 614 615 size_t index; 616 status_t err = codec->dequeueInputBuffer(&index, timeoutUs); 617 618 if (err == OK) { 619 return index; 620 } 621 622 return throwExceptionAsNecessary(env, err); 623} 624 625static jint android_media_MediaCodec_dequeueOutputBuffer( 626 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) { 627 ALOGV("android_media_MediaCodec_dequeueOutputBuffer"); 628 629 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 630 631 if (codec == NULL) { 632 jniThrowException(env, "java/lang/IllegalStateException", NULL); 633 return 0; 634 } 635 636 size_t index; 637 status_t err = codec->dequeueOutputBuffer( 638 env, bufferInfo, &index, timeoutUs); 639 640 if (err == OK) { 641 return index; 642 } 643 644 return throwExceptionAsNecessary(env, err); 645} 646 647static void android_media_MediaCodec_releaseOutputBuffer( 648 JNIEnv *env, jobject thiz, jint index, jboolean render) { 649 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease"); 650 651 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 652 653 if (codec == NULL) { 654 jniThrowException(env, "java/lang/IllegalStateException", NULL); 655 return; 656 } 657 658 status_t err = codec->releaseOutputBuffer(index, render); 659 660 throwExceptionAsNecessary(env, err); 661} 662 663static jobject android_media_MediaCodec_getOutputFormatNative( 664 JNIEnv *env, jobject thiz) { 665 ALOGV("android_media_MediaCodec_getOutputFormatNative"); 666 667 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 668 669 if (codec == NULL) { 670 jniThrowException(env, "java/lang/IllegalStateException", NULL); 671 return NULL; 672 } 673 674 jobject format; 675 status_t err = codec->getOutputFormat(env, &format); 676 677 if (err == OK) { 678 return format; 679 } 680 681 throwExceptionAsNecessary(env, err); 682 683 return NULL; 684} 685 686static jobjectArray android_media_MediaCodec_getBuffers( 687 JNIEnv *env, jobject thiz, jboolean input) { 688 ALOGV("android_media_MediaCodec_getBuffers"); 689 690 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 691 692 if (codec == NULL) { 693 jniThrowException(env, "java/lang/IllegalStateException", NULL); 694 return NULL; 695 } 696 697 jobjectArray buffers; 698 status_t err = codec->getBuffers(env, input, &buffers); 699 700 if (err == OK) { 701 return buffers; 702 } 703 704 throwExceptionAsNecessary(env, err); 705 706 return NULL; 707} 708 709static void android_media_MediaCodec_setVideoScalingMode( 710 JNIEnv *env, jobject thiz, jint mode) { 711 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 712 713 if (codec == NULL) { 714 jniThrowException(env, "java/lang/IllegalStateException", NULL); 715 return; 716 } 717 718 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW 719 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { 720 jniThrowException(env, "java/lang/InvalidArgumentException", NULL); 721 return; 722 } 723 724 codec->setVideoScalingMode(mode); 725} 726 727static void android_media_MediaCodec_native_init(JNIEnv *env) { 728 jclass clazz = env->FindClass("android/media/MediaCodec"); 729 CHECK(clazz != NULL); 730 731 gFields.context = env->GetFieldID(clazz, "mNativeContext", "I"); 732 CHECK(gFields.context != NULL); 733 734 clazz = env->FindClass("android/media/MediaCodec$CryptoInfo"); 735 CHECK(clazz != NULL); 736 737 gFields.cryptoInfoNumSubSamplesID = 738 env->GetFieldID(clazz, "numSubSamples", "I"); 739 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL); 740 741 gFields.cryptoInfoNumBytesOfClearDataID = 742 env->GetFieldID(clazz, "numBytesOfClearData", "[I"); 743 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL); 744 745 gFields.cryptoInfoNumBytesOfEncryptedDataID = 746 env->GetFieldID(clazz, "numBytesOfEncryptedData", "[I"); 747 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL); 748 749 gFields.cryptoInfoKeyID = env->GetFieldID(clazz, "key", "[B"); 750 CHECK(gFields.cryptoInfoKeyID != NULL); 751 752 gFields.cryptoInfoIVID = env->GetFieldID(clazz, "iv", "[B"); 753 CHECK(gFields.cryptoInfoIVID != NULL); 754 755 gFields.cryptoInfoModeID = env->GetFieldID(clazz, "mode", "I"); 756 CHECK(gFields.cryptoInfoModeID != NULL); 757} 758 759static void android_media_MediaCodec_native_setup( 760 JNIEnv *env, jobject thiz, 761 jstring name, jboolean nameIsType, jboolean encoder) { 762 if (name == NULL) { 763 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 764 return; 765 } 766 767 const char *tmp = env->GetStringUTFChars(name, NULL); 768 769 if (tmp == NULL) { 770 return; 771 } 772 773 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder); 774 775 status_t err = codec->initCheck(); 776 777 env->ReleaseStringUTFChars(name, tmp); 778 tmp = NULL; 779 780 if (err != OK) { 781 jniThrowException( 782 env, 783 "java/io/IOException", 784 "Failed to allocate component instance"); 785 return; 786 } 787 788 setMediaCodec(env,thiz, codec); 789} 790 791static void android_media_MediaCodec_native_finalize( 792 JNIEnv *env, jobject thiz) { 793 android_media_MediaCodec_release(env, thiz); 794} 795 796static JNINativeMethod gMethods[] = { 797 { "release", "()V", (void *)android_media_MediaCodec_release }, 798 799 { "native_configure", 800 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;" 801 "Landroid/media/MediaCrypto;I)V", 802 (void *)android_media_MediaCodec_native_configure }, 803 804 { "start", "()V", (void *)android_media_MediaCodec_start }, 805 { "stop", "()V", (void *)android_media_MediaCodec_stop }, 806 { "flush", "()V", (void *)android_media_MediaCodec_flush }, 807 808 { "queueInputBuffer", "(IIIJI)V", 809 (void *)android_media_MediaCodec_queueInputBuffer }, 810 811 { "queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V", 812 (void *)android_media_MediaCodec_queueSecureInputBuffer }, 813 814 { "dequeueInputBuffer", "(J)I", 815 (void *)android_media_MediaCodec_dequeueInputBuffer }, 816 817 { "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", 818 (void *)android_media_MediaCodec_dequeueOutputBuffer }, 819 820 { "releaseOutputBuffer", "(IZ)V", 821 (void *)android_media_MediaCodec_releaseOutputBuffer }, 822 823 { "getOutputFormatNative", "()Ljava/util/Map;", 824 (void *)android_media_MediaCodec_getOutputFormatNative }, 825 826 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;", 827 (void *)android_media_MediaCodec_getBuffers }, 828 829 { "setVideoScalingMode", "(I)V", 830 (void *)android_media_MediaCodec_setVideoScalingMode }, 831 832 { "native_init", "()V", (void *)android_media_MediaCodec_native_init }, 833 834 { "native_setup", "(Ljava/lang/String;ZZ)V", 835 (void *)android_media_MediaCodec_native_setup }, 836 837 { "native_finalize", "()V", 838 (void *)android_media_MediaCodec_native_finalize }, 839}; 840 841int register_android_media_MediaCodec(JNIEnv *env) { 842 return AndroidRuntime::registerNativeMethods(env, 843 "android/media/MediaCodec", gMethods, NELEM(gMethods)); 844} 845