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