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