android_media_MediaExtractor.cpp revision 4eaa2938084353a54dc259466172909329a048cc
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 44namespace android { 45 46struct fields_t { 47 jfieldID context; 48 49 jmethodID cryptoInfoSetID; 50}; 51 52static fields_t gFields; 53 54JMediaExtractor::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 66JMediaExtractor::~JMediaExtractor() { 67 JNIEnv *env = AndroidRuntime::getJNIEnv(); 68 69 env->DeleteWeakGlobalRef(mObject); 70 mObject = NULL; 71 env->DeleteGlobalRef(mClass); 72 mClass = NULL; 73} 74 75status_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 82status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) { 83 return mImpl->setDataSource(fd, offset, size); 84} 85 86status_t JMediaExtractor::setDataSource(const sp<DataSource> &datasource) { 87 return mImpl->setDataSource(datasource); 88} 89 90size_t JMediaExtractor::countTracks() const { 91 return mImpl->countTracks(); 92} 93 94status_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 106status_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 118status_t JMediaExtractor::selectTrack(size_t index) { 119 return mImpl->selectTrack(index); 120} 121 122status_t JMediaExtractor::unselectTrack(size_t index) { 123 return mImpl->unselectTrack(index); 124} 125 126status_t JMediaExtractor::seekTo( 127 int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) { 128 return mImpl->seekTo(timeUs, mode); 129} 130 131status_t JMediaExtractor::advance() { 132 return mImpl->advance(); 133} 134 135status_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 210status_t JMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { 211 return mImpl->getSampleTrackIndex(trackIndex); 212} 213 214status_t JMediaExtractor::getSampleTime(int64_t *sampleTimeUs) { 215 return mImpl->getSampleTime(sampleTimeUs); 216} 217 218status_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 243status_t JMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) { 244 return mImpl->getSampleMeta(sampleMeta); 245} 246 247bool JMediaExtractor::getCachedDuration(int64_t *durationUs, bool *eos) const { 248 return mImpl->getCachedDuration(durationUs, eos); 249} 250 251} // namespace android 252 253//////////////////////////////////////////////////////////////////////////////// 254 255using namespace android; 256 257static 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 273static sp<JMediaExtractor> getMediaExtractor(JNIEnv *env, jobject thiz) { 274 return (JMediaExtractor *)env->GetLongField(thiz, gFields.context); 275} 276 277static void android_media_MediaExtractor_release(JNIEnv *env, jobject thiz) { 278 setMediaExtractor(env, thiz, NULL); 279} 280 281static 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 293static 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 313static 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 333static 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 350static 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 367static 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 385static 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 406static 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 428static 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 450static 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 472static 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 494static 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 598static 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 614static 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 620static 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 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<DataSource> bridge = 714 DataSource::CreateFromIDataSource(new JMediaDataSource(env, callbackObj)); 715 status_t err = extractor->setDataSource(bridge); 716 717 if (err != OK) { 718 jniThrowException( 719 env, 720 "java/io/IOException", 721 "Failed to instantiate extractor."); 722 return; 723 } 724} 725 726static jlong android_media_MediaExtractor_getCachedDurationUs( 727 JNIEnv *env, jobject thiz) { 728 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 729 730 if (extractor == NULL) { 731 jniThrowException(env, "java/lang/IllegalStateException", NULL); 732 return -1ll; 733 } 734 735 int64_t cachedDurationUs; 736 bool eos; 737 if (!extractor->getCachedDuration(&cachedDurationUs, &eos)) { 738 return -1ll; 739 } 740 741 return (jlong) cachedDurationUs; 742} 743 744static jboolean android_media_MediaExtractor_hasCacheReachedEOS( 745 JNIEnv *env, jobject thiz) { 746 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 747 748 if (extractor == NULL) { 749 jniThrowException(env, "java/lang/IllegalStateException", NULL); 750 return JNI_TRUE; 751 } 752 753 int64_t cachedDurationUs; 754 bool eos; 755 if (!extractor->getCachedDuration(&cachedDurationUs, &eos)) { 756 return JNI_TRUE; 757 } 758 759 return eos ? JNI_TRUE : JNI_FALSE; 760} 761 762static void android_media_MediaExtractor_native_finalize( 763 JNIEnv *env, jobject thiz) { 764 android_media_MediaExtractor_release(env, thiz); 765} 766 767static JNINativeMethod gMethods[] = { 768 { "release", "()V", (void *)android_media_MediaExtractor_release }, 769 770 { "getTrackCount", "()I", (void *)android_media_MediaExtractor_getTrackCount }, 771 772 { "getFileFormatNative", "()Ljava/util/Map;", 773 (void *)android_media_MediaExtractor_getFileFormatNative }, 774 775 { "getTrackFormatNative", "(I)Ljava/util/Map;", 776 (void *)android_media_MediaExtractor_getTrackFormatNative }, 777 778 { "selectTrack", "(I)V", (void *)android_media_MediaExtractor_selectTrack }, 779 780 { "unselectTrack", "(I)V", 781 (void *)android_media_MediaExtractor_unselectTrack }, 782 783 { "seekTo", "(JI)V", (void *)android_media_MediaExtractor_seekTo }, 784 785 { "advance", "()Z", (void *)android_media_MediaExtractor_advance }, 786 787 { "readSampleData", "(Ljava/nio/ByteBuffer;I)I", 788 (void *)android_media_MediaExtractor_readSampleData }, 789 790 { "getSampleTrackIndex", "()I", 791 (void *)android_media_MediaExtractor_getSampleTrackIndex }, 792 793 { "getSampleTime", "()J", 794 (void *)android_media_MediaExtractor_getSampleTime }, 795 796 { "getSampleFlags", "()I", 797 (void *)android_media_MediaExtractor_getSampleFlags }, 798 799 { "getSampleCryptoInfo", "(Landroid/media/MediaCodec$CryptoInfo;)Z", 800 (void *)android_media_MediaExtractor_getSampleCryptoInfo }, 801 802 { "native_init", "()V", (void *)android_media_MediaExtractor_native_init }, 803 804 { "native_setup", "()V", 805 (void *)android_media_MediaExtractor_native_setup }, 806 807 { "native_finalize", "()V", 808 (void *)android_media_MediaExtractor_native_finalize }, 809 810 { "nativeSetDataSource", 811 "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;" 812 "[Ljava/lang/String;)V", 813 (void *)android_media_MediaExtractor_setDataSource }, 814 815 { "setDataSource", "(Ljava/io/FileDescriptor;JJ)V", 816 (void *)android_media_MediaExtractor_setDataSourceFd }, 817 818 { "setDataSource", "(Landroid/media/MediaDataSource;)V", 819 (void *)android_media_MediaExtractor_setDataSourceCallback }, 820 821 { "getCachedDuration", "()J", 822 (void *)android_media_MediaExtractor_getCachedDurationUs }, 823 824 { "hasCacheReachedEndOfStream", "()Z", 825 (void *)android_media_MediaExtractor_hasCacheReachedEOS }, 826}; 827 828int register_android_media_MediaExtractor(JNIEnv *env) { 829 return AndroidRuntime::registerNativeMethods(env, 830 "android/media/MediaExtractor", gMethods, NELEM(gMethods)); 831} 832