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