android_media_MediaCodec.cpp revision d4023114e8cf7ec7db4d07958a303699b658f2c0
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 <cutils/compiler.h> 31 32#include <gui/Surface.h> 33 34#include <media/ICrypto.h> 35#include <media/stagefright/MediaCodec.h> 36#include <media/stagefright/foundation/ABuffer.h> 37#include <media/stagefright/foundation/ADebug.h> 38#include <media/stagefright/foundation/ALooper.h> 39#include <media/stagefright/foundation/AMessage.h> 40#include <media/stagefright/foundation/AString.h> 41#include <media/stagefright/MediaErrors.h> 42 43#include <nativehelper/ScopedLocalRef.h> 44 45#include <system/window.h> 46 47namespace android { 48 49// Keep these in sync with their equivalents in MediaCodec.java !!! 50enum { 51 DEQUEUE_INFO_TRY_AGAIN_LATER = -1, 52 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2, 53 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3, 54}; 55 56enum { 57 EVENT_CALLBACK = 1, 58 EVENT_SET_CALLBACK = 2, 59}; 60 61struct CryptoErrorCodes { 62 jint cryptoErrorNoKey; 63 jint cryptoErrorKeyExpired; 64 jint cryptoErrorResourceBusy; 65} gCryptoErrorCodes; 66 67struct fields_t { 68 jfieldID context; 69 jmethodID postEventFromNativeID; 70 jfieldID cryptoInfoNumSubSamplesID; 71 jfieldID cryptoInfoNumBytesOfClearDataID; 72 jfieldID cryptoInfoNumBytesOfEncryptedDataID; 73 jfieldID cryptoInfoKeyID; 74 jfieldID cryptoInfoIVID; 75 jfieldID cryptoInfoModeID; 76}; 77 78static fields_t gFields; 79 80//////////////////////////////////////////////////////////////////////////////// 81 82JMediaCodec::JMediaCodec( 83 JNIEnv *env, jobject thiz, 84 const char *name, bool nameIsType, bool encoder) 85 : mClass(NULL), 86 mObject(NULL) { 87 jclass clazz = env->GetObjectClass(thiz); 88 CHECK(clazz != NULL); 89 90 mClass = (jclass)env->NewGlobalRef(clazz); 91 mObject = env->NewWeakGlobalRef(thiz); 92 93 mLooper = new ALooper; 94 mLooper->setName("MediaCodec_looper"); 95 96 mLooper->start( 97 false, // runOnCallingThread 98 true, // canCallJava 99 PRIORITY_FOREGROUND); 100 101 if (nameIsType) { 102 mCodec = MediaCodec::CreateByType(mLooper, name, encoder); 103 } else { 104 mCodec = MediaCodec::CreateByComponentName(mLooper, name); 105 } 106} 107 108status_t JMediaCodec::initCheck() const { 109 return mCodec != NULL ? OK : NO_INIT; 110} 111 112void JMediaCodec::registerSelf() { 113 mLooper->registerHandler(this); 114} 115 116void JMediaCodec::release() { 117 if (mCodec != NULL) { 118 mCodec->release(); 119 mCodec.clear(); 120 } 121 122 if (mLooper != NULL) { 123 mLooper->unregisterHandler(id()); 124 mLooper->stop(); 125 mLooper.clear(); 126 } 127} 128 129JMediaCodec::~JMediaCodec() { 130 if (mCodec != NULL || mLooper != NULL) { 131 /* MediaCodec and looper should have been released explicitly already 132 * in setMediaCodec() (see comments in setMediaCodec()). 133 * 134 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the 135 * message handler, doing release() there risks deadlock as MediaCodec:: 136 * release() post synchronous message to the same looper. 137 * 138 * Print a warning and try to proceed with releasing. 139 */ 140 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()..."); 141 release(); 142 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec()."); 143 } 144 145 JNIEnv *env = AndroidRuntime::getJNIEnv(); 146 147 env->DeleteWeakGlobalRef(mObject); 148 mObject = NULL; 149 env->DeleteGlobalRef(mClass); 150 mClass = NULL; 151} 152 153status_t JMediaCodec::setCallback(jobject cb) { 154 if (cb != NULL) { 155 if (mCallbackNotification == NULL) { 156 mCallbackNotification = new AMessage(kWhatCallbackNotify, id()); 157 } 158 } else { 159 mCallbackNotification.clear(); 160 } 161 162 return mCodec->setCallback(mCallbackNotification); 163} 164 165status_t JMediaCodec::configure( 166 const sp<AMessage> &format, 167 const sp<IGraphicBufferProducer> &bufferProducer, 168 const sp<ICrypto> &crypto, 169 int flags) { 170 sp<Surface> client; 171 if (bufferProducer != NULL) { 172 mSurfaceTextureClient = 173 new Surface(bufferProducer, true /* controlledByApp */); 174 } else { 175 mSurfaceTextureClient.clear(); 176 } 177 178 return mCodec->configure(format, mSurfaceTextureClient, crypto, flags); 179} 180 181status_t JMediaCodec::createInputSurface( 182 sp<IGraphicBufferProducer>* bufferProducer) { 183 return mCodec->createInputSurface(bufferProducer); 184} 185 186status_t JMediaCodec::start() { 187 return mCodec->start(); 188} 189 190status_t JMediaCodec::stop() { 191 mSurfaceTextureClient.clear(); 192 193 return mCodec->stop(); 194} 195 196status_t JMediaCodec::flush() { 197 return mCodec->flush(); 198} 199 200status_t JMediaCodec::queueInputBuffer( 201 size_t index, 202 size_t offset, size_t size, int64_t timeUs, uint32_t flags, 203 AString *errorDetailMsg) { 204 return mCodec->queueInputBuffer( 205 index, offset, size, timeUs, flags, errorDetailMsg); 206} 207 208status_t JMediaCodec::queueSecureInputBuffer( 209 size_t index, 210 size_t offset, 211 const CryptoPlugin::SubSample *subSamples, 212 size_t numSubSamples, 213 const uint8_t key[16], 214 const uint8_t iv[16], 215 CryptoPlugin::Mode mode, 216 int64_t presentationTimeUs, 217 uint32_t flags, 218 AString *errorDetailMsg) { 219 return mCodec->queueSecureInputBuffer( 220 index, offset, subSamples, numSubSamples, key, iv, mode, 221 presentationTimeUs, flags, errorDetailMsg); 222} 223 224status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) { 225 return mCodec->dequeueInputBuffer(index, timeoutUs); 226} 227 228status_t JMediaCodec::dequeueOutputBuffer( 229 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) { 230 size_t size, offset; 231 int64_t timeUs; 232 uint32_t flags; 233 status_t err = mCodec->dequeueOutputBuffer( 234 index, &offset, &size, &timeUs, &flags, timeoutUs); 235 236 if (err != OK) { 237 return err; 238 } 239 240 ScopedLocalRef<jclass> clazz( 241 env, env->FindClass("android/media/MediaCodec$BufferInfo")); 242 243 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V"); 244 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags); 245 246 return OK; 247} 248 249status_t JMediaCodec::releaseOutputBuffer( 250 size_t index, bool render, bool updatePTS, int64_t timestampNs) { 251 if (updatePTS) { 252 return mCodec->renderOutputBufferAndRelease(index, timestampNs); 253 } 254 return render 255 ? mCodec->renderOutputBufferAndRelease(index) 256 : mCodec->releaseOutputBuffer(index); 257} 258 259status_t JMediaCodec::signalEndOfInputStream() { 260 return mCodec->signalEndOfInputStream(); 261} 262 263status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const { 264 sp<AMessage> msg; 265 status_t err; 266 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg); 267 if (err != OK) { 268 return err; 269 } 270 271 return ConvertMessageToMap(env, msg, format); 272} 273 274status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const { 275 sp<AMessage> msg; 276 status_t err; 277 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) { 278 return err; 279 } 280 281 return ConvertMessageToMap(env, msg, format); 282} 283 284status_t JMediaCodec::getBuffers( 285 JNIEnv *env, bool input, jobjectArray *bufArray) const { 286 Vector<sp<ABuffer> > buffers; 287 288 status_t err = 289 input 290 ? mCodec->getInputBuffers(&buffers) 291 : mCodec->getOutputBuffers(&buffers); 292 293 if (err != OK) { 294 return err; 295 } 296 297 ScopedLocalRef<jclass> byteBufferClass( 298 env, env->FindClass("java/nio/ByteBuffer")); 299 300 CHECK(byteBufferClass.get() != NULL); 301 302 jmethodID orderID = env->GetMethodID( 303 byteBufferClass.get(), 304 "order", 305 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"); 306 307 CHECK(orderID != NULL); 308 309 jmethodID asReadOnlyBufferID = env->GetMethodID( 310 byteBufferClass.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;"); 311 312 CHECK(asReadOnlyBufferID != NULL); 313 314 ScopedLocalRef<jclass> byteOrderClass( 315 env, env->FindClass("java/nio/ByteOrder")); 316 317 CHECK(byteOrderClass.get() != NULL); 318 319 jmethodID nativeOrderID = env->GetStaticMethodID( 320 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;"); 321 CHECK(nativeOrderID != NULL); 322 323 jobject nativeByteOrderObj = 324 env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID); 325 CHECK(nativeByteOrderObj != NULL); 326 327 *bufArray = (jobjectArray)env->NewObjectArray( 328 buffers.size(), byteBufferClass.get(), NULL); 329 if (*bufArray == NULL) { 330 env->DeleteLocalRef(nativeByteOrderObj); 331 return NO_MEMORY; 332 } 333 334 for (size_t i = 0; i < buffers.size(); ++i) { 335 const sp<ABuffer> &buffer = buffers.itemAt(i); 336 337 // if this is an ABuffer that doesn't actually hold any accessible memory, 338 // use a null ByteBuffer 339 if (buffer->base() == NULL) { 340 continue; 341 } 342 jobject byteBuffer = 343 env->NewDirectByteBuffer( 344 buffer->base(), 345 buffer->capacity()); 346 if (!input && byteBuffer != NULL) { 347 jobject readOnlyBuffer = env->CallObjectMethod( 348 byteBuffer, asReadOnlyBufferID); 349 env->DeleteLocalRef(byteBuffer); 350 byteBuffer = readOnlyBuffer; 351 } 352 if (byteBuffer == NULL) { 353 env->DeleteLocalRef(nativeByteOrderObj); 354 return NO_MEMORY; 355 } 356 jobject me = env->CallObjectMethod( 357 byteBuffer, orderID, nativeByteOrderObj); 358 env->DeleteLocalRef(me); 359 me = NULL; 360 361 env->SetObjectArrayElement( 362 *bufArray, i, byteBuffer); 363 364 env->DeleteLocalRef(byteBuffer); 365 byteBuffer = NULL; 366 } 367 368 env->DeleteLocalRef(nativeByteOrderObj); 369 nativeByteOrderObj = NULL; 370 371 return OK; 372} 373 374status_t JMediaCodec::getBuffer( 375 JNIEnv *env, bool input, size_t index, jobject *buf) const { 376 sp<ABuffer> buffer; 377 378 status_t err = 379 input 380 ? mCodec->getInputBuffer(index, &buffer) 381 : mCodec->getOutputBuffer(index, &buffer); 382 383 if (err != OK) { 384 return err; 385 } 386 387 ScopedLocalRef<jclass> byteBufferClass( 388 env, env->FindClass("java/nio/ByteBuffer")); 389 390 CHECK(byteBufferClass.get() != NULL); 391 392 jmethodID orderID = env->GetMethodID( 393 byteBufferClass.get(), 394 "order", 395 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"); 396 397 CHECK(orderID != NULL); 398 399 jmethodID asReadOnlyBufferID = env->GetMethodID( 400 byteBufferClass.get(), "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;"); 401 402 CHECK(asReadOnlyBufferID != NULL); 403 404 jmethodID positionID = env->GetMethodID( 405 byteBufferClass.get(), "position", "(I)Ljava/nio/Buffer;"); 406 407 CHECK(positionID != NULL); 408 409 jmethodID limitID = env->GetMethodID( 410 byteBufferClass.get(), "limit", "(I)Ljava/nio/Buffer;"); 411 412 CHECK(limitID != NULL); 413 414 ScopedLocalRef<jclass> byteOrderClass( 415 env, env->FindClass("java/nio/ByteOrder")); 416 417 CHECK(byteOrderClass.get() != NULL); 418 419 jmethodID nativeOrderID = env->GetStaticMethodID( 420 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;"); 421 CHECK(nativeOrderID != NULL); 422 423 jobject nativeByteOrderObj = 424 env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID); 425 CHECK(nativeByteOrderObj != NULL); 426 427 // if this is an ABuffer that doesn't actually hold any accessible memory, 428 // use a null ByteBuffer 429 if (buffer->base() == NULL) { 430 *buf = NULL; 431 return OK; 432 } 433 434 jobject byteBuffer = 435 env->NewDirectByteBuffer( 436 buffer->base(), 437 buffer->capacity()); 438 if (!input && byteBuffer != NULL) { 439 jobject readOnlyBuffer = env->CallObjectMethod( 440 byteBuffer, asReadOnlyBufferID); 441 env->DeleteLocalRef(byteBuffer); 442 byteBuffer = readOnlyBuffer; 443 } 444 if (byteBuffer == NULL) { 445 env->DeleteLocalRef(nativeByteOrderObj); 446 return NO_MEMORY; 447 } 448 jobject me = env->CallObjectMethod( 449 byteBuffer, orderID, nativeByteOrderObj); 450 env->DeleteLocalRef(me); 451 me = env->CallObjectMethod( 452 byteBuffer, positionID, 453 input ? 0 : buffer->offset()); 454 env->DeleteLocalRef(me); 455 me = env->CallObjectMethod( 456 byteBuffer, limitID, 457 input ? buffer->capacity() : (buffer->offset() + buffer->size())); 458 env->DeleteLocalRef(me); 459 me = NULL; 460 461 env->DeleteLocalRef(nativeByteOrderObj); 462 nativeByteOrderObj = NULL; 463 464 *buf = byteBuffer; 465 return OK; 466} 467 468status_t JMediaCodec::getImage( 469 JNIEnv *env, bool input, size_t index, jobject *buf) const { 470 sp<ABuffer> buffer; 471 472 status_t err = 473 input 474 ? mCodec->getInputBuffer(index, &buffer) 475 : mCodec->getOutputBuffer(index, &buffer); 476 477 if (err != OK) { 478 return err; 479 } 480 481 // if this is an ABuffer that doesn't actually hold any accessible memory, 482 // use a null ByteBuffer 483 *buf = NULL; 484 if (buffer->base() == NULL) { 485 return OK; 486 } 487 488 // check if buffer is an image 489 AString imageData; 490 if (!buffer->meta()->findString("image-data", &imageData)) { 491 return OK; 492 } 493 494 return OK; 495} 496 497 498status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const { 499 AString name; 500 501 status_t err = mCodec->getName(&name); 502 503 if (err != OK) { 504 return err; 505 } 506 507 *nameStr = env->NewStringUTF(name.c_str()); 508 509 return OK; 510} 511 512status_t JMediaCodec::setParameters(const sp<AMessage> &msg) { 513 return mCodec->setParameters(msg); 514} 515 516void JMediaCodec::setVideoScalingMode(int mode) { 517 if (mSurfaceTextureClient != NULL) { 518 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode); 519 } 520} 521 522void JMediaCodec::handleCallback(const sp<AMessage> &msg) { 523 int32_t arg1, arg2 = 0; 524 jobject obj = NULL; 525 CHECK(msg->findInt32("callbackID", &arg1)); 526 JNIEnv *env = AndroidRuntime::getJNIEnv(); 527 528 switch (arg1) { 529 case MediaCodec::CB_INPUT_AVAILABLE: 530 { 531 CHECK(msg->findInt32("index", &arg2)); 532 break; 533 } 534 535 case MediaCodec::CB_OUTPUT_AVAILABLE: 536 { 537 CHECK(msg->findInt32("index", &arg2)); 538 539 size_t size, offset; 540 int64_t timeUs; 541 uint32_t flags; 542 CHECK(msg->findSize("size", &size)); 543 CHECK(msg->findSize("offset", &offset)); 544 CHECK(msg->findInt64("timeUs", &timeUs)); 545 CHECK(msg->findInt32("flags", (int32_t *)&flags)); 546 547 ScopedLocalRef<jclass> clazz( 548 env, env->FindClass("android/media/MediaCodec$BufferInfo")); 549 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V"); 550 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V"); 551 552 obj = env->NewObject(clazz.get(), ctor); 553 554 if (obj == NULL) { 555 if (env->ExceptionCheck()) { 556 ALOGE("Could not create MediaCodec.BufferInfo."); 557 env->ExceptionClear(); 558 } 559 jniThrowException(env, "java/lang/IllegalStateException", NULL); 560 return; 561 } 562 563 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags); 564 break; 565 } 566 567 case MediaCodec::CB_ERROR: 568 { 569 CHECK(msg->findInt32("err", &arg2)); 570 571 int32_t actionCode; 572 CHECK(msg->findInt32("actionCode", &actionCode)); 573 574 // use Integer object to pass the action code 575 ScopedLocalRef<jclass> clazz( 576 env, env->FindClass("java/lang/Integer")); 577 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(I)V"); 578 obj = env->NewObject(clazz.get(), ctor, actionCode); 579 580 if (obj == NULL) { 581 if (env->ExceptionCheck()) { 582 ALOGE("Could not create Integer object for actionCode."); 583 env->ExceptionClear(); 584 } 585 jniThrowException(env, "java/lang/IllegalStateException", NULL); 586 return; 587 } 588 589 break; 590 } 591 592 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED: 593 { 594 sp<AMessage> format; 595 CHECK(msg->findMessage("format", &format)); 596 597 if (OK != ConvertMessageToMap(env, format, &obj)) { 598 jniThrowException(env, "java/lang/IllegalStateException", NULL); 599 return; 600 } 601 602 break; 603 } 604 605 default: 606 TRESPASS(); 607 } 608 609 env->CallVoidMethod( 610 mObject, 611 gFields.postEventFromNativeID, 612 EVENT_CALLBACK, 613 arg1, 614 arg2, 615 obj); 616 617 env->DeleteLocalRef(obj); 618} 619 620void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) { 621 switch (msg->what()) { 622 case kWhatCallbackNotify: 623 { 624 handleCallback(msg); 625 break; 626 } 627 default: 628 TRESPASS(); 629 } 630} 631 632} // namespace android 633 634//////////////////////////////////////////////////////////////////////////////// 635 636using namespace android; 637 638static sp<JMediaCodec> setMediaCodec( 639 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) { 640 sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context); 641 if (codec != NULL) { 642 codec->incStrong(thiz); 643 } 644 if (old != NULL) { 645 /* release MediaCodec and stop the looper now before decStrong. 646 * otherwise JMediaCodec::~JMediaCodec() could be called from within 647 * its message handler, doing release() from there will deadlock 648 * (as MediaCodec::release() post synchronous message to the same looper) 649 */ 650 old->release(); 651 old->decStrong(thiz); 652 } 653 env->SetLongField(thiz, gFields.context, (jlong)codec.get()); 654 655 return old; 656} 657 658static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) { 659 return (JMediaCodec *)env->GetLongField(thiz, gFields.context); 660} 661 662static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) { 663 setMediaCodec(env, thiz, NULL); 664} 665 666static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) { 667 ScopedLocalRef<jclass> clazz( 668 env, env->FindClass("android/media/MediaCodec$CryptoException")); 669 CHECK(clazz.get() != NULL); 670 671 jmethodID constructID = 672 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V"); 673 CHECK(constructID != NULL); 674 675 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error"); 676 677 /* translate OS errors to Java API CryptoException errorCodes */ 678 switch (err) { 679 case ERROR_DRM_NO_LICENSE: 680 err = gCryptoErrorCodes.cryptoErrorNoKey; 681 break; 682 case ERROR_DRM_LICENSE_EXPIRED: 683 err = gCryptoErrorCodes.cryptoErrorKeyExpired; 684 break; 685 case ERROR_DRM_RESOURCE_BUSY: 686 err = gCryptoErrorCodes.cryptoErrorResourceBusy; 687 break; 688 default: 689 break; 690 } 691 692 jthrowable exception = 693 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj); 694 695 env->Throw(exception); 696} 697 698static jint throwExceptionAsNecessary( 699 JNIEnv *env, status_t err, const char *msg = NULL) { 700 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) { 701 // We'll throw our custom MediaCodec.CryptoException 702 throwCryptoException(env, err, msg); 703 return 0; 704 } 705 706 switch (err) { 707 case OK: 708 return 0; 709 710 case -EAGAIN: 711 return DEQUEUE_INFO_TRY_AGAIN_LATER; 712 713 case INFO_FORMAT_CHANGED: 714 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED; 715 716 case INFO_OUTPUT_BUFFERS_CHANGED: 717 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED; 718 719 case ERROR_DRM_NO_LICENSE: 720 case ERROR_DRM_LICENSE_EXPIRED: 721 case ERROR_DRM_RESOURCE_BUSY: 722 throwCryptoException(env, err, msg); 723 break; 724 725 default: 726 { 727 jniThrowException(env, "java/lang/IllegalStateException", msg); 728 break; 729 } 730 } 731 732 return 0; 733} 734 735static void android_media_MediaCodec_native_setCallback( 736 JNIEnv *env, 737 jobject thiz, 738 jobject cb) { 739 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 740 741 if (codec == NULL) { 742 jniThrowException(env, "java/lang/IllegalStateException", NULL); 743 return; 744 } 745 746 status_t err = codec->setCallback(cb); 747 748 throwExceptionAsNecessary(env, err); 749} 750 751static void android_media_MediaCodec_native_configure( 752 JNIEnv *env, 753 jobject thiz, 754 jobjectArray keys, jobjectArray values, 755 jobject jsurface, 756 jobject jcrypto, 757 jint flags) { 758 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 759 760 if (codec == NULL) { 761 jniThrowException(env, "java/lang/IllegalStateException", NULL); 762 return; 763 } 764 765 sp<AMessage> format; 766 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format); 767 768 if (err != OK) { 769 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 770 return; 771 } 772 773 sp<IGraphicBufferProducer> bufferProducer; 774 if (jsurface != NULL) { 775 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 776 if (surface != NULL) { 777 bufferProducer = surface->getIGraphicBufferProducer(); 778 } else { 779 jniThrowException( 780 env, 781 "java/lang/IllegalArgumentException", 782 "The surface has been released"); 783 return; 784 } 785 } 786 787 sp<ICrypto> crypto; 788 if (jcrypto != NULL) { 789 crypto = JCrypto::GetCrypto(env, jcrypto); 790 } 791 792 err = codec->configure(format, bufferProducer, crypto, flags); 793 794 throwExceptionAsNecessary(env, err); 795} 796 797static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env, 798 jobject thiz) { 799 ALOGV("android_media_MediaCodec_createInputSurface"); 800 801 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 802 if (codec == NULL) { 803 jniThrowException(env, "java/lang/IllegalStateException", NULL); 804 return NULL; 805 } 806 807 // Tell the MediaCodec that we want to use a Surface as input. 808 sp<IGraphicBufferProducer> bufferProducer; 809 status_t err = codec->createInputSurface(&bufferProducer); 810 if (err != NO_ERROR) { 811 throwExceptionAsNecessary(env, err); 812 return NULL; 813 } 814 815 // Wrap the IGBP in a Java-language Surface. 816 return android_view_Surface_createFromIGraphicBufferProducer(env, 817 bufferProducer); 818} 819 820static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) { 821 ALOGV("android_media_MediaCodec_start"); 822 823 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 824 825 if (codec == NULL) { 826 jniThrowException(env, "java/lang/IllegalStateException", "no codec found"); 827 return; 828 } 829 830 status_t err = codec->start(); 831 832 throwExceptionAsNecessary(env, err, "start failed"); 833} 834 835static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) { 836 ALOGV("android_media_MediaCodec_stop"); 837 838 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 839 840 if (codec == NULL) { 841 jniThrowException(env, "java/lang/IllegalStateException", NULL); 842 return; 843 } 844 845 status_t err = codec->stop(); 846 847 throwExceptionAsNecessary(env, err); 848} 849 850static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) { 851 ALOGV("android_media_MediaCodec_flush"); 852 853 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 854 855 if (codec == NULL) { 856 jniThrowException(env, "java/lang/IllegalStateException", NULL); 857 return; 858 } 859 860 status_t err = codec->flush(); 861 862 throwExceptionAsNecessary(env, err); 863} 864 865static void android_media_MediaCodec_queueInputBuffer( 866 JNIEnv *env, 867 jobject thiz, 868 jint index, 869 jint offset, 870 jint size, 871 jlong timestampUs, 872 jint flags) { 873 ALOGV("android_media_MediaCodec_queueInputBuffer"); 874 875 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 876 877 if (codec == NULL) { 878 jniThrowException(env, "java/lang/IllegalStateException", NULL); 879 return; 880 } 881 882 AString errorDetailMsg; 883 884 status_t err = codec->queueInputBuffer( 885 index, offset, size, timestampUs, flags, &errorDetailMsg); 886 887 throwExceptionAsNecessary( 888 env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 889} 890 891static void android_media_MediaCodec_queueSecureInputBuffer( 892 JNIEnv *env, 893 jobject thiz, 894 jint index, 895 jint offset, 896 jobject cryptoInfoObj, 897 jlong timestampUs, 898 jint flags) { 899 ALOGV("android_media_MediaCodec_queueSecureInputBuffer"); 900 901 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 902 903 if (codec == NULL) { 904 jniThrowException(env, "java/lang/IllegalStateException", NULL); 905 return; 906 } 907 908 jint numSubSamples = 909 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID); 910 911 jintArray numBytesOfClearDataObj = 912 (jintArray)env->GetObjectField( 913 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID); 914 915 jintArray numBytesOfEncryptedDataObj = 916 (jintArray)env->GetObjectField( 917 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID); 918 919 jbyteArray keyObj = 920 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID); 921 922 jbyteArray ivObj = 923 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID); 924 925 jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID); 926 927 status_t err = OK; 928 929 CryptoPlugin::SubSample *subSamples = NULL; 930 jbyte *key = NULL; 931 jbyte *iv = NULL; 932 933 if (numSubSamples <= 0) { 934 err = -EINVAL; 935 } else if (numBytesOfClearDataObj == NULL 936 && numBytesOfEncryptedDataObj == NULL) { 937 err = -EINVAL; 938 } else if (numBytesOfEncryptedDataObj != NULL 939 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) { 940 err = -ERANGE; 941 } else if (numBytesOfClearDataObj != NULL 942 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) { 943 err = -ERANGE; 944 // subSamples array may silently overflow if number of samples are too large. Use 945 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms 946 } else if ( CC_UNLIKELY(numSubSamples >= INT32_MAX / sizeof(*subSamples)) ) { 947 err = -EINVAL; 948 } else { 949 jboolean isCopy; 950 951 jint *numBytesOfClearData = 952 (numBytesOfClearDataObj == NULL) 953 ? NULL 954 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy); 955 956 jint *numBytesOfEncryptedData = 957 (numBytesOfEncryptedDataObj == NULL) 958 ? NULL 959 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); 960 961 subSamples = new CryptoPlugin::SubSample[numSubSamples]; 962 963 for (jint i = 0; i < numSubSamples; ++i) { 964 subSamples[i].mNumBytesOfClearData = 965 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i]; 966 967 subSamples[i].mNumBytesOfEncryptedData = 968 (numBytesOfEncryptedData == NULL) 969 ? 0 : numBytesOfEncryptedData[i]; 970 } 971 972 if (numBytesOfEncryptedData != NULL) { 973 env->ReleaseIntArrayElements( 974 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0); 975 numBytesOfEncryptedData = NULL; 976 } 977 978 if (numBytesOfClearData != NULL) { 979 env->ReleaseIntArrayElements( 980 numBytesOfClearDataObj, numBytesOfClearData, 0); 981 numBytesOfClearData = NULL; 982 } 983 } 984 985 if (err == OK && keyObj != NULL) { 986 if (env->GetArrayLength(keyObj) != 16) { 987 err = -EINVAL; 988 } else { 989 jboolean isCopy; 990 key = env->GetByteArrayElements(keyObj, &isCopy); 991 } 992 } 993 994 if (err == OK && ivObj != NULL) { 995 if (env->GetArrayLength(ivObj) != 16) { 996 err = -EINVAL; 997 } else { 998 jboolean isCopy; 999 iv = env->GetByteArrayElements(ivObj, &isCopy); 1000 } 1001 } 1002 1003 AString errorDetailMsg; 1004 1005 if (err == OK) { 1006 err = codec->queueSecureInputBuffer( 1007 index, offset, 1008 subSamples, numSubSamples, 1009 (const uint8_t *)key, (const uint8_t *)iv, 1010 (CryptoPlugin::Mode)mode, 1011 timestampUs, 1012 flags, 1013 &errorDetailMsg); 1014 } 1015 1016 if (iv != NULL) { 1017 env->ReleaseByteArrayElements(ivObj, iv, 0); 1018 iv = NULL; 1019 } 1020 1021 if (key != NULL) { 1022 env->ReleaseByteArrayElements(keyObj, key, 0); 1023 key = NULL; 1024 } 1025 1026 delete[] subSamples; 1027 subSamples = NULL; 1028 1029 throwExceptionAsNecessary( 1030 env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 1031} 1032 1033static jint android_media_MediaCodec_dequeueInputBuffer( 1034 JNIEnv *env, jobject thiz, jlong timeoutUs) { 1035 ALOGV("android_media_MediaCodec_dequeueInputBuffer"); 1036 1037 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1038 1039 if (codec == NULL) { 1040 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1041 return -1; 1042 } 1043 1044 size_t index; 1045 status_t err = codec->dequeueInputBuffer(&index, timeoutUs); 1046 1047 if (err == OK) { 1048 return (jint) index; 1049 } 1050 1051 return throwExceptionAsNecessary(env, err); 1052} 1053 1054static jint android_media_MediaCodec_dequeueOutputBuffer( 1055 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) { 1056 ALOGV("android_media_MediaCodec_dequeueOutputBuffer"); 1057 1058 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1059 1060 if (codec == NULL) { 1061 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1062 return 0; 1063 } 1064 1065 size_t index; 1066 status_t err = codec->dequeueOutputBuffer( 1067 env, bufferInfo, &index, timeoutUs); 1068 1069 if (err == OK) { 1070 return (jint) index; 1071 } 1072 1073 return throwExceptionAsNecessary(env, err); 1074} 1075 1076static void android_media_MediaCodec_releaseOutputBuffer( 1077 JNIEnv *env, jobject thiz, 1078 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) { 1079 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease"); 1080 1081 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1082 1083 if (codec == NULL) { 1084 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1085 return; 1086 } 1087 1088 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs); 1089 1090 throwExceptionAsNecessary(env, err); 1091} 1092 1093static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env, 1094 jobject thiz) { 1095 ALOGV("android_media_MediaCodec_signalEndOfInputStream"); 1096 1097 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1098 if (codec == NULL) { 1099 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1100 return; 1101 } 1102 1103 status_t err = codec->signalEndOfInputStream(); 1104 1105 throwExceptionAsNecessary(env, err); 1106} 1107 1108static jobject android_media_MediaCodec_getFormatNative( 1109 JNIEnv *env, jobject thiz, jboolean input) { 1110 ALOGV("android_media_MediaCodec_getFormatNative"); 1111 1112 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1113 1114 if (codec == NULL) { 1115 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1116 return NULL; 1117 } 1118 1119 jobject format; 1120 status_t err = codec->getFormat(env, input, &format); 1121 1122 if (err == OK) { 1123 return format; 1124 } 1125 1126 throwExceptionAsNecessary(env, err); 1127 1128 return NULL; 1129} 1130 1131static jobject android_media_MediaCodec_getOutputFormatForIndexNative( 1132 JNIEnv *env, jobject thiz, jint index) { 1133 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative"); 1134 1135 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1136 1137 if (codec == NULL) { 1138 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1139 return NULL; 1140 } 1141 1142 jobject format; 1143 status_t err = codec->getOutputFormat(env, index, &format); 1144 1145 if (err == OK) { 1146 return format; 1147 } 1148 1149 throwExceptionAsNecessary(env, err); 1150 1151 return NULL; 1152} 1153 1154static jobjectArray android_media_MediaCodec_getBuffers( 1155 JNIEnv *env, jobject thiz, jboolean input) { 1156 ALOGV("android_media_MediaCodec_getBuffers"); 1157 1158 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1159 1160 if (codec == NULL) { 1161 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1162 return NULL; 1163 } 1164 1165 jobjectArray buffers; 1166 status_t err = codec->getBuffers(env, input, &buffers); 1167 1168 if (err == OK) { 1169 return buffers; 1170 } 1171 1172 // if we're out of memory, an exception was already thrown 1173 if (err != NO_MEMORY) { 1174 throwExceptionAsNecessary(env, err); 1175 } 1176 1177 return NULL; 1178} 1179 1180static jobject android_media_MediaCodec_getBuffer( 1181 JNIEnv *env, jobject thiz, jboolean input, jint index) { 1182 ALOGV("android_media_MediaCodec_getBuffer"); 1183 1184 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1185 1186 if (codec == NULL) { 1187 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1188 return NULL; 1189 } 1190 1191 jobject buffer; 1192 status_t err = codec->getBuffer(env, input, index, &buffer); 1193 1194 if (err == OK) { 1195 return buffer; 1196 } 1197 1198 // if we're out of memory, an exception was already thrown 1199 if (err != NO_MEMORY) { 1200 throwExceptionAsNecessary(env, err); 1201 } 1202 1203 return NULL; 1204} 1205 1206static jobject android_media_MediaCodec_getImage( 1207 JNIEnv *env, jobject thiz, jboolean input, jint index) { 1208 ALOGV("android_media_MediaCodec_getImage"); 1209 1210 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1211 1212 if (codec == NULL) { 1213 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1214 return NULL; 1215 } 1216 1217 jobject image; 1218 status_t err = codec->getImage(env, input, index, &image); 1219 1220 if (err == OK) { 1221 return image; 1222 } 1223 1224 // if we're out of memory, an exception was already thrown 1225 if (err != NO_MEMORY) { 1226 throwExceptionAsNecessary(env, err); 1227 } 1228 1229 return NULL; 1230} 1231 1232static jobject android_media_MediaCodec_getName( 1233 JNIEnv *env, jobject thiz) { 1234 ALOGV("android_media_MediaCodec_getName"); 1235 1236 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1237 1238 if (codec == NULL) { 1239 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1240 return NULL; 1241 } 1242 1243 jstring name; 1244 status_t err = codec->getName(env, &name); 1245 1246 if (err == OK) { 1247 return name; 1248 } 1249 1250 throwExceptionAsNecessary(env, err); 1251 1252 return NULL; 1253} 1254 1255static void android_media_MediaCodec_setParameters( 1256 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) { 1257 ALOGV("android_media_MediaCodec_setParameters"); 1258 1259 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1260 1261 if (codec == NULL) { 1262 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1263 return; 1264 } 1265 1266 sp<AMessage> params; 1267 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, ¶ms); 1268 1269 if (err == OK) { 1270 err = codec->setParameters(params); 1271 } 1272 1273 throwExceptionAsNecessary(env, err); 1274} 1275 1276static void android_media_MediaCodec_setVideoScalingMode( 1277 JNIEnv *env, jobject thiz, jint mode) { 1278 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1279 1280 if (codec == NULL) { 1281 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1282 return; 1283 } 1284 1285 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW 1286 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { 1287 jniThrowException(env, "java/lang/InvalidArgumentException", NULL); 1288 return; 1289 } 1290 1291 codec->setVideoScalingMode(mode); 1292} 1293 1294static void android_media_MediaCodec_native_init(JNIEnv *env) { 1295 ScopedLocalRef<jclass> clazz( 1296 env, env->FindClass("android/media/MediaCodec")); 1297 CHECK(clazz.get() != NULL); 1298 1299 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J"); 1300 CHECK(gFields.context != NULL); 1301 1302 gFields.postEventFromNativeID = 1303 env->GetMethodID( 1304 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V"); 1305 1306 CHECK(gFields.postEventFromNativeID != NULL); 1307 1308 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo")); 1309 CHECK(clazz.get() != NULL); 1310 1311 gFields.cryptoInfoNumSubSamplesID = 1312 env->GetFieldID(clazz.get(), "numSubSamples", "I"); 1313 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL); 1314 1315 gFields.cryptoInfoNumBytesOfClearDataID = 1316 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I"); 1317 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL); 1318 1319 gFields.cryptoInfoNumBytesOfEncryptedDataID = 1320 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I"); 1321 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL); 1322 1323 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B"); 1324 CHECK(gFields.cryptoInfoKeyID != NULL); 1325 1326 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B"); 1327 CHECK(gFields.cryptoInfoIVID != NULL); 1328 1329 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I"); 1330 CHECK(gFields.cryptoInfoModeID != NULL); 1331 1332 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException")); 1333 CHECK(clazz.get() != NULL); 1334 1335 jfieldID field; 1336 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I"); 1337 CHECK(field != NULL); 1338 gCryptoErrorCodes.cryptoErrorNoKey = 1339 env->GetStaticIntField(clazz.get(), field); 1340 1341 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I"); 1342 CHECK(field != NULL); 1343 gCryptoErrorCodes.cryptoErrorKeyExpired = 1344 env->GetStaticIntField(clazz.get(), field); 1345 1346 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I"); 1347 CHECK(field != NULL); 1348 gCryptoErrorCodes.cryptoErrorResourceBusy = 1349 env->GetStaticIntField(clazz.get(), field); 1350} 1351 1352static void android_media_MediaCodec_native_setup( 1353 JNIEnv *env, jobject thiz, 1354 jstring name, jboolean nameIsType, jboolean encoder) { 1355 if (name == NULL) { 1356 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 1357 return; 1358 } 1359 1360 const char *tmp = env->GetStringUTFChars(name, NULL); 1361 1362 if (tmp == NULL) { 1363 return; 1364 } 1365 1366 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder); 1367 1368 status_t err = codec->initCheck(); 1369 1370 env->ReleaseStringUTFChars(name, tmp); 1371 tmp = NULL; 1372 1373 if (err != OK) { 1374 jniThrowException( 1375 env, 1376 "java/io/IOException", 1377 "Failed to allocate component instance"); 1378 return; 1379 } 1380 1381 codec->registerSelf(); 1382 1383 setMediaCodec(env,thiz, codec); 1384} 1385 1386static void android_media_MediaCodec_native_finalize( 1387 JNIEnv *env, jobject thiz) { 1388 android_media_MediaCodec_release(env, thiz); 1389} 1390 1391static JNINativeMethod gMethods[] = { 1392 { "native_release", "()V", (void *)android_media_MediaCodec_release }, 1393 1394 { "native_setCallback", 1395 "(Landroid/media/MediaCodec$Callback;)V", 1396 (void *)android_media_MediaCodec_native_setCallback }, 1397 1398 { "native_configure", 1399 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;" 1400 "Landroid/media/MediaCrypto;I)V", 1401 (void *)android_media_MediaCodec_native_configure }, 1402 1403 { "createInputSurface", "()Landroid/view/Surface;", 1404 (void *)android_media_MediaCodec_createInputSurface }, 1405 1406 { "native_start", "()V", (void *)android_media_MediaCodec_start }, 1407 { "native_stop", "()V", (void *)android_media_MediaCodec_stop }, 1408 { "native_flush", "()V", (void *)android_media_MediaCodec_flush }, 1409 1410 { "native_queueInputBuffer", "(IIIJI)V", 1411 (void *)android_media_MediaCodec_queueInputBuffer }, 1412 1413 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V", 1414 (void *)android_media_MediaCodec_queueSecureInputBuffer }, 1415 1416 { "native_dequeueInputBuffer", "(J)I", 1417 (void *)android_media_MediaCodec_dequeueInputBuffer }, 1418 1419 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", 1420 (void *)android_media_MediaCodec_dequeueOutputBuffer }, 1421 1422 { "releaseOutputBuffer", "(IZZJ)V", 1423 (void *)android_media_MediaCodec_releaseOutputBuffer }, 1424 1425 { "signalEndOfInputStream", "()V", 1426 (void *)android_media_MediaCodec_signalEndOfInputStream }, 1427 1428 { "getFormatNative", "(Z)Ljava/util/Map;", 1429 (void *)android_media_MediaCodec_getFormatNative }, 1430 1431 { "getOutputFormatNative", "(I)Ljava/util/Map;", 1432 (void *)android_media_MediaCodec_getOutputFormatForIndexNative }, 1433 1434 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;", 1435 (void *)android_media_MediaCodec_getBuffers }, 1436 1437 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;", 1438 (void *)android_media_MediaCodec_getBuffer }, 1439 1440 { "getImage", "(ZI)Landroid/media/Image;", 1441 (void *)android_media_MediaCodec_getImage }, 1442 1443 { "getName", "()Ljava/lang/String;", 1444 (void *)android_media_MediaCodec_getName }, 1445 1446 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V", 1447 (void *)android_media_MediaCodec_setParameters }, 1448 1449 { "setVideoScalingMode", "(I)V", 1450 (void *)android_media_MediaCodec_setVideoScalingMode }, 1451 1452 { "native_init", "()V", (void *)android_media_MediaCodec_native_init }, 1453 1454 { "native_setup", "(Ljava/lang/String;ZZ)V", 1455 (void *)android_media_MediaCodec_native_setup }, 1456 1457 { "native_finalize", "()V", 1458 (void *)android_media_MediaCodec_native_finalize }, 1459}; 1460 1461int register_android_media_MediaCodec(JNIEnv *env) { 1462 return AndroidRuntime::registerNativeMethods(env, 1463 "android/media/MediaCodec", gMethods, NELEM(gMethods)); 1464} 1465