• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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