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