android_media_MediaCodec.cpp revision 4273dd03a83fd5f9ba25f3b7c3a4add7bce7206c
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright 2012, The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 171d3165f10b12165f02b7015ac1a817c5f60e6399Neal Nguyen//#define LOG_NDEBUG 0 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "MediaCodec-JNI" 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h> 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "android_media_MediaCodec.h" 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "android_media_MediaCrypto.h" 241d3165f10b12165f02b7015ac1a817c5f60e6399Neal Nguyen#include "android_media_Utils.h" 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "android_runtime/AndroidRuntime.h" 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "android_runtime/android_view_Surface.h" 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "jni.h" 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "JNIHelp.h" 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <cutils/compiler.h> 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <gui/Surface.h> 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/ICrypto.h> 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/MediaCodecBuffer.h> 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/MediaCodec.h> 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/foundation/ABuffer.h> 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/foundation/ADebug.h> 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/foundation/ALooper.h> 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/foundation/AMessage.h> 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/foundation/AString.h> 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/MediaErrors.h> 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/PersistentSurface.h> 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <nativehelper/ScopedLocalRef.h> 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <system/window.h> 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android { 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Keep these in sync with their equivalents in MediaCodec.java !!! 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectenum { 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DEQUEUE_INFO_TRY_AGAIN_LATER = -1, 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED = -2, 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED = -3, 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectenum { 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project EVENT_CALLBACK = 1, 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project EVENT_SET_CALLBACK = 2, 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project EVENT_FRAME_RENDERED = 3, 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic struct CryptoErrorCodes { 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jint cryptoErrorNoKey; 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jint cryptoErrorKeyExpired; 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jint cryptoErrorResourceBusy; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jint cryptoErrorInsufficientOutputProtection; 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jint cryptoErrorSessionNotOpened; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jint cryptoErrorUnsupportedOperation; 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} gCryptoErrorCodes; 71 72static struct CodecActionCodes { 73 jint codecActionTransient; 74 jint codecActionRecoverable; 75} gCodecActionCodes; 76 77static struct CodecErrorCodes { 78 jint errorInsufficientResource; 79 jint errorReclaimed; 80} gCodecErrorCodes; 81 82static struct { 83 jclass clazz; 84 jfieldID mLock; 85 jfieldID mPersistentObject; 86 jmethodID ctor; 87 jmethodID setNativeObjectLocked; 88} gPersistentSurfaceClassInfo; 89 90static struct { 91 jint Unencrypted; 92 jint AesCtr; 93 jint AesCbc; 94} gCryptoModes; 95 96 97struct fields_t { 98 jfieldID context; 99 jmethodID postEventFromNativeID; 100 jfieldID cryptoInfoNumSubSamplesID; 101 jfieldID cryptoInfoNumBytesOfClearDataID; 102 jfieldID cryptoInfoNumBytesOfEncryptedDataID; 103 jfieldID cryptoInfoKeyID; 104 jfieldID cryptoInfoIVID; 105 jfieldID cryptoInfoModeID; 106 jfieldID cryptoInfoPatternID; 107 jfieldID patternEncryptBlocksID; 108 jfieldID patternSkipBlocksID; 109}; 110 111static fields_t gFields; 112static const void *sRefBaseOwner; 113 114//////////////////////////////////////////////////////////////////////////////// 115 116JMediaCodec::JMediaCodec( 117 JNIEnv *env, jobject thiz, 118 const char *name, bool nameIsType, bool encoder) 119 : mClass(NULL), 120 mObject(NULL) { 121 jclass clazz = env->GetObjectClass(thiz); 122 CHECK(clazz != NULL); 123 124 mClass = (jclass)env->NewGlobalRef(clazz); 125 mObject = env->NewWeakGlobalRef(thiz); 126 127 cacheJavaObjects(env); 128 129 mLooper = new ALooper; 130 mLooper->setName("MediaCodec_looper"); 131 132 mLooper->start( 133 false, // runOnCallingThread 134 true, // canCallJava 135 PRIORITY_FOREGROUND); 136 137 if (nameIsType) { 138 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus); 139 } else { 140 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus); 141 } 142 CHECK((mCodec != NULL) != (mInitStatus != OK)); 143} 144 145void JMediaCodec::cacheJavaObjects(JNIEnv *env) { 146 jclass clazz = (jclass)env->FindClass("java/nio/ByteBuffer"); 147 mByteBufferClass = (jclass)env->NewGlobalRef(clazz); 148 CHECK(mByteBufferClass != NULL); 149 150 ScopedLocalRef<jclass> byteOrderClass( 151 env, env->FindClass("java/nio/ByteOrder")); 152 CHECK(byteOrderClass.get() != NULL); 153 154 jmethodID nativeOrderID = env->GetStaticMethodID( 155 byteOrderClass.get(), "nativeOrder", "()Ljava/nio/ByteOrder;"); 156 CHECK(nativeOrderID != NULL); 157 158 jobject nativeByteOrderObj = 159 env->CallStaticObjectMethod(byteOrderClass.get(), nativeOrderID); 160 mNativeByteOrderObj = env->NewGlobalRef(nativeByteOrderObj); 161 CHECK(mNativeByteOrderObj != NULL); 162 env->DeleteLocalRef(nativeByteOrderObj); 163 nativeByteOrderObj = NULL; 164 165 mByteBufferOrderMethodID = env->GetMethodID( 166 mByteBufferClass, 167 "order", 168 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"); 169 CHECK(mByteBufferOrderMethodID != NULL); 170 171 mByteBufferAsReadOnlyBufferMethodID = env->GetMethodID( 172 mByteBufferClass, "asReadOnlyBuffer", "()Ljava/nio/ByteBuffer;"); 173 CHECK(mByteBufferAsReadOnlyBufferMethodID != NULL); 174 175 mByteBufferPositionMethodID = env->GetMethodID( 176 mByteBufferClass, "position", "(I)Ljava/nio/Buffer;"); 177 CHECK(mByteBufferPositionMethodID != NULL); 178 179 mByteBufferLimitMethodID = env->GetMethodID( 180 mByteBufferClass, "limit", "(I)Ljava/nio/Buffer;"); 181 CHECK(mByteBufferLimitMethodID != NULL); 182} 183 184status_t JMediaCodec::initCheck() const { 185 return mInitStatus; 186} 187 188void JMediaCodec::registerSelf() { 189 mLooper->registerHandler(this); 190} 191 192void JMediaCodec::release() { 193 if (mCodec != NULL) { 194 mCodec->release(); 195 mCodec.clear(); 196 mInitStatus = NO_INIT; 197 } 198 199 if (mLooper != NULL) { 200 mLooper->unregisterHandler(id()); 201 mLooper->stop(); 202 mLooper.clear(); 203 } 204} 205 206JMediaCodec::~JMediaCodec() { 207 if (mCodec != NULL || mLooper != NULL) { 208 /* MediaCodec and looper should have been released explicitly already 209 * in setMediaCodec() (see comments in setMediaCodec()). 210 * 211 * Otherwise JMediaCodec::~JMediaCodec() might be called from within the 212 * message handler, doing release() there risks deadlock as MediaCodec:: 213 * release() post synchronous message to the same looper. 214 * 215 * Print a warning and try to proceed with releasing. 216 */ 217 ALOGW("try to release MediaCodec from JMediaCodec::~JMediaCodec()..."); 218 release(); 219 ALOGW("done releasing MediaCodec from JMediaCodec::~JMediaCodec()."); 220 } 221 222 JNIEnv *env = AndroidRuntime::getJNIEnv(); 223 224 env->DeleteWeakGlobalRef(mObject); 225 mObject = NULL; 226 env->DeleteGlobalRef(mClass); 227 mClass = NULL; 228 deleteJavaObjects(env); 229} 230 231void JMediaCodec::deleteJavaObjects(JNIEnv *env) { 232 env->DeleteGlobalRef(mByteBufferClass); 233 mByteBufferClass = NULL; 234 env->DeleteGlobalRef(mNativeByteOrderObj); 235 mNativeByteOrderObj = NULL; 236 237 mByteBufferOrderMethodID = NULL; 238 mByteBufferAsReadOnlyBufferMethodID = NULL; 239 mByteBufferPositionMethodID = NULL; 240 mByteBufferLimitMethodID = NULL; 241} 242 243status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) { 244 if (enable) { 245 if (mOnFrameRenderedNotification == NULL) { 246 mOnFrameRenderedNotification = new AMessage(kWhatFrameRendered, this); 247 } 248 } else { 249 mOnFrameRenderedNotification.clear(); 250 } 251 252 return mCodec->setOnFrameRenderedNotification(mOnFrameRenderedNotification); 253} 254 255status_t JMediaCodec::setCallback(jobject cb) { 256 if (cb != NULL) { 257 if (mCallbackNotification == NULL) { 258 mCallbackNotification = new AMessage(kWhatCallbackNotify, this); 259 } 260 } else { 261 mCallbackNotification.clear(); 262 } 263 264 return mCodec->setCallback(mCallbackNotification); 265} 266 267status_t JMediaCodec::configure( 268 const sp<AMessage> &format, 269 const sp<IGraphicBufferProducer> &bufferProducer, 270 const sp<ICrypto> &crypto, 271 int flags) { 272 sp<Surface> client; 273 if (bufferProducer != NULL) { 274 mSurfaceTextureClient = 275 new Surface(bufferProducer, true /* controlledByApp */); 276 } else { 277 mSurfaceTextureClient.clear(); 278 } 279 280 return mCodec->configure(format, mSurfaceTextureClient, crypto, flags); 281} 282 283status_t JMediaCodec::setSurface( 284 const sp<IGraphicBufferProducer> &bufferProducer) { 285 sp<Surface> client; 286 if (bufferProducer != NULL) { 287 client = new Surface(bufferProducer, true /* controlledByApp */); 288 } 289 status_t err = mCodec->setSurface(client); 290 if (err == OK) { 291 mSurfaceTextureClient = client; 292 } 293 return err; 294} 295 296status_t JMediaCodec::createInputSurface( 297 sp<IGraphicBufferProducer>* bufferProducer) { 298 return mCodec->createInputSurface(bufferProducer); 299} 300 301status_t JMediaCodec::setInputSurface( 302 const sp<PersistentSurface> &surface) { 303 return mCodec->setInputSurface(surface); 304} 305 306status_t JMediaCodec::start() { 307 return mCodec->start(); 308} 309 310status_t JMediaCodec::stop() { 311 mSurfaceTextureClient.clear(); 312 313 return mCodec->stop(); 314} 315 316status_t JMediaCodec::flush() { 317 return mCodec->flush(); 318} 319 320status_t JMediaCodec::reset() { 321 return mCodec->reset(); 322} 323 324status_t JMediaCodec::queueInputBuffer( 325 size_t index, 326 size_t offset, size_t size, int64_t timeUs, uint32_t flags, 327 AString *errorDetailMsg) { 328 return mCodec->queueInputBuffer( 329 index, offset, size, timeUs, flags, errorDetailMsg); 330} 331 332status_t JMediaCodec::queueSecureInputBuffer( 333 size_t index, 334 size_t offset, 335 const CryptoPlugin::SubSample *subSamples, 336 size_t numSubSamples, 337 const uint8_t key[16], 338 const uint8_t iv[16], 339 CryptoPlugin::Mode mode, 340 const CryptoPlugin::Pattern &pattern, 341 int64_t presentationTimeUs, 342 uint32_t flags, 343 AString *errorDetailMsg) { 344 return mCodec->queueSecureInputBuffer( 345 index, offset, subSamples, numSubSamples, key, iv, mode, pattern, 346 presentationTimeUs, flags, errorDetailMsg); 347} 348 349status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) { 350 return mCodec->dequeueInputBuffer(index, timeoutUs); 351} 352 353status_t JMediaCodec::dequeueOutputBuffer( 354 JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs) { 355 size_t size, offset; 356 int64_t timeUs; 357 uint32_t flags; 358 status_t err = mCodec->dequeueOutputBuffer( 359 index, &offset, &size, &timeUs, &flags, timeoutUs); 360 361 if (err != OK) { 362 return err; 363 } 364 365 ScopedLocalRef<jclass> clazz( 366 env, env->FindClass("android/media/MediaCodec$BufferInfo")); 367 368 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V"); 369 env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags); 370 371 return OK; 372} 373 374status_t JMediaCodec::releaseOutputBuffer( 375 size_t index, bool render, bool updatePTS, int64_t timestampNs) { 376 if (updatePTS) { 377 return mCodec->renderOutputBufferAndRelease(index, timestampNs); 378 } 379 return render 380 ? mCodec->renderOutputBufferAndRelease(index) 381 : mCodec->releaseOutputBuffer(index); 382} 383 384status_t JMediaCodec::signalEndOfInputStream() { 385 return mCodec->signalEndOfInputStream(); 386} 387 388status_t JMediaCodec::getFormat(JNIEnv *env, bool input, jobject *format) const { 389 sp<AMessage> msg; 390 status_t err; 391 err = input ? mCodec->getInputFormat(&msg) : mCodec->getOutputFormat(&msg); 392 if (err != OK) { 393 return err; 394 } 395 396 return ConvertMessageToMap(env, msg, format); 397} 398 399status_t JMediaCodec::getOutputFormat(JNIEnv *env, size_t index, jobject *format) const { 400 sp<AMessage> msg; 401 status_t err; 402 if ((err = mCodec->getOutputFormat(index, &msg)) != OK) { 403 return err; 404 } 405 406 return ConvertMessageToMap(env, msg, format); 407} 408 409status_t JMediaCodec::getBuffers( 410 JNIEnv *env, bool input, jobjectArray *bufArray) const { 411 Vector<sp<MediaCodecBuffer> > buffers; 412 413 status_t err = 414 input 415 ? mCodec->getInputBuffers(&buffers) 416 : mCodec->getOutputBuffers(&buffers); 417 418 if (err != OK) { 419 return err; 420 } 421 422 *bufArray = (jobjectArray)env->NewObjectArray( 423 buffers.size(), mByteBufferClass, NULL); 424 if (*bufArray == NULL) { 425 return NO_MEMORY; 426 } 427 428 for (size_t i = 0; i < buffers.size(); ++i) { 429 const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i); 430 431 jobject byteBuffer = NULL; 432 err = createByteBufferFromABuffer( 433 env, !input /* readOnly */, true /* clearBuffer */, buffer, &byteBuffer); 434 if (err != OK) { 435 return err; 436 } 437 if (byteBuffer != NULL) { 438 env->SetObjectArrayElement( 439 *bufArray, i, byteBuffer); 440 441 env->DeleteLocalRef(byteBuffer); 442 byteBuffer = NULL; 443 } 444 } 445 446 return OK; 447} 448 449// static 450template <typename T> 451status_t JMediaCodec::createByteBufferFromABuffer( 452 JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer, 453 jobject *buf) const { 454 // if this is an ABuffer that doesn't actually hold any accessible memory, 455 // use a null ByteBuffer 456 *buf = NULL; 457 458 if (buffer == NULL) { 459 ALOGV("createByteBufferFromABuffer - given NULL, returning NULL"); 460 return OK; 461 } 462 463 if (buffer->base() == NULL) { 464 return OK; 465 } 466 467 jobject byteBuffer = 468 env->NewDirectByteBuffer(buffer->base(), buffer->capacity()); 469 if (readOnly && byteBuffer != NULL) { 470 jobject readOnlyBuffer = env->CallObjectMethod( 471 byteBuffer, mByteBufferAsReadOnlyBufferMethodID); 472 env->DeleteLocalRef(byteBuffer); 473 byteBuffer = readOnlyBuffer; 474 } 475 if (byteBuffer == NULL) { 476 return NO_MEMORY; 477 } 478 jobject me = env->CallObjectMethod( 479 byteBuffer, mByteBufferOrderMethodID, mNativeByteOrderObj); 480 env->DeleteLocalRef(me); 481 me = env->CallObjectMethod( 482 byteBuffer, mByteBufferLimitMethodID, 483 clearBuffer ? buffer->capacity() : (buffer->offset() + buffer->size())); 484 env->DeleteLocalRef(me); 485 me = env->CallObjectMethod( 486 byteBuffer, mByteBufferPositionMethodID, 487 clearBuffer ? 0 : buffer->offset()); 488 env->DeleteLocalRef(me); 489 me = NULL; 490 491 *buf = byteBuffer; 492 return OK; 493} 494 495status_t JMediaCodec::getBuffer( 496 JNIEnv *env, bool input, size_t index, jobject *buf) const { 497 sp<MediaCodecBuffer> buffer; 498 499 status_t err = 500 input 501 ? mCodec->getInputBuffer(index, &buffer) 502 : mCodec->getOutputBuffer(index, &buffer); 503 504 if (err != OK) { 505 return err; 506 } 507 508 return createByteBufferFromABuffer( 509 env, !input /* readOnly */, input /* clearBuffer */, buffer, buf); 510} 511 512status_t JMediaCodec::getImage( 513 JNIEnv *env, bool input, size_t index, jobject *buf) const { 514 sp<MediaCodecBuffer> buffer; 515 516 status_t err = 517 input 518 ? mCodec->getInputBuffer(index, &buffer) 519 : mCodec->getOutputBuffer(index, &buffer); 520 521 if (err != OK) { 522 return err; 523 } 524 525 // if this is an ABuffer that doesn't actually hold any accessible memory, 526 // use a null ByteBuffer 527 *buf = NULL; 528 if (buffer->base() == NULL) { 529 return OK; 530 } 531 532 // check if buffer is an image 533 sp<ABuffer> imageData; 534 if (!buffer->meta()->findBuffer("image-data", &imageData)) { 535 return OK; 536 } 537 538 int64_t timestamp = 0; 539 if (!input && buffer->meta()->findInt64("timeUs", ×tamp)) { 540 timestamp *= 1000; // adjust to ns 541 } 542 543 jobject byteBuffer = NULL; 544 err = createByteBufferFromABuffer( 545 env, !input /* readOnly */, input /* clearBuffer */, buffer, &byteBuffer); 546 if (err != OK) { 547 return OK; 548 } 549 550 jobject infoBuffer = NULL; 551 err = createByteBufferFromABuffer( 552 env, true /* readOnly */, true /* clearBuffer */, imageData, &infoBuffer); 553 if (err != OK) { 554 env->DeleteLocalRef(byteBuffer); 555 byteBuffer = NULL; 556 return OK; 557 } 558 559 jobject cropRect = NULL; 560 int32_t left, top, right, bottom; 561 if (buffer->meta()->findRect("crop-rect", &left, &top, &right, &bottom)) { 562 ScopedLocalRef<jclass> rectClazz( 563 env, env->FindClass("android/graphics/Rect")); 564 CHECK(rectClazz.get() != NULL); 565 566 jmethodID rectConstructID = env->GetMethodID( 567 rectClazz.get(), "<init>", "(IIII)V"); 568 569 cropRect = env->NewObject( 570 rectClazz.get(), rectConstructID, left, top, right + 1, bottom + 1); 571 } 572 573 ScopedLocalRef<jclass> imageClazz( 574 env, env->FindClass("android/media/MediaCodec$MediaImage")); 575 CHECK(imageClazz.get() != NULL); 576 577 jmethodID imageConstructID = env->GetMethodID(imageClazz.get(), "<init>", 578 "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;ZJIILandroid/graphics/Rect;)V"); 579 580 *buf = env->NewObject(imageClazz.get(), imageConstructID, 581 byteBuffer, infoBuffer, 582 (jboolean)!input /* readOnly */, 583 (jlong)timestamp, 584 (jint)0 /* xOffset */, (jint)0 /* yOffset */, cropRect); 585 586 // if MediaImage creation fails, return null 587 if (env->ExceptionCheck()) { 588 env->ExceptionDescribe(); 589 env->ExceptionClear(); 590 *buf = NULL; 591 } 592 593 if (cropRect != NULL) { 594 env->DeleteLocalRef(cropRect); 595 cropRect = NULL; 596 } 597 598 env->DeleteLocalRef(byteBuffer); 599 byteBuffer = NULL; 600 601 env->DeleteLocalRef(infoBuffer); 602 infoBuffer = NULL; 603 604 return OK; 605} 606 607status_t JMediaCodec::getName(JNIEnv *env, jstring *nameStr) const { 608 AString name; 609 610 status_t err = mCodec->getName(&name); 611 612 if (err != OK) { 613 return err; 614 } 615 616 *nameStr = env->NewStringUTF(name.c_str()); 617 618 return OK; 619} 620 621status_t JMediaCodec::setParameters(const sp<AMessage> &msg) { 622 return mCodec->setParameters(msg); 623} 624 625void JMediaCodec::setVideoScalingMode(int mode) { 626 if (mSurfaceTextureClient != NULL) { 627 native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode); 628 } 629} 630 631static jthrowable createCodecException( 632 JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) { 633 ScopedLocalRef<jclass> clazz( 634 env, env->FindClass("android/media/MediaCodec$CodecException")); 635 CHECK(clazz.get() != NULL); 636 637 const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V"); 638 CHECK(ctor != NULL); 639 640 ScopedLocalRef<jstring> msgObj( 641 env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err))); 642 643 // translate action code to Java equivalent 644 switch (actionCode) { 645 case ACTION_CODE_TRANSIENT: 646 actionCode = gCodecActionCodes.codecActionTransient; 647 break; 648 case ACTION_CODE_RECOVERABLE: 649 actionCode = gCodecActionCodes.codecActionRecoverable; 650 break; 651 default: 652 actionCode = 0; // everything else is fatal 653 break; 654 } 655 656 /* translate OS errors to Java API CodecException errorCodes */ 657 switch (err) { 658 case NO_MEMORY: 659 err = gCodecErrorCodes.errorInsufficientResource; 660 break; 661 case DEAD_OBJECT: 662 err = gCodecErrorCodes.errorReclaimed; 663 break; 664 default: /* Other error codes go out as is. */ 665 break; 666 } 667 668 return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get()); 669} 670 671void JMediaCodec::handleCallback(const sp<AMessage> &msg) { 672 int32_t arg1, arg2 = 0; 673 jobject obj = NULL; 674 CHECK(msg->findInt32("callbackID", &arg1)); 675 JNIEnv *env = AndroidRuntime::getJNIEnv(); 676 677 switch (arg1) { 678 case MediaCodec::CB_INPUT_AVAILABLE: 679 { 680 CHECK(msg->findInt32("index", &arg2)); 681 break; 682 } 683 684 case MediaCodec::CB_OUTPUT_AVAILABLE: 685 { 686 CHECK(msg->findInt32("index", &arg2)); 687 688 size_t size, offset; 689 int64_t timeUs; 690 uint32_t flags; 691 CHECK(msg->findSize("size", &size)); 692 CHECK(msg->findSize("offset", &offset)); 693 CHECK(msg->findInt64("timeUs", &timeUs)); 694 CHECK(msg->findInt32("flags", (int32_t *)&flags)); 695 696 ScopedLocalRef<jclass> clazz( 697 env, env->FindClass("android/media/MediaCodec$BufferInfo")); 698 jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V"); 699 jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V"); 700 701 obj = env->NewObject(clazz.get(), ctor); 702 703 if (obj == NULL) { 704 if (env->ExceptionCheck()) { 705 ALOGE("Could not create MediaCodec.BufferInfo."); 706 env->ExceptionClear(); 707 } 708 jniThrowException(env, "java/lang/IllegalStateException", NULL); 709 return; 710 } 711 712 env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags); 713 break; 714 } 715 716 case MediaCodec::CB_ERROR: 717 { 718 int32_t err, actionCode; 719 CHECK(msg->findInt32("err", &err)); 720 CHECK(msg->findInt32("actionCode", &actionCode)); 721 722 // note that DRM errors could conceivably alias into a CodecException 723 obj = (jobject)createCodecException(env, err, actionCode); 724 725 if (obj == NULL) { 726 if (env->ExceptionCheck()) { 727 ALOGE("Could not create CodecException object."); 728 env->ExceptionClear(); 729 } 730 jniThrowException(env, "java/lang/IllegalStateException", NULL); 731 return; 732 } 733 734 break; 735 } 736 737 case MediaCodec::CB_OUTPUT_FORMAT_CHANGED: 738 { 739 sp<AMessage> format; 740 CHECK(msg->findMessage("format", &format)); 741 742 if (OK != ConvertMessageToMap(env, format, &obj)) { 743 jniThrowException(env, "java/lang/IllegalStateException", NULL); 744 return; 745 } 746 747 break; 748 } 749 750 default: 751 TRESPASS(); 752 } 753 754 env->CallVoidMethod( 755 mObject, 756 gFields.postEventFromNativeID, 757 EVENT_CALLBACK, 758 arg1, 759 arg2, 760 obj); 761 762 env->DeleteLocalRef(obj); 763} 764 765void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) { 766 int32_t arg1 = 0, arg2 = 0; 767 jobject obj = NULL; 768 JNIEnv *env = AndroidRuntime::getJNIEnv(); 769 770 sp<AMessage> data; 771 CHECK(msg->findMessage("data", &data)); 772 773 status_t err = ConvertMessageToMap(env, data, &obj); 774 if (err != OK) { 775 jniThrowException(env, "java/lang/IllegalStateException", NULL); 776 return; 777 } 778 779 env->CallVoidMethod( 780 mObject, gFields.postEventFromNativeID, 781 EVENT_FRAME_RENDERED, arg1, arg2, obj); 782 783 env->DeleteLocalRef(obj); 784} 785 786void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) { 787 switch (msg->what()) { 788 case kWhatCallbackNotify: 789 { 790 handleCallback(msg); 791 break; 792 } 793 case kWhatFrameRendered: 794 { 795 handleFrameRenderedNotification(msg); 796 break; 797 } 798 default: 799 TRESPASS(); 800 } 801} 802 803} // namespace android 804 805//////////////////////////////////////////////////////////////////////////////// 806 807using namespace android; 808 809static sp<JMediaCodec> setMediaCodec( 810 JNIEnv *env, jobject thiz, const sp<JMediaCodec> &codec) { 811 sp<JMediaCodec> old = (JMediaCodec *)env->GetLongField(thiz, gFields.context); 812 if (codec != NULL) { 813 codec->incStrong(thiz); 814 } 815 if (old != NULL) { 816 /* release MediaCodec and stop the looper now before decStrong. 817 * otherwise JMediaCodec::~JMediaCodec() could be called from within 818 * its message handler, doing release() from there will deadlock 819 * (as MediaCodec::release() post synchronous message to the same looper) 820 */ 821 old->release(); 822 old->decStrong(thiz); 823 } 824 env->SetLongField(thiz, gFields.context, (jlong)codec.get()); 825 826 return old; 827} 828 829static sp<JMediaCodec> getMediaCodec(JNIEnv *env, jobject thiz) { 830 return (JMediaCodec *)env->GetLongField(thiz, gFields.context); 831} 832 833static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) { 834 setMediaCodec(env, thiz, NULL); 835} 836 837static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) { 838 jthrowable exception = createCodecException(env, err, actionCode, msg); 839 env->Throw(exception); 840} 841 842static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) { 843 ScopedLocalRef<jclass> clazz( 844 env, env->FindClass("android/media/MediaCodec$CryptoException")); 845 CHECK(clazz.get() != NULL); 846 847 jmethodID constructID = 848 env->GetMethodID(clazz.get(), "<init>", "(ILjava/lang/String;)V"); 849 CHECK(constructID != NULL); 850 851 const char *defaultMsg = "Unknown Error"; 852 853 /* translate OS errors to Java API CryptoException errorCodes (which are positive) */ 854 switch (err) { 855 case ERROR_DRM_NO_LICENSE: 856 err = gCryptoErrorCodes.cryptoErrorNoKey; 857 defaultMsg = "Crypto key not available"; 858 break; 859 case ERROR_DRM_LICENSE_EXPIRED: 860 err = gCryptoErrorCodes.cryptoErrorKeyExpired; 861 defaultMsg = "License expired"; 862 break; 863 case ERROR_DRM_RESOURCE_BUSY: 864 err = gCryptoErrorCodes.cryptoErrorResourceBusy; 865 defaultMsg = "Resource busy or unavailable"; 866 break; 867 case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION: 868 err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection; 869 defaultMsg = "Required output protections are not active"; 870 break; 871 case ERROR_DRM_SESSION_NOT_OPENED: 872 err = gCryptoErrorCodes.cryptoErrorSessionNotOpened; 873 defaultMsg = "Attempted to use a closed session"; 874 break; 875 case ERROR_DRM_CANNOT_HANDLE: 876 err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation; 877 defaultMsg = "Operation not supported in this configuration"; 878 break; 879 default: /* Other negative DRM error codes go out as is. */ 880 break; 881 } 882 883 jstring msgObj = env->NewStringUTF(msg != NULL ? msg : defaultMsg); 884 885 jthrowable exception = 886 (jthrowable)env->NewObject(clazz.get(), constructID, err, msgObj); 887 888 env->Throw(exception); 889} 890 891static jint throwExceptionAsNecessary( 892 JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL, 893 const char *msg = NULL) { 894 switch (err) { 895 case OK: 896 return 0; 897 898 case -EAGAIN: 899 return DEQUEUE_INFO_TRY_AGAIN_LATER; 900 901 case INFO_FORMAT_CHANGED: 902 return DEQUEUE_INFO_OUTPUT_FORMAT_CHANGED; 903 904 case INFO_OUTPUT_BUFFERS_CHANGED: 905 return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED; 906 907 case INVALID_OPERATION: 908 jniThrowException(env, "java/lang/IllegalStateException", msg); 909 return 0; 910 911 case BAD_VALUE: 912 jniThrowException(env, "java/lang/IllegalArgumentException", msg); 913 return 0; 914 915 default: 916 if (isCryptoError(err)) { 917 throwCryptoException(env, err, msg); 918 return 0; 919 } 920 throwCodecException(env, err, actionCode, msg); 921 return 0; 922 } 923} 924 925static void android_media_MediaCodec_native_enableOnFrameRenderedListener( 926 JNIEnv *env, 927 jobject thiz, 928 jboolean enabled) { 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->enableOnFrameRenderedListener(enabled); 937 938 throwExceptionAsNecessary(env, err); 939} 940 941static void android_media_MediaCodec_native_setCallback( 942 JNIEnv *env, 943 jobject thiz, 944 jobject cb) { 945 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 946 947 if (codec == NULL) { 948 throwExceptionAsNecessary(env, INVALID_OPERATION); 949 return; 950 } 951 952 status_t err = codec->setCallback(cb); 953 954 throwExceptionAsNecessary(env, err); 955} 956 957static void android_media_MediaCodec_native_configure( 958 JNIEnv *env, 959 jobject thiz, 960 jobjectArray keys, jobjectArray values, 961 jobject jsurface, 962 jobject jcrypto, 963 jint flags) { 964 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 965 966 if (codec == NULL) { 967 throwExceptionAsNecessary(env, INVALID_OPERATION); 968 return; 969 } 970 971 sp<AMessage> format; 972 status_t err = ConvertKeyValueArraysToMessage(env, keys, values, &format); 973 974 if (err != OK) { 975 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 976 return; 977 } 978 979 sp<IGraphicBufferProducer> bufferProducer; 980 if (jsurface != NULL) { 981 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 982 if (surface != NULL) { 983 bufferProducer = surface->getIGraphicBufferProducer(); 984 } else { 985 jniThrowException( 986 env, 987 "java/lang/IllegalArgumentException", 988 "The surface has been released"); 989 return; 990 } 991 } 992 993 sp<ICrypto> crypto; 994 if (jcrypto != NULL) { 995 crypto = JCrypto::GetCrypto(env, jcrypto); 996 } 997 998 err = codec->configure(format, bufferProducer, crypto, flags); 999 1000 throwExceptionAsNecessary(env, err); 1001} 1002 1003static void android_media_MediaCodec_native_setSurface( 1004 JNIEnv *env, 1005 jobject thiz, 1006 jobject jsurface) { 1007 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1008 1009 if (codec == NULL) { 1010 throwExceptionAsNecessary(env, INVALID_OPERATION); 1011 return; 1012 } 1013 1014 sp<IGraphicBufferProducer> bufferProducer; 1015 if (jsurface != NULL) { 1016 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 1017 if (surface != NULL) { 1018 bufferProducer = surface->getIGraphicBufferProducer(); 1019 } else { 1020 jniThrowException( 1021 env, 1022 "java/lang/IllegalArgumentException", 1023 "The surface has been released"); 1024 return; 1025 } 1026 } 1027 1028 status_t err = codec->setSurface(bufferProducer); 1029 throwExceptionAsNecessary(env, err); 1030} 1031 1032sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface( 1033 JNIEnv* env, jobject object) { 1034 sp<PersistentSurface> persistentSurface; 1035 1036 jobject lock = env->GetObjectField( 1037 object, gPersistentSurfaceClassInfo.mLock); 1038 if (env->MonitorEnter(lock) == JNI_OK) { 1039 persistentSurface = reinterpret_cast<PersistentSurface *>( 1040 env->GetLongField(object, 1041 gPersistentSurfaceClassInfo.mPersistentObject)); 1042 env->MonitorExit(lock); 1043 } 1044 env->DeleteLocalRef(lock); 1045 1046 return persistentSurface; 1047} 1048 1049static jobject android_media_MediaCodec_createPersistentInputSurface( 1050 JNIEnv* env, jclass /* clazz */) { 1051 ALOGV("android_media_MediaCodec_createPersistentInputSurface"); 1052 sp<PersistentSurface> persistentSurface = 1053 MediaCodec::CreatePersistentInputSurface(); 1054 1055 if (persistentSurface == NULL) { 1056 return NULL; 1057 } 1058 1059 sp<Surface> surface = new Surface( 1060 persistentSurface->getBufferProducer(), true); 1061 if (surface == NULL) { 1062 return NULL; 1063 } 1064 1065 jobject object = env->NewObject( 1066 gPersistentSurfaceClassInfo.clazz, 1067 gPersistentSurfaceClassInfo.ctor); 1068 1069 if (object == NULL) { 1070 if (env->ExceptionCheck()) { 1071 ALOGE("Could not create PersistentSurface."); 1072 env->ExceptionClear(); 1073 } 1074 return NULL; 1075 } 1076 1077 jobject lock = env->GetObjectField( 1078 object, gPersistentSurfaceClassInfo.mLock); 1079 if (env->MonitorEnter(lock) == JNI_OK) { 1080 env->CallVoidMethod( 1081 object, 1082 gPersistentSurfaceClassInfo.setNativeObjectLocked, 1083 (jlong)surface.get()); 1084 env->SetLongField( 1085 object, 1086 gPersistentSurfaceClassInfo.mPersistentObject, 1087 (jlong)persistentSurface.get()); 1088 env->MonitorExit(lock); 1089 } else { 1090 env->DeleteLocalRef(object); 1091 object = NULL; 1092 } 1093 env->DeleteLocalRef(lock); 1094 1095 if (object != NULL) { 1096 surface->incStrong(&sRefBaseOwner); 1097 persistentSurface->incStrong(&sRefBaseOwner); 1098 } 1099 1100 return object; 1101} 1102 1103static void android_media_MediaCodec_releasePersistentInputSurface( 1104 JNIEnv* env, jclass /* clazz */, jobject object) { 1105 sp<PersistentSurface> persistentSurface; 1106 1107 jobject lock = env->GetObjectField( 1108 object, gPersistentSurfaceClassInfo.mLock); 1109 if (env->MonitorEnter(lock) == JNI_OK) { 1110 persistentSurface = reinterpret_cast<PersistentSurface *>( 1111 env->GetLongField( 1112 object, gPersistentSurfaceClassInfo.mPersistentObject)); 1113 env->SetLongField( 1114 object, 1115 gPersistentSurfaceClassInfo.mPersistentObject, 1116 (jlong)0); 1117 env->MonitorExit(lock); 1118 } 1119 env->DeleteLocalRef(lock); 1120 1121 if (persistentSurface != NULL) { 1122 persistentSurface->decStrong(&sRefBaseOwner); 1123 } 1124 // no need to release surface as it will be released by Surface's jni 1125} 1126 1127static void android_media_MediaCodec_setInputSurface( 1128 JNIEnv* env, jobject thiz, jobject object) { 1129 ALOGV("android_media_MediaCodec_setInputSurface"); 1130 1131 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1132 if (codec == NULL) { 1133 throwExceptionAsNecessary(env, INVALID_OPERATION); 1134 return; 1135 } 1136 1137 sp<PersistentSurface> persistentSurface = 1138 android_media_MediaCodec_getPersistentInputSurface(env, object); 1139 1140 status_t err = codec->setInputSurface(persistentSurface); 1141 if (err != NO_ERROR) { 1142 throwExceptionAsNecessary(env, err); 1143 } 1144} 1145 1146static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env, 1147 jobject thiz) { 1148 ALOGV("android_media_MediaCodec_createInputSurface"); 1149 1150 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1151 if (codec == NULL) { 1152 throwExceptionAsNecessary(env, INVALID_OPERATION); 1153 return NULL; 1154 } 1155 1156 // Tell the MediaCodec that we want to use a Surface as input. 1157 sp<IGraphicBufferProducer> bufferProducer; 1158 status_t err = codec->createInputSurface(&bufferProducer); 1159 if (err != NO_ERROR) { 1160 throwExceptionAsNecessary(env, err); 1161 return NULL; 1162 } 1163 1164 // Wrap the IGBP in a Java-language Surface. 1165 return android_view_Surface_createFromIGraphicBufferProducer(env, 1166 bufferProducer); 1167} 1168 1169static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) { 1170 ALOGV("android_media_MediaCodec_start"); 1171 1172 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1173 1174 if (codec == NULL) { 1175 throwExceptionAsNecessary(env, INVALID_OPERATION); 1176 return; 1177 } 1178 1179 status_t err = codec->start(); 1180 1181 throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed"); 1182} 1183 1184static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) { 1185 ALOGV("android_media_MediaCodec_stop"); 1186 1187 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1188 1189 if (codec == NULL) { 1190 throwExceptionAsNecessary(env, INVALID_OPERATION); 1191 return; 1192 } 1193 1194 status_t err = codec->stop(); 1195 1196 throwExceptionAsNecessary(env, err); 1197} 1198 1199static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) { 1200 ALOGV("android_media_MediaCodec_reset"); 1201 1202 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1203 1204 if (codec == NULL) { 1205 throwExceptionAsNecessary(env, INVALID_OPERATION); 1206 return; 1207 } 1208 1209 status_t err = codec->reset(); 1210 if (err != OK) { 1211 // treat all errors as fatal for now, though resource not available 1212 // errors could be treated as transient. 1213 // we also should avoid sending INVALID_OPERATION here due to 1214 // the transitory nature of reset(), it should not inadvertently 1215 // trigger an IllegalStateException. 1216 err = UNKNOWN_ERROR; 1217 } 1218 throwExceptionAsNecessary(env, err); 1219} 1220 1221static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) { 1222 ALOGV("android_media_MediaCodec_flush"); 1223 1224 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1225 1226 if (codec == NULL) { 1227 throwExceptionAsNecessary(env, INVALID_OPERATION); 1228 return; 1229 } 1230 1231 status_t err = codec->flush(); 1232 1233 throwExceptionAsNecessary(env, err); 1234} 1235 1236static void android_media_MediaCodec_queueInputBuffer( 1237 JNIEnv *env, 1238 jobject thiz, 1239 jint index, 1240 jint offset, 1241 jint size, 1242 jlong timestampUs, 1243 jint flags) { 1244 ALOGV("android_media_MediaCodec_queueInputBuffer"); 1245 1246 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1247 1248 if (codec == NULL) { 1249 throwExceptionAsNecessary(env, INVALID_OPERATION); 1250 return; 1251 } 1252 1253 AString errorDetailMsg; 1254 1255 status_t err = codec->queueInputBuffer( 1256 index, offset, size, timestampUs, flags, &errorDetailMsg); 1257 1258 throwExceptionAsNecessary( 1259 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 1260} 1261 1262static void android_media_MediaCodec_queueSecureInputBuffer( 1263 JNIEnv *env, 1264 jobject thiz, 1265 jint index, 1266 jint offset, 1267 jobject cryptoInfoObj, 1268 jlong timestampUs, 1269 jint flags) { 1270 ALOGV("android_media_MediaCodec_queueSecureInputBuffer"); 1271 1272 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1273 1274 if (codec == NULL) { 1275 throwExceptionAsNecessary(env, INVALID_OPERATION); 1276 return; 1277 } 1278 1279 jint numSubSamples = 1280 env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID); 1281 1282 jintArray numBytesOfClearDataObj = 1283 (jintArray)env->GetObjectField( 1284 cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID); 1285 1286 jintArray numBytesOfEncryptedDataObj = 1287 (jintArray)env->GetObjectField( 1288 cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID); 1289 1290 jbyteArray keyObj = 1291 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID); 1292 1293 jbyteArray ivObj = 1294 (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID); 1295 1296 jint jmode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID); 1297 enum CryptoPlugin::Mode mode; 1298 if (jmode == gCryptoModes.Unencrypted) { 1299 mode = CryptoPlugin::kMode_Unencrypted; 1300 } else if (jmode == gCryptoModes.AesCtr) { 1301 mode = CryptoPlugin::kMode_AES_CTR; 1302 } else if (jmode == gCryptoModes.AesCbc) { 1303 mode = CryptoPlugin::kMode_AES_CBC; 1304 } else { 1305 throwExceptionAsNecessary(env, INVALID_OPERATION); 1306 return; 1307 } 1308 1309 jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID); 1310 1311 CryptoPlugin::Pattern pattern; 1312 if (patternObj == NULL) { 1313 pattern.mEncryptBlocks = 0; 1314 pattern.mSkipBlocks = 0; 1315 } else { 1316 pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID); 1317 pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID); 1318 } 1319 1320 status_t err = OK; 1321 1322 CryptoPlugin::SubSample *subSamples = NULL; 1323 jbyte *key = NULL; 1324 jbyte *iv = NULL; 1325 1326 if (numSubSamples <= 0) { 1327 err = -EINVAL; 1328 } else if (numBytesOfClearDataObj == NULL 1329 && numBytesOfEncryptedDataObj == NULL) { 1330 err = -EINVAL; 1331 } else if (numBytesOfEncryptedDataObj != NULL 1332 && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) { 1333 err = -ERANGE; 1334 } else if (numBytesOfClearDataObj != NULL 1335 && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) { 1336 err = -ERANGE; 1337 // subSamples array may silently overflow if number of samples are too large. Use 1338 // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms 1339 } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) { 1340 err = -EINVAL; 1341 } else { 1342 jboolean isCopy; 1343 1344 jint *numBytesOfClearData = 1345 (numBytesOfClearDataObj == NULL) 1346 ? NULL 1347 : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy); 1348 1349 jint *numBytesOfEncryptedData = 1350 (numBytesOfEncryptedDataObj == NULL) 1351 ? NULL 1352 : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); 1353 1354 subSamples = new CryptoPlugin::SubSample[numSubSamples]; 1355 1356 for (jint i = 0; i < numSubSamples; ++i) { 1357 subSamples[i].mNumBytesOfClearData = 1358 (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i]; 1359 1360 subSamples[i].mNumBytesOfEncryptedData = 1361 (numBytesOfEncryptedData == NULL) 1362 ? 0 : numBytesOfEncryptedData[i]; 1363 } 1364 1365 if (numBytesOfEncryptedData != NULL) { 1366 env->ReleaseIntArrayElements( 1367 numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0); 1368 numBytesOfEncryptedData = NULL; 1369 } 1370 1371 if (numBytesOfClearData != NULL) { 1372 env->ReleaseIntArrayElements( 1373 numBytesOfClearDataObj, numBytesOfClearData, 0); 1374 numBytesOfClearData = NULL; 1375 } 1376 } 1377 1378 if (err == OK && keyObj != NULL) { 1379 if (env->GetArrayLength(keyObj) != 16) { 1380 err = -EINVAL; 1381 } else { 1382 jboolean isCopy; 1383 key = env->GetByteArrayElements(keyObj, &isCopy); 1384 } 1385 } 1386 1387 if (err == OK && ivObj != NULL) { 1388 if (env->GetArrayLength(ivObj) != 16) { 1389 err = -EINVAL; 1390 } else { 1391 jboolean isCopy; 1392 iv = env->GetByteArrayElements(ivObj, &isCopy); 1393 } 1394 } 1395 1396 AString errorDetailMsg; 1397 1398 if (err == OK) { 1399 err = codec->queueSecureInputBuffer( 1400 index, offset, 1401 subSamples, numSubSamples, 1402 (const uint8_t *)key, (const uint8_t *)iv, 1403 mode, 1404 pattern, 1405 timestampUs, 1406 flags, 1407 &errorDetailMsg); 1408 } 1409 1410 if (iv != NULL) { 1411 env->ReleaseByteArrayElements(ivObj, iv, 0); 1412 iv = NULL; 1413 } 1414 1415 if (key != NULL) { 1416 env->ReleaseByteArrayElements(keyObj, key, 0); 1417 key = NULL; 1418 } 1419 1420 delete[] subSamples; 1421 subSamples = NULL; 1422 1423 throwExceptionAsNecessary( 1424 env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str()); 1425} 1426 1427static jint android_media_MediaCodec_dequeueInputBuffer( 1428 JNIEnv *env, jobject thiz, jlong timeoutUs) { 1429 ALOGV("android_media_MediaCodec_dequeueInputBuffer"); 1430 1431 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1432 1433 if (codec == NULL) { 1434 throwExceptionAsNecessary(env, INVALID_OPERATION); 1435 return -1; 1436 } 1437 1438 size_t index; 1439 status_t err = codec->dequeueInputBuffer(&index, timeoutUs); 1440 1441 if (err == OK) { 1442 return (jint) index; 1443 } 1444 1445 return throwExceptionAsNecessary(env, err); 1446} 1447 1448static jint android_media_MediaCodec_dequeueOutputBuffer( 1449 JNIEnv *env, jobject thiz, jobject bufferInfo, jlong timeoutUs) { 1450 ALOGV("android_media_MediaCodec_dequeueOutputBuffer"); 1451 1452 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1453 1454 if (codec == NULL) { 1455 throwExceptionAsNecessary(env, INVALID_OPERATION); 1456 return 0; 1457 } 1458 1459 size_t index; 1460 status_t err = codec->dequeueOutputBuffer( 1461 env, bufferInfo, &index, timeoutUs); 1462 1463 if (err == OK) { 1464 return (jint) index; 1465 } 1466 1467 return throwExceptionAsNecessary(env, err); 1468} 1469 1470static void android_media_MediaCodec_releaseOutputBuffer( 1471 JNIEnv *env, jobject thiz, 1472 jint index, jboolean render, jboolean updatePTS, jlong timestampNs) { 1473 ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease"); 1474 1475 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1476 1477 if (codec == NULL) { 1478 throwExceptionAsNecessary(env, INVALID_OPERATION); 1479 return; 1480 } 1481 1482 status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs); 1483 1484 throwExceptionAsNecessary(env, err); 1485} 1486 1487static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env, 1488 jobject thiz) { 1489 ALOGV("android_media_MediaCodec_signalEndOfInputStream"); 1490 1491 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1492 if (codec == NULL) { 1493 throwExceptionAsNecessary(env, INVALID_OPERATION); 1494 return; 1495 } 1496 1497 status_t err = codec->signalEndOfInputStream(); 1498 1499 throwExceptionAsNecessary(env, err); 1500} 1501 1502static jobject android_media_MediaCodec_getFormatNative( 1503 JNIEnv *env, jobject thiz, jboolean input) { 1504 ALOGV("android_media_MediaCodec_getFormatNative"); 1505 1506 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1507 1508 if (codec == NULL) { 1509 throwExceptionAsNecessary(env, INVALID_OPERATION); 1510 return NULL; 1511 } 1512 1513 jobject format; 1514 status_t err = codec->getFormat(env, input, &format); 1515 1516 if (err == OK) { 1517 return format; 1518 } 1519 1520 throwExceptionAsNecessary(env, err); 1521 1522 return NULL; 1523} 1524 1525static jobject android_media_MediaCodec_getOutputFormatForIndexNative( 1526 JNIEnv *env, jobject thiz, jint index) { 1527 ALOGV("android_media_MediaCodec_getOutputFormatForIndexNative"); 1528 1529 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1530 1531 if (codec == NULL) { 1532 throwExceptionAsNecessary(env, INVALID_OPERATION); 1533 return NULL; 1534 } 1535 1536 jobject format; 1537 status_t err = codec->getOutputFormat(env, index, &format); 1538 1539 if (err == OK) { 1540 return format; 1541 } 1542 1543 throwExceptionAsNecessary(env, err); 1544 1545 return NULL; 1546} 1547 1548static jobjectArray android_media_MediaCodec_getBuffers( 1549 JNIEnv *env, jobject thiz, jboolean input) { 1550 ALOGV("android_media_MediaCodec_getBuffers"); 1551 1552 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1553 1554 if (codec == NULL) { 1555 throwExceptionAsNecessary(env, INVALID_OPERATION); 1556 return NULL; 1557 } 1558 1559 jobjectArray buffers; 1560 status_t err = codec->getBuffers(env, input, &buffers); 1561 1562 if (err == OK) { 1563 return buffers; 1564 } 1565 1566 // if we're out of memory, an exception was already thrown 1567 if (err != NO_MEMORY) { 1568 throwExceptionAsNecessary(env, err); 1569 } 1570 1571 return NULL; 1572} 1573 1574static jobject android_media_MediaCodec_getBuffer( 1575 JNIEnv *env, jobject thiz, jboolean input, jint index) { 1576 ALOGV("android_media_MediaCodec_getBuffer"); 1577 1578 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1579 1580 if (codec == NULL) { 1581 throwExceptionAsNecessary(env, INVALID_OPERATION); 1582 return NULL; 1583 } 1584 1585 jobject buffer; 1586 status_t err = codec->getBuffer(env, input, index, &buffer); 1587 1588 if (err == OK) { 1589 return buffer; 1590 } 1591 1592 // if we're out of memory, an exception was already thrown 1593 if (err != NO_MEMORY) { 1594 throwExceptionAsNecessary(env, err); 1595 } 1596 1597 return NULL; 1598} 1599 1600static jobject android_media_MediaCodec_getImage( 1601 JNIEnv *env, jobject thiz, jboolean input, jint index) { 1602 ALOGV("android_media_MediaCodec_getImage"); 1603 1604 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1605 1606 if (codec == NULL) { 1607 throwExceptionAsNecessary(env, INVALID_OPERATION); 1608 return NULL; 1609 } 1610 1611 jobject image; 1612 status_t err = codec->getImage(env, input, index, &image); 1613 1614 if (err == OK) { 1615 return image; 1616 } 1617 1618 // if we're out of memory, an exception was already thrown 1619 if (err != NO_MEMORY) { 1620 throwExceptionAsNecessary(env, err); 1621 } 1622 1623 return NULL; 1624} 1625 1626static jobject android_media_MediaCodec_getName( 1627 JNIEnv *env, jobject thiz) { 1628 ALOGV("android_media_MediaCodec_getName"); 1629 1630 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1631 1632 if (codec == NULL) { 1633 throwExceptionAsNecessary(env, INVALID_OPERATION); 1634 return NULL; 1635 } 1636 1637 jstring name; 1638 status_t err = codec->getName(env, &name); 1639 1640 if (err == OK) { 1641 return name; 1642 } 1643 1644 throwExceptionAsNecessary(env, err); 1645 1646 return NULL; 1647} 1648 1649static void android_media_MediaCodec_setParameters( 1650 JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) { 1651 ALOGV("android_media_MediaCodec_setParameters"); 1652 1653 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1654 1655 if (codec == NULL) { 1656 throwExceptionAsNecessary(env, INVALID_OPERATION); 1657 return; 1658 } 1659 1660 sp<AMessage> params; 1661 status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, ¶ms); 1662 1663 if (err == OK) { 1664 err = codec->setParameters(params); 1665 } 1666 1667 throwExceptionAsNecessary(env, err); 1668} 1669 1670static void android_media_MediaCodec_setVideoScalingMode( 1671 JNIEnv *env, jobject thiz, jint mode) { 1672 sp<JMediaCodec> codec = getMediaCodec(env, thiz); 1673 1674 if (codec == NULL) { 1675 throwExceptionAsNecessary(env, INVALID_OPERATION); 1676 return; 1677 } 1678 1679 if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW 1680 && mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { 1681 jniThrowException(env, "java/lang/InvalidArgumentException", NULL); 1682 return; 1683 } 1684 1685 codec->setVideoScalingMode(mode); 1686} 1687 1688static void android_media_MediaCodec_native_init(JNIEnv *env) { 1689 ScopedLocalRef<jclass> clazz( 1690 env, env->FindClass("android/media/MediaCodec")); 1691 CHECK(clazz.get() != NULL); 1692 1693 gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J"); 1694 CHECK(gFields.context != NULL); 1695 1696 gFields.postEventFromNativeID = 1697 env->GetMethodID( 1698 clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V"); 1699 1700 CHECK(gFields.postEventFromNativeID != NULL); 1701 1702 jfieldID field; 1703 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_UNENCRYPTED", "I"); 1704 CHECK(field != NULL); 1705 gCryptoModes.Unencrypted = 1706 env->GetStaticIntField(clazz.get(), field); 1707 1708 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CTR", "I"); 1709 CHECK(field != NULL); 1710 gCryptoModes.AesCtr = 1711 env->GetStaticIntField(clazz.get(), field); 1712 1713 field = env->GetStaticFieldID(clazz.get(), "CRYPTO_MODE_AES_CBC", "I"); 1714 CHECK(field != NULL); 1715 gCryptoModes.AesCbc = 1716 env->GetStaticIntField(clazz.get(), field); 1717 1718 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo")); 1719 CHECK(clazz.get() != NULL); 1720 1721 gFields.cryptoInfoNumSubSamplesID = 1722 env->GetFieldID(clazz.get(), "numSubSamples", "I"); 1723 CHECK(gFields.cryptoInfoNumSubSamplesID != NULL); 1724 1725 gFields.cryptoInfoNumBytesOfClearDataID = 1726 env->GetFieldID(clazz.get(), "numBytesOfClearData", "[I"); 1727 CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL); 1728 1729 gFields.cryptoInfoNumBytesOfEncryptedDataID = 1730 env->GetFieldID(clazz.get(), "numBytesOfEncryptedData", "[I"); 1731 CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL); 1732 1733 gFields.cryptoInfoKeyID = env->GetFieldID(clazz.get(), "key", "[B"); 1734 CHECK(gFields.cryptoInfoKeyID != NULL); 1735 1736 gFields.cryptoInfoIVID = env->GetFieldID(clazz.get(), "iv", "[B"); 1737 CHECK(gFields.cryptoInfoIVID != NULL); 1738 1739 gFields.cryptoInfoModeID = env->GetFieldID(clazz.get(), "mode", "I"); 1740 CHECK(gFields.cryptoInfoModeID != NULL); 1741 1742 gFields.cryptoInfoPatternID = env->GetFieldID(clazz.get(), "pattern", 1743 "Landroid/media/MediaCodec$CryptoInfo$Pattern;"); 1744 CHECK(gFields.cryptoInfoPatternID != NULL); 1745 1746 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo$Pattern")); 1747 CHECK(clazz.get() != NULL); 1748 1749 gFields.patternEncryptBlocksID = env->GetFieldID(clazz.get(), "mEncryptBlocks", "I"); 1750 CHECK(gFields.patternEncryptBlocksID != NULL); 1751 1752 gFields.patternSkipBlocksID = env->GetFieldID(clazz.get(), "mSkipBlocks", "I"); 1753 CHECK(gFields.patternSkipBlocksID != NULL); 1754 1755 clazz.reset(env->FindClass("android/media/MediaCodec$CryptoException")); 1756 CHECK(clazz.get() != NULL); 1757 1758 field = env->GetStaticFieldID(clazz.get(), "ERROR_NO_KEY", "I"); 1759 CHECK(field != NULL); 1760 gCryptoErrorCodes.cryptoErrorNoKey = 1761 env->GetStaticIntField(clazz.get(), field); 1762 1763 field = env->GetStaticFieldID(clazz.get(), "ERROR_KEY_EXPIRED", "I"); 1764 CHECK(field != NULL); 1765 gCryptoErrorCodes.cryptoErrorKeyExpired = 1766 env->GetStaticIntField(clazz.get(), field); 1767 1768 field = env->GetStaticFieldID(clazz.get(), "ERROR_RESOURCE_BUSY", "I"); 1769 CHECK(field != NULL); 1770 gCryptoErrorCodes.cryptoErrorResourceBusy = 1771 env->GetStaticIntField(clazz.get(), field); 1772 1773 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I"); 1774 CHECK(field != NULL); 1775 gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection = 1776 env->GetStaticIntField(clazz.get(), field); 1777 1778 field = env->GetStaticFieldID(clazz.get(), "ERROR_SESSION_NOT_OPENED", "I"); 1779 CHECK(field != NULL); 1780 gCryptoErrorCodes.cryptoErrorSessionNotOpened = 1781 env->GetStaticIntField(clazz.get(), field); 1782 1783 field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I"); 1784 CHECK(field != NULL); 1785 gCryptoErrorCodes.cryptoErrorUnsupportedOperation = 1786 env->GetStaticIntField(clazz.get(), field); 1787 1788 clazz.reset(env->FindClass("android/media/MediaCodec$CodecException")); 1789 CHECK(clazz.get() != NULL); 1790 field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I"); 1791 CHECK(field != NULL); 1792 gCodecActionCodes.codecActionTransient = 1793 env->GetStaticIntField(clazz.get(), field); 1794 1795 field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I"); 1796 CHECK(field != NULL); 1797 gCodecActionCodes.codecActionRecoverable = 1798 env->GetStaticIntField(clazz.get(), field); 1799 1800 field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_RESOURCE", "I"); 1801 CHECK(field != NULL); 1802 gCodecErrorCodes.errorInsufficientResource = 1803 env->GetStaticIntField(clazz.get(), field); 1804 1805 field = env->GetStaticFieldID(clazz.get(), "ERROR_RECLAIMED", "I"); 1806 CHECK(field != NULL); 1807 gCodecErrorCodes.errorReclaimed = 1808 env->GetStaticIntField(clazz.get(), field); 1809 1810 clazz.reset(env->FindClass("android/view/Surface")); 1811 CHECK(clazz.get() != NULL); 1812 1813 field = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;"); 1814 CHECK(field != NULL); 1815 gPersistentSurfaceClassInfo.mLock = field; 1816 1817 jmethodID method = env->GetMethodID(clazz.get(), "setNativeObjectLocked", "(J)V"); 1818 CHECK(method != NULL); 1819 gPersistentSurfaceClassInfo.setNativeObjectLocked = method; 1820 1821 clazz.reset(env->FindClass("android/media/MediaCodec$PersistentSurface")); 1822 CHECK(clazz.get() != NULL); 1823 gPersistentSurfaceClassInfo.clazz = (jclass)env->NewGlobalRef(clazz.get()); 1824 1825 method = env->GetMethodID(clazz.get(), "<init>", "()V"); 1826 CHECK(method != NULL); 1827 gPersistentSurfaceClassInfo.ctor = method; 1828 1829 field = env->GetFieldID(clazz.get(), "mPersistentObject", "J"); 1830 CHECK(field != NULL); 1831 gPersistentSurfaceClassInfo.mPersistentObject = field; 1832} 1833 1834static void android_media_MediaCodec_native_setup( 1835 JNIEnv *env, jobject thiz, 1836 jstring name, jboolean nameIsType, jboolean encoder) { 1837 if (name == NULL) { 1838 jniThrowException(env, "java/lang/NullPointerException", NULL); 1839 return; 1840 } 1841 1842 const char *tmp = env->GetStringUTFChars(name, NULL); 1843 1844 if (tmp == NULL) { 1845 return; 1846 } 1847 1848 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder); 1849 1850 const status_t err = codec->initCheck(); 1851 if (err == NAME_NOT_FOUND) { 1852 // fail and do not try again. 1853 jniThrowException(env, "java/lang/IllegalArgumentException", 1854 String8::format("Failed to initialize %s, error %#x", tmp, err)); 1855 env->ReleaseStringUTFChars(name, tmp); 1856 return; 1857 } if (err == NO_MEMORY) { 1858 throwCodecException(env, err, ACTION_CODE_TRANSIENT, 1859 String8::format("Failed to initialize %s, error %#x", tmp, err)); 1860 env->ReleaseStringUTFChars(name, tmp); 1861 return; 1862 } else if (err != OK) { 1863 // believed possible to try again 1864 jniThrowException(env, "java/io/IOException", 1865 String8::format("Failed to find matching codec %s, error %#x", tmp, err)); 1866 env->ReleaseStringUTFChars(name, tmp); 1867 return; 1868 } 1869 1870 env->ReleaseStringUTFChars(name, tmp); 1871 1872 codec->registerSelf(); 1873 1874 setMediaCodec(env,thiz, codec); 1875} 1876 1877static void android_media_MediaCodec_native_finalize( 1878 JNIEnv *env, jobject thiz) { 1879 android_media_MediaCodec_release(env, thiz); 1880} 1881 1882static const JNINativeMethod gMethods[] = { 1883 { "native_release", "()V", (void *)android_media_MediaCodec_release }, 1884 1885 { "native_reset", "()V", (void *)android_media_MediaCodec_reset }, 1886 1887 { "native_releasePersistentInputSurface", 1888 "(Landroid/view/Surface;)V", 1889 (void *)android_media_MediaCodec_releasePersistentInputSurface}, 1890 1891 { "native_createPersistentInputSurface", 1892 "()Landroid/media/MediaCodec$PersistentSurface;", 1893 (void *)android_media_MediaCodec_createPersistentInputSurface }, 1894 1895 { "native_setInputSurface", "(Landroid/view/Surface;)V", 1896 (void *)android_media_MediaCodec_setInputSurface }, 1897 1898 { "native_enableOnFrameRenderedListener", "(Z)V", 1899 (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener }, 1900 1901 { "native_setCallback", 1902 "(Landroid/media/MediaCodec$Callback;)V", 1903 (void *)android_media_MediaCodec_native_setCallback }, 1904 1905 { "native_configure", 1906 "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;" 1907 "Landroid/media/MediaCrypto;I)V", 1908 (void *)android_media_MediaCodec_native_configure }, 1909 1910 { "native_setSurface", 1911 "(Landroid/view/Surface;)V", 1912 (void *)android_media_MediaCodec_native_setSurface }, 1913 1914 { "createInputSurface", "()Landroid/view/Surface;", 1915 (void *)android_media_MediaCodec_createInputSurface }, 1916 1917 { "native_start", "()V", (void *)android_media_MediaCodec_start }, 1918 { "native_stop", "()V", (void *)android_media_MediaCodec_stop }, 1919 { "native_flush", "()V", (void *)android_media_MediaCodec_flush }, 1920 1921 { "native_queueInputBuffer", "(IIIJI)V", 1922 (void *)android_media_MediaCodec_queueInputBuffer }, 1923 1924 { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V", 1925 (void *)android_media_MediaCodec_queueSecureInputBuffer }, 1926 1927 { "native_dequeueInputBuffer", "(J)I", 1928 (void *)android_media_MediaCodec_dequeueInputBuffer }, 1929 1930 { "native_dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", 1931 (void *)android_media_MediaCodec_dequeueOutputBuffer }, 1932 1933 { "releaseOutputBuffer", "(IZZJ)V", 1934 (void *)android_media_MediaCodec_releaseOutputBuffer }, 1935 1936 { "signalEndOfInputStream", "()V", 1937 (void *)android_media_MediaCodec_signalEndOfInputStream }, 1938 1939 { "getFormatNative", "(Z)Ljava/util/Map;", 1940 (void *)android_media_MediaCodec_getFormatNative }, 1941 1942 { "getOutputFormatNative", "(I)Ljava/util/Map;", 1943 (void *)android_media_MediaCodec_getOutputFormatForIndexNative }, 1944 1945 { "getBuffers", "(Z)[Ljava/nio/ByteBuffer;", 1946 (void *)android_media_MediaCodec_getBuffers }, 1947 1948 { "getBuffer", "(ZI)Ljava/nio/ByteBuffer;", 1949 (void *)android_media_MediaCodec_getBuffer }, 1950 1951 { "getImage", "(ZI)Landroid/media/Image;", 1952 (void *)android_media_MediaCodec_getImage }, 1953 1954 { "getName", "()Ljava/lang/String;", 1955 (void *)android_media_MediaCodec_getName }, 1956 1957 { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V", 1958 (void *)android_media_MediaCodec_setParameters }, 1959 1960 { "setVideoScalingMode", "(I)V", 1961 (void *)android_media_MediaCodec_setVideoScalingMode }, 1962 1963 { "native_init", "()V", (void *)android_media_MediaCodec_native_init }, 1964 1965 { "native_setup", "(Ljava/lang/String;ZZ)V", 1966 (void *)android_media_MediaCodec_native_setup }, 1967 1968 { "native_finalize", "()V", 1969 (void *)android_media_MediaCodec_native_finalize }, 1970}; 1971 1972int register_android_media_MediaCodec(JNIEnv *env) { 1973 return AndroidRuntime::registerNativeMethods(env, 1974 "android/media/MediaCodec", gMethods, NELEM(gMethods)); 1975} 1976