Skip to content

Commit c209a06

Browse files
committed
Let apps provide a custom data source for extractors
Adds android.media.DataSource, which is modeled after its native namesake, and a new method on MediaExtractor that lets apps specify their implementation of a DataSource as the source of data for the extractor. Change-Id: If1b169bd18d2691ebc4f8996494dfc8ee0894b6c
1 parent 6715d1e commit c209a06

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (C) 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+
18+
package android.media;
19+
20+
import java.io.Closeable;
21+
22+
/**
23+
* An abstraction for a media data source, e.g. a file or an http stream
24+
* {@hide}
25+
*/
26+
public interface DataSource extends Closeable {
27+
/**
28+
* Reads data from the data source at the requested position
29+
*
30+
* @param offset where in the source to read
31+
* @param buffer the buffer to read the data into
32+
* @param size how many bytes to read
33+
* @return the number of bytes read, or -1 if there was an error
34+
*/
35+
public int readAt(long offset, byte[] buffer, int size);
36+
37+
/**
38+
* Gets the size of the data source.
39+
*
40+
* @return size of data source, or -1 if the length is unknown
41+
*/
42+
public long getSize();
43+
}

media/java/android/media/MediaExtractor.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import android.media.MediaCodec;
2323
import android.media.MediaFormat;
2424
import android.net.Uri;
25+
2526
import java.io.FileDescriptor;
2627
import java.io.IOException;
2728
import java.nio.ByteBuffer;
@@ -59,6 +60,12 @@ public MediaExtractor() {
5960
native_setup();
6061
}
6162

63+
/**
64+
* Sets the DataSource object to be used as the data source for this extractor
65+
* {@hide}
66+
*/
67+
public native final void setDataSource(DataSource source);
68+
6269
/**
6370
* Sets the data source as a content Uri.
6471
*

media/jni/android_media_MediaExtractor.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,72 @@ struct fields_t {
4444

4545
static fields_t gFields;
4646

47+
class JavaDataSourceBridge : public DataSource {
48+
jmethodID mReadMethod;
49+
jmethodID mGetSizeMethod;
50+
jmethodID mCloseMethod;
51+
jobject mDataSource;
52+
public:
53+
JavaDataSourceBridge(JNIEnv *env, jobject source) {
54+
mDataSource = env->NewGlobalRef(source);
55+
56+
jclass datasourceclass = env->GetObjectClass(mDataSource);
57+
CHECK(datasourceclass != NULL);
58+
59+
mReadMethod = env->GetMethodID(datasourceclass, "readAt", "(J[BI)I");
60+
CHECK(mReadMethod != NULL);
61+
62+
mGetSizeMethod = env->GetMethodID(datasourceclass, "getSize", "()J");
63+
CHECK(mGetSizeMethod != NULL);
64+
65+
mCloseMethod = env->GetMethodID(datasourceclass, "close", "()V");
66+
CHECK(mCloseMethod != NULL);
67+
}
68+
69+
~JavaDataSourceBridge() {
70+
JNIEnv *env = AndroidRuntime::getJNIEnv();
71+
env->CallVoidMethod(mDataSource, mCloseMethod);
72+
env->DeleteGlobalRef(mDataSource);
73+
}
74+
75+
virtual status_t initCheck() const {
76+
return OK;
77+
}
78+
79+
virtual ssize_t readAt(off64_t offset, void* buffer, size_t size) {
80+
JNIEnv *env = AndroidRuntime::getJNIEnv();
81+
82+
// XXX could optimize this by reusing the same array
83+
jbyteArray byteArrayObj = env->NewByteArray(size);
84+
env->DeleteLocalRef(env->GetObjectClass(mDataSource));
85+
env->DeleteLocalRef(env->GetObjectClass(byteArrayObj));
86+
ssize_t numread = env->CallIntMethod(mDataSource, mReadMethod, offset, byteArrayObj, size);
87+
env->GetByteArrayRegion(byteArrayObj, 0, size, (jbyte*) buffer);
88+
env->DeleteLocalRef(byteArrayObj);
89+
if (env->ExceptionCheck()) {
90+
ALOGW("Exception occurred while reading %d at %lld", size, offset);
91+
LOGW_EX(env);
92+
env->ExceptionClear();
93+
return -1;
94+
}
95+
return numread;
96+
}
97+
98+
virtual status_t getSize(off64_t *size) {
99+
JNIEnv *env = AndroidRuntime::getJNIEnv();
100+
101+
CHECK(size != NULL);
102+
103+
int64_t len = env->CallLongMethod(mDataSource, mGetSizeMethod);
104+
if (len < 0) {
105+
*size = ERROR_UNSUPPORTED;
106+
} else {
107+
*size = len;
108+
}
109+
return OK;
110+
}
111+
};
112+
47113
////////////////////////////////////////////////////////////////////////////////
48114

49115
JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz)
@@ -76,6 +142,10 @@ status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
76142
return mImpl->setDataSource(fd, offset, size);
77143
}
78144

145+
status_t JMediaExtractor::setDataSource(const sp<DataSource> &datasource) {
146+
return mImpl->setDataSource(datasource);
147+
}
148+
79149
size_t JMediaExtractor::countTracks() const {
80150
return mImpl->countTracks();
81151
}
@@ -625,6 +695,33 @@ static void android_media_MediaExtractor_setDataSourceFd(
625695
}
626696
}
627697

698+
static void android_media_MediaExtractor_setDataSourceCallback(
699+
JNIEnv *env, jobject thiz,
700+
jobject callbackObj) {
701+
sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
702+
703+
if (extractor == NULL) {
704+
jniThrowException(env, "java/lang/IllegalStateException", NULL);
705+
return;
706+
}
707+
708+
if (callbackObj == NULL) {
709+
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
710+
return;
711+
}
712+
713+
sp<JavaDataSourceBridge> bridge = new JavaDataSourceBridge(env, callbackObj);
714+
status_t err = extractor->setDataSource(bridge);
715+
716+
if (err != OK) {
717+
jniThrowException(
718+
env,
719+
"java/io/IOException",
720+
"Failed to instantiate extractor.");
721+
return;
722+
}
723+
}
724+
628725
static jlong android_media_MediaExtractor_getCachedDurationUs(
629726
JNIEnv *env, jobject thiz) {
630727
sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
@@ -713,6 +810,9 @@ static JNINativeMethod gMethods[] = {
713810
{ "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
714811
(void *)android_media_MediaExtractor_setDataSourceFd },
715812

813+
{ "setDataSource", "(Landroid/media/DataSource;)V",
814+
(void *)android_media_MediaExtractor_setDataSourceCallback },
815+
716816
{ "getCachedDuration", "()J",
717817
(void *)android_media_MediaExtractor_getCachedDurationUs },
718818

media/jni/android_media_MediaExtractor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include <media/stagefright/foundation/ABase.h>
2121
#include <media/stagefright/MediaSource.h>
22+
#include <media/stagefright/DataSource.h>
2223
#include <utils/Errors.h>
2324
#include <utils/KeyedVector.h>
2425
#include <utils/RefBase.h>
@@ -39,6 +40,7 @@ struct JMediaExtractor : public RefBase {
3940
const KeyedVector<String8, String8> *headers);
4041

4142
status_t setDataSource(int fd, off64_t offset, off64_t size);
43+
status_t setDataSource(const sp<DataSource> &source);
4244

4345
size_t countTracks() const;
4446
status_t getTrackFormat(size_t index, jobject *format) const;

0 commit comments

Comments
 (0)