blob: 3dbf77ba74c9919d37a96881617b730a167bffeb [file] [log] [blame]
Andreas Huber88572f72012-02-21 11:47:18 -08001/*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "MediaExtractor-JNI"
19#include <utils/Log.h>
20
21#include "android_media_MediaExtractor.h"
22
23#include "android_media_Utils.h"
24#include "android_runtime/AndroidRuntime.h"
Ruben Brunk87eac992013-09-09 17:44:59 -070025#include "android_runtime/Log.h"
Andreas Huber88572f72012-02-21 11:47:18 -080026#include "jni.h"
27#include "JNIHelp.h"
28
Andreas Huberd2506a52014-01-29 10:32:46 -080029#include <media/IMediaHTTPService.h>
Andreas Huberab57d032012-04-18 15:59:43 -070030#include <media/hardware/CryptoAPI.h>
Andreas Huber88572f72012-02-21 11:47:18 -080031#include <media/stagefright/foundation/ABuffer.h>
32#include <media/stagefright/foundation/ADebug.h>
33#include <media/stagefright/foundation/AMessage.h>
34#include <media/stagefright/DataSource.h>
35#include <media/stagefright/MediaErrors.h>
Andreas Huber91befdc2012-04-18 12:19:51 -070036#include <media/stagefright/MetaData.h>
Andreas Huber88572f72012-02-21 11:47:18 -080037#include <media/stagefright/NuMediaExtractor.h>
38
Andreas Huberd2506a52014-01-29 10:32:46 -080039#include "android_util_Binder.h"
40
Andreas Huber88572f72012-02-21 11:47:18 -080041namespace android {
42
43struct fields_t {
44 jfieldID context;
Andreas Huber91befdc2012-04-18 12:19:51 -070045
46 jmethodID cryptoInfoSetID;
Andreas Huber88572f72012-02-21 11:47:18 -080047};
48
49static fields_t gFields;
50
Marco Nelissenc209a062012-08-24 09:55:44 -070051class JavaDataSourceBridge : public DataSource {
52 jmethodID mReadMethod;
53 jmethodID mGetSizeMethod;
54 jmethodID mCloseMethod;
55 jobject mDataSource;
56 public:
57 JavaDataSourceBridge(JNIEnv *env, jobject source) {
58 mDataSource = env->NewGlobalRef(source);
59
60 jclass datasourceclass = env->GetObjectClass(mDataSource);
61 CHECK(datasourceclass != NULL);
62
63 mReadMethod = env->GetMethodID(datasourceclass, "readAt", "(J[BI)I");
64 CHECK(mReadMethod != NULL);
65
66 mGetSizeMethod = env->GetMethodID(datasourceclass, "getSize", "()J");
67 CHECK(mGetSizeMethod != NULL);
68
69 mCloseMethod = env->GetMethodID(datasourceclass, "close", "()V");
70 CHECK(mCloseMethod != NULL);
71 }
72
73 ~JavaDataSourceBridge() {
74 JNIEnv *env = AndroidRuntime::getJNIEnv();
75 env->CallVoidMethod(mDataSource, mCloseMethod);
76 env->DeleteGlobalRef(mDataSource);
77 }
78
79 virtual status_t initCheck() const {
80 return OK;
81 }
82
83 virtual ssize_t readAt(off64_t offset, void* buffer, size_t size) {
84 JNIEnv *env = AndroidRuntime::getJNIEnv();
85
86 // XXX could optimize this by reusing the same array
87 jbyteArray byteArrayObj = env->NewByteArray(size);
88 env->DeleteLocalRef(env->GetObjectClass(mDataSource));
89 env->DeleteLocalRef(env->GetObjectClass(byteArrayObj));
Ashok Bhat136c08a2014-03-05 15:23:13 +000090 ssize_t numread = env->CallIntMethod(mDataSource, mReadMethod, offset, byteArrayObj, (jint)size);
Marco Nelissenc209a062012-08-24 09:55:44 -070091 env->GetByteArrayRegion(byteArrayObj, 0, size, (jbyte*) buffer);
92 env->DeleteLocalRef(byteArrayObj);
93 if (env->ExceptionCheck()) {
Ashok Bhat075e9a12014-01-06 13:45:09 +000094 ALOGW("Exception occurred while reading %zu at %lld", size, offset);
Marco Nelissenc209a062012-08-24 09:55:44 -070095 LOGW_EX(env);
96 env->ExceptionClear();
97 return -1;
98 }
99 return numread;
100 }
101
102 virtual status_t getSize(off64_t *size) {
103 JNIEnv *env = AndroidRuntime::getJNIEnv();
104
105 CHECK(size != NULL);
106
107 int64_t len = env->CallLongMethod(mDataSource, mGetSizeMethod);
108 if (len < 0) {
109 *size = ERROR_UNSUPPORTED;
110 } else {
111 *size = len;
112 }
113 return OK;
114 }
115};
116
Andreas Huber88572f72012-02-21 11:47:18 -0800117////////////////////////////////////////////////////////////////////////////////
118
119JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz)
120 : mClass(NULL),
121 mObject(NULL) {
122 jclass clazz = env->GetObjectClass(thiz);
123 CHECK(clazz != NULL);
124
125 mClass = (jclass)env->NewGlobalRef(clazz);
126 mObject = env->NewWeakGlobalRef(thiz);
127
128 mImpl = new NuMediaExtractor;
129}
130
131JMediaExtractor::~JMediaExtractor() {
132 JNIEnv *env = AndroidRuntime::getJNIEnv();
133
134 env->DeleteWeakGlobalRef(mObject);
135 mObject = NULL;
136 env->DeleteGlobalRef(mClass);
137 mClass = NULL;
138}
139
Andreas Huber07ea4262012-04-11 12:21:20 -0700140status_t JMediaExtractor::setDataSource(
Andreas Huberd2506a52014-01-29 10:32:46 -0800141 const sp<IMediaHTTPService> &httpService,
142 const char *path,
143 const KeyedVector<String8, String8> *headers) {
144 return mImpl->setDataSource(httpService, path, headers);
Andreas Huber07ea4262012-04-11 12:21:20 -0700145}
146
147status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
148 return mImpl->setDataSource(fd, offset, size);
Andreas Huber88572f72012-02-21 11:47:18 -0800149}
150
Marco Nelissenc209a062012-08-24 09:55:44 -0700151status_t JMediaExtractor::setDataSource(const sp<DataSource> &datasource) {
152 return mImpl->setDataSource(datasource);
153}
154
Andreas Huber88572f72012-02-21 11:47:18 -0800155size_t JMediaExtractor::countTracks() const {
156 return mImpl->countTracks();
157}
158
159status_t JMediaExtractor::getTrackFormat(size_t index, jobject *format) const {
160 sp<AMessage> msg;
161 status_t err;
162 if ((err = mImpl->getTrackFormat(index, &msg)) != OK) {
163 return err;
164 }
165
166 JNIEnv *env = AndroidRuntime::getJNIEnv();
167
168 return ConvertMessageToMap(env, msg, format);
169}
170
Marco Nelissene20a6d52013-04-08 14:28:55 -0700171status_t JMediaExtractor::getFileFormat(jobject *format) const {
172 sp<AMessage> msg;
173 status_t err;
174 if ((err = mImpl->getFileFormat(&msg)) != OK) {
175 return err;
176 }
177
178 JNIEnv *env = AndroidRuntime::getJNIEnv();
179
180 return ConvertMessageToMap(env, msg, format);
181}
182
Andreas Huber88572f72012-02-21 11:47:18 -0800183status_t JMediaExtractor::selectTrack(size_t index) {
184 return mImpl->selectTrack(index);
185}
186
Andreas Huberf2855b32012-04-25 15:57:43 -0700187status_t JMediaExtractor::unselectTrack(size_t index) {
188 return mImpl->unselectTrack(index);
189}
190
191status_t JMediaExtractor::seekTo(
192 int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) {
193 return mImpl->seekTo(timeUs, mode);
Andreas Huber88572f72012-02-21 11:47:18 -0800194}
195
196status_t JMediaExtractor::advance() {
197 return mImpl->advance();
198}
199
200status_t JMediaExtractor::readSampleData(
201 jobject byteBuf, size_t offset, size_t *sampleSize) {
202 JNIEnv *env = AndroidRuntime::getJNIEnv();
203
204 void *dst = env->GetDirectBufferAddress(byteBuf);
205
Ashok Bhat075e9a12014-01-06 13:45:09 +0000206 size_t dstSize;
Andreas Huberc52b9802012-03-12 14:04:01 -0700207 jbyteArray byteArray = NULL;
208
Andreas Huber88572f72012-02-21 11:47:18 -0800209 if (dst == NULL) {
Andreas Huberc52b9802012-03-12 14:04:01 -0700210 jclass byteBufClass = env->FindClass("java/nio/ByteBuffer");
211 CHECK(byteBufClass != NULL);
212
213 jmethodID arrayID =
214 env->GetMethodID(byteBufClass, "array", "()[B");
215 CHECK(arrayID != NULL);
216
217 byteArray =
218 (jbyteArray)env->CallObjectMethod(byteBuf, arrayID);
219
220 if (byteArray == NULL) {
221 return INVALID_OPERATION;
222 }
223
224 jboolean isCopy;
225 dst = env->GetByteArrayElements(byteArray, &isCopy);
226
Ashok Bhat075e9a12014-01-06 13:45:09 +0000227 dstSize = (size_t) env->GetArrayLength(byteArray);
Andreas Huberc52b9802012-03-12 14:04:01 -0700228 } else {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000229 dstSize = (size_t) env->GetDirectBufferCapacity(byteBuf);
Andreas Huber88572f72012-02-21 11:47:18 -0800230 }
231
Andreas Huber88572f72012-02-21 11:47:18 -0800232 if (dstSize < offset) {
Andreas Huberc52b9802012-03-12 14:04:01 -0700233 if (byteArray != NULL) {
234 env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0);
235 }
236
Andreas Huber88572f72012-02-21 11:47:18 -0800237 return -ERANGE;
238 }
239
240 sp<ABuffer> buffer = new ABuffer((char *)dst + offset, dstSize - offset);
241
242 status_t err = mImpl->readSampleData(buffer);
243
Andreas Huberc52b9802012-03-12 14:04:01 -0700244 if (byteArray != NULL) {
245 env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0);
246 }
247
Andreas Huber88572f72012-02-21 11:47:18 -0800248 if (err != OK) {
249 return err;
250 }
251
252 *sampleSize = buffer->size();
253
254 return OK;
255}
256
257status_t JMediaExtractor::getSampleTrackIndex(size_t *trackIndex) {
258 return mImpl->getSampleTrackIndex(trackIndex);
259}
260
261status_t JMediaExtractor::getSampleTime(int64_t *sampleTimeUs) {
262 return mImpl->getSampleTime(sampleTimeUs);
263}
264
Andreas Huber9b8e4962012-03-26 11:13:27 -0700265status_t JMediaExtractor::getSampleFlags(uint32_t *sampleFlags) {
Andreas Huber91befdc2012-04-18 12:19:51 -0700266 *sampleFlags = 0;
267
268 sp<MetaData> meta;
269 status_t err = mImpl->getSampleMeta(&meta);
270
271 if (err != OK) {
272 return err;
273 }
274
275 int32_t val;
276 if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) {
277 (*sampleFlags) |= NuMediaExtractor::SAMPLE_FLAG_SYNC;
278 }
279
280 uint32_t type;
281 const void *data;
282 size_t size;
283 if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
284 (*sampleFlags) |= NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED;
285 }
286
287 return OK;
288}
289
290status_t JMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) {
291 return mImpl->getSampleMeta(sampleMeta);
Andreas Huber9b8e4962012-03-26 11:13:27 -0700292}
293
Andreas Huber74a78b02012-04-19 16:24:32 -0700294bool JMediaExtractor::getCachedDuration(int64_t *durationUs, bool *eos) const {
295 return mImpl->getCachedDuration(durationUs, eos);
296}
297
Andreas Huber88572f72012-02-21 11:47:18 -0800298} // namespace android
299
300////////////////////////////////////////////////////////////////////////////////
301
302using namespace android;
303
304static sp<JMediaExtractor> setMediaExtractor(
305 JNIEnv *env, jobject thiz, const sp<JMediaExtractor> &extractor) {
306 sp<JMediaExtractor> old =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000307 (JMediaExtractor *)env->GetLongField(thiz, gFields.context);
Andreas Huber88572f72012-02-21 11:47:18 -0800308
309 if (extractor != NULL) {
310 extractor->incStrong(thiz);
311 }
312 if (old != NULL) {
313 old->decStrong(thiz);
314 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000315 env->SetLongField(thiz, gFields.context, (jlong)extractor.get());
Andreas Huber88572f72012-02-21 11:47:18 -0800316
317 return old;
318}
319
320static sp<JMediaExtractor> getMediaExtractor(JNIEnv *env, jobject thiz) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000321 return (JMediaExtractor *)env->GetLongField(thiz, gFields.context);
Andreas Huber88572f72012-02-21 11:47:18 -0800322}
323
324static void android_media_MediaExtractor_release(JNIEnv *env, jobject thiz) {
325 setMediaExtractor(env, thiz, NULL);
326}
327
Andreas Huber60d610b2012-05-02 16:06:09 -0700328static jint android_media_MediaExtractor_getTrackCount(
Andreas Huber88572f72012-02-21 11:47:18 -0800329 JNIEnv *env, jobject thiz) {
330 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
331
332 if (extractor == NULL) {
333 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Andreas Huber07ea4262012-04-11 12:21:20 -0700334 return -1;
Andreas Huber88572f72012-02-21 11:47:18 -0800335 }
336
Ashok Bhat075e9a12014-01-06 13:45:09 +0000337 return (jint) extractor->countTracks();
Andreas Huber88572f72012-02-21 11:47:18 -0800338}
339
Andreas Huber60d610b2012-05-02 16:06:09 -0700340static jobject android_media_MediaExtractor_getTrackFormatNative(
Andreas Huber88572f72012-02-21 11:47:18 -0800341 JNIEnv *env, jobject thiz, jint index) {
342 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
343
344 if (extractor == NULL) {
345 jniThrowException(env, "java/lang/IllegalStateException", NULL);
346 return NULL;
347 }
348
349 jobject format;
350 status_t err = extractor->getTrackFormat(index, &format);
351
352 if (err != OK) {
353 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
354 return NULL;
355 }
356
357 return format;
358}
359
Marco Nelissene20a6d52013-04-08 14:28:55 -0700360static jobject android_media_MediaExtractor_getFileFormatNative(
361 JNIEnv *env, jobject thiz) {
362 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
363
364 if (extractor == NULL) {
365 jniThrowException(env, "java/lang/IllegalStateException", NULL);
366 return NULL;
367 }
368
369 jobject format;
370 status_t err = extractor->getFileFormat(&format);
371
372 if (err != OK) {
373 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
374 return NULL;
375 }
376
377 return format;
378}
379
Andreas Huber88572f72012-02-21 11:47:18 -0800380static void android_media_MediaExtractor_selectTrack(
381 JNIEnv *env, jobject thiz, jint index) {
382 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
383
384 if (extractor == NULL) {
385 jniThrowException(env, "java/lang/IllegalStateException", NULL);
386 return;
387 }
388
389 status_t err = extractor->selectTrack(index);
390
391 if (err != OK) {
392 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
393 return;
394 }
395}
396
Andreas Huberf2855b32012-04-25 15:57:43 -0700397static void android_media_MediaExtractor_unselectTrack(
398 JNIEnv *env, jobject thiz, jint index) {
Andreas Huber88572f72012-02-21 11:47:18 -0800399 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
400
401 if (extractor == NULL) {
402 jniThrowException(env, "java/lang/IllegalStateException", NULL);
403 return;
404 }
405
Andreas Huberf2855b32012-04-25 15:57:43 -0700406 status_t err = extractor->unselectTrack(index);
407
408 if (err != OK) {
409 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
410 return;
411 }
412}
413
414static void android_media_MediaExtractor_seekTo(
415 JNIEnv *env, jobject thiz, jlong timeUs, jint mode) {
416 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
417
418 if (extractor == NULL) {
419 jniThrowException(env, "java/lang/IllegalStateException", NULL);
420 return;
421 }
422
423 if (mode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC
Andreas Huberf86374a2012-05-09 11:25:29 -0700424 || mode >= MediaSource::ReadOptions::SEEK_CLOSEST) {
Andreas Huberf2855b32012-04-25 15:57:43 -0700425 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
426 return;
427 }
428
429 extractor->seekTo(timeUs, (MediaSource::ReadOptions::SeekMode)mode);
Andreas Huber88572f72012-02-21 11:47:18 -0800430}
431
432static jboolean android_media_MediaExtractor_advance(
433 JNIEnv *env, jobject thiz) {
434 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
435
436 if (extractor == NULL) {
437 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000438 return JNI_FALSE;
Andreas Huber88572f72012-02-21 11:47:18 -0800439 }
440
441 status_t err = extractor->advance();
442
443 if (err == ERROR_END_OF_STREAM) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000444 return JNI_FALSE;
Andreas Huber88572f72012-02-21 11:47:18 -0800445 } else if (err != OK) {
446 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000447 return JNI_FALSE;
Andreas Huber88572f72012-02-21 11:47:18 -0800448 }
449
Ashok Bhat075e9a12014-01-06 13:45:09 +0000450 return JNI_TRUE;
Andreas Huber88572f72012-02-21 11:47:18 -0800451}
452
453static jint android_media_MediaExtractor_readSampleData(
454 JNIEnv *env, jobject thiz, jobject byteBuf, jint offset) {
455 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
456
457 if (extractor == NULL) {
458 jniThrowException(env, "java/lang/IllegalStateException", NULL);
459 return -1;
460 }
461
462 size_t sampleSize;
463 status_t err = extractor->readSampleData(byteBuf, offset, &sampleSize);
464
465 if (err == ERROR_END_OF_STREAM) {
466 return -1;
467 } else if (err != OK) {
468 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000469 return -1;
Andreas Huber88572f72012-02-21 11:47:18 -0800470 }
471
Ashok Bhat075e9a12014-01-06 13:45:09 +0000472 return (jint) sampleSize;
Andreas Huber88572f72012-02-21 11:47:18 -0800473}
474
475static jint android_media_MediaExtractor_getSampleTrackIndex(
476 JNIEnv *env, jobject thiz) {
477 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
478
479 if (extractor == NULL) {
480 jniThrowException(env, "java/lang/IllegalStateException", NULL);
481 return -1;
482 }
483
484 size_t trackIndex;
485 status_t err = extractor->getSampleTrackIndex(&trackIndex);
486
487 if (err == ERROR_END_OF_STREAM) {
488 return -1;
489 } else if (err != OK) {
490 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000491 return -1;
Andreas Huber88572f72012-02-21 11:47:18 -0800492 }
493
Ashok Bhat075e9a12014-01-06 13:45:09 +0000494 return (jint) trackIndex;
Andreas Huber88572f72012-02-21 11:47:18 -0800495}
496
497static jlong android_media_MediaExtractor_getSampleTime(
498 JNIEnv *env, jobject thiz) {
499 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
500
501 if (extractor == NULL) {
502 jniThrowException(env, "java/lang/IllegalStateException", NULL);
503 return -1ll;
504 }
505
506 int64_t sampleTimeUs;
507 status_t err = extractor->getSampleTime(&sampleTimeUs);
508
509 if (err == ERROR_END_OF_STREAM) {
510 return -1ll;
511 } else if (err != OK) {
512 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000513 return -1ll;
Andreas Huber88572f72012-02-21 11:47:18 -0800514 }
515
Ashok Bhat075e9a12014-01-06 13:45:09 +0000516 return (jlong) sampleTimeUs;
Andreas Huber88572f72012-02-21 11:47:18 -0800517}
518
Andreas Huber9b8e4962012-03-26 11:13:27 -0700519static jint android_media_MediaExtractor_getSampleFlags(
520 JNIEnv *env, jobject thiz) {
521 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
522
523 if (extractor == NULL) {
524 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000525 return -1;
Andreas Huber9b8e4962012-03-26 11:13:27 -0700526 }
527
528 uint32_t sampleFlags;
529 status_t err = extractor->getSampleFlags(&sampleFlags);
530
531 if (err == ERROR_END_OF_STREAM) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000532 return -1;
Andreas Huber9b8e4962012-03-26 11:13:27 -0700533 } else if (err != OK) {
534 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000535 return -1;
Andreas Huber9b8e4962012-03-26 11:13:27 -0700536 }
537
Ashok Bhat075e9a12014-01-06 13:45:09 +0000538 return (jint) sampleFlags;
Andreas Huber9b8e4962012-03-26 11:13:27 -0700539}
540
Andreas Huber91befdc2012-04-18 12:19:51 -0700541static jboolean android_media_MediaExtractor_getSampleCryptoInfo(
542 JNIEnv *env, jobject thiz, jobject cryptoInfoObj) {
543 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
544
545 if (extractor == NULL) {
546 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000547 return JNI_FALSE;
Andreas Huber91befdc2012-04-18 12:19:51 -0700548 }
549
550 sp<MetaData> meta;
551 status_t err = extractor->getSampleMeta(&meta);
552
553 if (err != OK) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000554 return JNI_FALSE;
Andreas Huber91befdc2012-04-18 12:19:51 -0700555 }
556
557 uint32_t type;
558 const void *data;
559 size_t size;
560 if (!meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000561 return JNI_FALSE;
Andreas Huber91befdc2012-04-18 12:19:51 -0700562 }
563
Ashok Bhate92416d2014-03-05 11:51:15 +0000564 size_t numSubSamples = size / sizeof(int32_t);
Andreas Huber91befdc2012-04-18 12:19:51 -0700565
566 if (numSubSamples == 0) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000567 return JNI_FALSE;
Andreas Huber91befdc2012-04-18 12:19:51 -0700568 }
569
570 jintArray numBytesOfEncryptedDataObj = env->NewIntArray(numSubSamples);
571 jboolean isCopy;
572 jint *dst = env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
573 for (size_t i = 0; i < numSubSamples; ++i) {
Ashok Bhate92416d2014-03-05 11:51:15 +0000574 dst[i] = ((const int32_t *)data)[i];
Andreas Huber91befdc2012-04-18 12:19:51 -0700575 }
576 env->ReleaseIntArrayElements(numBytesOfEncryptedDataObj, dst, 0);
577 dst = NULL;
578
579 size_t encSize = size;
580 jintArray numBytesOfPlainDataObj = NULL;
Andreas Huberab57d032012-04-18 15:59:43 -0700581 if (meta->findData(kKeyPlainSizes, &type, &data, &size)) {
Andreas Huber91befdc2012-04-18 12:19:51 -0700582 if (size != encSize) {
583 // The two must be of the same length.
Ashok Bhat075e9a12014-01-06 13:45:09 +0000584 return JNI_FALSE;
Andreas Huber91befdc2012-04-18 12:19:51 -0700585 }
586
587 numBytesOfPlainDataObj = env->NewIntArray(numSubSamples);
588 jboolean isCopy;
589 jint *dst = env->GetIntArrayElements(numBytesOfPlainDataObj, &isCopy);
590 for (size_t i = 0; i < numSubSamples; ++i) {
Ashok Bhate92416d2014-03-05 11:51:15 +0000591 dst[i] = ((const int32_t *)data)[i];
Andreas Huber91befdc2012-04-18 12:19:51 -0700592 }
593 env->ReleaseIntArrayElements(numBytesOfPlainDataObj, dst, 0);
594 dst = NULL;
595 }
596
597 jbyteArray keyObj = NULL;
598 if (meta->findData(kKeyCryptoKey, &type, &data, &size)) {
599 if (size != 16) {
600 // Keys must be 16 bytes in length.
Ashok Bhat075e9a12014-01-06 13:45:09 +0000601 return JNI_FALSE;
Andreas Huber91befdc2012-04-18 12:19:51 -0700602 }
603
604 keyObj = env->NewByteArray(size);
605 jboolean isCopy;
606 jbyte *dst = env->GetByteArrayElements(keyObj, &isCopy);
607 memcpy(dst, data, size);
608 env->ReleaseByteArrayElements(keyObj, dst, 0);
609 dst = NULL;
610 }
611
612 jbyteArray ivObj = NULL;
613 if (meta->findData(kKeyCryptoIV, &type, &data, &size)) {
614 if (size != 16) {
615 // IVs must be 16 bytes in length.
Ashok Bhat075e9a12014-01-06 13:45:09 +0000616 return JNI_FALSE;
Andreas Huber91befdc2012-04-18 12:19:51 -0700617 }
618
619 ivObj = env->NewByteArray(size);
620 jboolean isCopy;
621 jbyte *dst = env->GetByteArrayElements(ivObj, &isCopy);
622 memcpy(dst, data, size);
623 env->ReleaseByteArrayElements(ivObj, dst, 0);
624 dst = NULL;
625 }
626
627 int32_t mode;
628 if (!meta->findInt32(kKeyCryptoMode, &mode)) {
Andreas Huberab57d032012-04-18 15:59:43 -0700629 mode = CryptoPlugin::kMode_AES_CTR;
Andreas Huber91befdc2012-04-18 12:19:51 -0700630 }
631
632 env->CallVoidMethod(
633 cryptoInfoObj,
634 gFields.cryptoInfoSetID,
Ashok Bhat136c08a2014-03-05 15:23:13 +0000635 (jint)numSubSamples,
Andreas Huber91befdc2012-04-18 12:19:51 -0700636 numBytesOfPlainDataObj,
637 numBytesOfEncryptedDataObj,
638 keyObj,
639 ivObj,
640 mode);
641
Ashok Bhat075e9a12014-01-06 13:45:09 +0000642 return JNI_TRUE;
Andreas Huber91befdc2012-04-18 12:19:51 -0700643}
644
Andreas Huber88572f72012-02-21 11:47:18 -0800645static void android_media_MediaExtractor_native_init(JNIEnv *env) {
646 jclass clazz = env->FindClass("android/media/MediaExtractor");
647 CHECK(clazz != NULL);
648
Ashok Bhat075e9a12014-01-06 13:45:09 +0000649 gFields.context = env->GetFieldID(clazz, "mNativeContext", "J");
Andreas Huber88572f72012-02-21 11:47:18 -0800650 CHECK(gFields.context != NULL);
651
Andreas Huber91befdc2012-04-18 12:19:51 -0700652 clazz = env->FindClass("android/media/MediaCodec$CryptoInfo");
653 CHECK(clazz != NULL);
654
655 gFields.cryptoInfoSetID =
656 env->GetMethodID(clazz, "set", "(I[I[I[B[BI)V");
657
Andreas Huber88572f72012-02-21 11:47:18 -0800658 DataSource::RegisterDefaultSniffers();
659}
660
661static void android_media_MediaExtractor_native_setup(
Andreas Huber07ea4262012-04-11 12:21:20 -0700662 JNIEnv *env, jobject thiz) {
Andreas Huber88572f72012-02-21 11:47:18 -0800663 sp<JMediaExtractor> extractor = new JMediaExtractor(env, thiz);
Andreas Huber07ea4262012-04-11 12:21:20 -0700664 setMediaExtractor(env,thiz, extractor);
665}
Andreas Huber88572f72012-02-21 11:47:18 -0800666
Andreas Huber07ea4262012-04-11 12:21:20 -0700667static void android_media_MediaExtractor_setDataSource(
668 JNIEnv *env, jobject thiz,
Andreas Huberd2506a52014-01-29 10:32:46 -0800669 jobject httpServiceBinderObj,
670 jstring pathObj,
671 jobjectArray keysArray,
672 jobjectArray valuesArray) {
Andreas Huber07ea4262012-04-11 12:21:20 -0700673 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
674
675 if (extractor == NULL) {
676 jniThrowException(env, "java/lang/IllegalStateException", NULL);
677 return;
678 }
679
680 if (pathObj == NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800681 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
682 return;
683 }
684
Andreas Huber07ea4262012-04-11 12:21:20 -0700685 KeyedVector<String8, String8> headers;
686 if (!ConvertKeyValueArraysToKeyedVector(
687 env, keysArray, valuesArray, &headers)) {
Andreas Huber88572f72012-02-21 11:47:18 -0800688 return;
689 }
690
Andreas Huber07ea4262012-04-11 12:21:20 -0700691 const char *path = env->GetStringUTFChars(pathObj, NULL);
Andreas Huber88572f72012-02-21 11:47:18 -0800692
Andreas Huber07ea4262012-04-11 12:21:20 -0700693 if (path == NULL) {
694 return;
695 }
696
Andreas Huberd2506a52014-01-29 10:32:46 -0800697 sp<IMediaHTTPService> httpService;
698 if (httpServiceBinderObj != NULL) {
699 sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj);
700 httpService = interface_cast<IMediaHTTPService>(binder);
701 }
702
703 status_t err = extractor->setDataSource(httpService, path, &headers);
Andreas Huber07ea4262012-04-11 12:21:20 -0700704
705 env->ReleaseStringUTFChars(pathObj, path);
706 path = NULL;
Andreas Huber88572f72012-02-21 11:47:18 -0800707
708 if (err != OK) {
709 jniThrowException(
710 env,
711 "java/io/IOException",
712 "Failed to instantiate extractor.");
713 return;
714 }
Andreas Huber07ea4262012-04-11 12:21:20 -0700715}
Andreas Huber88572f72012-02-21 11:47:18 -0800716
Andreas Huber07ea4262012-04-11 12:21:20 -0700717static void android_media_MediaExtractor_setDataSourceFd(
718 JNIEnv *env, jobject thiz,
719 jobject fileDescObj, jlong offset, jlong length) {
720 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
721
722 if (extractor == NULL) {
723 jniThrowException(env, "java/lang/IllegalStateException", NULL);
724 return;
725 }
726
727 if (fileDescObj == NULL) {
728 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
729 return;
730 }
731
732 int fd = jniGetFDFromFileDescriptor(env, fileDescObj);
733
734 status_t err = extractor->setDataSource(fd, offset, length);
735
736 if (err != OK) {
737 jniThrowException(
738 env,
739 "java/io/IOException",
740 "Failed to instantiate extractor.");
741 return;
742 }
Andreas Huber88572f72012-02-21 11:47:18 -0800743}
744
Marco Nelissenc209a062012-08-24 09:55:44 -0700745static void android_media_MediaExtractor_setDataSourceCallback(
746 JNIEnv *env, jobject thiz,
747 jobject callbackObj) {
748 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
749
750 if (extractor == NULL) {
751 jniThrowException(env, "java/lang/IllegalStateException", NULL);
752 return;
753 }
754
755 if (callbackObj == NULL) {
756 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
757 return;
758 }
759
760 sp<JavaDataSourceBridge> bridge = new JavaDataSourceBridge(env, callbackObj);
761 status_t err = extractor->setDataSource(bridge);
762
763 if (err != OK) {
764 jniThrowException(
765 env,
766 "java/io/IOException",
767 "Failed to instantiate extractor.");
768 return;
769 }
770}
771
Andreas Huber74a78b02012-04-19 16:24:32 -0700772static 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
Ashok Bhat075e9a12014-01-06 13:45:09 +0000787 return (jlong) cachedDurationUs;
Andreas Huber74a78b02012-04-19 16:24:32 -0700788}
789
790static 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);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000796 return JNI_TRUE;
Andreas Huber74a78b02012-04-19 16:24:32 -0700797 }
798
799 int64_t cachedDurationUs;
800 bool eos;
801 if (!extractor->getCachedDuration(&cachedDurationUs, &eos)) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000802 return JNI_TRUE;
Andreas Huber74a78b02012-04-19 16:24:32 -0700803 }
804
Ashok Bhat075e9a12014-01-06 13:45:09 +0000805 return eos ? JNI_TRUE : JNI_FALSE;
Andreas Huber74a78b02012-04-19 16:24:32 -0700806}
807
Andreas Huber88572f72012-02-21 11:47:18 -0800808static void android_media_MediaExtractor_native_finalize(
809 JNIEnv *env, jobject thiz) {
810 android_media_MediaExtractor_release(env, thiz);
811}
812
813static JNINativeMethod gMethods[] = {
814 { "release", "()V", (void *)android_media_MediaExtractor_release },
815
Andreas Huber60d610b2012-05-02 16:06:09 -0700816 { "getTrackCount", "()I", (void *)android_media_MediaExtractor_getTrackCount },
Andreas Huber88572f72012-02-21 11:47:18 -0800817
Marco Nelissene20a6d52013-04-08 14:28:55 -0700818 { "getFileFormatNative", "()Ljava/util/Map;",
819 (void *)android_media_MediaExtractor_getFileFormatNative },
820
Andreas Huber60d610b2012-05-02 16:06:09 -0700821 { "getTrackFormatNative", "(I)Ljava/util/Map;",
822 (void *)android_media_MediaExtractor_getTrackFormatNative },
Andreas Huber88572f72012-02-21 11:47:18 -0800823
824 { "selectTrack", "(I)V", (void *)android_media_MediaExtractor_selectTrack },
825
Andreas Huberf2855b32012-04-25 15:57:43 -0700826 { "unselectTrack", "(I)V",
827 (void *)android_media_MediaExtractor_unselectTrack },
828
829 { "seekTo", "(JI)V", (void *)android_media_MediaExtractor_seekTo },
Andreas Huber88572f72012-02-21 11:47:18 -0800830
831 { "advance", "()Z", (void *)android_media_MediaExtractor_advance },
832
833 { "readSampleData", "(Ljava/nio/ByteBuffer;I)I",
834 (void *)android_media_MediaExtractor_readSampleData },
835
836 { "getSampleTrackIndex", "()I",
837 (void *)android_media_MediaExtractor_getSampleTrackIndex },
838
839 { "getSampleTime", "()J",
840 (void *)android_media_MediaExtractor_getSampleTime },
841
Andreas Huber9b8e4962012-03-26 11:13:27 -0700842 { "getSampleFlags", "()I",
843 (void *)android_media_MediaExtractor_getSampleFlags },
844
Andreas Huber91befdc2012-04-18 12:19:51 -0700845 { "getSampleCryptoInfo", "(Landroid/media/MediaCodec$CryptoInfo;)Z",
846 (void *)android_media_MediaExtractor_getSampleCryptoInfo },
847
Andreas Huber88572f72012-02-21 11:47:18 -0800848 { "native_init", "()V", (void *)android_media_MediaExtractor_native_init },
849
Andreas Huber07ea4262012-04-11 12:21:20 -0700850 { "native_setup", "()V",
Andreas Huber88572f72012-02-21 11:47:18 -0800851 (void *)android_media_MediaExtractor_native_setup },
852
853 { "native_finalize", "()V",
854 (void *)android_media_MediaExtractor_native_finalize },
Andreas Huber07ea4262012-04-11 12:21:20 -0700855
Andreas Huberd2506a52014-01-29 10:32:46 -0800856 { "nativeSetDataSource",
857 "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
858 "[Ljava/lang/String;)V",
Andreas Huber07ea4262012-04-11 12:21:20 -0700859 (void *)android_media_MediaExtractor_setDataSource },
860
861 { "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
862 (void *)android_media_MediaExtractor_setDataSourceFd },
Andreas Huber74a78b02012-04-19 16:24:32 -0700863
Marco Nelissenc209a062012-08-24 09:55:44 -0700864 { "setDataSource", "(Landroid/media/DataSource;)V",
865 (void *)android_media_MediaExtractor_setDataSourceCallback },
866
Andreas Huber74a78b02012-04-19 16:24:32 -0700867 { "getCachedDuration", "()J",
868 (void *)android_media_MediaExtractor_getCachedDurationUs },
869
870 { "hasCacheReachedEndOfStream", "()Z",
871 (void *)android_media_MediaExtractor_hasCacheReachedEOS },
Andreas Huber88572f72012-02-21 11:47:18 -0800872};
873
874int register_android_media_MediaExtractor(JNIEnv *env) {
875 return AndroidRuntime::registerNativeMethods(env,
876 "android/media/MediaExtractor", gMethods, NELEM(gMethods));
877}