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