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