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_AudioPresentation.h" 22 #include "android_media_MediaDataSource.h" 23 #include "android_media_MediaExtractor.h" 24 #include "android_media_MediaMetricsJNI.h" 25 #include "android_media_Streams.h" 26 #include "android_os_HwRemoteBinder.h" 27 #include "android_runtime/AndroidRuntime.h" 28 #include "android_runtime/Log.h" 29 #include "android_util_Binder.h" 30 #include "jni.h" 31 #include <nativehelper/JNIHelp.h> 32 33 #include <android/hardware/cas/1.0/BpHwCas.h> 34 #include <android/hardware/cas/1.0/BnHwCas.h> 35 #include <hidl/HybridInterface.h> 36 #include <media/IMediaHTTPService.h> 37 #include <media/hardware/CryptoAPI.h> 38 #include <media/stagefright/foundation/ABuffer.h> 39 #include <media/stagefright/foundation/ADebug.h> 40 #include <media/stagefright/foundation/AMessage.h> 41 #include <media/DataSource.h> 42 #include <media/stagefright/InterfaceUtils.h> 43 #include <media/stagefright/MediaErrors.h> 44 #include <media/stagefright/MetaData.h> 45 #include <media/stagefright/NuMediaExtractor.h> 46 #include <nativehelper/ScopedLocalRef.h> 47 48 namespace android { 49 50 using namespace hardware::cas::V1_0; 51 52 struct fields_t { 53 jfieldID context; 54 55 jmethodID cryptoInfoSetID; 56 jmethodID cryptoInfoSetPatternID; 57 }; 58 59 static fields_t gFields; 60 static JAudioPresentationInfo::fields_t gAudioPresentationFields; 61 62 JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz) 63 : mClass(NULL), 64 mObject(NULL) { 65 jclass clazz = env->GetObjectClass(thiz); 66 CHECK(clazz != NULL); 67 68 mClass = (jclass)env->NewGlobalRef(clazz); 69 mObject = env->NewWeakGlobalRef(thiz); 70 71 mImpl = new NuMediaExtractor; 72 } 73 74 JMediaExtractor::~JMediaExtractor() { 75 JNIEnv *env = AndroidRuntime::getJNIEnv(); 76 77 env->DeleteWeakGlobalRef(mObject); 78 mObject = NULL; 79 env->DeleteGlobalRef(mClass); 80 mClass = NULL; 81 } 82 83 status_t JMediaExtractor::setDataSource( 84 const sp<IMediaHTTPService> &httpService, 85 const char *path, 86 const KeyedVector<String8, String8> *headers) { 87 return mImpl->setDataSource(httpService, path, headers); 88 } 89 90 status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) { 91 return mImpl->setDataSource(fd, offset, size); 92 } 93 94 status_t JMediaExtractor::setDataSource(const sp<DataSource> &datasource) { 95 return mImpl->setDataSource(datasource); 96 } 97 98 status_t JMediaExtractor::setMediaCas(JNIEnv *env, jobject casBinderObj) { 99 if (casBinderObj == NULL) { 100 return BAD_VALUE; 101 } 102 103 sp<hardware::IBinder> hwBinder = 104 JHwRemoteBinder::GetNativeContext(env, casBinderObj)->getBinder(); 105 if (hwBinder == NULL) { 106 return BAD_VALUE; 107 } 108 109 sp<ICas> cas = hardware::fromBinder<ICas, BpHwCas, BnHwCas>(hwBinder); 110 if (cas == NULL) { 111 return BAD_VALUE; 112 } 113 114 HalToken halToken; 115 if (!createHalToken(cas, &halToken)) { 116 return BAD_VALUE; 117 } 118 119 return mImpl->setMediaCas(halToken); 120 } 121 122 size_t JMediaExtractor::countTracks() const { 123 return mImpl->countTracks(); 124 } 125 126 status_t JMediaExtractor::getTrackFormat(size_t index, jobject *format) const { 127 sp<AMessage> msg; 128 status_t err; 129 if ((err = mImpl->getTrackFormat(index, &msg)) != OK) { 130 return err; 131 } 132 133 JNIEnv *env = AndroidRuntime::getJNIEnv(); 134 135 return ConvertMessageToMap(env, msg, format); 136 } 137 138 status_t JMediaExtractor::getFileFormat(jobject *format) const { 139 sp<AMessage> msg; 140 status_t err; 141 if ((err = mImpl->getFileFormat(&msg)) != OK) { 142 return err; 143 } 144 145 JNIEnv *env = AndroidRuntime::getJNIEnv(); 146 147 return ConvertMessageToMap(env, msg, format); 148 } 149 150 status_t JMediaExtractor::selectTrack(size_t index) { 151 return mImpl->selectTrack(index); 152 } 153 154 status_t JMediaExtractor::unselectTrack(size_t index) { 155 return mImpl->unselectTrack(index); 156 } 157 158 status_t JMediaExtractor::seekTo( 159 int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) { 160 return mImpl->seekTo(timeUs, mode); 161 } 162 163 status_t JMediaExtractor::advance() { 164 return mImpl->advance(); 165 } 166 167 status_t JMediaExtractor::readSampleData( 168 jobject byteBuf, size_t offset, size_t *sampleSize) { 169 JNIEnv *env = AndroidRuntime::getJNIEnv(); 170 171 void *dst = env->GetDirectBufferAddress(byteBuf); 172 173 size_t dstSize; 174 jbyteArray byteArray = NULL; 175 176 ScopedLocalRef<jclass> byteBufClass(env, env->FindClass("java/nio/ByteBuffer")); 177 CHECK(byteBufClass.get() != NULL); 178 179 if (dst == NULL) { 180 jmethodID arrayID = 181 env->GetMethodID(byteBufClass.get(), "array", "()[B"); 182 CHECK(arrayID != NULL); 183 184 byteArray = 185 (jbyteArray)env->CallObjectMethod(byteBuf, arrayID); 186 187 if (byteArray == NULL) { 188 return INVALID_OPERATION; 189 } 190 191 jboolean isCopy; 192 dst = env->GetByteArrayElements(byteArray, &isCopy); 193 194 dstSize = (size_t) env->GetArrayLength(byteArray); 195 } else { 196 dstSize = (size_t) env->GetDirectBufferCapacity(byteBuf); 197 } 198 199 if (dstSize < offset) { 200 if (byteArray != NULL) { 201 env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0); 202 } 203 204 return -ERANGE; 205 } 206 207 sp<ABuffer> buffer = new ABuffer((char *)dst + offset, dstSize - offset); 208 209 status_t err = mImpl->readSampleData(buffer); 210 211 if (byteArray != NULL) { 212 env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0); 213 } 214 215 if (err != OK) { 216 return err; 217 } 218 219 *sampleSize = buffer->size(); 220 221 jmethodID positionID = env->GetMethodID( 222 byteBufClass.get(), "position", "(I)Ljava/nio/Buffer;"); 223 224 CHECK(positionID != NULL); 225 226 jmethodID limitID = env->GetMethodID( 227 byteBufClass.get(), "limit", "(I)Ljava/nio/Buffer;"); 228 229 CHECK(limitID != NULL); 230 231 jobject me = env->CallObjectMethod( 232 byteBuf, limitID, offset + *sampleSize); 233 env->DeleteLocalRef(me); 234 me = env->CallObjectMethod( 235 byteBuf, positionID, offset); 236 env->DeleteLocalRef(me); 237 me = NULL; 238 239 return OK; 240 } 241 242 status_t JMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { 243 return mImpl->getSampleTrackIndex(trackIndex); 244 } 245 246 status_t JMediaExtractor::getSampleTime(int64_t *sampleTimeUs) { 247 return mImpl->getSampleTime(sampleTimeUs); 248 } 249 250 status_t JMediaExtractor::getSampleSize(size_t *sampleSize) { 251 return mImpl->getSampleSize(sampleSize); 252 } 253 254 status_t JMediaExtractor::getSampleFlags(uint32_t *sampleFlags) { 255 *sampleFlags = 0; 256 257 sp<MetaData> meta; 258 status_t err = mImpl->getSampleMeta(&meta); 259 260 if (err != OK) { 261 return err; 262 } 263 264 int32_t val; 265 if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) { 266 (*sampleFlags) |= NuMediaExtractor::SAMPLE_FLAG_SYNC; 267 } 268 269 uint32_t type; 270 const void *data; 271 size_t size; 272 if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) { 273 (*sampleFlags) |= NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED; 274 } 275 276 return OK; 277 } 278 279 status_t JMediaExtractor::getMetrics(Parcel *reply) const { 280 281 status_t status = mImpl->getMetrics(reply); 282 return status; 283 } 284 285 286 status_t JMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) { 287 return mImpl->getSampleMeta(sampleMeta); 288 } 289 290 bool JMediaExtractor::getCachedDuration(int64_t *durationUs, bool *eos) const { 291 return mImpl->getCachedDuration(durationUs, eos); 292 } 293 294 status_t JMediaExtractor::getAudioPresentations(size_t trackIdx, 295 AudioPresentationCollection *presentations) const { 296 return mImpl->getAudioPresentations(trackIdx, presentations); 297 } 298 } // namespace android 299 300 //////////////////////////////////////////////////////////////////////////////// 301 302 using namespace android; 303 304 static 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 320 static sp<JMediaExtractor> getMediaExtractor(JNIEnv *env, jobject thiz) { 321 return (JMediaExtractor *)env->GetLongField(thiz, gFields.context); 322 } 323 324 static void android_media_MediaExtractor_release(JNIEnv *env, jobject thiz) { 325 setMediaExtractor(env, thiz, NULL); 326 } 327 328 static 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 340 static 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 360 static 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 380 static 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 397 static 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 414 static 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 432 static 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 453 static 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 475 static 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 497 static 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 519 static jlong android_media_MediaExtractor_getSampleSize( 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 -1LL; 526 } 527 528 size_t sampleSize; 529 status_t err = extractor->getSampleSize(&sampleSize); 530 531 if (err == ERROR_END_OF_STREAM) { 532 return -1LL; 533 } else if (err != OK) { 534 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 535 return -1LL; 536 } 537 538 return (jlong) sampleSize; 539 } 540 541 static jint android_media_MediaExtractor_getSampleFlags( 542 JNIEnv *env, jobject thiz) { 543 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 544 545 if (extractor == NULL) { 546 jniThrowException(env, "java/lang/IllegalStateException", NULL); 547 return -1; 548 } 549 550 uint32_t sampleFlags; 551 status_t err = extractor->getSampleFlags(&sampleFlags); 552 553 if (err == ERROR_END_OF_STREAM) { 554 return -1; 555 } else if (err != OK) { 556 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 557 return -1; 558 } 559 560 return (jint) sampleFlags; 561 } 562 563 static jboolean android_media_MediaExtractor_getSampleCryptoInfo( 564 JNIEnv *env, jobject thiz, jobject cryptoInfoObj) { 565 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 566 567 if (extractor == NULL) { 568 jniThrowException(env, "java/lang/IllegalStateException", NULL); 569 return JNI_FALSE; 570 } 571 572 sp<MetaData> meta; 573 status_t err = extractor->getSampleMeta(&meta); 574 575 if (err != OK) { 576 return JNI_FALSE; 577 } 578 579 uint32_t type; 580 const void *data; 581 size_t size; 582 if (!meta->findData(kKeyEncryptedSizes, &type, &data, &size)) { 583 return JNI_FALSE; 584 } 585 586 size_t numSubSamples = size / sizeof(int32_t); 587 588 if (numSubSamples == 0) { 589 return JNI_FALSE; 590 } 591 592 jintArray numBytesOfEncryptedDataObj = env->NewIntArray(numSubSamples); 593 jboolean isCopy; 594 jint *dst = env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); 595 for (size_t i = 0; i < numSubSamples; ++i) { 596 dst[i] = ((const int32_t *)data)[i]; 597 } 598 env->ReleaseIntArrayElements(numBytesOfEncryptedDataObj, dst, 0); 599 dst = NULL; 600 601 size_t encSize = size; 602 jintArray numBytesOfPlainDataObj = NULL; 603 if (meta->findData(kKeyPlainSizes, &type, &data, &size)) { 604 if (size != encSize) { 605 // The two must be of the same length. 606 return JNI_FALSE; 607 } 608 609 numBytesOfPlainDataObj = env->NewIntArray(numSubSamples); 610 jboolean isCopy; 611 jint *dst = env->GetIntArrayElements(numBytesOfPlainDataObj, &isCopy); 612 for (size_t i = 0; i < numSubSamples; ++i) { 613 dst[i] = ((const int32_t *)data)[i]; 614 } 615 env->ReleaseIntArrayElements(numBytesOfPlainDataObj, dst, 0); 616 dst = NULL; 617 } 618 619 jbyteArray keyObj = NULL; 620 if (meta->findData(kKeyCryptoKey, &type, &data, &size)) { 621 if (size != 16) { 622 // Keys must be 16 bytes in length. 623 return JNI_FALSE; 624 } 625 626 keyObj = env->NewByteArray(size); 627 jboolean isCopy; 628 jbyte *dst = env->GetByteArrayElements(keyObj, &isCopy); 629 memcpy(dst, data, size); 630 env->ReleaseByteArrayElements(keyObj, dst, 0); 631 dst = NULL; 632 } 633 634 jbyteArray ivObj = NULL; 635 if (meta->findData(kKeyCryptoIV, &type, &data, &size)) { 636 if (size != 16) { 637 // IVs must be 16 bytes in length. 638 return JNI_FALSE; 639 } 640 641 ivObj = env->NewByteArray(size); 642 jboolean isCopy; 643 jbyte *dst = env->GetByteArrayElements(ivObj, &isCopy); 644 memcpy(dst, data, size); 645 env->ReleaseByteArrayElements(ivObj, dst, 0); 646 dst = NULL; 647 } 648 649 int32_t mode; 650 if (!meta->findInt32(kKeyCryptoMode, &mode)) { 651 mode = CryptoPlugin::kMode_AES_CTR; 652 } 653 654 env->CallVoidMethod( 655 cryptoInfoObj, 656 gFields.cryptoInfoSetID, 657 (jint)numSubSamples, 658 numBytesOfPlainDataObj, 659 numBytesOfEncryptedDataObj, 660 keyObj, 661 ivObj, 662 mode); 663 664 int32_t encryptedByteBlock = 0, skipByteBlock = 0; 665 meta->findInt32(kKeyEncryptedByteBlock, &encryptedByteBlock); 666 meta->findInt32(kKeySkipByteBlock, &skipByteBlock); 667 668 env->CallVoidMethod( 669 cryptoInfoObj, 670 gFields.cryptoInfoSetPatternID, 671 encryptedByteBlock, 672 skipByteBlock); 673 674 return JNI_TRUE; 675 } 676 677 static jobject android_media_MediaExtractor_getAudioPresentations( 678 JNIEnv *env, jobject thiz, jint trackIdx) { 679 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 680 jobject presentationsJObj = JAudioPresentationInfo::asJobject(env, gAudioPresentationFields); 681 if (extractor == NULL) { 682 jniThrowException(env, "java/lang/IllegalStateException", NULL); 683 return presentationsJObj; 684 } 685 AudioPresentationCollection presentations; 686 status_t err = extractor->getAudioPresentations(trackIdx, &presentations); 687 if (err == ERROR_END_OF_STREAM || err == ERROR_UNSUPPORTED) { 688 return presentationsJObj; 689 } else if (err != OK) { 690 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 691 return presentationsJObj; 692 } 693 694 JAudioPresentationInfo::addPresentations( 695 env, gAudioPresentationFields, presentations, presentationsJObj); 696 return presentationsJObj; 697 } 698 699 static void android_media_MediaExtractor_native_init(JNIEnv *env) { 700 jclass clazz = env->FindClass("android/media/MediaExtractor"); 701 CHECK(clazz != NULL); 702 703 gFields.context = env->GetFieldID(clazz, "mNativeContext", "J"); 704 CHECK(gFields.context != NULL); 705 706 clazz = env->FindClass("android/media/MediaCodec$CryptoInfo"); 707 CHECK(clazz != NULL); 708 709 gFields.cryptoInfoSetID = 710 env->GetMethodID(clazz, "set", "(I[I[I[B[BI)V"); 711 712 gFields.cryptoInfoSetPatternID = 713 env->GetMethodID(clazz, "setPattern", "(II)V"); 714 715 gAudioPresentationFields.init(env); 716 } 717 718 static void android_media_MediaExtractor_native_setup( 719 JNIEnv *env, jobject thiz) { 720 sp<JMediaExtractor> extractor = new JMediaExtractor(env, thiz); 721 setMediaExtractor(env,thiz, extractor); 722 } 723 724 static void android_media_MediaExtractor_setDataSource( 725 JNIEnv *env, jobject thiz, 726 jobject httpServiceBinderObj, 727 jstring pathObj, 728 jobjectArray keysArray, 729 jobjectArray valuesArray) { 730 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 731 732 if (extractor == NULL) { 733 jniThrowException(env, "java/lang/IllegalStateException", NULL); 734 return; 735 } 736 737 if (pathObj == NULL) { 738 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 739 return; 740 } 741 742 KeyedVector<String8, String8> headers; 743 if (!ConvertKeyValueArraysToKeyedVector( 744 env, keysArray, valuesArray, &headers)) { 745 return; 746 } 747 748 const char *path = env->GetStringUTFChars(pathObj, NULL); 749 750 if (path == NULL) { 751 return; 752 } 753 754 sp<IMediaHTTPService> httpService; 755 if (httpServiceBinderObj != NULL) { 756 sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj); 757 httpService = interface_cast<IMediaHTTPService>(binder); 758 } 759 760 status_t err = extractor->setDataSource(httpService, path, &headers); 761 762 env->ReleaseStringUTFChars(pathObj, path); 763 path = NULL; 764 765 if (err != OK) { 766 jniThrowException( 767 env, 768 "java/io/IOException", 769 "Failed to instantiate extractor."); 770 return; 771 } 772 } 773 774 static void android_media_MediaExtractor_setDataSourceFd( 775 JNIEnv *env, jobject thiz, 776 jobject fileDescObj, jlong offset, jlong length) { 777 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 778 779 if (extractor == NULL) { 780 jniThrowException(env, "java/lang/IllegalStateException", NULL); 781 return; 782 } 783 784 if (fileDescObj == NULL) { 785 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 786 return; 787 } 788 789 int fd = jniGetFDFromFileDescriptor(env, fileDescObj); 790 791 status_t err = extractor->setDataSource(fd, offset, length); 792 793 if (err != OK) { 794 jniThrowException( 795 env, 796 "java/io/IOException", 797 "Failed to instantiate extractor."); 798 return; 799 } 800 } 801 802 static void android_media_MediaExtractor_setDataSourceCallback( 803 JNIEnv *env, jobject thiz, 804 jobject callbackObj) { 805 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 806 807 if (extractor == NULL) { 808 jniThrowException(env, "java/lang/IllegalStateException", NULL); 809 return; 810 } 811 812 if (callbackObj == NULL) { 813 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 814 return; 815 } 816 817 sp<DataSource> bridge = 818 CreateDataSourceFromIDataSource(new JMediaDataSource(env, callbackObj)); 819 status_t err = extractor->setDataSource(bridge); 820 821 if (err != OK) { 822 // Clear bridge so that JMediaDataSource::close() is called _before_ 823 // we throw the IOException. 824 // Otherwise close() gets called when we go out of scope, it calls 825 // Java with a pending exception and crashes the process. 826 bridge.clear(); 827 jniThrowException( 828 env, 829 "java/io/IOException", 830 "Failed to instantiate extractor."); 831 return; 832 } 833 } 834 835 static void android_media_MediaExtractor_setMediaCas( 836 JNIEnv *env, jobject thiz, jobject casBinderObj) { 837 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 838 839 if (extractor == NULL) { 840 jniThrowException(env, "java/lang/IllegalStateException", NULL); 841 return; 842 } 843 844 status_t err = extractor->setMediaCas(env, casBinderObj); 845 846 if (err != OK) { 847 extractor.clear(); 848 jniThrowException( 849 env, 850 "java/lang/IllegalArgumentException", 851 "Failed to set MediaCas on extractor."); 852 } 853 } 854 855 static jlong android_media_MediaExtractor_getCachedDurationUs( 856 JNIEnv *env, jobject thiz) { 857 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 858 859 if (extractor == NULL) { 860 jniThrowException(env, "java/lang/IllegalStateException", NULL); 861 return -1LL; 862 } 863 864 int64_t cachedDurationUs; 865 bool eos; 866 if (!extractor->getCachedDuration(&cachedDurationUs, &eos)) { 867 return -1LL; 868 } 869 870 return (jlong) cachedDurationUs; 871 } 872 873 static jboolean android_media_MediaExtractor_hasCacheReachedEOS( 874 JNIEnv *env, jobject thiz) { 875 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 876 877 if (extractor == NULL) { 878 jniThrowException(env, "java/lang/IllegalStateException", NULL); 879 return JNI_TRUE; 880 } 881 882 int64_t cachedDurationUs; 883 bool eos; 884 if (!extractor->getCachedDuration(&cachedDurationUs, &eos)) { 885 return JNI_TRUE; 886 } 887 888 return eos ? JNI_TRUE : JNI_FALSE; 889 } 890 891 static void android_media_MediaExtractor_native_finalize( 892 JNIEnv *env, jobject thiz) { 893 android_media_MediaExtractor_release(env, thiz); 894 } 895 896 static jobject 897 android_media_MediaExtractor_native_getMetrics(JNIEnv * env, jobject thiz) 898 { 899 ALOGV("android_media_MediaExtractor_native_getMetrics"); 900 901 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz); 902 if (extractor == NULL ) { 903 jniThrowException(env, "java/lang/IllegalStateException", NULL); 904 return NULL; 905 } 906 907 // get what we have for the metrics from the codec 908 Parcel reply; 909 status_t err = extractor->getMetrics(&reply); 910 if (err != OK) { 911 ALOGE("getMetrics failed"); 912 return (jobject) NULL; 913 } 914 915 // build and return the Bundle 916 std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create()); 917 item->readFromParcel(reply); 918 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item.get(), NULL); 919 920 return mybundle; 921 } 922 923 924 static const JNINativeMethod gMethods[] = { 925 { "release", "()V", (void *)android_media_MediaExtractor_release }, 926 927 { "getTrackCount", "()I", (void *)android_media_MediaExtractor_getTrackCount }, 928 929 { "getFileFormatNative", "()Ljava/util/Map;", 930 (void *)android_media_MediaExtractor_getFileFormatNative }, 931 932 { "getTrackFormatNative", "(I)Ljava/util/Map;", 933 (void *)android_media_MediaExtractor_getTrackFormatNative }, 934 935 { "selectTrack", "(I)V", (void *)android_media_MediaExtractor_selectTrack }, 936 937 { "unselectTrack", "(I)V", 938 (void *)android_media_MediaExtractor_unselectTrack }, 939 940 { "seekTo", "(JI)V", (void *)android_media_MediaExtractor_seekTo }, 941 942 { "advance", "()Z", (void *)android_media_MediaExtractor_advance }, 943 944 { "readSampleData", "(Ljava/nio/ByteBuffer;I)I", 945 (void *)android_media_MediaExtractor_readSampleData }, 946 947 { "getSampleTrackIndex", "()I", 948 (void *)android_media_MediaExtractor_getSampleTrackIndex }, 949 950 { "getSampleTime", "()J", 951 (void *)android_media_MediaExtractor_getSampleTime }, 952 953 { "getSampleSize", "()J", 954 (void *)android_media_MediaExtractor_getSampleSize }, 955 956 { "getSampleFlags", "()I", 957 (void *)android_media_MediaExtractor_getSampleFlags }, 958 959 { "getSampleCryptoInfo", "(Landroid/media/MediaCodec$CryptoInfo;)Z", 960 (void *)android_media_MediaExtractor_getSampleCryptoInfo }, 961 962 { "native_init", "()V", (void *)android_media_MediaExtractor_native_init }, 963 964 { "native_setup", "()V", 965 (void *)android_media_MediaExtractor_native_setup }, 966 967 { "native_finalize", "()V", 968 (void *)android_media_MediaExtractor_native_finalize }, 969 970 { "nativeSetDataSource", 971 "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;" 972 "[Ljava/lang/String;)V", 973 (void *)android_media_MediaExtractor_setDataSource }, 974 975 { "setDataSource", "(Ljava/io/FileDescriptor;JJ)V", 976 (void *)android_media_MediaExtractor_setDataSourceFd }, 977 978 { "setDataSource", "(Landroid/media/MediaDataSource;)V", 979 (void *)android_media_MediaExtractor_setDataSourceCallback }, 980 981 { "nativeSetMediaCas", "(Landroid/os/IHwBinder;)V", 982 (void *)android_media_MediaExtractor_setMediaCas }, 983 984 { "getCachedDuration", "()J", 985 (void *)android_media_MediaExtractor_getCachedDurationUs }, 986 987 { "hasCacheReachedEndOfStream", "()Z", 988 (void *)android_media_MediaExtractor_hasCacheReachedEOS }, 989 990 {"native_getMetrics", "()Landroid/os/PersistableBundle;", 991 (void *)android_media_MediaExtractor_native_getMetrics}, 992 993 { "native_getAudioPresentations", "(I)Ljava/util/List;", 994 (void *)android_media_MediaExtractor_getAudioPresentations }, 995 }; 996 997 int register_android_media_MediaExtractor(JNIEnv *env) { 998 return AndroidRuntime::registerNativeMethods(env, 999 "android/media/MediaExtractor", gMethods, NELEM(gMethods)); 1000 } 1001