blob: bf3d44aaec2145abedcc25dc628afd40d9f785df [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"
25#include "jni.h"
26#include "JNIHelp.h"
27
Andreas Huberab57d032012-04-18 15:59:43 -070028#include <media/hardware/CryptoAPI.h>
Andreas Huber88572f72012-02-21 11:47:18 -080029#include <media/stagefright/foundation/ABuffer.h>
30#include <media/stagefright/foundation/ADebug.h>
31#include <media/stagefright/foundation/AMessage.h>
32#include <media/stagefright/DataSource.h>
33#include <media/stagefright/MediaErrors.h>
Andreas Huber91befdc2012-04-18 12:19:51 -070034#include <media/stagefright/MetaData.h>
Andreas Huber88572f72012-02-21 11:47:18 -080035#include <media/stagefright/NuMediaExtractor.h>
36
37namespace android {
38
39struct fields_t {
40 jfieldID context;
Andreas Huber91befdc2012-04-18 12:19:51 -070041
42 jmethodID cryptoInfoSetID;
Andreas Huber88572f72012-02-21 11:47:18 -080043};
44
45static fields_t gFields;
46
47////////////////////////////////////////////////////////////////////////////////
48
49JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz)
50 : mClass(NULL),
51 mObject(NULL) {
52 jclass clazz = env->GetObjectClass(thiz);
53 CHECK(clazz != NULL);
54
55 mClass = (jclass)env->NewGlobalRef(clazz);
56 mObject = env->NewWeakGlobalRef(thiz);
57
58 mImpl = new NuMediaExtractor;
59}
60
61JMediaExtractor::~JMediaExtractor() {
62 JNIEnv *env = AndroidRuntime::getJNIEnv();
63
64 env->DeleteWeakGlobalRef(mObject);
65 mObject = NULL;
66 env->DeleteGlobalRef(mClass);
67 mClass = NULL;
68}
69
Andreas Huber07ea4262012-04-11 12:21:20 -070070status_t JMediaExtractor::setDataSource(
71 const char *path, const KeyedVector<String8, String8> *headers) {
72 return mImpl->setDataSource(path, headers);
73}
74
75status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
76 return mImpl->setDataSource(fd, offset, size);
Andreas Huber88572f72012-02-21 11:47:18 -080077}
78
79size_t JMediaExtractor::countTracks() const {
80 return mImpl->countTracks();
81}
82
83status_t JMediaExtractor::getTrackFormat(size_t index, jobject *format) const {
84 sp<AMessage> msg;
85 status_t err;
86 if ((err = mImpl->getTrackFormat(index, &msg)) != OK) {
87 return err;
88 }
89
90 JNIEnv *env = AndroidRuntime::getJNIEnv();
91
92 return ConvertMessageToMap(env, msg, format);
93}
94
95status_t JMediaExtractor::selectTrack(size_t index) {
96 return mImpl->selectTrack(index);
97}
98
99status_t JMediaExtractor::seekTo(int64_t timeUs) {
100 return mImpl->seekTo(timeUs);
101}
102
103status_t JMediaExtractor::advance() {
104 return mImpl->advance();
105}
106
107status_t JMediaExtractor::readSampleData(
108 jobject byteBuf, size_t offset, size_t *sampleSize) {
109 JNIEnv *env = AndroidRuntime::getJNIEnv();
110
111 void *dst = env->GetDirectBufferAddress(byteBuf);
112
Andreas Huberc52b9802012-03-12 14:04:01 -0700113 jlong dstSize;
114 jbyteArray byteArray = NULL;
115
Andreas Huber88572f72012-02-21 11:47:18 -0800116 if (dst == NULL) {
Andreas Huberc52b9802012-03-12 14:04:01 -0700117 jclass byteBufClass = env->FindClass("java/nio/ByteBuffer");
118 CHECK(byteBufClass != NULL);
119
120 jmethodID arrayID =
121 env->GetMethodID(byteBufClass, "array", "()[B");
122 CHECK(arrayID != NULL);
123
124 byteArray =
125 (jbyteArray)env->CallObjectMethod(byteBuf, arrayID);
126
127 if (byteArray == NULL) {
128 return INVALID_OPERATION;
129 }
130
131 jboolean isCopy;
132 dst = env->GetByteArrayElements(byteArray, &isCopy);
133
134 dstSize = env->GetArrayLength(byteArray);
135 } else {
136 dstSize = env->GetDirectBufferCapacity(byteBuf);
Andreas Huber88572f72012-02-21 11:47:18 -0800137 }
138
Andreas Huber88572f72012-02-21 11:47:18 -0800139 if (dstSize < offset) {
Andreas Huberc52b9802012-03-12 14:04:01 -0700140 if (byteArray != NULL) {
141 env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0);
142 }
143
Andreas Huber88572f72012-02-21 11:47:18 -0800144 return -ERANGE;
145 }
146
147 sp<ABuffer> buffer = new ABuffer((char *)dst + offset, dstSize - offset);
148
149 status_t err = mImpl->readSampleData(buffer);
150
Andreas Huberc52b9802012-03-12 14:04:01 -0700151 if (byteArray != NULL) {
152 env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0);
153 }
154
Andreas Huber88572f72012-02-21 11:47:18 -0800155 if (err != OK) {
156 return err;
157 }
158
159 *sampleSize = buffer->size();
160
161 return OK;
162}
163
164status_t JMediaExtractor::getSampleTrackIndex(size_t *trackIndex) {
165 return mImpl->getSampleTrackIndex(trackIndex);
166}
167
168status_t JMediaExtractor::getSampleTime(int64_t *sampleTimeUs) {
169 return mImpl->getSampleTime(sampleTimeUs);
170}
171
Andreas Huber9b8e4962012-03-26 11:13:27 -0700172status_t JMediaExtractor::getSampleFlags(uint32_t *sampleFlags) {
Andreas Huber91befdc2012-04-18 12:19:51 -0700173 *sampleFlags = 0;
174
175 sp<MetaData> meta;
176 status_t err = mImpl->getSampleMeta(&meta);
177
178 if (err != OK) {
179 return err;
180 }
181
182 int32_t val;
183 if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) {
184 (*sampleFlags) |= NuMediaExtractor::SAMPLE_FLAG_SYNC;
185 }
186
187 uint32_t type;
188 const void *data;
189 size_t size;
190 if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
191 (*sampleFlags) |= NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED;
192 }
193
194 return OK;
195}
196
197status_t JMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) {
198 return mImpl->getSampleMeta(sampleMeta);
Andreas Huber9b8e4962012-03-26 11:13:27 -0700199}
200
Andreas Huber88572f72012-02-21 11:47:18 -0800201} // namespace android
202
203////////////////////////////////////////////////////////////////////////////////
204
205using namespace android;
206
207static sp<JMediaExtractor> setMediaExtractor(
208 JNIEnv *env, jobject thiz, const sp<JMediaExtractor> &extractor) {
209 sp<JMediaExtractor> old =
210 (JMediaExtractor *)env->GetIntField(thiz, gFields.context);
211
212 if (extractor != NULL) {
213 extractor->incStrong(thiz);
214 }
215 if (old != NULL) {
216 old->decStrong(thiz);
217 }
218 env->SetIntField(thiz, gFields.context, (int)extractor.get());
219
220 return old;
221}
222
223static sp<JMediaExtractor> getMediaExtractor(JNIEnv *env, jobject thiz) {
224 return (JMediaExtractor *)env->GetIntField(thiz, gFields.context);
225}
226
227static void android_media_MediaExtractor_release(JNIEnv *env, jobject thiz) {
228 setMediaExtractor(env, thiz, NULL);
229}
230
231static jint android_media_MediaExtractor_countTracks(
232 JNIEnv *env, jobject thiz) {
233 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
234
235 if (extractor == NULL) {
236 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Andreas Huber07ea4262012-04-11 12:21:20 -0700237 return -1;
Andreas Huber88572f72012-02-21 11:47:18 -0800238 }
239
240 return extractor->countTracks();
241}
242
243static jobject android_media_MediaExtractor_getTrackFormat(
244 JNIEnv *env, jobject thiz, jint index) {
245 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
246
247 if (extractor == NULL) {
248 jniThrowException(env, "java/lang/IllegalStateException", NULL);
249 return NULL;
250 }
251
252 jobject format;
253 status_t err = extractor->getTrackFormat(index, &format);
254
255 if (err != OK) {
256 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
257 return NULL;
258 }
259
260 return format;
261}
262
263static void android_media_MediaExtractor_selectTrack(
264 JNIEnv *env, jobject thiz, jint index) {
265 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
266
267 if (extractor == NULL) {
268 jniThrowException(env, "java/lang/IllegalStateException", NULL);
269 return;
270 }
271
272 status_t err = extractor->selectTrack(index);
273
274 if (err != OK) {
275 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
276 return;
277 }
278}
279
280static void android_media_MediaExtractor_seekTo(
281 JNIEnv *env, jobject thiz, jlong timeUs) {
282 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
283
284 if (extractor == NULL) {
285 jniThrowException(env, "java/lang/IllegalStateException", NULL);
286 return;
287 }
288
Andreas Huber2b9d6bd2012-04-17 15:02:22 -0700289 extractor->seekTo(timeUs);
Andreas Huber88572f72012-02-21 11:47:18 -0800290}
291
292static jboolean android_media_MediaExtractor_advance(
293 JNIEnv *env, jobject thiz) {
294 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
295
296 if (extractor == NULL) {
297 jniThrowException(env, "java/lang/IllegalStateException", NULL);
298 return false;
299 }
300
301 status_t err = extractor->advance();
302
303 if (err == ERROR_END_OF_STREAM) {
304 return false;
305 } else if (err != OK) {
306 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
307 return false;
308 }
309
310 return true;
311}
312
313static jint android_media_MediaExtractor_readSampleData(
314 JNIEnv *env, jobject thiz, jobject byteBuf, jint offset) {
315 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
316
317 if (extractor == NULL) {
318 jniThrowException(env, "java/lang/IllegalStateException", NULL);
319 return -1;
320 }
321
322 size_t sampleSize;
323 status_t err = extractor->readSampleData(byteBuf, offset, &sampleSize);
324
325 if (err == ERROR_END_OF_STREAM) {
326 return -1;
327 } else if (err != OK) {
328 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
329 return false;
330 }
331
332 return sampleSize;
333}
334
335static jint android_media_MediaExtractor_getSampleTrackIndex(
336 JNIEnv *env, jobject thiz) {
337 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
338
339 if (extractor == NULL) {
340 jniThrowException(env, "java/lang/IllegalStateException", NULL);
341 return -1;
342 }
343
344 size_t trackIndex;
345 status_t err = extractor->getSampleTrackIndex(&trackIndex);
346
347 if (err == ERROR_END_OF_STREAM) {
348 return -1;
349 } else if (err != OK) {
350 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
351 return false;
352 }
353
354 return trackIndex;
355}
356
357static jlong android_media_MediaExtractor_getSampleTime(
358 JNIEnv *env, jobject thiz) {
359 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
360
361 if (extractor == NULL) {
362 jniThrowException(env, "java/lang/IllegalStateException", NULL);
363 return -1ll;
364 }
365
366 int64_t sampleTimeUs;
367 status_t err = extractor->getSampleTime(&sampleTimeUs);
368
369 if (err == ERROR_END_OF_STREAM) {
370 return -1ll;
371 } else if (err != OK) {
372 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
373 return false;
374 }
375
376 return sampleTimeUs;
377}
378
Andreas Huber9b8e4962012-03-26 11:13:27 -0700379static jint android_media_MediaExtractor_getSampleFlags(
380 JNIEnv *env, jobject thiz) {
381 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
382
383 if (extractor == NULL) {
384 jniThrowException(env, "java/lang/IllegalStateException", NULL);
385 return -1ll;
386 }
387
388 uint32_t sampleFlags;
389 status_t err = extractor->getSampleFlags(&sampleFlags);
390
391 if (err == ERROR_END_OF_STREAM) {
392 return -1ll;
393 } else if (err != OK) {
394 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
395 return false;
396 }
397
398 return sampleFlags;
399}
400
Andreas Huber91befdc2012-04-18 12:19:51 -0700401static jboolean android_media_MediaExtractor_getSampleCryptoInfo(
402 JNIEnv *env, jobject thiz, jobject cryptoInfoObj) {
403 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
404
405 if (extractor == NULL) {
406 jniThrowException(env, "java/lang/IllegalStateException", NULL);
407 return -1ll;
408 }
409
410 sp<MetaData> meta;
411 status_t err = extractor->getSampleMeta(&meta);
412
413 if (err != OK) {
414 return false;
415 }
416
417 uint32_t type;
418 const void *data;
419 size_t size;
420 if (!meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
421 return false;
422 }
423
424 size_t numSubSamples = size / sizeof(size_t);
425
426 if (numSubSamples == 0) {
427 return false;
428 }
429
430 jintArray numBytesOfEncryptedDataObj = env->NewIntArray(numSubSamples);
431 jboolean isCopy;
432 jint *dst = env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
433 for (size_t i = 0; i < numSubSamples; ++i) {
434 dst[i] = ((const size_t *)data)[i];
435 }
436 env->ReleaseIntArrayElements(numBytesOfEncryptedDataObj, dst, 0);
437 dst = NULL;
438
439 size_t encSize = size;
440 jintArray numBytesOfPlainDataObj = NULL;
Andreas Huberab57d032012-04-18 15:59:43 -0700441 if (meta->findData(kKeyPlainSizes, &type, &data, &size)) {
Andreas Huber91befdc2012-04-18 12:19:51 -0700442 if (size != encSize) {
443 // The two must be of the same length.
444 return false;
445 }
446
447 numBytesOfPlainDataObj = env->NewIntArray(numSubSamples);
448 jboolean isCopy;
449 jint *dst = env->GetIntArrayElements(numBytesOfPlainDataObj, &isCopy);
450 for (size_t i = 0; i < numSubSamples; ++i) {
451 dst[i] = ((const size_t *)data)[i];
452 }
453 env->ReleaseIntArrayElements(numBytesOfPlainDataObj, dst, 0);
454 dst = NULL;
455 }
456
457 jbyteArray keyObj = NULL;
458 if (meta->findData(kKeyCryptoKey, &type, &data, &size)) {
459 if (size != 16) {
460 // Keys must be 16 bytes in length.
461 return false;
462 }
463
464 keyObj = env->NewByteArray(size);
465 jboolean isCopy;
466 jbyte *dst = env->GetByteArrayElements(keyObj, &isCopy);
467 memcpy(dst, data, size);
468 env->ReleaseByteArrayElements(keyObj, dst, 0);
469 dst = NULL;
470 }
471
472 jbyteArray ivObj = NULL;
473 if (meta->findData(kKeyCryptoIV, &type, &data, &size)) {
474 if (size != 16) {
475 // IVs must be 16 bytes in length.
476 return false;
477 }
478
479 ivObj = env->NewByteArray(size);
480 jboolean isCopy;
481 jbyte *dst = env->GetByteArrayElements(ivObj, &isCopy);
482 memcpy(dst, data, size);
483 env->ReleaseByteArrayElements(ivObj, dst, 0);
484 dst = NULL;
485 }
486
487 int32_t mode;
488 if (!meta->findInt32(kKeyCryptoMode, &mode)) {
Andreas Huberab57d032012-04-18 15:59:43 -0700489 mode = CryptoPlugin::kMode_AES_CTR;
Andreas Huber91befdc2012-04-18 12:19:51 -0700490 }
491
492 env->CallVoidMethod(
493 cryptoInfoObj,
494 gFields.cryptoInfoSetID,
495 numSubSamples,
496 numBytesOfPlainDataObj,
497 numBytesOfEncryptedDataObj,
498 keyObj,
499 ivObj,
500 mode);
501
502 return true;
503}
504
Andreas Huber88572f72012-02-21 11:47:18 -0800505static void android_media_MediaExtractor_native_init(JNIEnv *env) {
506 jclass clazz = env->FindClass("android/media/MediaExtractor");
507 CHECK(clazz != NULL);
508
509 gFields.context = env->GetFieldID(clazz, "mNativeContext", "I");
510 CHECK(gFields.context != NULL);
511
Andreas Huber91befdc2012-04-18 12:19:51 -0700512 clazz = env->FindClass("android/media/MediaCodec$CryptoInfo");
513 CHECK(clazz != NULL);
514
515 gFields.cryptoInfoSetID =
516 env->GetMethodID(clazz, "set", "(I[I[I[B[BI)V");
517
Andreas Huber88572f72012-02-21 11:47:18 -0800518 DataSource::RegisterDefaultSniffers();
519}
520
521static void android_media_MediaExtractor_native_setup(
Andreas Huber07ea4262012-04-11 12:21:20 -0700522 JNIEnv *env, jobject thiz) {
Andreas Huber88572f72012-02-21 11:47:18 -0800523 sp<JMediaExtractor> extractor = new JMediaExtractor(env, thiz);
Andreas Huber07ea4262012-04-11 12:21:20 -0700524 setMediaExtractor(env,thiz, extractor);
525}
Andreas Huber88572f72012-02-21 11:47:18 -0800526
Andreas Huber07ea4262012-04-11 12:21:20 -0700527static void android_media_MediaExtractor_setDataSource(
528 JNIEnv *env, jobject thiz,
529 jstring pathObj, jobjectArray keysArray, jobjectArray valuesArray) {
530 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
531
532 if (extractor == NULL) {
533 jniThrowException(env, "java/lang/IllegalStateException", NULL);
534 return;
535 }
536
537 if (pathObj == NULL) {
Andreas Huber88572f72012-02-21 11:47:18 -0800538 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
539 return;
540 }
541
Andreas Huber07ea4262012-04-11 12:21:20 -0700542 KeyedVector<String8, String8> headers;
543 if (!ConvertKeyValueArraysToKeyedVector(
544 env, keysArray, valuesArray, &headers)) {
Andreas Huber88572f72012-02-21 11:47:18 -0800545 return;
546 }
547
Andreas Huber07ea4262012-04-11 12:21:20 -0700548 const char *path = env->GetStringUTFChars(pathObj, NULL);
Andreas Huber88572f72012-02-21 11:47:18 -0800549
Andreas Huber07ea4262012-04-11 12:21:20 -0700550 if (path == NULL) {
551 return;
552 }
553
554 status_t err = extractor->setDataSource(path, &headers);
555
556 env->ReleaseStringUTFChars(pathObj, path);
557 path = NULL;
Andreas Huber88572f72012-02-21 11:47:18 -0800558
559 if (err != OK) {
560 jniThrowException(
561 env,
562 "java/io/IOException",
563 "Failed to instantiate extractor.");
564 return;
565 }
Andreas Huber07ea4262012-04-11 12:21:20 -0700566}
Andreas Huber88572f72012-02-21 11:47:18 -0800567
Andreas Huber07ea4262012-04-11 12:21:20 -0700568static void android_media_MediaExtractor_setDataSourceFd(
569 JNIEnv *env, jobject thiz,
570 jobject fileDescObj, jlong offset, jlong length) {
571 sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
572
573 if (extractor == NULL) {
574 jniThrowException(env, "java/lang/IllegalStateException", NULL);
575 return;
576 }
577
578 if (fileDescObj == NULL) {
579 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
580 return;
581 }
582
583 int fd = jniGetFDFromFileDescriptor(env, fileDescObj);
584
585 status_t err = extractor->setDataSource(fd, offset, length);
586
587 if (err != OK) {
588 jniThrowException(
589 env,
590 "java/io/IOException",
591 "Failed to instantiate extractor.");
592 return;
593 }
Andreas Huber88572f72012-02-21 11:47:18 -0800594}
595
596static void android_media_MediaExtractor_native_finalize(
597 JNIEnv *env, jobject thiz) {
598 android_media_MediaExtractor_release(env, thiz);
599}
600
601static JNINativeMethod gMethods[] = {
602 { "release", "()V", (void *)android_media_MediaExtractor_release },
603
604 { "countTracks", "()I", (void *)android_media_MediaExtractor_countTracks },
605
606 { "getTrackFormat", "(I)Ljava/util/Map;",
607 (void *)android_media_MediaExtractor_getTrackFormat },
608
609 { "selectTrack", "(I)V", (void *)android_media_MediaExtractor_selectTrack },
610
611 { "seekTo", "(J)V", (void *)android_media_MediaExtractor_seekTo },
612
613 { "advance", "()Z", (void *)android_media_MediaExtractor_advance },
614
615 { "readSampleData", "(Ljava/nio/ByteBuffer;I)I",
616 (void *)android_media_MediaExtractor_readSampleData },
617
618 { "getSampleTrackIndex", "()I",
619 (void *)android_media_MediaExtractor_getSampleTrackIndex },
620
621 { "getSampleTime", "()J",
622 (void *)android_media_MediaExtractor_getSampleTime },
623
Andreas Huber9b8e4962012-03-26 11:13:27 -0700624 { "getSampleFlags", "()I",
625 (void *)android_media_MediaExtractor_getSampleFlags },
626
Andreas Huber91befdc2012-04-18 12:19:51 -0700627 { "getSampleCryptoInfo", "(Landroid/media/MediaCodec$CryptoInfo;)Z",
628 (void *)android_media_MediaExtractor_getSampleCryptoInfo },
629
Andreas Huber88572f72012-02-21 11:47:18 -0800630 { "native_init", "()V", (void *)android_media_MediaExtractor_native_init },
631
Andreas Huber07ea4262012-04-11 12:21:20 -0700632 { "native_setup", "()V",
Andreas Huber88572f72012-02-21 11:47:18 -0800633 (void *)android_media_MediaExtractor_native_setup },
634
635 { "native_finalize", "()V",
636 (void *)android_media_MediaExtractor_native_finalize },
Andreas Huber07ea4262012-04-11 12:21:20 -0700637
638 { "setDataSource", "(Ljava/lang/String;[Ljava/lang/String;"
639 "[Ljava/lang/String;)V",
640 (void *)android_media_MediaExtractor_setDataSource },
641
642 { "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
643 (void *)android_media_MediaExtractor_setDataSourceFd },
Andreas Huber88572f72012-02-21 11:47:18 -0800644};
645
646int register_android_media_MediaExtractor(JNIEnv *env) {
647 return AndroidRuntime::registerNativeMethods(env,
648 "android/media/MediaExtractor", gMethods, NELEM(gMethods));
649}