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