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