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