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