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