android_media_MediaExtractor.cpp revision 7be24522ce2e1821ad45e7ada7c3f91e6814889a
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 43namespace android { 44 45struct fields_t { 46 jfieldID context; 47 48 jmethodID cryptoInfoSetID; 49}; 50 51static fields_t gFields; 52 53class 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 121JMediaExtractor::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 133JMediaExtractor::~JMediaExtractor() { 134 JNIEnv *env = AndroidRuntime::getJNIEnv(); 135 136 env->DeleteWeakGlobalRef(mObject); 137 mObject = NULL; 138 env->DeleteGlobalRef(mClass); 139 mClass = NULL; 140} 141 142status_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 149status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) { 150 return mImpl->setDataSource(fd, offset, size); 151} 152 153status_t JMediaExtractor::setDataSource(const sp<DataSource> &datasource) { 154 return mImpl->setDataSource(datasource); 155} 156 157size_t JMediaExtractor::countTracks() const { 158 return mImpl->countTracks(); 159} 160 161status_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 173status_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 185status_t JMediaExtractor::selectTrack(size_t index) { 186 return mImpl->selectTrack(index); 187} 188 189status_t JMediaExtractor::unselectTrack(size_t index) { 190 return mImpl->unselectTrack(index); 191} 192 193status_t JMediaExtractor::seekTo( 194 int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) { 195 return mImpl->seekTo(timeUs, mode); 196} 197 198status_t JMediaExtractor::advance() { 199 return mImpl->advance(); 200} 201 202status_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 277status_t JMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { 278 return mImpl->getSampleTrackIndex(trackIndex); 279} 280 281status_t JMediaExtractor::getSampleTime(int64_t *sampleTimeUs) { 282 return mImpl->getSampleTime(sampleTimeUs); 283} 284 285status_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 310status_t JMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) { 311 return mImpl->getSampleMeta(sampleMeta); 312} 313 314bool JMediaExtractor::getCachedDuration(int64_t *durationUs, bool *eos) const { 315 return mImpl->getCachedDuration(durationUs, eos); 316} 317 318} // namespace android 319 320//////////////////////////////////////////////////////////////////////////////// 321 322using namespace android; 323 324static 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 340static sp<JMediaExtractor> getMediaExtractor(JNIEnv *env, jobject thiz) { 341 return (JMediaExtractor *)env->GetLongField(thiz, gFields.context); 342} 343 344static void android_media_MediaExtractor_release(JNIEnv *env, jobject thiz) { 345 setMediaExtractor(env, thiz, NULL); 346} 347 348static 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 360static 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 380static 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 400static 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 417static 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 434static 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 452static 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 473static 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 495static 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 517static 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 539static 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 561static 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 665static 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 681static 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 687static 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 737static 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 765static 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 792static 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 810static 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 828static void android_media_MediaExtractor_native_finalize( 829 JNIEnv *env, jobject thiz) { 830 android_media_MediaExtractor_release(env, thiz); 831} 832 833static 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 894int register_android_media_MediaExtractor(JNIEnv *env) { 895 return AndroidRuntime::registerNativeMethods(env, 896 "android/media/MediaExtractor", gMethods, NELEM(gMethods)); 897} 898