android_media_MediaCodec.cpp revision 0e0fee1e3a04023c9ec122d3bd7da54e9565c3e7
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_MediaMetricsJNI.h" 25#include "android_media_Utils.h" 26#include "android_runtime/AndroidRuntime.h" 27#include "android_runtime/android_view_Surface.h" 28#include "jni.h" 29#include "JNIHelp.h" 30 31#include <cutils/compiler.h> 32 33#include <gui/Surface.h> 34 35#include <media/ICrypto.h> 36#include <media/MediaCodecBuffer.h> 37#include <media/stagefright/MediaCodec.h> 38#include <media/stagefright/foundation/ABuffer.h> 39#include <media/stagefright/foundation/ADebug.h> 40#include <media/stagefright/foundation/ALooper.h> 41#include <media/stagefright/foundation/AMessage.h> 42#include <media/stagefright/foundation/AString.h> 43#include <media/stagefright/MediaErrors.h> 44#include <media/stagefright/PersistentSurface.h> 45#include <nativehelper/ScopedLocalRef.h> 46 47#include <system/window.h> 48 49namespace android { 50 51// Keep these in sync with their equivalents in MediaCodec.java !!! 52enum { 53 DEQUEUE_INFO_TRY_AGAIN_LATER = -1, 54 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2, 55 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3, 56}; 57 58enum { 59 EVENT_CALLBACK = 1, 60 EVENT_SET_CALLBACK = 2, 61 EVENT_FRAME_RENDERED = 3, 62}; 63 64static struct CryptoErrorCodes { 65 jint cryptoErrorNoKey; 66 jint cryptoErrorKeyExpired; 67 jint cryptoErrorResourceBusy; 68 jint cryptoErrorInsufficientOutputProtection; 69 jint cryptoErrorSessionNotOpened; 70 jint cryptoErrorUnsupportedOperation; 71} gCryptoErrorCodes; 72 73static struct CodecActionCodes { 74 jint codecActionTransient; 75 jint codecActionRecoverable; 76} gCodecActionCodes; 77 78static struct CodecErrorCodes { 79 jint errorInsufficientResource; 80 jint errorReclaimed; 81} gCodecErrorCodes; 82 83static struct { 84 jclass clazz; 85 jfieldID mLock; 86 jfieldID mPersistentObject; 87 jmethodID ctor; 88 jmethodID setNativeObjectLocked; 89} gPersistentSurfaceClassInfo; 90 91static struct { 92 jint Unencrypted; 93 jint AesCtr; 94 jint AesCbc; 95} gCryptoModes; 96 97 98struct fields_t { 99 jfieldID context; 100 jmethodID postEventFromNativeID; 101 jfieldID cryptoInfoNumSubSamplesID; 102 jfieldID cryptoInfoNumBytesOfClearDataID; 103 jfieldID cryptoInfoNumBytesOfEncryptedDataID; 104 jfieldID cryptoInfoKeyID; 105 jfieldID cryptoInfoIVID; 106 jfieldID cryptoInfoModeID; 107 jfieldID cryptoInfoPatternID; 108 jfieldID patternEncryptBlocksID; 109 jfieldID patternSkipBlocksID; 110}; 111 112static fields_t gFields; 113static const void *sRefBaseOwner; 114 115//////////////////////////////////////////////////////////////////////////////// 116 117JMediaCodec::JMediaCodec( 118 JNIEnv *env, jobject thiz, 119 const char *name, bool nameIsType, bool encoder) 120 : mClass(NULL), 121 mObject(NULL) { 122 jclass clazz = env->GetObjectClass(thiz); 123 CHECK(clazz != NULL); 124 125 mClass = (jclass)env->NewGlobalRef(clazz); 126 mObject = env->NewWeakGlobalRef(thiz); 127 128 cacheJavaObjects(env); 129 130 mLooper = new ALooper; 131 mLooper->setName("MediaCodec_looper"); 132 133 mLooper->start( 134 false, // runOnCallingThread 135 true, // canCallJava 136 PRIORITY_FOREGROUND); 137 138 if (nameIsType) { 139 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus); 140 } else { 141 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus); 142 } 143 CHECK((mCodec != NULL) != (mInitStatus != OK)); 144} 145 146void JMediaCodec::cacheJavaObjects(JNIEnv *env) { 147 jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer"); 148 mByteBufferClass = (jclass)env->NewGlobalRef(clazz); 149 CHECK(mByteBufferClass != NULL); 150 151 ScopedLocalRef<jclass> byteOrderClass( 152 env, env->FindClass("java/nio/ByteOrder")); 153 CHECK(byteOrderClass.get() != NULL); 154 155 jmethodID nativeOrderID = env->GetStaticMethodID( 156 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;"); 157 CHECK(nativeOrderID != NULL); 158 159 jobject nativeByteOrderObj = 160 env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID); 161 mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj); 162 CHECK(mNativeByteOrderObj != NULL); 163 env->DeleteLocalRef(nativeByteOrderObj); 164 nativeByteOrderObj = NULL; 165 166 mByteBufferOrderMethodID = env->GetMethodID( 167 mByteBufferClass, 168 "order", 169 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"); 170 CHECK(mByteBufferOrderMethodID != NULL); 171 172 mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID( 173 mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;"); 174 CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL); 175 176 mByteBufferPositionMethodID = env->GetMethodID( 177 mByteBufferClass, "position", "(I)Ljava/nio/Buffer;"); 178 CHECK(mByteBufferPositionMethodID != NULL); 179 180 mByteBufferLimitMethodID = env->GetMethodID( 181 mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;"); 182 CHECK(mByteBufferLimitMethodID != NULL); 183} 184 185status_t JMediaCodec::initCheck() const { 186 return mInitStatus; 187} 188 189void JMediaCodec::registerSelf() { 190 mLooper->registerHandler(this); 191} 192 193void JMediaCodec::release() { 194 if (mCodec != NULL) { 195 mCodec->release(); 196 mCodec.clear(); 197 mInitStatus = NO_INIT; 198 } 199 200 if (mLooper != NULL) { 201 mLooper->unregisterHandler(id()); 202 mLooper->stop(); 203 mLooper.clear(); 204 } 205} 206 207JMediaCodec::~JMediaCodec() { 208 if (mCodec != NULL || mLooper != NULL) { 209 /* MediaCodec and looper should have been released explicitly already 210 * in setMediaCodec() (see comments in setMediaCodec()). 211 * 212 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the 213 * message handler, doing release() there risks deadlock as MediaCodec:: 214 * release() post synchronous message to the same looper. 215 * 216 * Print a warning and try to proceed with releasing. 217 */ 218 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()..."); 219 release(); 220 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec()."); 221 } 222 223 JNIEnv *env = AndroidRuntime::getJNIEnv(); 224 225 env->DeleteWeakGlobalRef(mObject); 226 mObject = NULL; 227 env->DeleteGlobalRef(mClass); 228 mClass = NULL; 229 deleteJavaObjects(env); 230} 231 232void JMediaCodec::deleteJavaObjects(JNIEnv *env) { 233 env->DeleteGlobalRef(mByteBufferClass); 234 mByteBufferClass = NULL; 235 env->DeleteGlobalRef(mNativeByteOrderObj); 236 mNativeByteOrderObj = NULL; 237 238 mByteBufferOrderMethodID = NULL; 239 mByteBufferAsReadOnlyBufferMethodID = NULL; 240 mByteBufferPositionMethodID = NULL; 241 mByteBufferLimitMethodID = NULL; 242} 243 244status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) { 245 if (enable) { 246 if (mOnFrameRenderedNotification == NULL) { 247 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this); 248 } 249 } else { 250 mOnFrameRenderedNotification.clear(); 251 } 252 253 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification); 254} 255 256status_t JMediaCodec::setCallback(jobject cb) { 257 if (cb != NULL) { 258 if (mCallbackNotification == NULL) { 259 mCallbackNotification = new AMessage(kWhatCallbackNotify, this); 260 } 261 } else { 262 mCallbackNotification.clear(); 263 } 264 265 return mCodec->setCallback(mCallbackNotification); 266} 267 268status_t JMediaCodec::configure( 269 const sp<AMessage> &format, 270 const sp<IGraphicBufferProducer> &bufferProducer, 271 const sp<ICrypto> &crypto, 272 int flags) { 273 sp<Surface> client; 274 if (bufferProducer != NULL) { 275 mSurfaceTextureClient = 276 new Surface(bufferProducer, true /* controlledByApp */); 277 } else { 278 mSurfaceTextureClient.clear(); 279 } 280 281 return mCodec->configure(format, mSurfaceTextureClient, crypto, flags); 282} 283 284status_t JMediaCodec::setSurface( 285 const sp<IGraphicBufferProducer> &bufferProducer) { 286 sp<Surface> client; 287 if (bufferProducer != NULL) { 288 client = new Surface(bufferProducer, true /* controlledByApp */); 289 } 290 status_t err = mCodec->setSurface(client); 291 if (err == OK) { 292 mSurfaceTextureClient = client; 293 } 294 return err; 295} 296 297status_t JMediaCodec::createInputSurface( 298 sp<IGraphicBufferProducer>* bufferProducer) { 299 return mCodec->createInputSurface(bufferProducer); 300} 301 302status_t JMediaCodec::setInputSurface( 303 const sp<PersistentSurface> &surface) { 304 return mCodec->setInputSurface(surface); 305} 306 307status_t JMediaCodec::start() { 308 return mCodec->start(); 309} 310 311status_t JMediaCodec::stop() { 312 mSurfaceTextureClient.clear(); 313 314 return mCodec->stop(); 315} 316 317status_t JMediaCodec::flush() { 318 return mCodec->flush(); 319} 320 321status_t JMediaCodec::reset() { 322 return mCodec->reset(); 323} 324 325status_t JMediaCodec::queueInputBuffer( 326 size_t index, 327 size_t offset, size_t size, int64_t timeUs, uint32_t flags, 328 AString *errorDetailMsg) { 329 return mCodec->queueInputBuffer( 330 index, offset, size, timeUs, flags, errorDetailMsg); 331} 332 333status_t JMediaCodec::queueSecureInputBuffer( 334 size_t index, 335 size_t offset, 336 const CryptoPlugin::SubSample *subSamples, 337 size_t numSubSamples, 338 const uint8_t key[16], 339 const uint8_t iv[16], 340 CryptoPlugin::Mode mode, 341 const CryptoPlugin::Pattern &pattern, 342 int64_t presentationTimeUs, 343 uint32_t flags, 344 AString *errorDetailMsg) { 345 return mCodec->queueSecureInputBuffer( 346 index, offset, subSamples, numSubSamples, key, iv, mode, pattern, 347 presentationTimeUs, flags, errorDetailMsg); 348} 349 350status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) { 351 return mCodec->dequeueInputBuffer(index, timeoutUs); 352} 353 354status_t JMediaCodec::dequeueOutputBuffer( 355 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) { 356 size_t size, offset; 357 int64_t timeUs; 358 uint32_t flags; 359 status_t err = mCodec->dequeueOutputBuffer( 360 index, &offset, &size, &timeUs, &flags, timeoutUs); 361 362 if (err != OK) { 363 return err; 364 } 365 366 ScopedLocalRef<jclass> clazz( 367 env, env->FindClass("android/media/MediaCodec$BufferInfo")); 368 369 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V"); 370 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags); 371 372 return OK; 373} 374 375status_t JMediaCodec::releaseOutputBuffer( 376 size_t index, bool render, bool updatePTS, int64_t timestampNs) { 377 if (updatePTS) { 378 return mCodec->renderOutputBufferAndRelease(index, timestampNs); 379 } 380 return render 381 ? mCodec->renderOutputBufferAndRelease(index) 382 : mCodec->releaseOutputBuffer(index); 383} 384 385status_t JMediaCodec::signalEndOfInputStream() { 386 return mCodec->signalEndOfInputStream(); 387} 388 389status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const { 390 sp<AMessage> msg; 391 status_t err; 392 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg); 393 if (err != OK) { 394 return err; 395 } 396 397 return ConvertMessageToMap(env, msg, format); 398} 399 400status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const { 401 sp<AMessage> msg; 402 status_t err; 403 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) { 404 return err; 405 } 406 407 return ConvertMessageToMap(env, msg, format); 408} 409 410status_t JMediaCodec::getBuffers( 411 JNIEnv *env, bool input, jobjectArray *bufArray) const { 412 Vector<sp<MediaCodecBuffer> > buffers; 413 414 status_t err = 415 input 416 ? mCodec->getInputBuffers(&buffers) 417 : mCodec->getOutputBuffers(&buffers); 418 419 if (err != OK) { 420 return err; 421 } 422 423 *bufArray = (jobjectArray)env->NewObjectArray( 424 buffers.size(), mByteBufferClass, NULL); 425 if (*bufArray == NULL) { 426 return NO_MEMORY; 427 } 428 429 for (size_t i = 0; i < buffers.size(); ++i) { 430 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i); 431 432 jobject byteBuffer = NULL; 433 err = createByteBufferFromABuffer( 434 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer); 435 if (err != OK) { 436 return err; 437 } 438 if (byteBuffer != NULL) { 439 env->SetObjectArrayElement( 440 *bufArray, i, byteBuffer); 441 442 env->DeleteLocalRef(byteBuffer); 443 byteBuffer = NULL; 444 } 445 } 446 447 return OK; 448} 449 450// static 451template <typename T> 452status_t JMediaCodec::createByteBufferFromABuffer( 453 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer, 454 jobject *buf) const { 455 // if this is an ABuffer that doesn't actually hold any accessible memory, 456 // use a null ByteBuffer 457 *buf = NULL; 458 459 if (buffer == NULL) { 460 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL"); 461 return OK; 462 } 463 464 if (buffer->base() == NULL) { 465 return OK; 466 } 467 468 jobject byteBuffer = 469 env->NewDirectByteBuffer(buffer->base(), buffer->capacity()); 470 if (readOnly && byteBuffer != NULL) { 471 jobject readOnlyBuffer = env->CallObjectMethod( 472 byteBuffer, mByteBufferAsReadOnlyBufferMethodID); 473 env->DeleteLocalRef(byteBuffer); 474 byteBuffer = readOnlyBuffer; 475 } 476 if (byteBuffer == NULL) { 477 return NO_MEMORY; 478 } 479 jobject me = env->CallObjectMethod( 480 byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj); 481 env->DeleteLocalRef(me); 482 me = env->CallObjectMethod( 483 byteBuffer, mByteBufferLimitMethodID, 484 clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size())); 485 env->DeleteLocalRef(me); 486 me = env->CallObjectMethod( 487 byteBuffer, mByteBufferPositionMethodID, 488 clearBuffer ? 0 : buffer->offset()); 489 env->DeleteLocalRef(me); 490 me = NULL; 491 492 *buf = byteBuffer; 493 return OK; 494} 495 496status_t JMediaCodec::getBuffer( 497 JNIEnv *env, bool input, size_t index, jobject *buf) const { 498 sp<MediaCodecBuffer> buffer; 499 500 status_t err = 501 input 502 ? mCodec->getInputBuffer(index, &buffer) 503 : mCodec->getOutputBuffer(index, &buffer); 504 505 if (err != OK) { 506 return err; 507 } 508 509 return createByteBufferFromABuffer( 510 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf); 511} 512 513status_t JMediaCodec::getImage( 514 JNIEnv *env, bool input, size_t index, jobject *buf) const { 515 sp<MediaCodecBuffer> buffer; 516 517 status_t err = 518 input 519 ? mCodec->getInputBuffer(index, &buffer) 520 : mCodec->getOutputBuffer(index, &buffer); 521 522 if (err != OK) { 523 return err; 524 } 525 526 // if this is an ABuffer that doesn't actually hold any accessible memory, 527 // use a null ByteBuffer 528 *buf = NULL; 529 if (buffer->base() == NULL) { 530 return OK; 531 } 532 533 // check if buffer is an image 534 sp<ABuffer> imageData; 535 if (!buffer->meta()->findBuffer("image-data", &imageData)) { 536 return OK; 537 } 538 539 int64_t timestamp = 0; 540 if (!input && buffer->meta()->findInt64("timeUs", ×tamp)) { 541 timestamp *= 1000; // adjust to ns 542 } 543 544 jobject byteBuffer = NULL; 545 err = createByteBufferFromABuffer( 546 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer); 547 if (err != OK) { 548 return OK; 549 } 550 551 jobject infoBuffer = NULL; 552 err = createByteBufferFromABuffer( 553 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer); 554 if (err != OK) { 555 env->DeleteLocalRef(byteBuffer); 556 byteBuffer = NULL; 557 return OK; 558 } 559 560 jobject cropRect = NULL; 561 int32_t left, top, right, bottom; 562 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) { 563 ScopedLocalRef<jclass> rectClazz( 564 env, env->FindClass("android/graphics/Rect")); 565 CHECK(rectClazz.get() != NULL); 566 567 jmethodID rectConstructID = env->GetMethodID( 568 rectClazz.get(), "<init>", "(IIII)V"); 569 570 cropRect = env->NewObject( 571 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1); 572 } 573 574 ScopedLocalRef<jclass> imageClazz( 575 env, env->FindClass("android/media/MediaCodec$MediaImage")); 576 CHECK(imageClazz.get() != NULL); 577 578 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>", 579 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V"); 580 581 *buf = env->NewObject(imageClazz.get(), imageConstructID, 582 byteBuffer, infoBuffer, 583 (jboolean)!input /* readOnly */, 584 (jlong)timestamp, 585 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect); 586 587 // if MediaImage creation fails, return null 588 if (env->ExceptionCheck()) { 589 env->ExceptionDescribe(); 590 env->ExceptionClear(); 591 *buf = NULL; 592 } 593 594 if (cropRect != NULL) { 595 env->DeleteLocalRef(cropRect); 596 cropRect = NULL; 597 } 598 599 env->DeleteLocalRef(byteBuffer); 600 byteBuffer = NULL; 601 602 env->DeleteLocalRef(infoBuffer); 603 infoBuffer = NULL; 604 605 return OK; 606} 607 608status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const { 609 AString name; 610 611 status_t err = mCodec->getName(&name); 612 613 if (err != OK) { 614 return err; 615 } 616 617 *nameStr = env->NewStringUTF(name.c_str()); 618 619 return OK; 620} 621 622status_t JMediaCodec::getMetrics(JNIEnv *, Parcel *reply) const { 623 624 status_t status = mCodec->getMetrics(reply); 625 return status; 626} 627 628status_t JMediaCodec::setParameters(const sp<AMessage> &msg) { 629 return mCodec->setParameters(msg); 630} 631 632void JMediaCodec::setVideoScalingMode(int mode) { 633 if (mSurfaceTextureClient != NULL) { 634 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode); 635 } 636} 637 638static jthrowable createCodecException( 639 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) { 640 ScopedLocalRef<jclass> clazz( 641 env, env->FindClass("android/media/MediaCodec$CodecException")); 642 CHECK(clazz.get() != NULL); 643 644 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V"); 645 CHECK(ctor != NULL); 646 647 ScopedLocalRef<jstring> msgObj( 648 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err))); 649 650 // translate action code to Java equivalent 651 switch (actionCode) { 652 case ACTION_CODE_TRANSIENT: 653 actionCode = gCodecActionCodes.codecActionTransient; 654 break; 655 case ACTION_CODE_RECOVERABLE: 656 actionCode = gCodecActionCodes.codecActionRecoverable; 657 break; 658 default: 659 actionCode = 0; // everything else is fatal 660 break; 661 } 662 663 /* translate OS errors to Java API CodecException errorCodes */ 664 switch (err) { 665 case NO_MEMORY: 666 err = gCodecErrorCodes.errorInsufficientResource; 667 break; 668 case DEAD_OBJECT: 669 err = gCodecErrorCodes.errorReclaimed; 670 break; 671 default: /* Other error codes go out as is. */ 672 break; 673 } 674 675 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get()); 676} 677 678void JMediaCodec::handleCallback(const sp<AMessage> &msg) { 679 int32_t arg1, arg2 = 0; 680 jobject obj = NULL; 681 CHECK(msg->findInt32("callbackID", &arg1)); 682 JNIEnv *env = AndroidRuntime::getJNIEnv(); 683 684 switch (arg1) { 685 case MediaCodec::CB_INPUT_AVAILABLE: 686 { 687 CHECK(msg->findInt32("index", &arg2)); 688 break; 689 } 690 691 case MediaCodec::CB_OUTPUT_AVAILABLE: 692 { 693 CHECK(msg->findInt32("index", &arg2)); 694 695 size_t size, offset; 696 int64_t timeUs; 697 uint32_t flags; 698 CHECK(msg->findSize("size", &size)); 699 CHECK(msg->findSize("offset", &offset)); 700 CHECK(msg->findInt64("timeUs", &timeUs)); 701 CHECK(msg->findInt32("flags", (int32_t *)&flags)); 702 703 ScopedLocalRef<jclass> clazz( 704 env, env->FindClass("android/media/MediaCodec$BufferInfo")); 705 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V"); 706 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V"); 707 708 obj = env->NewObject(clazz.get(), ctor); 709 710 if (obj == NULL) { 711 if (env->ExceptionCheck()) { 712 ALOGE("Could not create MediaCodec.BufferInfo."); 713 env->ExceptionClear(); 714 } 715 jniThrowException(env, "java/lang/IllegalStateException", NULL); 716 return; 717 } 718 719 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags); 720 break; 721 } 722 723 case MediaCodec::CB_ERROR: 724 { 725 int32_t err, actionCode; 726 CHECK(msg->findInt32("err", &err)); 727 CHECK(msg->findInt32("actionCode", &actionCode)); 728 729 // note that DRM errors could conceivably alias into a CodecException 730 obj = (jobject)createCodecException(env, err, actionCode); 731 732 if (obj == NULL) { 733 if (env->ExceptionCheck()) { 734 ALOGE("Could not create CodecException object."); 735 env->ExceptionClear(); 736 } 737 jniThrowException(env, "java/lang/IllegalStateException", NULL); 738 return; 739 } 740 741 break; 742 } 743 744 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED: 745 { 746 sp<AMessage> format; 747 CHECK(msg->findMessage("format", &format)); 748 749 if (OK != ConvertMessageToMap(env, format, &obj)) { 750 jniThrowException(env, "java/lang/IllegalStateException", NULL); 751 return; 752 } 753 754 break; 755 } 756 757 default: 758 TRESPASS(); 759 } 760 761 env->CallVoidMethod( 762 mObject, 763 gFields.postEventFromNativeID, 764 EVENT_CALLBACK, 765 arg1, 766 arg2, 767 obj); 768 769 env->DeleteLocalRef(obj); 770} 771 772void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) { 773 int32_t arg1 = 0, arg2 = 0; 774 jobject obj = NULL; 775 JNIEnv *env = AndroidRuntime::getJNIEnv(); 776 777 sp<AMessage> data; 778 CHECK(msg->findMessage("data", &data)); 779 780 status_t err = ConvertMessageToMap(env, data, &obj); 781 if (err != OK) { 782 jniThrowException(env, "java/lang/IllegalStateException", NULL); 783 return; 784 } 785 786 env->CallVoidMethod( 787 mObject, gFields.postEventFromNativeID, 788 EVENT_FRAME_RENDERED, arg1, arg2, obj); 789 790 env->DeleteLocalRef(obj); 791} 792 793void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) { 794 switch (msg->what()) { 795 case kWhatCallbackNotify: 796 { 797 handleCallback(msg); 798 break; 799 } 800 case kWhatFrameRendered: 801 { 802 handleFrameRenderedNotification(msg); 803 break; 804 } 805 default: 806 TRESPASS(); 807 } 808} 809 810} // namespace android 811 812//////////////////////////////////////////////////////////////////////////////// 813 814using namespace android; 815 816static sp<JMediaCodec> setMediaCodec( 817 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) { 818 sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context); 819 if (codec != NULL) { 820 codec->incStrong(thiz); 821 } 822 if (old != NULL) { 823 /* release MediaCodec and stop the looper now before decStrong. 824 * otherwise JMediaCodec::~JMediaCodec() could be called from within 825 * its message handler, doing release() from there will deadlock 826 * (as MediaCodec::release() post synchronous message to the same looper) 827 */ 828 old->release(); 829 old->decStrong(thiz); 830 } 831 env->SetLongField(thiz, gFields.context, (jlong)codec.get()); 832 833 return old; 834} 835 836static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) { 837 return (JMediaCodec *)env->GetLongField(thiz, gFields.context); 838} 839 840static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) { 841 setMediaCodec(env, thiz, NULL); 842} 843 844static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) { 845 jthrowable exception = createCodecException(env, err, actionCode, msg); 846 env->Throw(exception); 847} 848 849static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) { 850 ScopedLocalRef<jclass> clazz( 851 env, env->FindClass("android/media/MediaCodec$CryptoException")); 852 CHECK(clazz.get() != NULL); 853 854 jmethodID constructID = 855 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V"); 856 CHECK(constructID != NULL); 857 858 const char *defaultMsg = "Unknown Error"; 859 860 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */ 861 switch (err) { 862 case ERROR_DRM_NO_LICENSE: 863 err = gCryptoErrorCodes.cryptoErrorNoKey; 864 defaultMsg = "Crypto key not available"; 865 break; 866 case ERROR_DRM_LICENSE_EXPIRED: 867 err = gCryptoErrorCodes.cryptoErrorKeyExpired; 868 defaultMsg = "License expired"; 869 break; 870 case ERROR_DRM_RESOURCE_BUSY: 871 err = gCryptoErrorCodes.cryptoErrorResourceBusy; 872 defaultMsg = "Resource busy or unavailable"; 873 break; 874 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION: 875 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection; 876 defaultMsg = "Required output protections are not active"; 877 break; 878 case ERROR_DRM_SESSION_NOT_OPENED: 879 err = gCryptoErrorCodes.cryptoErrorSessionNotOpened; 880 defaultMsg = "Attempted to use a closed session"; 881 break; 882 case ERROR_DRM_CANNOT_HANDLE: 883 err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation; 884 defaultMsg = "Operation not supported in this configuration"; 885 break; 886 default: /* Other negative DRM error codes go out as is. */ 887 break; 888 } 889 890 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : defaultMsg); 891 892 jthrowable exception = 893 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj); 894 895 env->Throw(exception); 896} 897 898static jint throwExceptionAsNecessary( 899 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL, 900 const char *msg = NULL) { 901 switch (err) { 902 case OK: 903 return 0; 904 905 case -EAGAIN: 906 return DEQUEUE_INFO_TRY_AGAIN_LATER; 907 908 case INFO_FORMAT_CHANGED: 909 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED; 910 911 case INFO_OUTPUT_BUFFERS_CHANGED: 912 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED; 913 914 case INVALID_OPERATION: 915 jniThrowException(env, "java/lang/IllegalStateException", msg); 916 return 0; 917 918 case BAD_VALUE: 919 jniThrowException(env, "java/lang/IllegalArgumentException", msg); 920 return 0; 921 922 default: 923 if (isCryptoError(err)) { 924 throwCryptoException(env, err, msg); 925 return 0; 926 } 927 throwCodecException(env, err, actionCode, msg); 928 return 0; 929 } 930} 931 932static void android_media_MediaCodec_native_enableOnFrameRenderedListener( 933 JNIEnv *env, 934 jobject thiz, 935 jboolean enabled) { 936 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 937 938 if (codec == NULL) { 939 throwExceptionAsNecessary(env, INVALID_OPERATION); 940 return; 941 } 942 943 status_t err = codec->enableOnFrameRenderedListener(enabled); 944 945 throwExceptionAsNecessary(env, err); 946} 947 948static void android_media_MediaCodec_native_setCallback( 949 JNIEnv *env, 950 jobject thiz, 951 jobject cb) { 952 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 953 954 if (codec == NULL) { 955 throwExceptionAsNecessary(env, INVALID_OPERATION); 956 return; 957 } 958 959 status_t err = codec->setCallback(cb); 960 961 throwExceptionAsNecessary(env, err); 962} 963 964static void android_media_MediaCodec_native_configure( 965 JNIEnv *env, 966 jobject thiz, 967 jobjectArray keys, jobjectArray values, 968 jobject jsurface, 969 jobject jcrypto, 970 jint flags) { 971 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 972 973 if (codec == NULL) { 974 throwExceptionAsNecessary(env, INVALID_OPERATION); 975 return; 976 } 977 978 sp<AMessage> format; 979 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format); 980 981 if (err != OK) { 982 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 983 return; 984 } 985 986 sp<IGraphicBufferProducer> bufferProducer; 987 if (jsurface != NULL) { 988 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 989 if (surface != NULL) { 990 bufferProducer = surface->getIGraphicBufferProducer(); 991 } else { 992 jniThrowException( 993 env, 994 "java/lang/IllegalArgumentException", 995 "The surface has been released"); 996 return; 997 } 998 } 999 1000 sp<ICrypto> crypto; 1001 if (jcrypto != NULL) { 1002 crypto = JCrypto::GetCrypto(env, jcrypto); 1003 } 1004 1005 err = codec->configure(format, bufferProducer, crypto, flags); 1006 1007 throwExceptionAsNecessary(env, err); 1008} 1009 1010static void android_media_MediaCodec_native_setSurface( 1011 JNIEnv *env, 1012 jobject thiz, 1013 jobject jsurface) { 1014 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1015 1016 if (codec == NULL) { 1017 throwExceptionAsNecessary(env, INVALID_OPERATION); 1018 return; 1019 } 1020 1021 sp<IGraphicBufferProducer> bufferProducer; 1022 if (jsurface != NULL) { 1023 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 1024 if (surface != NULL) { 1025 bufferProducer = surface->getIGraphicBufferProducer(); 1026 } else { 1027 jniThrowException( 1028 env, 1029 "java/lang/IllegalArgumentException", 1030 "The surface has been released"); 1031 return; 1032 } 1033 } 1034 1035 status_t err = codec->setSurface(bufferProducer); 1036 throwExceptionAsNecessary(env, err); 1037} 1038 1039sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface( 1040 JNIEnv* env, jobject object) { 1041 sp<PersistentSurface> persistentSurface; 1042 1043 jobject lock = env->GetObjectField( 1044 object, gPersistentSurfaceClassInfo.mLock); 1045 if (env->MonitorEnter(lock) == JNI_OK) { 1046 persistentSurface = reinterpret_cast<PersistentSurface *>( 1047 env->GetLongField(object, 1048 gPersistentSurfaceClassInfo.mPersistentObject)); 1049 env->MonitorExit(lock); 1050 } 1051 env->DeleteLocalRef(lock); 1052 1053 return persistentSurface; 1054} 1055 1056static jobject android_media_MediaCodec_createPersistentInputSurface( 1057 JNIEnv* env, jclass /* clazz */) { 1058 ALOGV("android_media_MediaCodec_createPersistentInputSurface"); 1059 sp<PersistentSurface> persistentSurface = 1060 MediaCodec::CreatePersistentInputSurface(); 1061 1062 if (persistentSurface == NULL) { 1063 return NULL; 1064 } 1065 1066 sp<Surface> surface = new Surface( 1067 persistentSurface->getBufferProducer(), true); 1068 if (surface == NULL) { 1069 return NULL; 1070 } 1071 1072 jobject object = env->NewObject( 1073 gPersistentSurfaceClassInfo.clazz, 1074 gPersistentSurfaceClassInfo.ctor); 1075 1076 if (object == NULL) { 1077 if (env->ExceptionCheck()) { 1078 ALOGE("Could not create PersistentSurface."); 1079 env->ExceptionClear(); 1080 } 1081 return NULL; 1082 } 1083 1084 jobject lock = env->GetObjectField( 1085 object, gPersistentSurfaceClassInfo.mLock); 1086 if (env->MonitorEnter(lock) == JNI_OK) { 1087 env->CallVoidMethod( 1088 object, 1089 gPersistentSurfaceClassInfo.setNativeObjectLocked, 1090 (jlong)surface.get()); 1091 env->SetLongField( 1092 object, 1093 gPersistentSurfaceClassInfo.mPersistentObject, 1094 (jlong)persistentSurface.get()); 1095 env->MonitorExit(lock); 1096 } else { 1097 env->DeleteLocalRef(object); 1098 object = NULL; 1099 } 1100 env->DeleteLocalRef(lock); 1101 1102 if (object != NULL) { 1103 surface->incStrong(&sRefBaseOwner); 1104 persistentSurface->incStrong(&sRefBaseOwner); 1105 } 1106 1107 return object; 1108} 1109 1110static void android_media_MediaCodec_releasePersistentInputSurface( 1111 JNIEnv* env, jclass /* clazz */, jobject object) { 1112 sp<PersistentSurface> persistentSurface; 1113 1114 jobject lock = env->GetObjectField( 1115 object, gPersistentSurfaceClassInfo.mLock); 1116 if (env->MonitorEnter(lock) == JNI_OK) { 1117 persistentSurface = reinterpret_cast<PersistentSurface *>( 1118 env->GetLongField( 1119 object, gPersistentSurfaceClassInfo.mPersistentObject)); 1120 env->SetLongField( 1121 object, 1122 gPersistentSurfaceClassInfo.mPersistentObject, 1123 (jlong)0); 1124 env->MonitorExit(lock); 1125 } 1126 env->DeleteLocalRef(lock); 1127 1128 if (persistentSurface != NULL) { 1129 persistentSurface->decStrong(&sRefBaseOwner); 1130 } 1131 // no need to release surface as it will be released by Surface's jni 1132} 1133 1134static void android_media_MediaCodec_setInputSurface( 1135 JNIEnv* env, jobject thiz, jobject object) { 1136 ALOGV("android_media_MediaCodec_setInputSurface"); 1137 1138 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1139 if (codec == NULL) { 1140 throwExceptionAsNecessary(env, INVALID_OPERATION); 1141 return; 1142 } 1143 1144 sp<PersistentSurface> persistentSurface = 1145 android_media_MediaCodec_getPersistentInputSurface(env, object); 1146 1147 status_t err = codec->setInputSurface(persistentSurface); 1148 if (err != NO_ERROR) { 1149 throwExceptionAsNecessary(env, err); 1150 } 1151} 1152 1153static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env, 1154 jobject thiz) { 1155 ALOGV("android_media_MediaCodec_createInputSurface"); 1156 1157 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1158 if (codec == NULL) { 1159 throwExceptionAsNecessary(env, INVALID_OPERATION); 1160 return NULL; 1161 } 1162 1163 // Tell the MediaCodec that we want to use a Surface as input. 1164 sp<IGraphicBufferProducer> bufferProducer; 1165 status_t err = codec->createInputSurface(&bufferProducer); 1166 if (err != NO_ERROR) { 1167 throwExceptionAsNecessary(env, err); 1168 return NULL; 1169 } 1170 1171 // Wrap the IGBP in a Java-language Surface. 1172 return android_view_Surface_createFromIGraphicBufferProducer(env, 1173 bufferProducer); 1174} 1175 1176static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) { 1177 ALOGV("android_media_MediaCodec_start"); 1178 1179 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1180 1181 if (codec == NULL) { 1182 throwExceptionAsNecessary(env, INVALID_OPERATION); 1183 return; 1184 } 1185 1186 status_t err = codec->start(); 1187 1188 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed"); 1189} 1190 1191static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) { 1192 ALOGV("android_media_MediaCodec_stop"); 1193 1194 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1195 1196 if (codec == NULL) { 1197 throwExceptionAsNecessary(env, INVALID_OPERATION); 1198 return; 1199 } 1200 1201 status_t err = codec->stop(); 1202 1203 throwExceptionAsNecessary(env, err); 1204} 1205 1206static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) { 1207 ALOGV("android_media_MediaCodec_reset"); 1208 1209 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1210 1211 if (codec == NULL) { 1212 throwExceptionAsNecessary(env, INVALID_OPERATION); 1213 return; 1214 } 1215 1216 status_t err = codec->reset(); 1217 if (err != OK) { 1218 // treat all errors as fatal for now, though resource not available 1219 // errors could be treated as transient. 1220 // we also should avoid sending INVALID_OPERATION here due to 1221 // the transitory nature of reset(), it should not inadvertently 1222 // trigger an IllegalStateException. 1223 err = UNKNOWN_ERROR; 1224 } 1225 throwExceptionAsNecessary(env, err); 1226} 1227 1228static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) { 1229 ALOGV("android_media_MediaCodec_flush"); 1230 1231 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1232 1233 if (codec == NULL) { 1234 throwExceptionAsNecessary(env, INVALID_OPERATION); 1235 return; 1236 } 1237 1238 status_t err = codec->flush(); 1239 1240 throwExceptionAsNecessary(env, err); 1241} 1242 1243static void android_media_MediaCodec_queueInputBuffer( 1244 JNIEnv *env, 1245 jobject thiz, 1246 jint index, 1247 jint offset, 1248 jint size, 1249 jlong timestampUs, 1250 jint flags) { 1251 ALOGV("android_media_MediaCodec_queueInputBuffer"); 1252 1253 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1254 1255 if (codec == NULL) { 1256 throwExceptionAsNecessary(env, INVALID_OPERATION); 1257 return; 1258 } 1259 1260 AString errorDetailMsg; 1261 1262 status_t err = codec->queueInputBuffer( 1263 index, offset, size, timestampUs, flags, &errorDetailMsg); 1264 1265 throwExceptionAsNecessary( 1266 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 1267} 1268 1269static void android_media_MediaCodec_queueSecureInputBuffer( 1270 JNIEnv *env, 1271 jobject thiz, 1272 jint index, 1273 jint offset, 1274 jobject cryptoInfoObj, 1275 jlong timestampUs, 1276 jint flags) { 1277 ALOGV("android_media_MediaCodec_queueSecureInputBuffer"); 1278 1279 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1280 1281 if (codec == NULL) { 1282 throwExceptionAsNecessary(env, INVALID_OPERATION); 1283 return; 1284 } 1285 1286 jint numSubSamples = 1287 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID); 1288 1289 jintArray numBytesOfClearDataObj = 1290 (jintArray)env->GetObjectField( 1291 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID); 1292 1293 jintArray numBytesOfEncryptedDataObj = 1294 (jintArray)env->GetObjectField( 1295 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID); 1296 1297 jbyteArray keyObj = 1298 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID); 1299 1300 jbyteArray ivObj = 1301 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID); 1302 1303 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID); 1304 enum CryptoPlugin::Mode mode; 1305 if (jmode == gCryptoModes.Unencrypted) { 1306 mode = CryptoPlugin::kMode_Unencrypted; 1307 } else if (jmode == gCryptoModes.AesCtr) { 1308 mode = CryptoPlugin::kMode_AES_CTR; 1309 } else if (jmode == gCryptoModes.AesCbc) { 1310 mode = CryptoPlugin::kMode_AES_CBC; 1311 } else { 1312 throwExceptionAsNecessary(env, INVALID_OPERATION); 1313 return; 1314 } 1315 1316 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID); 1317 1318 CryptoPlugin::Pattern pattern; 1319 if (patternObj == NULL) { 1320 pattern.mEncryptBlocks = 0; 1321 pattern.mSkipBlocks = 0; 1322 } else { 1323 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID); 1324 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID); 1325 } 1326 1327 status_t err = OK; 1328 1329 CryptoPlugin::SubSample *subSamples = NULL; 1330 jbyte *key = NULL; 1331 jbyte *iv = NULL; 1332 1333 if (numSubSamples <= 0) { 1334 err = -EINVAL; 1335 } else if (numBytesOfClearDataObj == NULL 1336 && numBytesOfEncryptedDataObj == NULL) { 1337 err = -EINVAL; 1338 } else if (numBytesOfEncryptedDataObj != NULL 1339 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) { 1340 err = -ERANGE; 1341 } else if (numBytesOfClearDataObj != NULL 1342 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) { 1343 err = -ERANGE; 1344 // subSamples array may silently overflow if number of samples are too large. Use 1345 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms 1346 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) { 1347 err = -EINVAL; 1348 } else { 1349 jboolean isCopy; 1350 1351 jint *numBytesOfClearData = 1352 (numBytesOfClearDataObj == NULL) 1353 ? NULL 1354 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy); 1355 1356 jint *numBytesOfEncryptedData = 1357 (numBytesOfEncryptedDataObj == NULL) 1358 ? NULL 1359 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); 1360 1361 subSamples = new CryptoPlugin::SubSample[numSubSamples]; 1362 1363 for (jint i = 0; i < numSubSamples; ++i) { 1364 subSamples[i].mNumBytesOfClearData = 1365 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i]; 1366 1367 subSamples[i].mNumBytesOfEncryptedData = 1368 (numBytesOfEncryptedData == NULL) 1369 ? 0 : numBytesOfEncryptedData[i]; 1370 } 1371 1372 if (numBytesOfEncryptedData != NULL) { 1373 env->ReleaseIntArrayElements( 1374 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0); 1375 numBytesOfEncryptedData = NULL; 1376 } 1377 1378 if (numBytesOfClearData != NULL) { 1379 env->ReleaseIntArrayElements( 1380 numBytesOfClearDataObj, numBytesOfClearData, 0); 1381 numBytesOfClearData = NULL; 1382 } 1383 } 1384 1385 if (err == OK && keyObj != NULL) { 1386 if (env->GetArrayLength(keyObj) != 16) { 1387 err = -EINVAL; 1388 } else { 1389 jboolean isCopy; 1390 key = env->GetByteArrayElements(keyObj, &isCopy); 1391 } 1392 } 1393 1394 if (err == OK && ivObj != NULL) { 1395 if (env->GetArrayLength(ivObj) != 16) { 1396 err = -EINVAL; 1397 } else { 1398 jboolean isCopy; 1399 iv = env->GetByteArrayElements(ivObj, &isCopy); 1400 } 1401 } 1402 1403 AString errorDetailMsg; 1404 1405 if (err == OK) { 1406 err = codec->queueSecureInputBuffer( 1407 index, offset, 1408 subSamples, numSubSamples, 1409 (const uint8_t *)key, (const uint8_t *)iv, 1410 mode, 1411 pattern, 1412 timestampUs, 1413 flags, 1414 &errorDetailMsg); 1415 } 1416 1417 if (iv != NULL) { 1418 env->ReleaseByteArrayElements(ivObj, iv, 0); 1419 iv = NULL; 1420 } 1421 1422 if (key != NULL) { 1423 env->ReleaseByteArrayElements(keyObj, key, 0); 1424 key = NULL; 1425 } 1426 1427 delete[] subSamples; 1428 subSamples = NULL; 1429 1430 throwExceptionAsNecessary( 1431 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 1432} 1433 1434static jint android_media_MediaCodec_dequeueInputBuffer( 1435 JNIEnv *env, jobject thiz, jlong timeoutUs) { 1436 ALOGV("android_media_MediaCodec_dequeueInputBuffer"); 1437 1438 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1439 1440 if (codec == NULL) { 1441 throwExceptionAsNecessary(env, INVALID_OPERATION); 1442 return -1; 1443 } 1444 1445 size_t index; 1446 status_t err = codec->dequeueInputBuffer(&index, timeoutUs); 1447 1448 if (err == OK) { 1449 return (jint) index; 1450 } 1451 1452 return throwExceptionAsNecessary(env, err); 1453} 1454 1455static jint android_media_MediaCodec_dequeueOutputBuffer( 1456 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) { 1457 ALOGV("android_media_MediaCodec_dequeueOutputBuffer"); 1458 1459 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1460 1461 if (codec == NULL) { 1462 throwExceptionAsNecessary(env, INVALID_OPERATION); 1463 return 0; 1464 } 1465 1466 size_t index; 1467 status_t err = codec->dequeueOutputBuffer( 1468 env, bufferInfo, &index, timeoutUs); 1469 1470 if (err == OK) { 1471 return (jint) index; 1472 } 1473 1474 return throwExceptionAsNecessary(env, err); 1475} 1476 1477static void android_media_MediaCodec_releaseOutputBuffer( 1478 JNIEnv *env, jobject thiz, 1479 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) { 1480 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease"); 1481 1482 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1483 1484 if (codec == NULL) { 1485 throwExceptionAsNecessary(env, INVALID_OPERATION); 1486 return; 1487 } 1488 1489 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs); 1490 1491 throwExceptionAsNecessary(env, err); 1492} 1493 1494static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env, 1495 jobject thiz) { 1496 ALOGV("android_media_MediaCodec_signalEndOfInputStream"); 1497 1498 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1499 if (codec == NULL) { 1500 throwExceptionAsNecessary(env, INVALID_OPERATION); 1501 return; 1502 } 1503 1504 status_t err = codec->signalEndOfInputStream(); 1505 1506 throwExceptionAsNecessary(env, err); 1507} 1508 1509static jobject android_media_MediaCodec_getFormatNative( 1510 JNIEnv *env, jobject thiz, jboolean input) { 1511 ALOGV("android_media_MediaCodec_getFormatNative"); 1512 1513 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1514 1515 if (codec == NULL) { 1516 throwExceptionAsNecessary(env, INVALID_OPERATION); 1517 return NULL; 1518 } 1519 1520 jobject format; 1521 status_t err = codec->getFormat(env, input, &format); 1522 1523 if (err == OK) { 1524 return format; 1525 } 1526 1527 throwExceptionAsNecessary(env, err); 1528 1529 return NULL; 1530} 1531 1532static jobject android_media_MediaCodec_getOutputFormatForIndexNative( 1533 JNIEnv *env, jobject thiz, jint index) { 1534 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative"); 1535 1536 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1537 1538 if (codec == NULL) { 1539 throwExceptionAsNecessary(env, INVALID_OPERATION); 1540 return NULL; 1541 } 1542 1543 jobject format; 1544 status_t err = codec->getOutputFormat(env, index, &format); 1545 1546 if (err == OK) { 1547 return format; 1548 } 1549 1550 throwExceptionAsNecessary(env, err); 1551 1552 return NULL; 1553} 1554 1555static jobjectArray android_media_MediaCodec_getBuffers( 1556 JNIEnv *env, jobject thiz, jboolean input) { 1557 ALOGV("android_media_MediaCodec_getBuffers"); 1558 1559 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1560 1561 if (codec == NULL) { 1562 throwExceptionAsNecessary(env, INVALID_OPERATION); 1563 return NULL; 1564 } 1565 1566 jobjectArray buffers; 1567 status_t err = codec->getBuffers(env, input, &buffers); 1568 1569 if (err == OK) { 1570 return buffers; 1571 } 1572 1573 // if we're out of memory, an exception was already thrown 1574 if (err != NO_MEMORY) { 1575 throwExceptionAsNecessary(env, err); 1576 } 1577 1578 return NULL; 1579} 1580 1581static jobject android_media_MediaCodec_getBuffer( 1582 JNIEnv *env, jobject thiz, jboolean input, jint index) { 1583 ALOGV("android_media_MediaCodec_getBuffer"); 1584 1585 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1586 1587 if (codec == NULL) { 1588 throwExceptionAsNecessary(env, INVALID_OPERATION); 1589 return NULL; 1590 } 1591 1592 jobject buffer; 1593 status_t err = codec->getBuffer(env, input, index, &buffer); 1594 1595 if (err == OK) { 1596 return buffer; 1597 } 1598 1599 // if we're out of memory, an exception was already thrown 1600 if (err != NO_MEMORY) { 1601 throwExceptionAsNecessary(env, err); 1602 } 1603 1604 return NULL; 1605} 1606 1607static jobject android_media_MediaCodec_getImage( 1608 JNIEnv *env, jobject thiz, jboolean input, jint index) { 1609 ALOGV("android_media_MediaCodec_getImage"); 1610 1611 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1612 1613 if (codec == NULL) { 1614 throwExceptionAsNecessary(env, INVALID_OPERATION); 1615 return NULL; 1616 } 1617 1618 jobject image; 1619 status_t err = codec->getImage(env, input, index, &image); 1620 1621 if (err == OK) { 1622 return image; 1623 } 1624 1625 // if we're out of memory, an exception was already thrown 1626 if (err != NO_MEMORY) { 1627 throwExceptionAsNecessary(env, err); 1628 } 1629 1630 return NULL; 1631} 1632 1633static jobject android_media_MediaCodec_getName( 1634 JNIEnv *env, jobject thiz) { 1635 ALOGV("android_media_MediaCodec_getName"); 1636 1637 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1638 1639 if (codec == NULL) { 1640 throwExceptionAsNecessary(env, INVALID_OPERATION); 1641 return NULL; 1642 } 1643 1644 jstring name; 1645 status_t err = codec->getName(env, &name); 1646 1647 if (err == OK) { 1648 return name; 1649 } 1650 1651 throwExceptionAsNecessary(env, err); 1652 1653 return NULL; 1654} 1655 1656static jobject 1657android_media_MediaCodec_getMetrics(JNIEnv *env, jobject thiz) 1658{ 1659 ALOGV("android_media_MediaCodec_getMetrics"); 1660 1661 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1662 if (codec == NULL ) { 1663 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1664 return 0; 1665 } 1666 1667 // get what we have for the metrics from the codec 1668 Parcel reply; 1669 status_t err = codec->getMetrics(env, &reply); 1670 if (err != OK) { 1671 ALOGE("getMetrics failed"); 1672 return (jobject) NULL; 1673 } 1674 1675 // build and return the Bundle 1676 MediaAnalyticsItem *item = new MediaAnalyticsItem; 1677 item->readFromParcel(reply); 1678 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL); 1679 1680 // housekeeping 1681 delete item; 1682 item = NULL; 1683 1684 return mybundle; 1685} 1686 1687static void android_media_MediaCodec_setParameters( 1688 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) { 1689 ALOGV("android_media_MediaCodec_setParameters"); 1690 1691 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1692 1693 if (codec == NULL) { 1694 throwExceptionAsNecessary(env, INVALID_OPERATION); 1695 return; 1696 } 1697 1698 sp<AMessage> params; 1699 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, ¶ms); 1700 1701 if (err == OK) { 1702 err = codec->setParameters(params); 1703 } 1704 1705 throwExceptionAsNecessary(env, err); 1706} 1707 1708static void android_media_MediaCodec_setVideoScalingMode( 1709 JNIEnv *env, jobject thiz, jint mode) { 1710 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1711 1712 if (codec == NULL) { 1713 throwExceptionAsNecessary(env, INVALID_OPERATION); 1714 return; 1715 } 1716 1717 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW 1718 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { 1719 jniThrowException(env, "java/lang/InvalidArgumentException", NULL); 1720 return; 1721 } 1722 1723 codec->setVideoScalingMode(mode); 1724} 1725 1726static void android_media_MediaCodec_native_init(JNIEnv *env) { 1727 ScopedLocalRef<jclass> clazz( 1728 env, env->FindClass("android/media/MediaCodec")); 1729 CHECK(clazz.get() != NULL); 1730 1731 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J"); 1732 CHECK(gFields.context != NULL); 1733 1734 gFields.postEventFromNativeID = 1735 env->GetMethodID( 1736 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V"); 1737 1738 CHECK(gFields.postEventFromNativeID != NULL); 1739 1740 jfieldID field; 1741 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I"); 1742 CHECK(field != NULL); 1743 gCryptoModes.Unencrypted = 1744 env->GetStaticIntField(clazz.get(), field); 1745 1746 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I"); 1747 CHECK(field != NULL); 1748 gCryptoModes.AesCtr = 1749 env->GetStaticIntField(clazz.get(), field); 1750 1751 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I"); 1752 CHECK(field != NULL); 1753 gCryptoModes.AesCbc = 1754 env->GetStaticIntField(clazz.get(), field); 1755 1756 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo")); 1757 CHECK(clazz.get() != NULL); 1758 1759 gFields.cryptoInfoNumSubSamplesID = 1760 env->GetFieldID(clazz.get(), "numSubSamples", "I"); 1761 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL); 1762 1763 gFields.cryptoInfoNumBytesOfClearDataID = 1764 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I"); 1765 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL); 1766 1767 gFields.cryptoInfoNumBytesOfEncryptedDataID = 1768 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I"); 1769 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL); 1770 1771 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B"); 1772 CHECK(gFields.cryptoInfoKeyID != NULL); 1773 1774 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B"); 1775 CHECK(gFields.cryptoInfoIVID != NULL); 1776 1777 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I"); 1778 CHECK(gFields.cryptoInfoModeID != NULL); 1779 1780 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "pattern", 1781 "Landroid/media/MediaCodec$CryptoInfo$Pattern;"); 1782 CHECK(gFields.cryptoInfoPatternID != NULL); 1783 1784 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern")); 1785 CHECK(clazz.get() != NULL); 1786 1787 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I"); 1788 CHECK(gFields.patternEncryptBlocksID != NULL); 1789 1790 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I"); 1791 CHECK(gFields.patternSkipBlocksID != NULL); 1792 1793 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException")); 1794 CHECK(clazz.get() != NULL); 1795 1796 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I"); 1797 CHECK(field != NULL); 1798 gCryptoErrorCodes.cryptoErrorNoKey = 1799 env->GetStaticIntField(clazz.get(), field); 1800 1801 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I"); 1802 CHECK(field != NULL); 1803 gCryptoErrorCodes.cryptoErrorKeyExpired = 1804 env->GetStaticIntField(clazz.get(), field); 1805 1806 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I"); 1807 CHECK(field != NULL); 1808 gCryptoErrorCodes.cryptoErrorResourceBusy = 1809 env->GetStaticIntField(clazz.get(), field); 1810 1811 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I"); 1812 CHECK(field != NULL); 1813 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection = 1814 env->GetStaticIntField(clazz.get(), field); 1815 1816 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I"); 1817 CHECK(field != NULL); 1818 gCryptoErrorCodes.cryptoErrorSessionNotOpened = 1819 env->GetStaticIntField(clazz.get(), field); 1820 1821 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I"); 1822 CHECK(field != NULL); 1823 gCryptoErrorCodes.cryptoErrorUnsupportedOperation = 1824 env->GetStaticIntField(clazz.get(), field); 1825 1826 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException")); 1827 CHECK(clazz.get() != NULL); 1828 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I"); 1829 CHECK(field != NULL); 1830 gCodecActionCodes.codecActionTransient = 1831 env->GetStaticIntField(clazz.get(), field); 1832 1833 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I"); 1834 CHECK(field != NULL); 1835 gCodecActionCodes.codecActionRecoverable = 1836 env->GetStaticIntField(clazz.get(), field); 1837 1838 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I"); 1839 CHECK(field != NULL); 1840 gCodecErrorCodes.errorInsufficientResource = 1841 env->GetStaticIntField(clazz.get(), field); 1842 1843 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I"); 1844 CHECK(field != NULL); 1845 gCodecErrorCodes.errorReclaimed = 1846 env->GetStaticIntField(clazz.get(), field); 1847 1848 clazz.reset(env->FindClass("android/view/Surface")); 1849 CHECK(clazz.get() != NULL); 1850 1851 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;"); 1852 CHECK(field != NULL); 1853 gPersistentSurfaceClassInfo.mLock = field; 1854 1855 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V"); 1856 CHECK(method != NULL); 1857 gPersistentSurfaceClassInfo.setNativeObjectLocked = method; 1858 1859 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface")); 1860 CHECK(clazz.get() != NULL); 1861 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get()); 1862 1863 method = env->GetMethodID(clazz.get(), "<init>", "()V"); 1864 CHECK(method != NULL); 1865 gPersistentSurfaceClassInfo.ctor = method; 1866 1867 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J"); 1868 CHECK(field != NULL); 1869 gPersistentSurfaceClassInfo.mPersistentObject = field; 1870} 1871 1872static void android_media_MediaCodec_native_setup( 1873 JNIEnv *env, jobject thiz, 1874 jstring name, jboolean nameIsType, jboolean encoder) { 1875 if (name == NULL) { 1876 jniThrowException(env, "java/lang/NullPointerException", NULL); 1877 return; 1878 } 1879 1880 const char *tmp = env->GetStringUTFChars(name, NULL); 1881 1882 if (tmp == NULL) { 1883 return; 1884 } 1885 1886 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder); 1887 1888 const status_t err = codec->initCheck(); 1889 if (err == NAME_NOT_FOUND) { 1890 // fail and do not try again. 1891 jniThrowException(env, "java/lang/IllegalArgumentException", 1892 String8::format("Failed to initialize %s, error %#x", tmp, err)); 1893 env->ReleaseStringUTFChars(name, tmp); 1894 return; 1895 } if (err == NO_MEMORY) { 1896 throwCodecException(env, err, ACTION_CODE_TRANSIENT, 1897 String8::format("Failed to initialize %s, error %#x", tmp, err)); 1898 env->ReleaseStringUTFChars(name, tmp); 1899 return; 1900 } else if (err != OK) { 1901 // believed possible to try again 1902 jniThrowException(env, "java/io/IOException", 1903 String8::format("Failed to find matching codec %s, error %#x", tmp, err)); 1904 env->ReleaseStringUTFChars(name, tmp); 1905 return; 1906 } 1907 1908 env->ReleaseStringUTFChars(name, tmp); 1909 1910 codec->registerSelf(); 1911 1912 setMediaCodec(env,thiz, codec); 1913} 1914 1915static void android_media_MediaCodec_native_finalize( 1916 JNIEnv *env, jobject thiz) { 1917 android_media_MediaCodec_release(env, thiz); 1918} 1919 1920static const JNINativeMethod gMethods[] = { 1921 { "native_release", "()V", (void *)android_media_MediaCodec_release }, 1922 1923 { "native_reset", "()V", (void *)android_media_MediaCodec_reset }, 1924 1925 { "native_releasePersistentInputSurface", 1926 "(Landroid/view/Surface;)V", 1927 (void *)android_media_MediaCodec_releasePersistentInputSurface}, 1928 1929 { "native_createPersistentInputSurface", 1930 "()Landroid/media/MediaCodec$PersistentSurface;", 1931 (void *)android_media_MediaCodec_createPersistentInputSurface }, 1932 1933 { "native_setInputSurface", "(Landroid/view/Surface;)V", 1934 (void *)android_media_MediaCodec_setInputSurface }, 1935 1936 { "native_enableOnFrameRenderedListener", "(Z)V", 1937 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener }, 1938 1939 { "native_setCallback", 1940 "(Landroid/media/MediaCodec$Callback;)V", 1941 (void *)android_media_MediaCodec_native_setCallback }, 1942 1943 { "native_configure", 1944 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;" 1945 "Landroid/media/MediaCrypto;I)V", 1946 (void *)android_media_MediaCodec_native_configure }, 1947 1948 { "native_setSurface", 1949 "(Landroid/view/Surface;)V", 1950 (void *)android_media_MediaCodec_native_setSurface }, 1951 1952 { "createInputSurface", "()Landroid/view/Surface;", 1953 (void *)android_media_MediaCodec_createInputSurface }, 1954 1955 { "native_start", "()V", (void *)android_media_MediaCodec_start }, 1956 { "native_stop", "()V", (void *)android_media_MediaCodec_stop }, 1957 { "native_flush", "()V", (void *)android_media_MediaCodec_flush }, 1958 1959 { "native_queueInputBuffer", "(IIIJI)V", 1960 (void *)android_media_MediaCodec_queueInputBuffer }, 1961 1962 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V", 1963 (void *)android_media_MediaCodec_queueSecureInputBuffer }, 1964 1965 { "native_dequeueInputBuffer", "(J)I", 1966 (void *)android_media_MediaCodec_dequeueInputBuffer }, 1967 1968 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", 1969 (void *)android_media_MediaCodec_dequeueOutputBuffer }, 1970 1971 { "releaseOutputBuffer", "(IZZJ)V", 1972 (void *)android_media_MediaCodec_releaseOutputBuffer }, 1973 1974 { "signalEndOfInputStream", "()V", 1975 (void *)android_media_MediaCodec_signalEndOfInputStream }, 1976 1977 { "getFormatNative", "(Z)Ljava/util/Map;", 1978 (void *)android_media_MediaCodec_getFormatNative }, 1979 1980 { "getOutputFormatNative", "(I)Ljava/util/Map;", 1981 (void *)android_media_MediaCodec_getOutputFormatForIndexNative }, 1982 1983 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;", 1984 (void *)android_media_MediaCodec_getBuffers }, 1985 1986 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;", 1987 (void *)android_media_MediaCodec_getBuffer }, 1988 1989 { "getImage", "(ZI)Landroid/media/Image;", 1990 (void *)android_media_MediaCodec_getImage }, 1991 1992 { "getName", "()Ljava/lang/String;", 1993 (void *)android_media_MediaCodec_getName }, 1994 1995 { "getMetrics", "()Landroid/os/Bundle;", 1996 (void *)android_media_MediaCodec_getMetrics}, 1997 1998 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V", 1999 (void *)android_media_MediaCodec_setParameters }, 2000 2001 { "setVideoScalingMode", "(I)V", 2002 (void *)android_media_MediaCodec_setVideoScalingMode }, 2003 2004 { "native_init", "()V", (void *)android_media_MediaCodec_native_init }, 2005 2006 { "native_setup", "(Ljava/lang/String;ZZ)V", 2007 (void *)android_media_MediaCodec_native_setup }, 2008 2009 { "native_finalize", "()V", 2010 (void *)android_media_MediaCodec_native_finalize }, 2011}; 2012 2013int register_android_media_MediaCodec(JNIEnv *env) { 2014 return AndroidRuntime::registerNativeMethods(env, 2015 "android/media/MediaCodec", gMethods, NELEM(gMethods)); 2016} 2017