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