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