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