Unhide the android.media.[Media]DataSource interface.

This allows apps to implement MediaDataSource, which is modeled on
stagefright's DataSource, to supply media data to the framework. This
was already implemented for MediaExtractor, but it was renamed from
DataSource.

MediaExtractor, MediaPlayer and MediaMetadataRetriever each have a new
overload: #setDataSource(android.media.MediaDataSource)

Only NuPlayer supports this new data source.

The change introduces:
 * IDataSource:        The binder interface for DataSource.
 * JMediaDataSource:   The native counterpart to the java interface. It
                       implements IDataSource.
 * CallbackDataSource: A stagefright DataSource that wraps an IDataSource.

Change-Id: I6d9c1167b4a7384c469b1e928f31791a7ebed716
This commit is contained in:
Chris Watkins
2015-03-20 10:31:42 -07:00
parent ca25b8768d
commit 4eaa293808
14 changed files with 377 additions and 120 deletions

View File

@@ -15444,6 +15444,11 @@ package android.media {
ctor public MediaCryptoException(java.lang.String);
}
public abstract interface MediaDataSource implements java.io.Closeable {
method public abstract long getSize();
method public abstract int readAt(long, byte[], int);
}
public class MediaDescription implements android.os.Parcelable {
method public int describeContents();
method public java.lang.CharSequence getDescription();
@@ -15579,6 +15584,7 @@ package android.media {
method public final void release();
method public void seekTo(long, int);
method public void selectTrack(int);
method public final void setDataSource(android.media.MediaDataSource) throws java.io.IOException, java.lang.IllegalArgumentException;
method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
method public final void setDataSource(java.lang.String) throws java.io.IOException;
@@ -15758,6 +15764,7 @@ package android.media {
method public void setDataSource(java.io.FileDescriptor, long, long) throws java.lang.IllegalArgumentException;
method public void setDataSource(java.io.FileDescriptor) throws java.lang.IllegalArgumentException;
method public void setDataSource(android.content.Context, android.net.Uri) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException;
field public static final int METADATA_KEY_ALBUM = 1; // 0x1
field public static final int METADATA_KEY_ALBUMARTIST = 13; // 0xd
field public static final int METADATA_KEY_ARTIST = 2; // 0x2
@@ -15842,6 +15849,7 @@ package android.media {
method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDisplay(android.view.SurfaceHolder);
method public void setLooping(boolean);
method public void setNextMediaPlayer(android.media.MediaPlayer);

View File

@@ -16656,6 +16656,11 @@ package android.media {
ctor public MediaCryptoException(java.lang.String);
}
public abstract interface MediaDataSource implements java.io.Closeable {
method public abstract long getSize();
method public abstract int readAt(long, byte[], int);
}
public class MediaDescription implements android.os.Parcelable {
method public int describeContents();
method public java.lang.CharSequence getDescription();
@@ -16792,6 +16797,7 @@ package android.media {
method public final void release();
method public void seekTo(long, int);
method public void selectTrack(int);
method public final void setDataSource(android.media.MediaDataSource) throws java.io.IOException, java.lang.IllegalArgumentException;
method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
method public final void setDataSource(java.lang.String) throws java.io.IOException;
@@ -16971,6 +16977,7 @@ package android.media {
method public void setDataSource(java.io.FileDescriptor, long, long) throws java.lang.IllegalArgumentException;
method public void setDataSource(java.io.FileDescriptor) throws java.lang.IllegalArgumentException;
method public void setDataSource(android.content.Context, android.net.Uri) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException;
field public static final int METADATA_KEY_ALBUM = 1; // 0x1
field public static final int METADATA_KEY_ALBUMARTIST = 13; // 0xd
field public static final int METADATA_KEY_ARTIST = 2; // 0x2
@@ -17055,6 +17062,7 @@ package android.media {
method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDataSource(android.media.MediaDataSource) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void setDisplay(android.view.SurfaceHolder);
method public void setLooping(boolean);
method public void setNextMediaPlayer(android.media.MediaPlayer);

View File

@@ -1,43 +0,0 @@
/*
* 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();
}

View File

@@ -0,0 +1,62 @@
/*
* 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;
/**
* For supplying media data to the framework. Implement this if your app has
* special requirements for the way media data is obtained.
*
* <p class="note">Methods of this interface may be called on multiple different
* threads. There will be a thread synchronization point between each call to ensure that
* modifications to the state of your MediaDataSource are visible to future calls. This means
* you don't need to do your own synchronization unless you're modifying the
* MediaDataSource from another thread while it's being used by the framework.</p>
*/
public interface MediaDataSource extends Closeable {
/**
* Called to request data from the given position.
*
* Implementations should should write up to {@code size} bytes into
* {@code buffer}, and return the number of bytes written.
*
* Return {@code 0} to indicate that {@code position} is at, or beyond, the
* end of the source.
*
* Return {@code -1} to indicate that a fatal error occurred. The failed
* read will not be retried, so transient errors should be handled
* internally.
*
* Throwing an exception from this method will have the same effect as
* returning {@code -1}.
*
* @param position the position in the data source to read from.
* @param buffer the buffer to read the data into.
* @param size the number of bytes to read.
* @return the number of bytes read, or -1 if there was an error.
*/
public int readAt(long position, byte[] buffer, int size);
/**
* Called to get the size of the data source.
*
* @return the size of data source in bytes, or -1 if the size is unknown.
*/
public long getSize();
}

View File

@@ -66,10 +66,11 @@ final public class MediaExtractor {
}
/**
* Sets the DataSource object to be used as the data source for this extractor
* {@hide}
* Sets the data source (MediaDataSource) to use.
*
* @param dataSource the MediaDataSource for the media you want to extract from
*/
public native final void setDataSource(DataSource source) throws IOException;
public native final void setDataSource(MediaDataSource dataSource) throws IllegalArgumentException, IOException;
/**
* Sets the data source as a content Uri.

View File

@@ -203,7 +203,20 @@ public class MediaMetadataRetriever
}
/**
* Call this method after setDataSource(). This method retrieves the
* Sets the data source (MediaDataSource) to use.
*
* @param dataSource the MediaDataSource for the media you want to play
*/
public void setDataSource(MediaDataSource dataSource)
throws IllegalArgumentException {
_setDataSource(dataSource);
}
private native void _setDataSource(MediaDataSource dataSource)
throws IllegalArgumentException;
/**
* Call this method after setDataSource(). This method retrieves the
* meta data value associated with the keyCode.
*
* The keyCode currently supported is listed below as METADATA_XXX

View File

@@ -181,7 +181,8 @@ import java.lang.ref.WeakReference;
* {@link #setDataSource(FileDescriptor)}, or
* {@link #setDataSource(String)}, or
* {@link #setDataSource(Context, Uri)}, or
* {@link #setDataSource(FileDescriptor, long, long)} transfers a
* {@link #setDataSource(FileDescriptor, long, long)}, or
* {@link #setDataSource(MediaDataSource)} transfers a
* MediaPlayer object in the <em>Idle</em> state to the
* <em>Initialized</em> state.
* <ul>
@@ -1126,6 +1127,20 @@ public class MediaPlayer implements SubtitleController.Listener
private native void _setDataSource(FileDescriptor fd, long offset, long length)
throws IOException, IllegalArgumentException, IllegalStateException;
/**
* Sets the data source (MediaDataSource) to use.
*
* @param dataSource the MediaDataSource for the media you want to play
* @throws IllegalStateException if it is called in an invalid state
*/
public void setDataSource(MediaDataSource dataSource)
throws IllegalArgumentException, IllegalStateException {
_setDataSource(dataSource);
}
private native void _setDataSource(MediaDataSource dataSource)
throws IllegalArgumentException, IllegalStateException;
/**
* Prepares the player for playback, synchronously.
*

View File

@@ -7,6 +7,7 @@ LOCAL_SRC_FILES:= \
android_media_MediaCrypto.cpp \
android_media_MediaCodec.cpp \
android_media_MediaCodecList.cpp \
android_media_MediaDataSource.cpp \
android_media_MediaDrm.cpp \
android_media_MediaExtractor.cpp \
android_media_MediaHTTPConnection.cpp \

View File

@@ -0,0 +1,148 @@
/*
* Copyright 2015, 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.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "JMediaDataSource-JNI"
#include <utils/Log.h>
#include "android_media_MediaDataSource.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
#include "jni.h"
#include "JNIHelp.h"
#include <binder/MemoryDealer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <nativehelper/ScopedLocalRef.h>
namespace android {
JMediaDataSource::JMediaDataSource(JNIEnv* env, jobject source)
: mJavaObjStatus(OK), mSizeIsCached(false), mCachedSize(0), mMemory(NULL) {
mMediaDataSourceObj = env->NewGlobalRef(source);
CHECK(mMediaDataSourceObj != NULL);
ScopedLocalRef<jclass> mediaDataSourceClass(env, env->GetObjectClass(mMediaDataSourceObj));
CHECK(mediaDataSourceClass.get() != NULL);
mReadMethod = env->GetMethodID(mediaDataSourceClass.get(), "readAt", "(J[BI)I");
CHECK(mReadMethod != NULL);
mGetSizeMethod = env->GetMethodID(mediaDataSourceClass.get(), "getSize", "()J");
CHECK(mGetSizeMethod != NULL);
mCloseMethod = env->GetMethodID(mediaDataSourceClass.get(), "close", "()V");
CHECK(mCloseMethod != NULL);
ScopedLocalRef<jbyteArray> tmp(env, env->NewByteArray(kBufferSize));
mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get());
CHECK(mByteArrayObj != NULL);
sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "JMediaDataSource");
mMemory = memoryDealer->allocate(kBufferSize);
if (mMemory == NULL) {
ALOGE("Failed to allocate memory!");
}
}
JMediaDataSource::~JMediaDataSource() {
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->DeleteGlobalRef(mMediaDataSourceObj);
env->DeleteGlobalRef(mByteArrayObj);
}
sp<IMemory> JMediaDataSource::getIMemory() {
Mutex::Autolock lock(mLock);
return mMemory;
}
ssize_t JMediaDataSource::readAt(off64_t offset, size_t size) {
Mutex::Autolock lock(mLock);
if (mJavaObjStatus != OK || mMemory == NULL) {
return -1;
}
if (size > kBufferSize) {
size = kBufferSize;
}
JNIEnv* env = AndroidRuntime::getJNIEnv();
jint numread = env->CallIntMethod(mMediaDataSourceObj, mReadMethod,
(jlong)offset, mByteArrayObj, (jint)size);
if (env->ExceptionCheck()) {
ALOGW("An exception occurred in readAt()");
LOGW_EX(env);
env->ExceptionClear();
mJavaObjStatus = UNKNOWN_ERROR;
return -1;
}
if (numread < 0) {
ALOGW("An error occurred in readAt()");
mJavaObjStatus = UNKNOWN_ERROR;
return -1;
}
if ((size_t)numread > size) {
ALOGE("readAt read too many bytes.");
mJavaObjStatus = UNKNOWN_ERROR;
return -1;
}
ALOGV("readAt %lld / %zu => %d.", (long long)offset, size, numread);
env->GetByteArrayRegion(mByteArrayObj, 0, numread, (jbyte*)mMemory->pointer());
return numread;
}
status_t JMediaDataSource::getSize(off64_t* size) {
Mutex::Autolock lock(mLock);
if (mJavaObjStatus != OK) {
return UNKNOWN_ERROR;
}
if (mSizeIsCached) {
return mCachedSize;
}
JNIEnv* env = AndroidRuntime::getJNIEnv();
*size = env->CallLongMethod(mMediaDataSourceObj, mGetSizeMethod);
if (env->ExceptionCheck()) {
ALOGW("An exception occurred in getSize()");
LOGW_EX(env);
env->ExceptionClear();
// After returning an error, size shouldn't be used by callers.
*size = UNKNOWN_ERROR;
mJavaObjStatus = UNKNOWN_ERROR;
return UNKNOWN_ERROR;
}
// The minimum size should be -1, which indicates unknown size.
if (*size < 0) {
*size = -1;
}
mCachedSize = *size;
mSizeIsCached = true;
return OK;
}
void JMediaDataSource::close() {
Mutex::Autolock lock(mLock);
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->CallVoidMethod(mMediaDataSourceObj, mCloseMethod);
// The closed state is effectively the same as an error state.
mJavaObjStatus = UNKNOWN_ERROR;
}
} // namespace android

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2015, 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.
*/
#ifndef _ANDROID_MEDIA_MEDIADATASOURCE_H_
#define _ANDROID_MEDIA_MEDIADATASOURCE_H_
#include "jni.h"
#include <media/IDataSource.h>
#include <media/stagefright/foundation/ABase.h>
#include <utils/Errors.h>
#include <utils/Mutex.h>
namespace android {
// The native counterpart to a Java android.media.MediaDataSource. It inherits from
// IDataSource so that it can be accessed remotely.
//
// If the java DataSource returns an error or throws an exception it
// will be considered to be in a broken state, and the only further call this
// will make is to close().
class JMediaDataSource : public BnDataSource {
public:
enum {
kBufferSize = 64 * 1024,
};
JMediaDataSource(JNIEnv *env, jobject source);
virtual ~JMediaDataSource();
virtual sp<IMemory> getIMemory();
virtual ssize_t readAt(off64_t offset, size_t size);
virtual status_t getSize(off64_t* size);
virtual void close();
private:
// Protect all member variables with mLock because this object will be
// accessed on different binder worker threads.
Mutex mLock;
// The status of the java DataSource. Set to OK unless an error occurred or
// close() was called.
status_t mJavaObjStatus;
// Only call the java getSize() once so the app can't change the size on us.
bool mSizeIsCached;
off64_t mCachedSize;
sp<IMemory> mMemory;
jobject mMediaDataSourceObj;
jmethodID mReadMethod;
jmethodID mGetSizeMethod;
jmethodID mCloseMethod;
jbyteArray mByteArrayObj;
DISALLOW_EVIL_CONSTRUCTORS(JMediaDataSource);
};
} // namespace android
#endif // _ANDROID_MEDIA_MEDIADATASOURCE_H_

View File

@@ -25,6 +25,7 @@
#include "android_runtime/Log.h"
#include "jni.h"
#include "JNIHelp.h"
#include "android_media_MediaDataSource.h"
#include <media/IMediaHTTPService.h>
#include <media/hardware/CryptoAPI.h>
@@ -50,74 +51,6 @@ 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, (jint)size);
env->GetByteArrayRegion(byteArrayObj, 0, size, (jbyte*) buffer);
env->DeleteLocalRef(byteArrayObj);
if (env->ExceptionCheck()) {
ALOGW("Exception occurred while reading %zu at %lld", size, (long long)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)
: mClass(NULL),
mObject(NULL) {
@@ -777,7 +710,8 @@ static void android_media_MediaExtractor_setDataSourceCallback(
return;
}
sp<JavaDataSourceBridge> bridge = new JavaDataSourceBridge(env, callbackObj);
sp<DataSource> bridge =
DataSource::CreateFromIDataSource(new JMediaDataSource(env, callbackObj));
status_t err = extractor->setDataSource(bridge);
if (err != OK) {
@@ -881,7 +815,7 @@ static JNINativeMethod gMethods[] = {
{ "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
(void *)android_media_MediaExtractor_setDataSourceFd },
{ "setDataSource", "(Landroid/media/DataSource;)V",
{ "setDataSource", "(Landroid/media/MediaDataSource;)V",
(void *)android_media_MediaExtractor_setDataSourceCallback },
{ "getCachedDuration", "()J",

View File

@@ -134,7 +134,6 @@ static jobject android_media_MediaHTTPConnection_native_getIMemory(
static jint android_media_MediaHTTPConnection_native_readAt(
JNIEnv *env, jobject thiz, jlong offset, jint size) {
sp<JMediaHTTPConnection> conn = getObject(env, thiz);
if (size > JMediaHTTPConnection::kBufferSize) {
size = JMediaHTTPConnection::kBufferSize;
}

View File

@@ -30,6 +30,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_media_MediaDataSource.h"
#include "android_media_Utils.h"
#include "android_util_Binder.h"
@@ -171,6 +172,23 @@ static void android_media_MediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jo
process_media_retriever_call(env, retriever->setDataSource(fd, offset, length), "java/lang/RuntimeException", "setDataSource failed");
}
static void android_media_MediaMetadataRetriever_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject dataSource)
{
ALOGV("setDataSourceCallback");
MediaMetadataRetriever* retriever = getRetriever(env, thiz);
if (retriever == 0) {
jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
return;
}
if (dataSource == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
sp<IDataSource> callbackDataSource = new JMediaDataSource(env, dataSource);
process_media_retriever_call(env, retriever->setDataSource(callbackDataSource), "java/lang/RuntimeException", "setDataSourceCallback failed");
}
template<typename T>
static void rotate0(T* dst, const T* src, size_t width, size_t height)
{
@@ -457,6 +475,7 @@ static JNINativeMethod nativeMethods[] = {
},
{"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
{"_setDataSource", "(Landroid/media/MediaDataSource;)V", (void *)android_media_MediaMetadataRetriever_setDataSourceCallback},
{"_getFrameAtTime", "(JI)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
{"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata},
{"getEmbeddedPicture", "(I)[B", (void *)android_media_MediaMetadataRetriever_getEmbeddedPicture},

View File

@@ -36,6 +36,7 @@
#include "utils/Errors.h" // for status_t
#include "utils/KeyedVector.h"
#include "utils/String8.h"
#include "android_media_MediaDataSource.h"
#include "android_media_Utils.h"
#include "android_os_Parcel.h"
@@ -251,6 +252,23 @@ android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fil
process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
}
static void
android_media_MediaPlayer_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject dataSource)
{
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
if (dataSource == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
sp<IDataSource> callbackDataSource = new JMediaDataSource(env, dataSource);
process_media_player_call(env, thiz, mp->setDataSource(callbackDataSource), "java/lang/RuntimeException", "setDataSourceCallback failed." );
}
static sp<IGraphicBufferProducer>
getVideoSurfaceTexture(JNIEnv* env, jobject thiz) {
IGraphicBufferProducer * const p = (IGraphicBufferProducer*)env->GetLongField(thiz, fields.surface_texture);
@@ -871,7 +889,8 @@ static JNINativeMethod gMethods[] = {
(void *)android_media_MediaPlayer_setDataSourceAndHeaders
},
{"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
{"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
{"_setDataSource", "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },
{"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface},
{"_prepare", "()V", (void *)android_media_MediaPlayer_prepare},
{"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync},