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