android_media_MediaCodec.cpp revision 7be24522ce2e1821ad45e7ada7c3f91e6814889a
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, limitID, 453 input ? buffer->capacity() : (buffer->offset() + buffer->size())); 454 env->DeleteLocalRef(me); 455 me = env->CallObjectMethod( 456 byteBuffer, positionID, 457 input ? 0 : buffer->offset()); 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 int32_t err, actionCode; 570 CHECK(msg->findInt32("err", &err)); 571 CHECK(msg->findInt32("actionCode", &actionCode)); 572 573 // use Integer object to pass the action code 574 ScopedLocalRef<jclass> clazz( 575 env, env->FindClass("android/media/MediaCodec$CodecException")); 576 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V"); 577 578 AString str; 579 const char *detail = "Unknown error"; 580 if (msg->findString("detail", &str)) { 581 detail = str.c_str(); 582 } 583 jstring msgObj = env->NewStringUTF(detail); 584 585 obj = env->NewObject(clazz.get(), ctor, err, actionCode, msgObj); 586 587 if (obj == NULL) { 588 if (env->ExceptionCheck()) { 589 ALOGE("Could not create CodecException object."); 590 env->ExceptionClear(); 591 } 592 jniThrowException(env, "java/lang/IllegalStateException", NULL); 593 return; 594 } 595 596 break; 597 } 598 599 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED: 600 { 601 sp<AMessage> format; 602 CHECK(msg->findMessage("format", &format)); 603 604 if (OK != ConvertMessageToMap(env, format, &obj)) { 605 jniThrowException(env, "java/lang/IllegalStateException", NULL); 606 return; 607 } 608 609 break; 610 } 611 612 default: 613 TRESPASS(); 614 } 615 616 env->CallVoidMethod( 617 mObject, 618 gFields.postEventFromNativeID, 619 EVENT_CALLBACK, 620 arg1, 621 arg2, 622 obj); 623 624 env->DeleteLocalRef(obj); 625} 626 627void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) { 628 switch (msg->what()) { 629 case kWhatCallbackNotify: 630 { 631 handleCallback(msg); 632 break; 633 } 634 default: 635 TRESPASS(); 636 } 637} 638 639} // namespace android 640 641//////////////////////////////////////////////////////////////////////////////// 642 643using namespace android; 644 645static sp<JMediaCodec> setMediaCodec( 646 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) { 647 sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context); 648 if (codec != NULL) { 649 codec->incStrong(thiz); 650 } 651 if (old != NULL) { 652 /* release MediaCodec and stop the looper now before decStrong. 653 * otherwise JMediaCodec::~JMediaCodec() could be called from within 654 * its message handler, doing release() from there will deadlock 655 * (as MediaCodec::release() post synchronous message to the same looper) 656 */ 657 old->release(); 658 old->decStrong(thiz); 659 } 660 env->SetLongField(thiz, gFields.context, (jlong)codec.get()); 661 662 return old; 663} 664 665static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) { 666 return (JMediaCodec *)env->GetLongField(thiz, gFields.context); 667} 668 669static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) { 670 setMediaCodec(env, thiz, NULL); 671} 672 673static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) { 674 ScopedLocalRef<jclass> clazz( 675 env, env->FindClass("android/media/MediaCodec$CryptoException")); 676 CHECK(clazz.get() != NULL); 677 678 jmethodID constructID = 679 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V"); 680 CHECK(constructID != NULL); 681 682 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error"); 683 684 /* translate OS errors to Java API CryptoException errorCodes */ 685 switch (err) { 686 case ERROR_DRM_NO_LICENSE: 687 err = gCryptoErrorCodes.cryptoErrorNoKey; 688 break; 689 case ERROR_DRM_LICENSE_EXPIRED: 690 err = gCryptoErrorCodes.cryptoErrorKeyExpired; 691 break; 692 case ERROR_DRM_RESOURCE_BUSY: 693 err = gCryptoErrorCodes.cryptoErrorResourceBusy; 694 break; 695 default: 696 break; 697 } 698 699 jthrowable exception = 700 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj); 701 702 env->Throw(exception); 703} 704 705static jint throwExceptionAsNecessary( 706 JNIEnv *env, status_t err, const char *msg = NULL) { 707 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) { 708 // We'll throw our custom MediaCodec.CryptoException 709 throwCryptoException(env, err, msg); 710 return 0; 711 } 712 713 switch (err) { 714 case OK: 715 return 0; 716 717 case -EAGAIN: 718 return DEQUEUE_INFO_TRY_AGAIN_LATER; 719 720 case INFO_FORMAT_CHANGED: 721 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED; 722 723 case INFO_OUTPUT_BUFFERS_CHANGED: 724 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED; 725 726 case ERROR_DRM_NO_LICENSE: 727 case ERROR_DRM_LICENSE_EXPIRED: 728 case ERROR_DRM_RESOURCE_BUSY: 729 throwCryptoException(env, err, msg); 730 break; 731 732 default: 733 { 734 jniThrowException(env, "java/lang/IllegalStateException", msg); 735 break; 736 } 737 } 738 739 return 0; 740} 741 742static void android_media_MediaCodec_native_setCallback( 743 JNIEnv *env, 744 jobject thiz, 745 jobject cb) { 746 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 747 748 if (codec == NULL) { 749 jniThrowException(env, "java/lang/IllegalStateException", NULL); 750 return; 751 } 752 753 status_t err = codec->setCallback(cb); 754 755 throwExceptionAsNecessary(env, err); 756} 757 758static void android_media_MediaCodec_native_configure( 759 JNIEnv *env, 760 jobject thiz, 761 jobjectArray keys, jobjectArray values, 762 jobject jsurface, 763 jobject jcrypto, 764 jint flags) { 765 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 766 767 if (codec == NULL) { 768 jniThrowException(env, "java/lang/IllegalStateException", NULL); 769 return; 770 } 771 772 sp<AMessage> format; 773 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format); 774 775 if (err != OK) { 776 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 777 return; 778 } 779 780 sp<IGraphicBufferProducer> bufferProducer; 781 if (jsurface != NULL) { 782 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 783 if (surface != NULL) { 784 bufferProducer = surface->getIGraphicBufferProducer(); 785 } else { 786 jniThrowException( 787 env, 788 "java/lang/IllegalArgumentException", 789 "The surface has been released"); 790 return; 791 } 792 } 793 794 sp<ICrypto> crypto; 795 if (jcrypto != NULL) { 796 crypto = JCrypto::GetCrypto(env, jcrypto); 797 } 798 799 err = codec->configure(format, bufferProducer, crypto, flags); 800 801 throwExceptionAsNecessary(env, err); 802} 803 804static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env, 805 jobject thiz) { 806 ALOGV("android_media_MediaCodec_createInputSurface"); 807 808 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 809 if (codec == NULL) { 810 jniThrowException(env, "java/lang/IllegalStateException", NULL); 811 return NULL; 812 } 813 814 // Tell the MediaCodec that we want to use a Surface as input. 815 sp<IGraphicBufferProducer> bufferProducer; 816 status_t err = codec->createInputSurface(&bufferProducer); 817 if (err != NO_ERROR) { 818 throwExceptionAsNecessary(env, err); 819 return NULL; 820 } 821 822 // Wrap the IGBP in a Java-language Surface. 823 return android_view_Surface_createFromIGraphicBufferProducer(env, 824 bufferProducer); 825} 826 827static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) { 828 ALOGV("android_media_MediaCodec_start"); 829 830 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 831 832 if (codec == NULL) { 833 jniThrowException(env, "java/lang/IllegalStateException", "no codec found"); 834 return; 835 } 836 837 status_t err = codec->start(); 838 839 throwExceptionAsNecessary(env, err, "start failed"); 840} 841 842static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) { 843 ALOGV("android_media_MediaCodec_stop"); 844 845 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 846 847 if (codec == NULL) { 848 jniThrowException(env, "java/lang/IllegalStateException", NULL); 849 return; 850 } 851 852 status_t err = codec->stop(); 853 854 throwExceptionAsNecessary(env, err); 855} 856 857static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) { 858 ALOGV("android_media_MediaCodec_flush"); 859 860 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 861 862 if (codec == NULL) { 863 jniThrowException(env, "java/lang/IllegalStateException", NULL); 864 return; 865 } 866 867 status_t err = codec->flush(); 868 869 throwExceptionAsNecessary(env, err); 870} 871 872static void android_media_MediaCodec_queueInputBuffer( 873 JNIEnv *env, 874 jobject thiz, 875 jint index, 876 jint offset, 877 jint size, 878 jlong timestampUs, 879 jint flags) { 880 ALOGV("android_media_MediaCodec_queueInputBuffer"); 881 882 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 883 884 if (codec == NULL) { 885 jniThrowException(env, "java/lang/IllegalStateException", NULL); 886 return; 887 } 888 889 AString errorDetailMsg; 890 891 status_t err = codec->queueInputBuffer( 892 index, offset, size, timestampUs, flags, &errorDetailMsg); 893 894 throwExceptionAsNecessary( 895 env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 896} 897 898static void android_media_MediaCodec_queueSecureInputBuffer( 899 JNIEnv *env, 900 jobject thiz, 901 jint index, 902 jint offset, 903 jobject cryptoInfoObj, 904 jlong timestampUs, 905 jint flags) { 906 ALOGV("android_media_MediaCodec_queueSecureInputBuffer"); 907 908 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 909 910 if (codec == NULL) { 911 jniThrowException(env, "java/lang/IllegalStateException", NULL); 912 return; 913 } 914 915 jint numSubSamples = 916 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID); 917 918 jintArray numBytesOfClearDataObj = 919 (jintArray)env->GetObjectField( 920 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID); 921 922 jintArray numBytesOfEncryptedDataObj = 923 (jintArray)env->GetObjectField( 924 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID); 925 926 jbyteArray keyObj = 927 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID); 928 929 jbyteArray ivObj = 930 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID); 931 932 jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID); 933 934 status_t err = OK; 935 936 CryptoPlugin::SubSample *subSamples = NULL; 937 jbyte *key = NULL; 938 jbyte *iv = NULL; 939 940 if (numSubSamples <= 0) { 941 err = -EINVAL; 942 } else if (numBytesOfClearDataObj == NULL 943 && numBytesOfEncryptedDataObj == NULL) { 944 err = -EINVAL; 945 } else if (numBytesOfEncryptedDataObj != NULL 946 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) { 947 err = -ERANGE; 948 } else if (numBytesOfClearDataObj != NULL 949 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) { 950 err = -ERANGE; 951 // subSamples array may silently overflow if number of samples are too large. Use 952 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms 953 } else if ( CC_UNLIKELY(numSubSamples >= INT32_MAX / sizeof(*subSamples)) ) { 954 err = -EINVAL; 955 } else { 956 jboolean isCopy; 957 958 jint *numBytesOfClearData = 959 (numBytesOfClearDataObj == NULL) 960 ? NULL 961 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy); 962 963 jint *numBytesOfEncryptedData = 964 (numBytesOfEncryptedDataObj == NULL) 965 ? NULL 966 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); 967 968 subSamples = new CryptoPlugin::SubSample[numSubSamples]; 969 970 for (jint i = 0; i < numSubSamples; ++i) { 971 subSamples[i].mNumBytesOfClearData = 972 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i]; 973 974 subSamples[i].mNumBytesOfEncryptedData = 975 (numBytesOfEncryptedData == NULL) 976 ? 0 : numBytesOfEncryptedData[i]; 977 } 978 979 if (numBytesOfEncryptedData != NULL) { 980 env->ReleaseIntArrayElements( 981 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0); 982 numBytesOfEncryptedData = NULL; 983 } 984 985 if (numBytesOfClearData != NULL) { 986 env->ReleaseIntArrayElements( 987 numBytesOfClearDataObj, numBytesOfClearData, 0); 988 numBytesOfClearData = NULL; 989 } 990 } 991 992 if (err == OK && keyObj != NULL) { 993 if (env->GetArrayLength(keyObj) != 16) { 994 err = -EINVAL; 995 } else { 996 jboolean isCopy; 997 key = env->GetByteArrayElements(keyObj, &isCopy); 998 } 999 } 1000 1001 if (err == OK && ivObj != NULL) { 1002 if (env->GetArrayLength(ivObj) != 16) { 1003 err = -EINVAL; 1004 } else { 1005 jboolean isCopy; 1006 iv = env->GetByteArrayElements(ivObj, &isCopy); 1007 } 1008 } 1009 1010 AString errorDetailMsg; 1011 1012 if (err == OK) { 1013 err = codec->queueSecureInputBuffer( 1014 index, offset, 1015 subSamples, numSubSamples, 1016 (const uint8_t *)key, (const uint8_t *)iv, 1017 (CryptoPlugin::Mode)mode, 1018 timestampUs, 1019 flags, 1020 &errorDetailMsg); 1021 } 1022 1023 if (iv != NULL) { 1024 env->ReleaseByteArrayElements(ivObj, iv, 0); 1025 iv = NULL; 1026 } 1027 1028 if (key != NULL) { 1029 env->ReleaseByteArrayElements(keyObj, key, 0); 1030 key = NULL; 1031 } 1032 1033 delete[] subSamples; 1034 subSamples = NULL; 1035 1036 throwExceptionAsNecessary( 1037 env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 1038} 1039 1040static jint android_media_MediaCodec_dequeueInputBuffer( 1041 JNIEnv *env, jobject thiz, jlong timeoutUs) { 1042 ALOGV("android_media_MediaCodec_dequeueInputBuffer"); 1043 1044 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1045 1046 if (codec == NULL) { 1047 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1048 return -1; 1049 } 1050 1051 size_t index; 1052 status_t err = codec->dequeueInputBuffer(&index, timeoutUs); 1053 1054 if (err == OK) { 1055 return (jint) index; 1056 } 1057 1058 return throwExceptionAsNecessary(env, err); 1059} 1060 1061static jint android_media_MediaCodec_dequeueOutputBuffer( 1062 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) { 1063 ALOGV("android_media_MediaCodec_dequeueOutputBuffer"); 1064 1065 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1066 1067 if (codec == NULL) { 1068 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1069 return 0; 1070 } 1071 1072 size_t index; 1073 status_t err = codec->dequeueOutputBuffer( 1074 env, bufferInfo, &index, timeoutUs); 1075 1076 if (err == OK) { 1077 return (jint) index; 1078 } 1079 1080 return throwExceptionAsNecessary(env, err); 1081} 1082 1083static void android_media_MediaCodec_releaseOutputBuffer( 1084 JNIEnv *env, jobject thiz, 1085 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) { 1086 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease"); 1087 1088 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1089 1090 if (codec == NULL) { 1091 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1092 return; 1093 } 1094 1095 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs); 1096 1097 throwExceptionAsNecessary(env, err); 1098} 1099 1100static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env, 1101 jobject thiz) { 1102 ALOGV("android_media_MediaCodec_signalEndOfInputStream"); 1103 1104 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1105 if (codec == NULL) { 1106 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1107 return; 1108 } 1109 1110 status_t err = codec->signalEndOfInputStream(); 1111 1112 throwExceptionAsNecessary(env, err); 1113} 1114 1115static jobject android_media_MediaCodec_getFormatNative( 1116 JNIEnv *env, jobject thiz, jboolean input) { 1117 ALOGV("android_media_MediaCodec_getFormatNative"); 1118 1119 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1120 1121 if (codec == NULL) { 1122 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1123 return NULL; 1124 } 1125 1126 jobject format; 1127 status_t err = codec->getFormat(env, input, &format); 1128 1129 if (err == OK) { 1130 return format; 1131 } 1132 1133 throwExceptionAsNecessary(env, err); 1134 1135 return NULL; 1136} 1137 1138static jobject android_media_MediaCodec_getOutputFormatForIndexNative( 1139 JNIEnv *env, jobject thiz, jint index) { 1140 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative"); 1141 1142 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1143 1144 if (codec == NULL) { 1145 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1146 return NULL; 1147 } 1148 1149 jobject format; 1150 status_t err = codec->getOutputFormat(env, index, &format); 1151 1152 if (err == OK) { 1153 return format; 1154 } 1155 1156 throwExceptionAsNecessary(env, err); 1157 1158 return NULL; 1159} 1160 1161static jobjectArray android_media_MediaCodec_getBuffers( 1162 JNIEnv *env, jobject thiz, jboolean input) { 1163 ALOGV("android_media_MediaCodec_getBuffers"); 1164 1165 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1166 1167 if (codec == NULL) { 1168 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1169 return NULL; 1170 } 1171 1172 jobjectArray buffers; 1173 status_t err = codec->getBuffers(env, input, &buffers); 1174 1175 if (err == OK) { 1176 return buffers; 1177 } 1178 1179 // if we're out of memory, an exception was already thrown 1180 if (err != NO_MEMORY) { 1181 throwExceptionAsNecessary(env, err); 1182 } 1183 1184 return NULL; 1185} 1186 1187static jobject android_media_MediaCodec_getBuffer( 1188 JNIEnv *env, jobject thiz, jboolean input, jint index) { 1189 ALOGV("android_media_MediaCodec_getBuffer"); 1190 1191 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1192 1193 if (codec == NULL) { 1194 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1195 return NULL; 1196 } 1197 1198 jobject buffer; 1199 status_t err = codec->getBuffer(env, input, index, &buffer); 1200 1201 if (err == OK) { 1202 return buffer; 1203 } 1204 1205 // if we're out of memory, an exception was already thrown 1206 if (err != NO_MEMORY) { 1207 throwExceptionAsNecessary(env, err); 1208 } 1209 1210 return NULL; 1211} 1212 1213static jobject android_media_MediaCodec_getImage( 1214 JNIEnv *env, jobject thiz, jboolean input, jint index) { 1215 ALOGV("android_media_MediaCodec_getImage"); 1216 1217 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1218 1219 if (codec == NULL) { 1220 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1221 return NULL; 1222 } 1223 1224 jobject image; 1225 status_t err = codec->getImage(env, input, index, &image); 1226 1227 if (err == OK) { 1228 return image; 1229 } 1230 1231 // if we're out of memory, an exception was already thrown 1232 if (err != NO_MEMORY) { 1233 throwExceptionAsNecessary(env, err); 1234 } 1235 1236 return NULL; 1237} 1238 1239static jobject android_media_MediaCodec_getName( 1240 JNIEnv *env, jobject thiz) { 1241 ALOGV("android_media_MediaCodec_getName"); 1242 1243 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1244 1245 if (codec == NULL) { 1246 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1247 return NULL; 1248 } 1249 1250 jstring name; 1251 status_t err = codec->getName(env, &name); 1252 1253 if (err == OK) { 1254 return name; 1255 } 1256 1257 throwExceptionAsNecessary(env, err); 1258 1259 return NULL; 1260} 1261 1262static void android_media_MediaCodec_setParameters( 1263 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) { 1264 ALOGV("android_media_MediaCodec_setParameters"); 1265 1266 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1267 1268 if (codec == NULL) { 1269 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1270 return; 1271 } 1272 1273 sp<AMessage> params; 1274 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, ¶ms); 1275 1276 if (err == OK) { 1277 err = codec->setParameters(params); 1278 } 1279 1280 throwExceptionAsNecessary(env, err); 1281} 1282 1283static void android_media_MediaCodec_setVideoScalingMode( 1284 JNIEnv *env, jobject thiz, jint mode) { 1285 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1286 1287 if (codec == NULL) { 1288 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1289 return; 1290 } 1291 1292 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW 1293 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { 1294 jniThrowException(env, "java/lang/InvalidArgumentException", NULL); 1295 return; 1296 } 1297 1298 codec->setVideoScalingMode(mode); 1299} 1300 1301static void android_media_MediaCodec_native_init(JNIEnv *env) { 1302 ScopedLocalRef<jclass> clazz( 1303 env, env->FindClass("android/media/MediaCodec")); 1304 CHECK(clazz.get() != NULL); 1305 1306 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J"); 1307 CHECK(gFields.context != NULL); 1308 1309 gFields.postEventFromNativeID = 1310 env->GetMethodID( 1311 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V"); 1312 1313 CHECK(gFields.postEventFromNativeID != NULL); 1314 1315 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo")); 1316 CHECK(clazz.get() != NULL); 1317 1318 gFields.cryptoInfoNumSubSamplesID = 1319 env->GetFieldID(clazz.get(), "numSubSamples", "I"); 1320 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL); 1321 1322 gFields.cryptoInfoNumBytesOfClearDataID = 1323 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I"); 1324 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL); 1325 1326 gFields.cryptoInfoNumBytesOfEncryptedDataID = 1327 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I"); 1328 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL); 1329 1330 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B"); 1331 CHECK(gFields.cryptoInfoKeyID != NULL); 1332 1333 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B"); 1334 CHECK(gFields.cryptoInfoIVID != NULL); 1335 1336 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I"); 1337 CHECK(gFields.cryptoInfoModeID != NULL); 1338 1339 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException")); 1340 CHECK(clazz.get() != NULL); 1341 1342 jfieldID field; 1343 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I"); 1344 CHECK(field != NULL); 1345 gCryptoErrorCodes.cryptoErrorNoKey = 1346 env->GetStaticIntField(clazz.get(), field); 1347 1348 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I"); 1349 CHECK(field != NULL); 1350 gCryptoErrorCodes.cryptoErrorKeyExpired = 1351 env->GetStaticIntField(clazz.get(), field); 1352 1353 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I"); 1354 CHECK(field != NULL); 1355 gCryptoErrorCodes.cryptoErrorResourceBusy = 1356 env->GetStaticIntField(clazz.get(), field); 1357} 1358 1359static void android_media_MediaCodec_native_setup( 1360 JNIEnv *env, jobject thiz, 1361 jstring name, jboolean nameIsType, jboolean encoder) { 1362 if (name == NULL) { 1363 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 1364 return; 1365 } 1366 1367 const char *tmp = env->GetStringUTFChars(name, NULL); 1368 1369 if (tmp == NULL) { 1370 return; 1371 } 1372 1373 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder); 1374 1375 status_t err = codec->initCheck(); 1376 1377 env->ReleaseStringUTFChars(name, tmp); 1378 tmp = NULL; 1379 1380 if (err != OK) { 1381 jniThrowException( 1382 env, 1383 "java/io/IOException", 1384 "Failed to allocate component instance"); 1385 return; 1386 } 1387 1388 codec->registerSelf(); 1389 1390 setMediaCodec(env,thiz, codec); 1391} 1392 1393static void android_media_MediaCodec_native_finalize( 1394 JNIEnv *env, jobject thiz) { 1395 android_media_MediaCodec_release(env, thiz); 1396} 1397 1398static JNINativeMethod gMethods[] = { 1399 { "native_release", "()V", (void *)android_media_MediaCodec_release }, 1400 1401 { "native_setCallback", 1402 "(Landroid/media/MediaCodec$Callback;)V", 1403 (void *)android_media_MediaCodec_native_setCallback }, 1404 1405 { "native_configure", 1406 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;" 1407 "Landroid/media/MediaCrypto;I)V", 1408 (void *)android_media_MediaCodec_native_configure }, 1409 1410 { "createInputSurface", "()Landroid/view/Surface;", 1411 (void *)android_media_MediaCodec_createInputSurface }, 1412 1413 { "native_start", "()V", (void *)android_media_MediaCodec_start }, 1414 { "native_stop", "()V", (void *)android_media_MediaCodec_stop }, 1415 { "native_flush", "()V", (void *)android_media_MediaCodec_flush }, 1416 1417 { "native_queueInputBuffer", "(IIIJI)V", 1418 (void *)android_media_MediaCodec_queueInputBuffer }, 1419 1420 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V", 1421 (void *)android_media_MediaCodec_queueSecureInputBuffer }, 1422 1423 { "native_dequeueInputBuffer", "(J)I", 1424 (void *)android_media_MediaCodec_dequeueInputBuffer }, 1425 1426 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", 1427 (void *)android_media_MediaCodec_dequeueOutputBuffer }, 1428 1429 { "releaseOutputBuffer", "(IZZJ)V", 1430 (void *)android_media_MediaCodec_releaseOutputBuffer }, 1431 1432 { "signalEndOfInputStream", "()V", 1433 (void *)android_media_MediaCodec_signalEndOfInputStream }, 1434 1435 { "getFormatNative", "(Z)Ljava/util/Map;", 1436 (void *)android_media_MediaCodec_getFormatNative }, 1437 1438 { "getOutputFormatNative", "(I)Ljava/util/Map;", 1439 (void *)android_media_MediaCodec_getOutputFormatForIndexNative }, 1440 1441 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;", 1442 (void *)android_media_MediaCodec_getBuffers }, 1443 1444 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;", 1445 (void *)android_media_MediaCodec_getBuffer }, 1446 1447 { "getImage", "(ZI)Landroid/media/Image;", 1448 (void *)android_media_MediaCodec_getImage }, 1449 1450 { "getName", "()Ljava/lang/String;", 1451 (void *)android_media_MediaCodec_getName }, 1452 1453 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V", 1454 (void *)android_media_MediaCodec_setParameters }, 1455 1456 { "setVideoScalingMode", "(I)V", 1457 (void *)android_media_MediaCodec_setVideoScalingMode }, 1458 1459 { "native_init", "()V", (void *)android_media_MediaCodec_native_init }, 1460 1461 { "native_setup", "(Ljava/lang/String;ZZ)V", 1462 (void *)android_media_MediaCodec_native_setup }, 1463 1464 { "native_finalize", "()V", 1465 (void *)android_media_MediaCodec_native_finalize }, 1466}; 1467 1468int register_android_media_MediaCodec(JNIEnv *env) { 1469 return AndroidRuntime::registerNativeMethods(env, 1470 "android/media/MediaCodec", gMethods, NELEM(gMethods)); 1471} 1472