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