android_media_MediaCodec.cpp revision 3ccb34d7070d73ba6c7842801b070b41de32b842
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 const char *defaultMsg = "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 defaultMsg = "Crypto key not available"; 844 break; 845 case ERROR_DRM_LICENSE_EXPIRED: 846 err = gCryptoErrorCodes.cryptoErrorKeyExpired; 847 defaultMsg = "License expired"; 848 break; 849 case ERROR_DRM_RESOURCE_BUSY: 850 err = gCryptoErrorCodes.cryptoErrorResourceBusy; 851 defaultMsg = "Resource busy or unavailable"; 852 break; 853 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION: 854 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection; 855 defaultMsg = "Required output protections are not active"; 856 break; 857 case ERROR_DRM_SESSION_NOT_OPENED: 858 err = gCryptoErrorCodes.cryptoErrorSessionNotOpened; 859 defaultMsg = "Attempted to use a closed session"; 860 break; 861 default: /* Other negative DRM error codes go out as is. */ 862 break; 863 } 864 865 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : defaultMsg); 866 867 jthrowable exception = 868 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj); 869 870 env->Throw(exception); 871} 872 873static jint throwExceptionAsNecessary( 874 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL, 875 const char *msg = NULL) { 876 switch (err) { 877 case OK: 878 return 0; 879 880 case -EAGAIN: 881 return DEQUEUE_INFO_TRY_AGAIN_LATER; 882 883 case INFO_FORMAT_CHANGED: 884 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED; 885 886 case INFO_OUTPUT_BUFFERS_CHANGED: 887 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED; 888 889 case INVALID_OPERATION: 890 jniThrowException(env, "java/lang/IllegalStateException", msg); 891 return 0; 892 893 case BAD_VALUE: 894 jniThrowException(env, "java/lang/IllegalArgumentException", msg); 895 return 0; 896 897 default: 898 if (isCryptoError(err)) { 899 throwCryptoException(env, err, msg); 900 return 0; 901 } 902 throwCodecException(env, err, actionCode, msg); 903 return 0; 904 } 905} 906 907static void android_media_MediaCodec_native_enableOnFrameRenderedListener( 908 JNIEnv *env, 909 jobject thiz, 910 jboolean enabled) { 911 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 912 913 if (codec == NULL) { 914 throwExceptionAsNecessary(env, INVALID_OPERATION); 915 return; 916 } 917 918 status_t err = codec->enableOnFrameRenderedListener(enabled); 919 920 throwExceptionAsNecessary(env, err); 921} 922 923static void android_media_MediaCodec_native_setCallback( 924 JNIEnv *env, 925 jobject thiz, 926 jobject cb) { 927 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 928 929 if (codec == NULL) { 930 throwExceptionAsNecessary(env, INVALID_OPERATION); 931 return; 932 } 933 934 status_t err = codec->setCallback(cb); 935 936 throwExceptionAsNecessary(env, err); 937} 938 939static void android_media_MediaCodec_native_configure( 940 JNIEnv *env, 941 jobject thiz, 942 jobjectArray keys, jobjectArray values, 943 jobject jsurface, 944 jobject jcrypto, 945 jint flags) { 946 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 947 948 if (codec == NULL) { 949 throwExceptionAsNecessary(env, INVALID_OPERATION); 950 return; 951 } 952 953 sp<AMessage> format; 954 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format); 955 956 if (err != OK) { 957 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 958 return; 959 } 960 961 sp<IGraphicBufferProducer> bufferProducer; 962 if (jsurface != NULL) { 963 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 964 if (surface != NULL) { 965 bufferProducer = surface->getIGraphicBufferProducer(); 966 } else { 967 jniThrowException( 968 env, 969 "java/lang/IllegalArgumentException", 970 "The surface has been released"); 971 return; 972 } 973 } 974 975 sp<ICrypto> crypto; 976 if (jcrypto != NULL) { 977 crypto = JCrypto::GetCrypto(env, jcrypto); 978 } 979 980 err = codec->configure(format, bufferProducer, crypto, flags); 981 982 throwExceptionAsNecessary(env, err); 983} 984 985static void android_media_MediaCodec_native_setSurface( 986 JNIEnv *env, 987 jobject thiz, 988 jobject jsurface) { 989 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 990 991 if (codec == NULL) { 992 throwExceptionAsNecessary(env, INVALID_OPERATION); 993 return; 994 } 995 996 sp<IGraphicBufferProducer> bufferProducer; 997 if (jsurface != NULL) { 998 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 999 if (surface != NULL) { 1000 bufferProducer = surface->getIGraphicBufferProducer(); 1001 } else { 1002 jniThrowException( 1003 env, 1004 "java/lang/IllegalArgumentException", 1005 "The surface has been released"); 1006 return; 1007 } 1008 } 1009 1010 status_t err = codec->setSurface(bufferProducer); 1011 throwExceptionAsNecessary(env, err); 1012} 1013 1014sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface( 1015 JNIEnv* env, jobject object) { 1016 sp<PersistentSurface> persistentSurface; 1017 1018 jobject lock = env->GetObjectField( 1019 object, gPersistentSurfaceClassInfo.mLock); 1020 if (env->MonitorEnter(lock) == JNI_OK) { 1021 persistentSurface = reinterpret_cast<PersistentSurface *>( 1022 env->GetLongField(object, 1023 gPersistentSurfaceClassInfo.mPersistentObject)); 1024 env->MonitorExit(lock); 1025 } 1026 env->DeleteLocalRef(lock); 1027 1028 return persistentSurface; 1029} 1030 1031static jobject android_media_MediaCodec_createPersistentInputSurface( 1032 JNIEnv* env, jclass /* clazz */) { 1033 ALOGV("android_media_MediaCodec_createPersistentInputSurface"); 1034 sp<PersistentSurface> persistentSurface = 1035 MediaCodec::CreatePersistentInputSurface(); 1036 1037 if (persistentSurface == NULL) { 1038 return NULL; 1039 } 1040 1041 sp<Surface> surface = new Surface( 1042 persistentSurface->getBufferProducer(), true); 1043 if (surface == NULL) { 1044 return NULL; 1045 } 1046 1047 jobject object = env->NewObject( 1048 gPersistentSurfaceClassInfo.clazz, 1049 gPersistentSurfaceClassInfo.ctor); 1050 1051 if (object == NULL) { 1052 if (env->ExceptionCheck()) { 1053 ALOGE("Could not create PersistentSurface."); 1054 env->ExceptionClear(); 1055 } 1056 return NULL; 1057 } 1058 1059 jobject lock = env->GetObjectField( 1060 object, gPersistentSurfaceClassInfo.mLock); 1061 if (env->MonitorEnter(lock) == JNI_OK) { 1062 env->CallVoidMethod( 1063 object, 1064 gPersistentSurfaceClassInfo.setNativeObjectLocked, 1065 (jlong)surface.get()); 1066 env->SetLongField( 1067 object, 1068 gPersistentSurfaceClassInfo.mPersistentObject, 1069 (jlong)persistentSurface.get()); 1070 env->MonitorExit(lock); 1071 } else { 1072 env->DeleteLocalRef(object); 1073 object = NULL; 1074 } 1075 env->DeleteLocalRef(lock); 1076 1077 if (object != NULL) { 1078 surface->incStrong(&sRefBaseOwner); 1079 persistentSurface->incStrong(&sRefBaseOwner); 1080 } 1081 1082 return object; 1083} 1084 1085static void android_media_MediaCodec_releasePersistentInputSurface( 1086 JNIEnv* env, jclass /* clazz */, jobject object) { 1087 sp<PersistentSurface> persistentSurface; 1088 1089 jobject lock = env->GetObjectField( 1090 object, gPersistentSurfaceClassInfo.mLock); 1091 if (env->MonitorEnter(lock) == JNI_OK) { 1092 persistentSurface = reinterpret_cast<PersistentSurface *>( 1093 env->GetLongField( 1094 object, gPersistentSurfaceClassInfo.mPersistentObject)); 1095 env->SetLongField( 1096 object, 1097 gPersistentSurfaceClassInfo.mPersistentObject, 1098 (jlong)0); 1099 env->MonitorExit(lock); 1100 } 1101 env->DeleteLocalRef(lock); 1102 1103 if (persistentSurface != NULL) { 1104 persistentSurface->decStrong(&sRefBaseOwner); 1105 } 1106 // no need to release surface as it will be released by Surface's jni 1107} 1108 1109static void android_media_MediaCodec_setInputSurface( 1110 JNIEnv* env, jobject thiz, jobject object) { 1111 ALOGV("android_media_MediaCodec_setInputSurface"); 1112 1113 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1114 if (codec == NULL) { 1115 throwExceptionAsNecessary(env, INVALID_OPERATION); 1116 return; 1117 } 1118 1119 sp<PersistentSurface> persistentSurface = 1120 android_media_MediaCodec_getPersistentInputSurface(env, object); 1121 1122 status_t err = codec->setInputSurface(persistentSurface); 1123 if (err != NO_ERROR) { 1124 throwExceptionAsNecessary(env, err); 1125 } 1126} 1127 1128static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env, 1129 jobject thiz) { 1130 ALOGV("android_media_MediaCodec_createInputSurface"); 1131 1132 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1133 if (codec == NULL) { 1134 throwExceptionAsNecessary(env, INVALID_OPERATION); 1135 return NULL; 1136 } 1137 1138 // Tell the MediaCodec that we want to use a Surface as input. 1139 sp<IGraphicBufferProducer> bufferProducer; 1140 status_t err = codec->createInputSurface(&bufferProducer); 1141 if (err != NO_ERROR) { 1142 throwExceptionAsNecessary(env, err); 1143 return NULL; 1144 } 1145 1146 // Wrap the IGBP in a Java-language Surface. 1147 return android_view_Surface_createFromIGraphicBufferProducer(env, 1148 bufferProducer); 1149} 1150 1151static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) { 1152 ALOGV("android_media_MediaCodec_start"); 1153 1154 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1155 1156 if (codec == NULL) { 1157 throwExceptionAsNecessary(env, INVALID_OPERATION); 1158 return; 1159 } 1160 1161 status_t err = codec->start(); 1162 1163 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed"); 1164} 1165 1166static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) { 1167 ALOGV("android_media_MediaCodec_stop"); 1168 1169 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1170 1171 if (codec == NULL) { 1172 throwExceptionAsNecessary(env, INVALID_OPERATION); 1173 return; 1174 } 1175 1176 status_t err = codec->stop(); 1177 1178 throwExceptionAsNecessary(env, err); 1179} 1180 1181static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) { 1182 ALOGV("android_media_MediaCodec_reset"); 1183 1184 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1185 1186 if (codec == NULL) { 1187 throwExceptionAsNecessary(env, INVALID_OPERATION); 1188 return; 1189 } 1190 1191 status_t err = codec->reset(); 1192 if (err != OK) { 1193 // treat all errors as fatal for now, though resource not available 1194 // errors could be treated as transient. 1195 // we also should avoid sending INVALID_OPERATION here due to 1196 // the transitory nature of reset(), it should not inadvertently 1197 // trigger an IllegalStateException. 1198 err = UNKNOWN_ERROR; 1199 } 1200 throwExceptionAsNecessary(env, err); 1201} 1202 1203static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) { 1204 ALOGV("android_media_MediaCodec_flush"); 1205 1206 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1207 1208 if (codec == NULL) { 1209 throwExceptionAsNecessary(env, INVALID_OPERATION); 1210 return; 1211 } 1212 1213 status_t err = codec->flush(); 1214 1215 throwExceptionAsNecessary(env, err); 1216} 1217 1218static void android_media_MediaCodec_queueInputBuffer( 1219 JNIEnv *env, 1220 jobject thiz, 1221 jint index, 1222 jint offset, 1223 jint size, 1224 jlong timestampUs, 1225 jint flags) { 1226 ALOGV("android_media_MediaCodec_queueInputBuffer"); 1227 1228 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1229 1230 if (codec == NULL) { 1231 throwExceptionAsNecessary(env, INVALID_OPERATION); 1232 return; 1233 } 1234 1235 AString errorDetailMsg; 1236 1237 status_t err = codec->queueInputBuffer( 1238 index, offset, size, timestampUs, flags, &errorDetailMsg); 1239 1240 throwExceptionAsNecessary( 1241 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 1242} 1243 1244static void android_media_MediaCodec_queueSecureInputBuffer( 1245 JNIEnv *env, 1246 jobject thiz, 1247 jint index, 1248 jint offset, 1249 jobject cryptoInfoObj, 1250 jlong timestampUs, 1251 jint flags) { 1252 ALOGV("android_media_MediaCodec_queueSecureInputBuffer"); 1253 1254 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1255 1256 if (codec == NULL) { 1257 throwExceptionAsNecessary(env, INVALID_OPERATION); 1258 return; 1259 } 1260 1261 jint numSubSamples = 1262 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID); 1263 1264 jintArray numBytesOfClearDataObj = 1265 (jintArray)env->GetObjectField( 1266 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID); 1267 1268 jintArray numBytesOfEncryptedDataObj = 1269 (jintArray)env->GetObjectField( 1270 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID); 1271 1272 jbyteArray keyObj = 1273 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID); 1274 1275 jbyteArray ivObj = 1276 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID); 1277 1278 jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID); 1279 1280 status_t err = OK; 1281 1282 CryptoPlugin::SubSample *subSamples = NULL; 1283 jbyte *key = NULL; 1284 jbyte *iv = NULL; 1285 1286 if (numSubSamples <= 0) { 1287 err = -EINVAL; 1288 } else if (numBytesOfClearDataObj == NULL 1289 && numBytesOfEncryptedDataObj == NULL) { 1290 err = -EINVAL; 1291 } else if (numBytesOfEncryptedDataObj != NULL 1292 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) { 1293 err = -ERANGE; 1294 } else if (numBytesOfClearDataObj != NULL 1295 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) { 1296 err = -ERANGE; 1297 // subSamples array may silently overflow if number of samples are too large. Use 1298 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms 1299 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) { 1300 err = -EINVAL; 1301 } else { 1302 jboolean isCopy; 1303 1304 jint *numBytesOfClearData = 1305 (numBytesOfClearDataObj == NULL) 1306 ? NULL 1307 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy); 1308 1309 jint *numBytesOfEncryptedData = 1310 (numBytesOfEncryptedDataObj == NULL) 1311 ? NULL 1312 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); 1313 1314 subSamples = new CryptoPlugin::SubSample[numSubSamples]; 1315 1316 for (jint i = 0; i < numSubSamples; ++i) { 1317 subSamples[i].mNumBytesOfClearData = 1318 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i]; 1319 1320 subSamples[i].mNumBytesOfEncryptedData = 1321 (numBytesOfEncryptedData == NULL) 1322 ? 0 : numBytesOfEncryptedData[i]; 1323 } 1324 1325 if (numBytesOfEncryptedData != NULL) { 1326 env->ReleaseIntArrayElements( 1327 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0); 1328 numBytesOfEncryptedData = NULL; 1329 } 1330 1331 if (numBytesOfClearData != NULL) { 1332 env->ReleaseIntArrayElements( 1333 numBytesOfClearDataObj, numBytesOfClearData, 0); 1334 numBytesOfClearData = NULL; 1335 } 1336 } 1337 1338 if (err == OK && keyObj != NULL) { 1339 if (env->GetArrayLength(keyObj) != 16) { 1340 err = -EINVAL; 1341 } else { 1342 jboolean isCopy; 1343 key = env->GetByteArrayElements(keyObj, &isCopy); 1344 } 1345 } 1346 1347 if (err == OK && ivObj != NULL) { 1348 if (env->GetArrayLength(ivObj) != 16) { 1349 err = -EINVAL; 1350 } else { 1351 jboolean isCopy; 1352 iv = env->GetByteArrayElements(ivObj, &isCopy); 1353 } 1354 } 1355 1356 AString errorDetailMsg; 1357 1358 if (err == OK) { 1359 err = codec->queueSecureInputBuffer( 1360 index, offset, 1361 subSamples, numSubSamples, 1362 (const uint8_t *)key, (const uint8_t *)iv, 1363 (CryptoPlugin::Mode)mode, 1364 timestampUs, 1365 flags, 1366 &errorDetailMsg); 1367 } 1368 1369 if (iv != NULL) { 1370 env->ReleaseByteArrayElements(ivObj, iv, 0); 1371 iv = NULL; 1372 } 1373 1374 if (key != NULL) { 1375 env->ReleaseByteArrayElements(keyObj, key, 0); 1376 key = NULL; 1377 } 1378 1379 delete[] subSamples; 1380 subSamples = NULL; 1381 1382 throwExceptionAsNecessary( 1383 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 1384} 1385 1386static jint android_media_MediaCodec_dequeueInputBuffer( 1387 JNIEnv *env, jobject thiz, jlong timeoutUs) { 1388 ALOGV("android_media_MediaCodec_dequeueInputBuffer"); 1389 1390 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1391 1392 if (codec == NULL) { 1393 throwExceptionAsNecessary(env, INVALID_OPERATION); 1394 return -1; 1395 } 1396 1397 size_t index; 1398 status_t err = codec->dequeueInputBuffer(&index, timeoutUs); 1399 1400 if (err == OK) { 1401 return (jint) index; 1402 } 1403 1404 return throwExceptionAsNecessary(env, err); 1405} 1406 1407static jint android_media_MediaCodec_dequeueOutputBuffer( 1408 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) { 1409 ALOGV("android_media_MediaCodec_dequeueOutputBuffer"); 1410 1411 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1412 1413 if (codec == NULL) { 1414 throwExceptionAsNecessary(env, INVALID_OPERATION); 1415 return 0; 1416 } 1417 1418 size_t index; 1419 status_t err = codec->dequeueOutputBuffer( 1420 env, bufferInfo, &index, timeoutUs); 1421 1422 if (err == OK) { 1423 return (jint) index; 1424 } 1425 1426 return throwExceptionAsNecessary(env, err); 1427} 1428 1429static void android_media_MediaCodec_releaseOutputBuffer( 1430 JNIEnv *env, jobject thiz, 1431 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) { 1432 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease"); 1433 1434 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1435 1436 if (codec == NULL) { 1437 throwExceptionAsNecessary(env, INVALID_OPERATION); 1438 return; 1439 } 1440 1441 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs); 1442 1443 throwExceptionAsNecessary(env, err); 1444} 1445 1446static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env, 1447 jobject thiz) { 1448 ALOGV("android_media_MediaCodec_signalEndOfInputStream"); 1449 1450 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1451 if (codec == NULL) { 1452 throwExceptionAsNecessary(env, INVALID_OPERATION); 1453 return; 1454 } 1455 1456 status_t err = codec->signalEndOfInputStream(); 1457 1458 throwExceptionAsNecessary(env, err); 1459} 1460 1461static jobject android_media_MediaCodec_getFormatNative( 1462 JNIEnv *env, jobject thiz, jboolean input) { 1463 ALOGV("android_media_MediaCodec_getFormatNative"); 1464 1465 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1466 1467 if (codec == NULL) { 1468 throwExceptionAsNecessary(env, INVALID_OPERATION); 1469 return NULL; 1470 } 1471 1472 jobject format; 1473 status_t err = codec->getFormat(env, input, &format); 1474 1475 if (err == OK) { 1476 return format; 1477 } 1478 1479 throwExceptionAsNecessary(env, err); 1480 1481 return NULL; 1482} 1483 1484static jobject android_media_MediaCodec_getOutputFormatForIndexNative( 1485 JNIEnv *env, jobject thiz, jint index) { 1486 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative"); 1487 1488 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1489 1490 if (codec == NULL) { 1491 throwExceptionAsNecessary(env, INVALID_OPERATION); 1492 return NULL; 1493 } 1494 1495 jobject format; 1496 status_t err = codec->getOutputFormat(env, index, &format); 1497 1498 if (err == OK) { 1499 return format; 1500 } 1501 1502 throwExceptionAsNecessary(env, err); 1503 1504 return NULL; 1505} 1506 1507static jobjectArray android_media_MediaCodec_getBuffers( 1508 JNIEnv *env, jobject thiz, jboolean input) { 1509 ALOGV("android_media_MediaCodec_getBuffers"); 1510 1511 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1512 1513 if (codec == NULL) { 1514 throwExceptionAsNecessary(env, INVALID_OPERATION); 1515 return NULL; 1516 } 1517 1518 jobjectArray buffers; 1519 status_t err = codec->getBuffers(env, input, &buffers); 1520 1521 if (err == OK) { 1522 return buffers; 1523 } 1524 1525 // if we're out of memory, an exception was already thrown 1526 if (err != NO_MEMORY) { 1527 throwExceptionAsNecessary(env, err); 1528 } 1529 1530 return NULL; 1531} 1532 1533static jobject android_media_MediaCodec_getBuffer( 1534 JNIEnv *env, jobject thiz, jboolean input, jint index) { 1535 ALOGV("android_media_MediaCodec_getBuffer"); 1536 1537 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1538 1539 if (codec == NULL) { 1540 throwExceptionAsNecessary(env, INVALID_OPERATION); 1541 return NULL; 1542 } 1543 1544 jobject buffer; 1545 status_t err = codec->getBuffer(env, input, index, &buffer); 1546 1547 if (err == OK) { 1548 return buffer; 1549 } 1550 1551 // if we're out of memory, an exception was already thrown 1552 if (err != NO_MEMORY) { 1553 throwExceptionAsNecessary(env, err); 1554 } 1555 1556 return NULL; 1557} 1558 1559static jobject android_media_MediaCodec_getImage( 1560 JNIEnv *env, jobject thiz, jboolean input, jint index) { 1561 ALOGV("android_media_MediaCodec_getImage"); 1562 1563 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1564 1565 if (codec == NULL) { 1566 throwExceptionAsNecessary(env, INVALID_OPERATION); 1567 return NULL; 1568 } 1569 1570 jobject image; 1571 status_t err = codec->getImage(env, input, index, &image); 1572 1573 if (err == OK) { 1574 return image; 1575 } 1576 1577 // if we're out of memory, an exception was already thrown 1578 if (err != NO_MEMORY) { 1579 throwExceptionAsNecessary(env, err); 1580 } 1581 1582 return NULL; 1583} 1584 1585static jobject android_media_MediaCodec_getName( 1586 JNIEnv *env, jobject thiz) { 1587 ALOGV("android_media_MediaCodec_getName"); 1588 1589 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1590 1591 if (codec == NULL) { 1592 throwExceptionAsNecessary(env, INVALID_OPERATION); 1593 return NULL; 1594 } 1595 1596 jstring name; 1597 status_t err = codec->getName(env, &name); 1598 1599 if (err == OK) { 1600 return name; 1601 } 1602 1603 throwExceptionAsNecessary(env, err); 1604 1605 return NULL; 1606} 1607 1608static void android_media_MediaCodec_setParameters( 1609 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) { 1610 ALOGV("android_media_MediaCodec_setParameters"); 1611 1612 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1613 1614 if (codec == NULL) { 1615 throwExceptionAsNecessary(env, INVALID_OPERATION); 1616 return; 1617 } 1618 1619 sp<AMessage> params; 1620 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, ¶ms); 1621 1622 if (err == OK) { 1623 err = codec->setParameters(params); 1624 } 1625 1626 throwExceptionAsNecessary(env, err); 1627} 1628 1629static void android_media_MediaCodec_setVideoScalingMode( 1630 JNIEnv *env, jobject thiz, jint mode) { 1631 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1632 1633 if (codec == NULL) { 1634 throwExceptionAsNecessary(env, INVALID_OPERATION); 1635 return; 1636 } 1637 1638 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW 1639 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { 1640 jniThrowException(env, "java/lang/InvalidArgumentException", NULL); 1641 return; 1642 } 1643 1644 codec->setVideoScalingMode(mode); 1645} 1646 1647static void android_media_MediaCodec_native_init(JNIEnv *env) { 1648 ScopedLocalRef<jclass> clazz( 1649 env, env->FindClass("android/media/MediaCodec")); 1650 CHECK(clazz.get() != NULL); 1651 1652 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J"); 1653 CHECK(gFields.context != NULL); 1654 1655 gFields.postEventFromNativeID = 1656 env->GetMethodID( 1657 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V"); 1658 1659 CHECK(gFields.postEventFromNativeID != NULL); 1660 1661 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo")); 1662 CHECK(clazz.get() != NULL); 1663 1664 gFields.cryptoInfoNumSubSamplesID = 1665 env->GetFieldID(clazz.get(), "numSubSamples", "I"); 1666 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL); 1667 1668 gFields.cryptoInfoNumBytesOfClearDataID = 1669 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I"); 1670 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL); 1671 1672 gFields.cryptoInfoNumBytesOfEncryptedDataID = 1673 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I"); 1674 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL); 1675 1676 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B"); 1677 CHECK(gFields.cryptoInfoKeyID != NULL); 1678 1679 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B"); 1680 CHECK(gFields.cryptoInfoIVID != NULL); 1681 1682 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I"); 1683 CHECK(gFields.cryptoInfoModeID != NULL); 1684 1685 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException")); 1686 CHECK(clazz.get() != NULL); 1687 1688 jfieldID field; 1689 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I"); 1690 CHECK(field != NULL); 1691 gCryptoErrorCodes.cryptoErrorNoKey = 1692 env->GetStaticIntField(clazz.get(), field); 1693 1694 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I"); 1695 CHECK(field != NULL); 1696 gCryptoErrorCodes.cryptoErrorKeyExpired = 1697 env->GetStaticIntField(clazz.get(), field); 1698 1699 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I"); 1700 CHECK(field != NULL); 1701 gCryptoErrorCodes.cryptoErrorResourceBusy = 1702 env->GetStaticIntField(clazz.get(), field); 1703 1704 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I"); 1705 CHECK(field != NULL); 1706 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection = 1707 env->GetStaticIntField(clazz.get(), field); 1708 1709 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I"); 1710 CHECK(field != NULL); 1711 gCryptoErrorCodes.cryptoErrorSessionNotOpened = 1712 env->GetStaticIntField(clazz.get(), field); 1713 1714 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException")); 1715 CHECK(clazz.get() != NULL); 1716 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I"); 1717 CHECK(field != NULL); 1718 gCodecActionCodes.codecActionTransient = 1719 env->GetStaticIntField(clazz.get(), field); 1720 1721 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I"); 1722 CHECK(field != NULL); 1723 gCodecActionCodes.codecActionRecoverable = 1724 env->GetStaticIntField(clazz.get(), field); 1725 1726 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I"); 1727 CHECK(field != NULL); 1728 gCodecErrorCodes.errorInsufficientResource = 1729 env->GetStaticIntField(clazz.get(), field); 1730 1731 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I"); 1732 CHECK(field != NULL); 1733 gCodecErrorCodes.errorReclaimed = 1734 env->GetStaticIntField(clazz.get(), field); 1735 1736 clazz.reset(env->FindClass("android/view/Surface")); 1737 CHECK(clazz.get() != NULL); 1738 1739 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;"); 1740 CHECK(field != NULL); 1741 gPersistentSurfaceClassInfo.mLock = field; 1742 1743 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V"); 1744 CHECK(method != NULL); 1745 gPersistentSurfaceClassInfo.setNativeObjectLocked = method; 1746 1747 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface")); 1748 CHECK(clazz.get() != NULL); 1749 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get()); 1750 1751 method = env->GetMethodID(clazz.get(), "<init>", "()V"); 1752 CHECK(method != NULL); 1753 gPersistentSurfaceClassInfo.ctor = method; 1754 1755 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J"); 1756 CHECK(field != NULL); 1757 gPersistentSurfaceClassInfo.mPersistentObject = field; 1758} 1759 1760static void android_media_MediaCodec_native_setup( 1761 JNIEnv *env, jobject thiz, 1762 jstring name, jboolean nameIsType, jboolean encoder) { 1763 if (name == NULL) { 1764 jniThrowException(env, "java/lang/NullPointerException", NULL); 1765 return; 1766 } 1767 1768 const char *tmp = env->GetStringUTFChars(name, NULL); 1769 1770 if (tmp == NULL) { 1771 return; 1772 } 1773 1774 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder); 1775 1776 const status_t err = codec->initCheck(); 1777 if (err == NAME_NOT_FOUND) { 1778 // fail and do not try again. 1779 jniThrowException(env, "java/lang/IllegalArgumentException", 1780 String8::format("Failed to initialize %s, error %#x", tmp, err)); 1781 env->ReleaseStringUTFChars(name, tmp); 1782 return; 1783 } if (err == NO_MEMORY) { 1784 throwCodecException(env, err, ACTION_CODE_TRANSIENT, 1785 String8::format("Failed to initialize %s, error %#x", tmp, err)); 1786 env->ReleaseStringUTFChars(name, tmp); 1787 return; 1788 } else if (err != OK) { 1789 // believed possible to try again 1790 jniThrowException(env, "java/io/IOException", 1791 String8::format("Failed to find matching codec %s, error %#x", tmp, err)); 1792 env->ReleaseStringUTFChars(name, tmp); 1793 return; 1794 } 1795 1796 env->ReleaseStringUTFChars(name, tmp); 1797 1798 codec->registerSelf(); 1799 1800 setMediaCodec(env,thiz, codec); 1801} 1802 1803static void android_media_MediaCodec_native_finalize( 1804 JNIEnv *env, jobject thiz) { 1805 android_media_MediaCodec_release(env, thiz); 1806} 1807 1808static const JNINativeMethod gMethods[] = { 1809 { "native_release", "()V", (void *)android_media_MediaCodec_release }, 1810 1811 { "native_reset", "()V", (void *)android_media_MediaCodec_reset }, 1812 1813 { "native_releasePersistentInputSurface", 1814 "(Landroid/view/Surface;)V", 1815 (void *)android_media_MediaCodec_releasePersistentInputSurface}, 1816 1817 { "native_createPersistentInputSurface", 1818 "()Landroid/media/MediaCodec$PersistentSurface;", 1819 (void *)android_media_MediaCodec_createPersistentInputSurface }, 1820 1821 { "native_setInputSurface", "(Landroid/view/Surface;)V", 1822 (void *)android_media_MediaCodec_setInputSurface }, 1823 1824 { "native_enableOnFrameRenderedListener", "(Z)V", 1825 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener }, 1826 1827 { "native_setCallback", 1828 "(Landroid/media/MediaCodec$Callback;)V", 1829 (void *)android_media_MediaCodec_native_setCallback }, 1830 1831 { "native_configure", 1832 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;" 1833 "Landroid/media/MediaCrypto;I)V", 1834 (void *)android_media_MediaCodec_native_configure }, 1835 1836 { "native_setSurface", 1837 "(Landroid/view/Surface;)V", 1838 (void *)android_media_MediaCodec_native_setSurface }, 1839 1840 { "createInputSurface", "()Landroid/view/Surface;", 1841 (void *)android_media_MediaCodec_createInputSurface }, 1842 1843 { "native_start", "()V", (void *)android_media_MediaCodec_start }, 1844 { "native_stop", "()V", (void *)android_media_MediaCodec_stop }, 1845 { "native_flush", "()V", (void *)android_media_MediaCodec_flush }, 1846 1847 { "native_queueInputBuffer", "(IIIJI)V", 1848 (void *)android_media_MediaCodec_queueInputBuffer }, 1849 1850 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V", 1851 (void *)android_media_MediaCodec_queueSecureInputBuffer }, 1852 1853 { "native_dequeueInputBuffer", "(J)I", 1854 (void *)android_media_MediaCodec_dequeueInputBuffer }, 1855 1856 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", 1857 (void *)android_media_MediaCodec_dequeueOutputBuffer }, 1858 1859 { "releaseOutputBuffer", "(IZZJ)V", 1860 (void *)android_media_MediaCodec_releaseOutputBuffer }, 1861 1862 { "signalEndOfInputStream", "()V", 1863 (void *)android_media_MediaCodec_signalEndOfInputStream }, 1864 1865 { "getFormatNative", "(Z)Ljava/util/Map;", 1866 (void *)android_media_MediaCodec_getFormatNative }, 1867 1868 { "getOutputFormatNative", "(I)Ljava/util/Map;", 1869 (void *)android_media_MediaCodec_getOutputFormatForIndexNative }, 1870 1871 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;", 1872 (void *)android_media_MediaCodec_getBuffers }, 1873 1874 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;", 1875 (void *)android_media_MediaCodec_getBuffer }, 1876 1877 { "getImage", "(ZI)Landroid/media/Image;", 1878 (void *)android_media_MediaCodec_getImage }, 1879 1880 { "getName", "()Ljava/lang/String;", 1881 (void *)android_media_MediaCodec_getName }, 1882 1883 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V", 1884 (void *)android_media_MediaCodec_setParameters }, 1885 1886 { "setVideoScalingMode", "(I)V", 1887 (void *)android_media_MediaCodec_setVideoScalingMode }, 1888 1889 { "native_init", "()V", (void *)android_media_MediaCodec_native_init }, 1890 1891 { "native_setup", "(Ljava/lang/String;ZZ)V", 1892 (void *)android_media_MediaCodec_native_setup }, 1893 1894 { "native_finalize", "()V", 1895 (void *)android_media_MediaCodec_native_finalize }, 1896}; 1897 1898int register_android_media_MediaCodec(JNIEnv *env) { 1899 return AndroidRuntime::registerNativeMethods(env, 1900 "android/media/MediaCodec", gMethods, NELEM(gMethods)); 1901} 1902