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