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