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