Merge "Let apps provide a custom data source for extractors" into jb-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
4ff8d37934
43
media/java/android/media/DataSource.java
Normal file
43
media/java/android/media/DataSource.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package android.media;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
/**
|
||||
* An abstraction for a media data source, e.g. a file or an http stream
|
||||
* {@hide}
|
||||
*/
|
||||
public interface DataSource extends Closeable {
|
||||
/**
|
||||
* Reads data from the data source at the requested position
|
||||
*
|
||||
* @param offset where in the source to read
|
||||
* @param buffer the buffer to read the data into
|
||||
* @param size how many bytes to read
|
||||
* @return the number of bytes read, or -1 if there was an error
|
||||
*/
|
||||
public int readAt(long offset, byte[] buffer, int size);
|
||||
|
||||
/**
|
||||
* Gets the size of the data source.
|
||||
*
|
||||
* @return size of data source, or -1 if the length is unknown
|
||||
*/
|
||||
public long getSize();
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import android.content.res.AssetFileDescriptor;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaFormat;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -59,6 +60,12 @@ final public class MediaExtractor {
|
||||
native_setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the DataSource object to be used as the data source for this extractor
|
||||
* {@hide}
|
||||
*/
|
||||
public native final void setDataSource(DataSource source);
|
||||
|
||||
/**
|
||||
* Sets the data source as a content Uri.
|
||||
*
|
||||
|
||||
@@ -44,6 +44,72 @@ struct fields_t {
|
||||
|
||||
static fields_t gFields;
|
||||
|
||||
class JavaDataSourceBridge : public DataSource {
|
||||
jmethodID mReadMethod;
|
||||
jmethodID mGetSizeMethod;
|
||||
jmethodID mCloseMethod;
|
||||
jobject mDataSource;
|
||||
public:
|
||||
JavaDataSourceBridge(JNIEnv *env, jobject source) {
|
||||
mDataSource = env->NewGlobalRef(source);
|
||||
|
||||
jclass datasourceclass = env->GetObjectClass(mDataSource);
|
||||
CHECK(datasourceclass != NULL);
|
||||
|
||||
mReadMethod = env->GetMethodID(datasourceclass, "readAt", "(J[BI)I");
|
||||
CHECK(mReadMethod != NULL);
|
||||
|
||||
mGetSizeMethod = env->GetMethodID(datasourceclass, "getSize", "()J");
|
||||
CHECK(mGetSizeMethod != NULL);
|
||||
|
||||
mCloseMethod = env->GetMethodID(datasourceclass, "close", "()V");
|
||||
CHECK(mCloseMethod != NULL);
|
||||
}
|
||||
|
||||
~JavaDataSourceBridge() {
|
||||
JNIEnv *env = AndroidRuntime::getJNIEnv();
|
||||
env->CallVoidMethod(mDataSource, mCloseMethod);
|
||||
env->DeleteGlobalRef(mDataSource);
|
||||
}
|
||||
|
||||
virtual status_t initCheck() const {
|
||||
return OK;
|
||||
}
|
||||
|
||||
virtual ssize_t readAt(off64_t offset, void* buffer, size_t size) {
|
||||
JNIEnv *env = AndroidRuntime::getJNIEnv();
|
||||
|
||||
// XXX could optimize this by reusing the same array
|
||||
jbyteArray byteArrayObj = env->NewByteArray(size);
|
||||
env->DeleteLocalRef(env->GetObjectClass(mDataSource));
|
||||
env->DeleteLocalRef(env->GetObjectClass(byteArrayObj));
|
||||
ssize_t numread = env->CallIntMethod(mDataSource, mReadMethod, offset, byteArrayObj, size);
|
||||
env->GetByteArrayRegion(byteArrayObj, 0, size, (jbyte*) buffer);
|
||||
env->DeleteLocalRef(byteArrayObj);
|
||||
if (env->ExceptionCheck()) {
|
||||
ALOGW("Exception occurred while reading %d at %lld", size, offset);
|
||||
LOGW_EX(env);
|
||||
env->ExceptionClear();
|
||||
return -1;
|
||||
}
|
||||
return numread;
|
||||
}
|
||||
|
||||
virtual status_t getSize(off64_t *size) {
|
||||
JNIEnv *env = AndroidRuntime::getJNIEnv();
|
||||
|
||||
CHECK(size != NULL);
|
||||
|
||||
int64_t len = env->CallLongMethod(mDataSource, mGetSizeMethod);
|
||||
if (len < 0) {
|
||||
*size = ERROR_UNSUPPORTED;
|
||||
} else {
|
||||
*size = len;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz)
|
||||
@@ -76,6 +142,10 @@ status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
|
||||
return mImpl->setDataSource(fd, offset, size);
|
||||
}
|
||||
|
||||
status_t JMediaExtractor::setDataSource(const sp<DataSource> &datasource) {
|
||||
return mImpl->setDataSource(datasource);
|
||||
}
|
||||
|
||||
size_t JMediaExtractor::countTracks() const {
|
||||
return mImpl->countTracks();
|
||||
}
|
||||
@@ -625,6 +695,33 @@ static void android_media_MediaExtractor_setDataSourceFd(
|
||||
}
|
||||
}
|
||||
|
||||
static void android_media_MediaExtractor_setDataSourceCallback(
|
||||
JNIEnv *env, jobject thiz,
|
||||
jobject callbackObj) {
|
||||
sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
|
||||
|
||||
if (extractor == NULL) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException", NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (callbackObj == NULL) {
|
||||
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
sp<JavaDataSourceBridge> bridge = new JavaDataSourceBridge(env, callbackObj);
|
||||
status_t err = extractor->setDataSource(bridge);
|
||||
|
||||
if (err != OK) {
|
||||
jniThrowException(
|
||||
env,
|
||||
"java/io/IOException",
|
||||
"Failed to instantiate extractor.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static jlong android_media_MediaExtractor_getCachedDurationUs(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
|
||||
@@ -713,6 +810,9 @@ static JNINativeMethod gMethods[] = {
|
||||
{ "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
|
||||
(void *)android_media_MediaExtractor_setDataSourceFd },
|
||||
|
||||
{ "setDataSource", "(Landroid/media/DataSource;)V",
|
||||
(void *)android_media_MediaExtractor_setDataSourceCallback },
|
||||
|
||||
{ "getCachedDuration", "()J",
|
||||
(void *)android_media_MediaExtractor_getCachedDurationUs },
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <media/stagefright/foundation/ABase.h>
|
||||
#include <media/stagefright/MediaSource.h>
|
||||
#include <media/stagefright/DataSource.h>
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/RefBase.h>
|
||||
@@ -39,6 +40,7 @@ struct JMediaExtractor : public RefBase {
|
||||
const KeyedVector<String8, String8> *headers);
|
||||
|
||||
status_t setDataSource(int fd, off64_t offset, off64_t size);
|
||||
status_t setDataSource(const sp<DataSource> &source);
|
||||
|
||||
size_t countTracks() const;
|
||||
status_t getTrackFormat(size_t index, jobject *format) const;
|
||||
|
||||
Reference in New Issue
Block a user