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