android_media_MediaCodec.cpp revision 91befdc0c4710234840cdfd853e7d30e8f9de62c
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 <gui/Surface.h> 31#include <gui/SurfaceTextureClient.h> 32 33#include <media/ICrypto.h> 34#include <media/stagefright/MediaCodec.h> 35#include <media/stagefright/foundation/ABuffer.h> 36#include <media/stagefright/foundation/ADebug.h> 37#include <media/stagefright/foundation/ALooper.h> 38#include <media/stagefright/foundation/AMessage.h> 39#include <media/stagefright/MediaErrors.h> 40 41namespace android { 42 43// Keep these in sync with their equivalents in MediaCodec.java !!! 44enum { 45 DEQUEUE_INFO_TRY_AGAIN_LATER = -1, 46 DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2, 47 DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3, 48}; 49 50struct fields_t { 51 jfieldID context; 52 53 jfieldID cryptoInfoNumSubSamplesID; 54 jfieldID cryptoInfoNumBytesOfClearDataID; 55 jfieldID cryptoInfoNumBytesOfEncryptedDataID; 56 jfieldID cryptoInfoKeyID; 57 jfieldID cryptoInfoIVID; 58 jfieldID cryptoInfoModeID; 59}; 60 61static fields_t gFields; 62 63//////////////////////////////////////////////////////////////////////////////// 64 65JMediaCodec::JMediaCodec( 66 JNIEnv *env, jobject thiz, 67 const char *name, bool nameIsType, bool encoder) 68 : mClass(NULL), 69 mObject(NULL) { 70 jclass clazz = env->GetObjectClass(thiz); 71 CHECK(clazz != NULL); 72 73 mClass = (jclass)env->NewGlobalRef(clazz); 74 mObject = env->NewWeakGlobalRef(thiz); 75 76 mLooper = new ALooper; 77 mLooper->setName("MediaCodec_looper"); 78 79 mLooper->start( 80 false, // runOnCallingThread 81 false, // canCallJava 82 PRIORITY_DEFAULT); 83 84 if (nameIsType) { 85 mCodec = MediaCodec::CreateByType(mLooper, name, encoder); 86 } else { 87 mCodec = MediaCodec::CreateByComponentName(mLooper, name); 88 } 89} 90 91status_t JMediaCodec::initCheck() const { 92 return mCodec != NULL ? OK : NO_INIT; 93} 94 95JMediaCodec::~JMediaCodec() { 96 mCodec->release(); 97 98 JNIEnv *env = AndroidRuntime::getJNIEnv(); 99 100 env->DeleteWeakGlobalRef(mObject); 101 mObject = NULL; 102 env->DeleteGlobalRef(mClass); 103 mClass = NULL; 104} 105 106status_t JMediaCodec::configure( 107 const sp<AMessage> &format, 108 const sp<ISurfaceTexture> &surfaceTexture, 109 const sp<ICrypto> &crypto, 110 int flags) { 111 sp<SurfaceTextureClient> client; 112 if (surfaceTexture != NULL) { 113 client = new SurfaceTextureClient(surfaceTexture); 114 } 115 return mCodec->configure(format, client, crypto, flags); 116} 117 118status_t JMediaCodec::start() { 119 return mCodec->start(); 120} 121 122status_t JMediaCodec::stop() { 123 return mCodec->stop(); 124} 125 126status_t JMediaCodec::flush() { 127 return mCodec->flush(); 128} 129 130status_t JMediaCodec::queueInputBuffer( 131 size_t index, 132 size_t offset, size_t size, int64_t timeUs, uint32_t flags) { 133 return mCodec->queueInputBuffer(index, offset, size, timeUs, flags); 134} 135 136status_t JMediaCodec::queueSecureInputBuffer( 137 size_t index, 138 size_t offset, 139 const CryptoPlugin::SubSample *subSamples, 140 size_t numSubSamples, 141 const uint8_t key[16], 142 const uint8_t iv[16], 143 CryptoPlugin::Mode mode, 144 int64_t presentationTimeUs, 145 uint32_t flags) { 146 return mCodec->queueSecureInputBuffer( 147 index, offset, subSamples, numSubSamples, key, iv, mode, 148 presentationTimeUs, flags); 149} 150 151status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) { 152 return mCodec->dequeueInputBuffer(index, timeoutUs); 153} 154 155status_t JMediaCodec::dequeueOutputBuffer( 156 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) { 157 size_t size, offset; 158 int64_t timeUs; 159 uint32_t flags; 160 status_t err; 161 if ((err = mCodec->dequeueOutputBuffer( 162 index, &offset, &size, &timeUs, &flags, timeoutUs)) != OK) { 163 return err; 164 } 165 166 jclass clazz = env->FindClass("android/media/MediaCodec$BufferInfo"); 167 168 jmethodID method = env->GetMethodID(clazz, "set", "(IIJI)V"); 169 env->CallVoidMethod(bufferInfo, method, offset, size, timeUs, flags); 170 171 return OK; 172} 173 174status_t JMediaCodec::releaseOutputBuffer(size_t index, bool render) { 175 return render 176 ? mCodec->renderOutputBufferAndRelease(index) 177 : mCodec->releaseOutputBuffer(index); 178} 179 180status_t JMediaCodec::getOutputFormat(JNIEnv *env, jobject *format) const { 181 sp<AMessage> msg; 182 status_t err; 183 if ((err = mCodec->getOutputFormat(&msg)) != OK) { 184 return err; 185 } 186 187 return ConvertMessageToMap(env, msg, format); 188} 189 190status_t JMediaCodec::getBuffers( 191 JNIEnv *env, bool input, jobjectArray *bufArray) const { 192 Vector<sp<ABuffer> > buffers; 193 194 status_t err = 195 input 196 ? mCodec->getInputBuffers(&buffers) 197 : mCodec->getOutputBuffers(&buffers); 198 199 if (err != OK) { 200 return err; 201 } 202 203 jclass byteBufferClass = env->FindClass("java/nio/ByteBuffer"); 204 205 *bufArray = (jobjectArray)env->NewObjectArray( 206 buffers.size(), byteBufferClass, NULL); 207 208 for (size_t i = 0; i < buffers.size(); ++i) { 209 const sp<ABuffer> &buffer = buffers.itemAt(i); 210 211 jobject byteBuffer = 212 env->NewDirectByteBuffer( 213 buffer->base(), 214 buffer->capacity()); 215 216 env->SetObjectArrayElement( 217 *bufArray, i, byteBuffer); 218 219 env->DeleteLocalRef(byteBuffer); 220 byteBuffer = NULL; 221 } 222 223 return OK; 224} 225 226} // namespace android 227 228//////////////////////////////////////////////////////////////////////////////// 229 230using namespace android; 231 232static sp<JMediaCodec> setMediaCodec( 233 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) { 234 sp<JMediaCodec> old = (JMediaCodec *)env->GetIntField(thiz, gFields.context); 235 if (codec != NULL) { 236 codec->incStrong(thiz); 237 } 238 if (old != NULL) { 239 old->decStrong(thiz); 240 } 241 env->SetIntField(thiz, gFields.context, (int)codec.get()); 242 243 return old; 244} 245 246static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) { 247 return (JMediaCodec *)env->GetIntField(thiz, gFields.context); 248} 249 250static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) { 251 setMediaCodec(env, thiz, NULL); 252} 253 254static jint throwExceptionAsNecessary(JNIEnv *env, status_t err) { 255 switch (err) { 256 case OK: 257 return 0; 258 259 case -EAGAIN: 260 return DEQUEUE_INFO_TRY_AGAIN_LATER; 261 262 case INFO_FORMAT_CHANGED: 263 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED; 264 265 case INFO_OUTPUT_BUFFERS_CHANGED: 266 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED; 267 268 default: 269 { 270 jniThrowException(env, "java/lang/IllegalStateException", NULL); 271 break; 272 } 273 } 274 275 return 0; 276} 277 278static void android_media_MediaCodec_native_configure( 279 JNIEnv *env, 280 jobject thiz, 281 jobjectArray keys, jobjectArray values, 282 jobject jsurface, 283 jobject jcrypto, 284 jint flags) { 285 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 286 287 if (codec == NULL) { 288 jniThrowException(env, "java/lang/IllegalStateException", NULL); 289 return; 290 } 291 292 sp<AMessage> format; 293 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format); 294 295 if (err != OK) { 296 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 297 return; 298 } 299 300 sp<ISurfaceTexture> surfaceTexture; 301 if (jsurface != NULL) { 302 sp<Surface> surface(Surface_getSurface(env, jsurface)); 303 if (surface != NULL) { 304 surfaceTexture = surface->getSurfaceTexture(); 305 } else { 306 jniThrowException( 307 env, 308 "java/lang/IllegalArgumentException", 309 "The surface has been released"); 310 return; 311 } 312 } 313 314 sp<ICrypto> crypto; 315 if (jcrypto != NULL) { 316 crypto = JCrypto::GetCrypto(env, jcrypto); 317 } 318 319 err = codec->configure(format, surfaceTexture, crypto, flags); 320 321 throwExceptionAsNecessary(env, err); 322} 323 324static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) { 325 ALOGV("android_media_MediaCodec_start"); 326 327 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 328 329 if (codec == NULL) { 330 jniThrowException(env, "java/lang/IllegalStateException", NULL); 331 return; 332 } 333 334 status_t err = codec->start(); 335 336 throwExceptionAsNecessary(env, err); 337} 338 339static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) { 340 ALOGV("android_media_MediaCodec_stop"); 341 342 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 343 344 if (codec == NULL) { 345 jniThrowException(env, "java/lang/IllegalStateException", NULL); 346 return; 347 } 348 349 status_t err = codec->stop(); 350 351 throwExceptionAsNecessary(env, err); 352} 353 354static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) { 355 ALOGV("android_media_MediaCodec_flush"); 356 357 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 358 359 if (codec == NULL) { 360 jniThrowException(env, "java/lang/IllegalStateException", NULL); 361 return; 362 } 363 364 status_t err = codec->flush(); 365 366 throwExceptionAsNecessary(env, err); 367} 368 369static void android_media_MediaCodec_queueInputBuffer( 370 JNIEnv *env, 371 jobject thiz, 372 jint index, 373 jint offset, 374 jint size, 375 jlong timestampUs, 376 jint flags) { 377 ALOGV("android_media_MediaCodec_queueInputBuffer"); 378 379 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 380 381 if (codec == NULL) { 382 jniThrowException(env, "java/lang/IllegalStateException", NULL); 383 return; 384 } 385 386 status_t err = codec->queueInputBuffer( 387 index, offset, size, timestampUs, flags); 388 389 throwExceptionAsNecessary(env, err); 390} 391 392static void android_media_MediaCodec_queueSecureInputBuffer( 393 JNIEnv *env, 394 jobject thiz, 395 jint index, 396 jint offset, 397 jobject cryptoInfoObj, 398 jlong timestampUs, 399 jint flags) { 400 ALOGV("android_media_MediaCodec_queueSecureInputBuffer"); 401 402 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 403 404 if (codec == NULL) { 405 jniThrowException(env, "java/lang/IllegalStateException", NULL); 406 return; 407 } 408 409 jint numSubSamples = 410 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID); 411 412 jintArray numBytesOfClearDataObj = 413 (jintArray)env->GetObjectField( 414 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID); 415 416 jintArray numBytesOfEncryptedDataObj = 417 (jintArray)env->GetObjectField( 418 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID); 419 420 jbyteArray keyObj = 421 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID); 422 423 jbyteArray ivObj = 424 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID); 425 426 jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID); 427 428 status_t err = OK; 429 430 CryptoPlugin::SubSample *subSamples = NULL; 431 jbyte *key = NULL; 432 jbyte *iv = NULL; 433 434 if (numSubSamples <= 0) { 435 err = -EINVAL; 436 } else if (numBytesOfClearDataObj == NULL 437 && numBytesOfEncryptedDataObj == NULL) { 438 err = -EINVAL; 439 } else if (numBytesOfEncryptedDataObj != NULL 440 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) { 441 err = -ERANGE; 442 } else if (numBytesOfClearDataObj != NULL 443 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) { 444 err = -ERANGE; 445 } else { 446 jboolean isCopy; 447 448 jint *numBytesOfClearData = 449 (numBytesOfClearDataObj == NULL) 450 ? NULL 451 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy); 452 453 jint *numBytesOfEncryptedData = 454 (numBytesOfEncryptedDataObj == NULL) 455 ? NULL 456 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); 457 458 subSamples = new CryptoPlugin::SubSample[numSubSamples]; 459 460 for (jint i = 0; i < numSubSamples; ++i) { 461 subSamples[i].mNumBytesOfClearData = 462 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i]; 463 464 subSamples[i].mNumBytesOfEncryptedData = 465 (numBytesOfEncryptedData == NULL) 466 ? 0 : numBytesOfEncryptedData[i]; 467 } 468 469 if (numBytesOfEncryptedData != NULL) { 470 env->ReleaseIntArrayElements( 471 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0); 472 numBytesOfEncryptedData = NULL; 473 } 474 475 if (numBytesOfClearData != NULL) { 476 env->ReleaseIntArrayElements( 477 numBytesOfClearDataObj, numBytesOfClearData, 0); 478 numBytesOfClearData = NULL; 479 } 480 } 481 482 if (err == OK && keyObj != NULL) { 483 if (env->GetArrayLength(keyObj) != 16) { 484 err = -EINVAL; 485 } else { 486 jboolean isCopy; 487 key = env->GetByteArrayElements(keyObj, &isCopy); 488 } 489 } 490 491 if (err == OK && ivObj != NULL) { 492 if (env->GetArrayLength(ivObj) != 16) { 493 err = -EINVAL; 494 } else { 495 jboolean isCopy; 496 iv = env->GetByteArrayElements(ivObj, &isCopy); 497 } 498 } 499 500 if (err == OK) { 501 err = codec->queueSecureInputBuffer( 502 index, offset, 503 subSamples, numSubSamples, 504 (const uint8_t *)key, (const uint8_t *)iv, 505 (CryptoPlugin::Mode)mode, 506 timestampUs, flags); 507 } 508 509 if (iv != NULL) { 510 env->ReleaseByteArrayElements(ivObj, iv, 0); 511 iv = NULL; 512 } 513 514 if (key != NULL) { 515 env->ReleaseByteArrayElements(keyObj, key, 0); 516 key = NULL; 517 } 518 519 delete[] subSamples; 520 subSamples = NULL; 521 522 throwExceptionAsNecessary(env, err); 523} 524 525static jint android_media_MediaCodec_dequeueInputBuffer( 526 JNIEnv *env, jobject thiz, jlong timeoutUs) { 527 ALOGV("android_media_MediaCodec_dequeueInputBuffer"); 528 529 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 530 531 if (codec == NULL) { 532 jniThrowException(env, "java/lang/IllegalStateException", NULL); 533 return -1; 534 } 535 536 size_t index; 537 status_t err = codec->dequeueInputBuffer(&index, timeoutUs); 538 539 if (err == OK) { 540 return index; 541 } 542 543 return throwExceptionAsNecessary(env, err); 544} 545 546static jint android_media_MediaCodec_dequeueOutputBuffer( 547 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) { 548 ALOGV("android_media_MediaCodec_dequeueOutputBuffer"); 549 550 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 551 552 if (codec == NULL) { 553 jniThrowException(env, "java/lang/IllegalStateException", NULL); 554 return 0; 555 } 556 557 size_t index; 558 status_t err = codec->dequeueOutputBuffer( 559 env, bufferInfo, &index, timeoutUs); 560 561 if (err == OK) { 562 return index; 563 } 564 565 return throwExceptionAsNecessary(env, err); 566} 567 568static void android_media_MediaCodec_releaseOutputBuffer( 569 JNIEnv *env, jobject thiz, jint index, jboolean render) { 570 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease"); 571 572 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 573 574 if (codec == NULL) { 575 jniThrowException(env, "java/lang/IllegalStateException", NULL); 576 return; 577 } 578 579 status_t err = codec->releaseOutputBuffer(index, render); 580 581 throwExceptionAsNecessary(env, err); 582} 583 584static jobject android_media_MediaCodec_getOutputFormat( 585 JNIEnv *env, jobject thiz) { 586 ALOGV("android_media_MediaCodec_getOutputFormat"); 587 588 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 589 590 if (codec == NULL) { 591 jniThrowException(env, "java/lang/IllegalStateException", NULL); 592 return NULL; 593 } 594 595 jobject format; 596 status_t err = codec->getOutputFormat(env, &format); 597 598 if (err == OK) { 599 return format; 600 } 601 602 throwExceptionAsNecessary(env, err); 603 604 return NULL; 605} 606 607static jobjectArray android_media_MediaCodec_getBuffers( 608 JNIEnv *env, jobject thiz, jboolean input) { 609 ALOGV("android_media_MediaCodec_getBuffers"); 610 611 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 612 613 if (codec == NULL) { 614 jniThrowException(env, "java/lang/IllegalStateException", NULL); 615 return NULL; 616 } 617 618 jobjectArray buffers; 619 status_t err = codec->getBuffers(env, input, &buffers); 620 621 if (err == OK) { 622 return buffers; 623 } 624 625 throwExceptionAsNecessary(env, err); 626 627 return NULL; 628} 629 630static void android_media_MediaCodec_native_init(JNIEnv *env) { 631 jclass clazz = env->FindClass("android/media/MediaCodec"); 632 CHECK(clazz != NULL); 633 634 gFields.context = env->GetFieldID(clazz, "mNativeContext", "I"); 635 CHECK(gFields.context != NULL); 636 637 clazz = env->FindClass("android/media/MediaCodec$CryptoInfo"); 638 CHECK(clazz != NULL); 639 640 gFields.cryptoInfoNumSubSamplesID = 641 env->GetFieldID(clazz, "numSubSamples", "I"); 642 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL); 643 644 gFields.cryptoInfoNumBytesOfClearDataID = 645 env->GetFieldID(clazz, "numBytesOfClearData", "[I"); 646 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL); 647 648 gFields.cryptoInfoNumBytesOfEncryptedDataID = 649 env->GetFieldID(clazz, "numBytesOfEncryptedData", "[I"); 650 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL); 651 652 gFields.cryptoInfoKeyID = env->GetFieldID(clazz, "key", "[B"); 653 CHECK(gFields.cryptoInfoKeyID != NULL); 654 655 gFields.cryptoInfoIVID = env->GetFieldID(clazz, "iv", "[B"); 656 CHECK(gFields.cryptoInfoIVID != NULL); 657 658 gFields.cryptoInfoModeID = env->GetFieldID(clazz, "mode", "I"); 659 CHECK(gFields.cryptoInfoModeID != NULL); 660} 661 662static void android_media_MediaCodec_native_setup( 663 JNIEnv *env, jobject thiz, 664 jstring name, jboolean nameIsType, jboolean encoder) { 665 if (name == NULL) { 666 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 667 return; 668 } 669 670 const char *tmp = env->GetStringUTFChars(name, NULL); 671 672 if (tmp == NULL) { 673 return; 674 } 675 676 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder); 677 678 status_t err = codec->initCheck(); 679 680 env->ReleaseStringUTFChars(name, tmp); 681 tmp = NULL; 682 683 if (err != OK) { 684 jniThrowException( 685 env, 686 "java/io/IOException", 687 "Failed to allocate component instance"); 688 return; 689 } 690 691 setMediaCodec(env,thiz, codec); 692} 693 694static void android_media_MediaCodec_native_finalize( 695 JNIEnv *env, jobject thiz) { 696 android_media_MediaCodec_release(env, thiz); 697} 698 699static JNINativeMethod gMethods[] = { 700 { "release", "()V", (void *)android_media_MediaCodec_release }, 701 702 { "native_configure", 703 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;" 704 "Landroid/media/MediaCrypto;I)V", 705 (void *)android_media_MediaCodec_native_configure }, 706 707 { "start", "()V", (void *)android_media_MediaCodec_start }, 708 { "stop", "()V", (void *)android_media_MediaCodec_stop }, 709 { "flush", "()V", (void *)android_media_MediaCodec_flush }, 710 711 { "queueInputBuffer", "(IIIJI)V", 712 (void *)android_media_MediaCodec_queueInputBuffer }, 713 714 { "queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V", 715 (void *)android_media_MediaCodec_queueSecureInputBuffer }, 716 717 { "dequeueInputBuffer", "(J)I", 718 (void *)android_media_MediaCodec_dequeueInputBuffer }, 719 720 { "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", 721 (void *)android_media_MediaCodec_dequeueOutputBuffer }, 722 723 { "releaseOutputBuffer", "(IZ)V", 724 (void *)android_media_MediaCodec_releaseOutputBuffer }, 725 726 { "getOutputFormat", "()Ljava/util/Map;", 727 (void *)android_media_MediaCodec_getOutputFormat }, 728 729 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;", 730 (void *)android_media_MediaCodec_getBuffers }, 731 732 { "native_init", "()V", (void *)android_media_MediaCodec_native_init }, 733 734 { "native_setup", "(Ljava/lang/String;ZZ)V", 735 (void *)android_media_MediaCodec_native_setup }, 736 737 { "native_finalize", "()V", 738 (void *)android_media_MediaCodec_native_finalize }, 739}; 740 741int register_android_media_MediaCodec(JNIEnv *env) { 742 return AndroidRuntime::registerNativeMethods(env, 743 "android/media/MediaCodec", gMethods, NELEM(gMethods)); 744} 745