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 "MediaExtractor-JNI" 19#include <utils/Log.h> 20 21#include "android_media_MediaExtractor.h" 22#include "android_media_MediaMetricsJNI.h" 23 24#include "android_media_Utils.h" 25#include "android_runtime/AndroidRuntime.h" 26#include "android_runtime/Log.h" 27#include "jni.h" 28#include "JNIHelp.h" 29#include "android_media_MediaDataSource.h" 30 31#include <media/IMediaHTTPService.h> 32#include <media/hardware/CryptoAPI.h> 33#include <media/stagefright/foundation/ABuffer.h> 34#include <media/stagefright/foundation/ADebug.h> 35#include <media/stagefright/foundation/AMessage.h> 36#include <media/stagefright/DataSource.h> 37#include <media/stagefright/MediaErrors.h> 38#include <media/stagefright/MetaData.h> 39#include <media/stagefright/NuMediaExtractor.h> 40#include <android/media/ICas.h> 41 42#include <nativehelper/ScopedLocalRef.h> 43 44#include "android_util_Binder.h" 45 46namespace android { 47 48struct fields_t { 49 jfieldID context; 50 51 jmethodID cryptoInfoSetID; 52}; 53 54static fields_t gFields; 55 56JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz) 57 : mClass(NULL), 58 mObject(NULL) { 59 jclass clazz = env->GetObjectClass(thiz); 60 CHECK(clazz != NULL); 61 62 mClass = (jclass)env->NewGlobalRef(clazz); 63 mObject = env->NewWeakGlobalRef(thiz); 64 65 mImpl = new NuMediaExtractor; 66} 67 68JMediaExtractor::~JMediaExtractor() { 69 JNIEnv *env = AndroidRuntime::getJNIEnv(); 70 71 env->DeleteWeakGlobalRef(mObject); 72 mObject = NULL; 73 env->DeleteGlobalRef(mClass); 74 mClass = NULL; 75} 76 77status_t JMediaExtractor::setDataSource( 78 const sp<IMediaHTTPService> &httpService, 79 const char *path, 80 const KeyedVector<String8, String8> *headers) { 81 return mImpl->setDataSource(httpService, path, headers); 82} 83 84status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) { 85 return mImpl->setDataSource(fd, offset, size); 86} 87 88status_t JMediaExtractor::setDataSource(const sp<DataSource> &datasource) { 89 return mImpl->setDataSource(datasource); 90} 91 92status_t JMediaExtractor::setMediaCas(const sp<ICas> &cas) { 93 return mImpl->setMediaCas(cas); 94} 95 96size_t JMediaExtractor::countTracks() const { 97 return mImpl->countTracks(); 98} 99 100status_t JMediaExtractor::getTrackFormat(size_t index, jobject *format) const { 101 sp<AMessage> msg; 102 status_t err; 103 if ((err = mImpl->getTrackFormat(index, &msg)) != OK) { 104 return err; 105 } 106 107 JNIEnv *env = AndroidRuntime::getJNIEnv(); 108 109 return ConvertMessageToMap(env, msg, format); 110} 111 112status_t JMediaExtractor::getFileFormat(jobject *format) const { 113 sp<AMessage> msg; 114 status_t err; 115 if ((err = mImpl->getFileFormat(&msg)) != OK) { 116 return err; 117 } 118 119 JNIEnv *env = AndroidRuntime::getJNIEnv(); 120 121 return ConvertMessageToMap(env, msg, format); 122} 123 124status_t JMediaExtractor::selectTrack(size_t index) { 125 return mImpl->selectTrack(index); 126} 127 128status_t JMediaExtractor::unselectTrack(size_t index) { 129 return mImpl->unselectTrack(index); 130} 131 132status_t JMediaExtractor::seekTo( 133 int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) { 134 return mImpl->seekTo(timeUs, mode); 135} 136 137status_t JMediaExtractor::advance() { 138 return mImpl->advance(); 139} 140 141status_t JMediaExtractor::readSampleData( 142 jobject byteBuf, size_t offset, size_t *sampleSize) { 143 JNIEnv *env = AndroidRuntime::getJNIEnv(); 144 145 void *dst = env->GetDirectBufferAddress(byteBuf); 146 147 size_t dstSize; 148 jbyteArray byteArray = NULL; 149 150 ScopedLocalRef<jclass> byteBufClass(env, env->FindClass("java/nio/ByteBuffer")); 151 CHECK(byteBufClass.get() != NULL); 152 153 if (dst == NULL) { 154 jmethodID arrayID = 155 env->GetMethodID(byteBufClass.get(), "array", "()[B"); 156 CHECK(arrayID != NULL); 157 158 byteArray = 159 (jbyteArray)env->CallObjectMethod(byteBuf, arrayID); 160 161 if (byteArray == NULL) { 162 return INVALID_OPERATION; 163 } 164 165 jboolean isCopy; 166 dst = env->GetByteArrayElements(byteArray, &isCopy); 167 168 dstSize = (size_t) env->GetArrayLength(byteArray); 169 } else { 170 dstSize = (size_t) env->GetDirectBufferCapacity(byteBuf); 171 } 172 173 if (dstSize < offset) { 174 if (byteArray != NULL) { 175 env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0); 176 } 177 178 return -ERANGE; 179 } 180 181 sp<ABuffer> buffer = new ABuffer((char *)dst + offset, dstSize - offset); 182 183 status_t err = mImpl->readSampleData(buffer); 184 185 if (byteArray != NULL) { 186 env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0); 187 } 188 189 if (err != OK) { 190 return err; 191 } 192 193 *sampleSize = buffer->size(); 194 195 jmethodID positionID = env->GetMethodID( 196 byteBufClass.get(), "position", "(I)Ljava/nio/Buffer;"); 197 198 CHECK(positionID != NULL); 199 200 jmethodID limitID = env->GetMethodID( 201 byteBufClass.get(), "limit", "(I)Ljava/nio/Buffer;"); 202 203 CHECK(limitID != NULL); 204 205 jobject me = env->CallObjectMethod( 206 byteBuf, limitID, offset + *sampleSize); 207 env->DeleteLocalRef(me); 208 me = env->CallObjectMethod( 209 byteBuf, positionID, offset); 210 env->DeleteLocalRef(me); 211 me = NULL; 212 213 return OK; 214} 215 216status_t JMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { 217 return mImpl->getSampleTrackIndex(trackIndex); 218} 219 220status_t JMediaExtractor::getSampleTime(int64_t *sampleTimeUs) { 221 return mImpl->getSampleTime(sampleTimeUs); 222} 223 224status_t JMediaExtractor::getSampleFlags(uint32_t *sampleFlags) { 225 *sampleFlags = 0; 226 227 sp<MetaData> meta; 228 status_t err = mImpl->getSampleMeta(&meta); 229 230 if (err != OK) { 231 return err; 232 } 233 234 int32_t val; 235 if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) { 236 (*sampleFlags) |= NuMediaExtractor::SAMPLE_FLAG_SYNC; 237 } 238 239 uint32_t type; 240 const void *data; 241 size_t size; 242 if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) { 243 (*sampleFlags) |= NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED; 244 } 245 246 return OK; 247} 248 249status_t JMediaExtractor::getMetrics(Parcel *reply) const { 250 251 status_t status = mImpl->getMetrics(reply); 252 return status; 253} 254 255 256status_t JMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) { 257 return mImpl->getSampleMeta(sampleMeta); 258} 259 260bool JMediaExtractor::getCachedDuration(int64_t *durationUs, bool *eos) const { 261 return mImpl->getCachedDuration(durationUs, eos); 262} 263 264} // namespace android 265 266//////////////////////////////////////////////////////////////////////////////// 267 268using namespace android; 269 270static sp<JMediaExtractor> setMediaExtractor( 271 JNIEnv *env, jobject thiz, const sp<JMediaExtractor> &extractor) { 272 sp<JMediaExtractor> old = 273 (JMediaExtractor *)env->GetLongField(thiz, gFields.context); 274 275 if (extractor != NULL) { 276 extractor->incStrong(thiz); 277 } 278 if (old != NULL) { 279 old->decStrong(thiz); 280 } 281 env->SetLongField(thiz, gFields.context, (jlong)extractor.get()); 282 283 return old; 284} 285 286static sp<JMediaExtractor> getMediaExtractor(JNIEnv *env, jobject thiz) { 287 return (JMediaExtractor *)env->GetLongField(thiz, gFields.context); 288} 289 290static void android_media_MediaExtractor_release(JNIEnv *env, jobject thiz) { 291 setMediaExtractor(env, thiz, NULL); 292} 293 294static jint android_media_MediaExtractor_getTrackCount( 295 JNIEnv *env, jobject thiz) { 296 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 297 298 if (extractor == NULL) { 299 jniThrowException(env, "java/lang/IllegalStateException", NULL); 300 return -1; 301 } 302 303 return (jint) extractor->countTracks(); 304} 305 306static jobject android_media_MediaExtractor_getTrackFormatNative( 307 JNIEnv *env, jobject thiz, jint index) { 308 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 309 310 if (extractor == NULL) { 311 jniThrowException(env, "java/lang/IllegalStateException", NULL); 312 return NULL; 313 } 314 315 jobject format; 316 status_t err = extractor->getTrackFormat(index, &format); 317 318 if (err != OK) { 319 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 320 return NULL; 321 } 322 323 return format; 324} 325 326static jobject android_media_MediaExtractor_getFileFormatNative( 327 JNIEnv *env, jobject thiz) { 328 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 329 330 if (extractor == NULL) { 331 jniThrowException(env, "java/lang/IllegalStateException", NULL); 332 return NULL; 333 } 334 335 jobject format; 336 status_t err = extractor->getFileFormat(&format); 337 338 if (err != OK) { 339 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 340 return NULL; 341 } 342 343 return format; 344} 345 346static void android_media_MediaExtractor_selectTrack( 347 JNIEnv *env, jobject thiz, jint index) { 348 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 349 350 if (extractor == NULL) { 351 jniThrowException(env, "java/lang/IllegalStateException", NULL); 352 return; 353 } 354 355 status_t err = extractor->selectTrack(index); 356 357 if (err != OK) { 358 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 359 return; 360 } 361} 362 363static void android_media_MediaExtractor_unselectTrack( 364 JNIEnv *env, jobject thiz, jint index) { 365 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 366 367 if (extractor == NULL) { 368 jniThrowException(env, "java/lang/IllegalStateException", NULL); 369 return; 370 } 371 372 status_t err = extractor->unselectTrack(index); 373 374 if (err != OK) { 375 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 376 return; 377 } 378} 379 380static void android_media_MediaExtractor_seekTo( 381 JNIEnv *env, jobject thiz, jlong timeUs, jint mode) { 382 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 383 384 if (extractor == NULL) { 385 jniThrowException(env, "java/lang/IllegalStateException", NULL); 386 return; 387 } 388 389 if (mode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC 390 || mode >= MediaSource::ReadOptions::SEEK_CLOSEST) { 391 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 392 return; 393 } 394 395 extractor->seekTo(timeUs, (MediaSource::ReadOptions::SeekMode)mode); 396} 397 398static jboolean android_media_MediaExtractor_advance( 399 JNIEnv *env, jobject thiz) { 400 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 401 402 if (extractor == NULL) { 403 jniThrowException(env, "java/lang/IllegalStateException", NULL); 404 return JNI_FALSE; 405 } 406 407 status_t err = extractor->advance(); 408 409 if (err == ERROR_END_OF_STREAM) { 410 return JNI_FALSE; 411 } else if (err != OK) { 412 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 413 return JNI_FALSE; 414 } 415 416 return JNI_TRUE; 417} 418 419static jint android_media_MediaExtractor_readSampleData( 420 JNIEnv *env, jobject thiz, jobject byteBuf, jint offset) { 421 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 422 423 if (extractor == NULL) { 424 jniThrowException(env, "java/lang/IllegalStateException", NULL); 425 return -1; 426 } 427 428 size_t sampleSize; 429 status_t err = extractor->readSampleData(byteBuf, offset, &sampleSize); 430 431 if (err == ERROR_END_OF_STREAM) { 432 return -1; 433 } else if (err != OK) { 434 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 435 return -1; 436 } 437 438 return (jint) sampleSize; 439} 440 441static jint android_media_MediaExtractor_getSampleTrackIndex( 442 JNIEnv *env, jobject thiz) { 443 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 444 445 if (extractor == NULL) { 446 jniThrowException(env, "java/lang/IllegalStateException", NULL); 447 return -1; 448 } 449 450 size_t trackIndex; 451 status_t err = extractor->getSampleTrackIndex(&trackIndex); 452 453 if (err == ERROR_END_OF_STREAM) { 454 return -1; 455 } else if (err != OK) { 456 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 457 return -1; 458 } 459 460 return (jint) trackIndex; 461} 462 463static jlong android_media_MediaExtractor_getSampleTime( 464 JNIEnv *env, jobject thiz) { 465 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 466 467 if (extractor == NULL) { 468 jniThrowException(env, "java/lang/IllegalStateException", NULL); 469 return -1ll; 470 } 471 472 int64_t sampleTimeUs; 473 status_t err = extractor->getSampleTime(&sampleTimeUs); 474 475 if (err == ERROR_END_OF_STREAM) { 476 return -1ll; 477 } else if (err != OK) { 478 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 479 return -1ll; 480 } 481 482 return (jlong) sampleTimeUs; 483} 484 485static jint android_media_MediaExtractor_getSampleFlags( 486 JNIEnv *env, jobject thiz) { 487 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 488 489 if (extractor == NULL) { 490 jniThrowException(env, "java/lang/IllegalStateException", NULL); 491 return -1; 492 } 493 494 uint32_t sampleFlags; 495 status_t err = extractor->getSampleFlags(&sampleFlags); 496 497 if (err == ERROR_END_OF_STREAM) { 498 return -1; 499 } else if (err != OK) { 500 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 501 return -1; 502 } 503 504 return (jint) sampleFlags; 505} 506 507static jboolean android_media_MediaExtractor_getSampleCryptoInfo( 508 JNIEnv *env, jobject thiz, jobject cryptoInfoObj) { 509 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 510 511 if (extractor == NULL) { 512 jniThrowException(env, "java/lang/IllegalStateException", NULL); 513 return JNI_FALSE; 514 } 515 516 sp<MetaData> meta; 517 status_t err = extractor->getSampleMeta(&meta); 518 519 if (err != OK) { 520 return JNI_FALSE; 521 } 522 523 uint32_t type; 524 const void *data; 525 size_t size; 526 if (!meta->findData(kKeyEncryptedSizes, &type, &data, &size)) { 527 return JNI_FALSE; 528 } 529 530 size_t numSubSamples = size / sizeof(int32_t); 531 532 if (numSubSamples == 0) { 533 return JNI_FALSE; 534 } 535 536 jintArray numBytesOfEncryptedDataObj = env->NewIntArray(numSubSamples); 537 jboolean isCopy; 538 jint *dst = env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); 539 for (size_t i = 0; i < numSubSamples; ++i) { 540 dst[i] = ((const int32_t *)data)[i]; 541 } 542 env->ReleaseIntArrayElements(numBytesOfEncryptedDataObj, dst, 0); 543 dst = NULL; 544 545 size_t encSize = size; 546 jintArray numBytesOfPlainDataObj = NULL; 547 if (meta->findData(kKeyPlainSizes, &type, &data, &size)) { 548 if (size != encSize) { 549 // The two must be of the same length. 550 return JNI_FALSE; 551 } 552 553 numBytesOfPlainDataObj = env->NewIntArray(numSubSamples); 554 jboolean isCopy; 555 jint *dst = env->GetIntArrayElements(numBytesOfPlainDataObj, &isCopy); 556 for (size_t i = 0; i < numSubSamples; ++i) { 557 dst[i] = ((const int32_t *)data)[i]; 558 } 559 env->ReleaseIntArrayElements(numBytesOfPlainDataObj, dst, 0); 560 dst = NULL; 561 } 562 563 jbyteArray keyObj = NULL; 564 if (meta->findData(kKeyCryptoKey, &type, &data, &size)) { 565 if (size != 16) { 566 // Keys must be 16 bytes in length. 567 return JNI_FALSE; 568 } 569 570 keyObj = env->NewByteArray(size); 571 jboolean isCopy; 572 jbyte *dst = env->GetByteArrayElements(keyObj, &isCopy); 573 memcpy(dst, data, size); 574 env->ReleaseByteArrayElements(keyObj, dst, 0); 575 dst = NULL; 576 } 577 578 jbyteArray ivObj = NULL; 579 if (meta->findData(kKeyCryptoIV, &type, &data, &size)) { 580 if (size != 16) { 581 // IVs must be 16 bytes in length. 582 return JNI_FALSE; 583 } 584 585 ivObj = env->NewByteArray(size); 586 jboolean isCopy; 587 jbyte *dst = env->GetByteArrayElements(ivObj, &isCopy); 588 memcpy(dst, data, size); 589 env->ReleaseByteArrayElements(ivObj, dst, 0); 590 dst = NULL; 591 } 592 593 int32_t mode; 594 if (!meta->findInt32(kKeyCryptoMode, &mode)) { 595 mode = CryptoPlugin::kMode_AES_CTR; 596 } 597 598 env->CallVoidMethod( 599 cryptoInfoObj, 600 gFields.cryptoInfoSetID, 601 (jint)numSubSamples, 602 numBytesOfPlainDataObj, 603 numBytesOfEncryptedDataObj, 604 keyObj, 605 ivObj, 606 mode); 607 608 return JNI_TRUE; 609} 610 611static void android_media_MediaExtractor_native_init(JNIEnv *env) { 612 jclass clazz = env->FindClass("android/media/MediaExtractor"); 613 CHECK(clazz != NULL); 614 615 gFields.context = env->GetFieldID(clazz, "mNativeContext", "J"); 616 CHECK(gFields.context != NULL); 617 618 clazz = env->FindClass("android/media/MediaCodec$CryptoInfo"); 619 CHECK(clazz != NULL); 620 621 gFields.cryptoInfoSetID = 622 env->GetMethodID(clazz, "set", "(I[I[I[B[BI)V"); 623} 624 625static void android_media_MediaExtractor_native_setup( 626 JNIEnv *env, jobject thiz) { 627 sp<JMediaExtractor> extractor = new JMediaExtractor(env, thiz); 628 setMediaExtractor(env,thiz, extractor); 629} 630 631static void android_media_MediaExtractor_setDataSource( 632 JNIEnv *env, jobject thiz, 633 jobject httpServiceBinderObj, 634 jstring pathObj, 635 jobjectArray keysArray, 636 jobjectArray valuesArray) { 637 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 638 639 if (extractor == NULL) { 640 jniThrowException(env, "java/lang/IllegalStateException", NULL); 641 return; 642 } 643 644 if (pathObj == NULL) { 645 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 646 return; 647 } 648 649 KeyedVector<String8, String8> headers; 650 if (!ConvertKeyValueArraysToKeyedVector( 651 env, keysArray, valuesArray, &headers)) { 652 return; 653 } 654 655 const char *path = env->GetStringUTFChars(pathObj, NULL); 656 657 if (path == NULL) { 658 return; 659 } 660 661 sp<IMediaHTTPService> httpService; 662 if (httpServiceBinderObj != NULL) { 663 sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj); 664 httpService = interface_cast<IMediaHTTPService>(binder); 665 } 666 667 status_t err = extractor->setDataSource(httpService, path, &headers); 668 669 env->ReleaseStringUTFChars(pathObj, path); 670 path = NULL; 671 672 if (err != OK) { 673 jniThrowException( 674 env, 675 "java/io/IOException", 676 "Failed to instantiate extractor."); 677 return; 678 } 679} 680 681static void android_media_MediaExtractor_setDataSourceFd( 682 JNIEnv *env, jobject thiz, 683 jobject fileDescObj, jlong offset, jlong length) { 684 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 685 686 if (extractor == NULL) { 687 jniThrowException(env, "java/lang/IllegalStateException", NULL); 688 return; 689 } 690 691 if (fileDescObj == NULL) { 692 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 693 return; 694 } 695 696 int fd = jniGetFDFromFileDescriptor(env, fileDescObj); 697 698 status_t err = extractor->setDataSource(fd, offset, length); 699 700 if (err != OK) { 701 jniThrowException( 702 env, 703 "java/io/IOException", 704 "Failed to instantiate extractor."); 705 return; 706 } 707} 708 709static void android_media_MediaExtractor_setDataSourceCallback( 710 JNIEnv *env, jobject thiz, 711 jobject callbackObj) { 712 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 713 714 if (extractor == NULL) { 715 jniThrowException(env, "java/lang/IllegalStateException", NULL); 716 return; 717 } 718 719 if (callbackObj == NULL) { 720 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 721 return; 722 } 723 724 sp<DataSource> bridge = 725 DataSource::CreateFromIDataSource(new JMediaDataSource(env, callbackObj)); 726 status_t err = extractor->setDataSource(bridge); 727 728 if (err != OK) { 729 // Clear bridge so that JMediaDataSource::close() is called _before_ 730 // we throw the IOException. 731 // Otherwise close() gets called when we go out of scope, it calls 732 // Java with a pending exception and crashes the process. 733 bridge.clear(); 734 jniThrowException( 735 env, 736 "java/io/IOException", 737 "Failed to instantiate extractor."); 738 return; 739 } 740} 741 742static void android_media_MediaExtractor_setMediaCas( 743 JNIEnv *env, jobject thiz, jobject casBinderObj) { 744 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 745 746 if (extractor == NULL) { 747 jniThrowException(env, "java/lang/IllegalStateException", NULL); 748 return; 749 } 750 751 if (casBinderObj == NULL) { 752 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 753 return; 754 } 755 756 sp<ICas> cas; 757 if (casBinderObj != NULL) { 758 sp<IBinder> binder = ibinderForJavaObject(env, casBinderObj); 759 cas = interface_cast<ICas>(binder); 760 } 761 status_t err = extractor->setMediaCas(cas); 762 763 if (err != OK) { 764 cas.clear(); 765 jniThrowException( 766 env, 767 "java/io/IllegalArgumentException", 768 "Failed to set MediaCas on extractor."); 769 } 770} 771 772static jlong android_media_MediaExtractor_getCachedDurationUs( 773 JNIEnv *env, jobject thiz) { 774 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 775 776 if (extractor == NULL) { 777 jniThrowException(env, "java/lang/IllegalStateException", NULL); 778 return -1ll; 779 } 780 781 int64_t cachedDurationUs; 782 bool eos; 783 if (!extractor->getCachedDuration(&cachedDurationUs, &eos)) { 784 return -1ll; 785 } 786 787 return (jlong) cachedDurationUs; 788} 789 790static jboolean android_media_MediaExtractor_hasCacheReachedEOS( 791 JNIEnv *env, jobject thiz) { 792 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 793 794 if (extractor == NULL) { 795 jniThrowException(env, "java/lang/IllegalStateException", NULL); 796 return JNI_TRUE; 797 } 798 799 int64_t cachedDurationUs; 800 bool eos; 801 if (!extractor->getCachedDuration(&cachedDurationUs, &eos)) { 802 return JNI_TRUE; 803 } 804 805 return eos ? JNI_TRUE : JNI_FALSE; 806} 807 808static void android_media_MediaExtractor_native_finalize( 809 JNIEnv *env, jobject thiz) { 810 android_media_MediaExtractor_release(env, thiz); 811} 812 813static jobject 814android_media_MediaExtractor_native_getMetrics(JNIEnv * env, jobject thiz) 815{ 816 ALOGV("android_media_MediaExtractor_native_getMetrics"); 817 818 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 819 if (extractor == NULL ) { 820 jniThrowException(env, "java/lang/IllegalStateException", NULL); 821 return NULL; 822 } 823 824 // get what we have for the metrics from the codec 825 Parcel reply; 826 status_t err = extractor->getMetrics(&reply); 827 if (err != OK) { 828 ALOGE("getMetrics failed"); 829 return (jobject) NULL; 830 } 831 832 // build and return the Bundle 833 MediaAnalyticsItem *item = new MediaAnalyticsItem; 834 item->readFromParcel(reply); 835 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL); 836 837 // housekeeping 838 delete item; 839 item = NULL; 840 841 return mybundle; 842} 843 844 845static const JNINativeMethod gMethods[] = { 846 { "release", "()V", (void *)android_media_MediaExtractor_release }, 847 848 { "getTrackCount", "()I", (void *)android_media_MediaExtractor_getTrackCount }, 849 850 { "getFileFormatNative", "()Ljava/util/Map;", 851 (void *)android_media_MediaExtractor_getFileFormatNative }, 852 853 { "getTrackFormatNative", "(I)Ljava/util/Map;", 854 (void *)android_media_MediaExtractor_getTrackFormatNative }, 855 856 { "selectTrack", "(I)V", (void *)android_media_MediaExtractor_selectTrack }, 857 858 { "unselectTrack", "(I)V", 859 (void *)android_media_MediaExtractor_unselectTrack }, 860 861 { "seekTo", "(JI)V", (void *)android_media_MediaExtractor_seekTo }, 862 863 { "advance", "()Z", (void *)android_media_MediaExtractor_advance }, 864 865 { "readSampleData", "(Ljava/nio/ByteBuffer;I)I", 866 (void *)android_media_MediaExtractor_readSampleData }, 867 868 { "getSampleTrackIndex", "()I", 869 (void *)android_media_MediaExtractor_getSampleTrackIndex }, 870 871 { "getSampleTime", "()J", 872 (void *)android_media_MediaExtractor_getSampleTime }, 873 874 { "getSampleFlags", "()I", 875 (void *)android_media_MediaExtractor_getSampleFlags }, 876 877 { "getSampleCryptoInfo", "(Landroid/media/MediaCodec$CryptoInfo;)Z", 878 (void *)android_media_MediaExtractor_getSampleCryptoInfo }, 879 880 { "native_init", "()V", (void *)android_media_MediaExtractor_native_init }, 881 882 { "native_setup", "()V", 883 (void *)android_media_MediaExtractor_native_setup }, 884 885 { "native_finalize", "()V", 886 (void *)android_media_MediaExtractor_native_finalize }, 887 888 { "nativeSetDataSource", 889 "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;" 890 "[Ljava/lang/String;)V", 891 (void *)android_media_MediaExtractor_setDataSource }, 892 893 { "setDataSource", "(Ljava/io/FileDescriptor;JJ)V", 894 (void *)android_media_MediaExtractor_setDataSourceFd }, 895 896 { "setDataSource", "(Landroid/media/MediaDataSource;)V", 897 (void *)android_media_MediaExtractor_setDataSourceCallback }, 898 899 { "nativeSetMediaCas", "(Landroid/os/IBinder;)V", 900 (void *)android_media_MediaExtractor_setMediaCas }, 901 902 { "getCachedDuration", "()J", 903 (void *)android_media_MediaExtractor_getCachedDurationUs }, 904 905 { "hasCacheReachedEndOfStream", "()Z", 906 (void *)android_media_MediaExtractor_hasCacheReachedEOS }, 907 908 {"native_getMetrics", "()Landroid/os/PersistableBundle;", 909 (void *)android_media_MediaExtractor_native_getMetrics}, 910}; 911 912int register_android_media_MediaExtractor(JNIEnv *env) { 913 return AndroidRuntime::registerNativeMethods(env, 914 "android/media/MediaExtractor", gMethods, NELEM(gMethods)); 915} 916