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