From 4eaa2938084353a54dc259466172909329a048cc Mon Sep 17 00:00:00 2001 From: Chris Watkins Date: Fri, 20 Mar 2015 10:31:42 -0700 Subject: [PATCH] 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 --- api/current.txt | 8 + api/system-current.txt | 8 + media/java/android/media/DataSource.java | 43 ----- media/java/android/media/MediaDataSource.java | 62 ++++++++ media/java/android/media/MediaExtractor.java | 7 +- .../android/media/MediaMetadataRetriever.java | 15 +- media/java/android/media/MediaPlayer.java | 17 +- media/jni/Android.mk | 1 + media/jni/android_media_MediaDataSource.cpp | 148 ++++++++++++++++++ media/jni/android_media_MediaDataSource.h | 73 +++++++++ media/jni/android_media_MediaExtractor.cpp | 74 +-------- .../jni/android_media_MediaHTTPConnection.cpp | 1 - .../android_media_MediaMetadataRetriever.cpp | 19 +++ media/jni/android_media_MediaPlayer.cpp | 21 ++- 14 files changed, 377 insertions(+), 120 deletions(-) delete mode 100644 media/java/android/media/DataSource.java create mode 100644 media/java/android/media/MediaDataSource.java create mode 100644 media/jni/android_media_MediaDataSource.cpp create mode 100644 media/jni/android_media_MediaDataSource.h diff --git a/api/current.txt b/api/current.txt index fdeda0baeb138..8165e0ad5a672 100644 --- a/api/current.txt +++ b/api/current.txt @@ -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) throws java.io.IOException; method public final void setDataSource(java.lang.String, java.util.Map) 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); diff --git a/api/system-current.txt b/api/system-current.txt index deaf916f50401..22410300f074d 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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) throws java.io.IOException; method public final void setDataSource(java.lang.String, java.util.Map) 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); diff --git a/media/java/android/media/DataSource.java b/media/java/android/media/DataSource.java deleted file mode 100644 index 347bd5f32a259..0000000000000 --- a/media/java/android/media/DataSource.java +++ /dev/null @@ -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(); -} diff --git a/media/java/android/media/MediaDataSource.java b/media/java/android/media/MediaDataSource.java new file mode 100644 index 0000000000000..246c0ef0a3d04 --- /dev/null +++ b/media/java/android/media/MediaDataSource.java @@ -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. + * + *

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.

+ */ +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(); +} diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java index b23b540ebee22..b4acbc0c06fdb 100644 --- a/media/java/android/media/MediaExtractor.java +++ b/media/java/android/media/MediaExtractor.java @@ -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. diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java index 9aa8003e93209..a3ff080c53f03 100644 --- a/media/java/android/media/MediaMetadataRetriever.java +++ b/media/java/android/media/MediaMetadataRetriever.java @@ -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 diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 83954aec894b5..cb80bc4cf49dd 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -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 Idle state to the * Initialized state. *
    @@ -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. * diff --git a/media/jni/Android.mk b/media/jni/Android.mk index 5b177e574a6d3..8cf98747a9bad 100644 --- a/media/jni/Android.mk +++ b/media/jni/Android.mk @@ -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 \ diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp new file mode 100644 index 0000000000000..1e6d2afa84b84 --- /dev/null +++ b/media/jni/android_media_MediaDataSource.cpp @@ -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 + +#include "android_media_MediaDataSource.h" + +#include "android_runtime/AndroidRuntime.h" +#include "android_runtime/Log.h" +#include "jni.h" +#include "JNIHelp.h" + +#include +#include +#include + +namespace android { + +JMediaDataSource::JMediaDataSource(JNIEnv* env, jobject source) + : mJavaObjStatus(OK), mSizeIsCached(false), mCachedSize(0), mMemory(NULL) { + mMediaDataSourceObj = env->NewGlobalRef(source); + CHECK(mMediaDataSourceObj != NULL); + + ScopedLocalRef 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 tmp(env, env->NewByteArray(kBufferSize)); + mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get()); + CHECK(mByteArrayObj != NULL); + + sp 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 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 diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h new file mode 100644 index 0000000000000..2bc237e02b064 --- /dev/null +++ b/media/jni/android_media_MediaDataSource.h @@ -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 +#include +#include +#include + +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 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 mMemory; + + jobject mMediaDataSourceObj; + jmethodID mReadMethod; + jmethodID mGetSizeMethod; + jmethodID mCloseMethod; + jbyteArray mByteArrayObj; + + DISALLOW_EVIL_CONSTRUCTORS(JMediaDataSource); +}; + +} // namespace android + +#endif // _ANDROID_MEDIA_MEDIADATASOURCE_H_ diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp index c0795b612d72e..b6b7a80e6a3f7 100644 --- a/media/jni/android_media_MediaExtractor.cpp +++ b/media/jni/android_media_MediaExtractor.cpp @@ -25,6 +25,7 @@ #include "android_runtime/Log.h" #include "jni.h" #include "JNIHelp.h" +#include "android_media_MediaDataSource.h" #include #include @@ -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 bridge = new JavaDataSourceBridge(env, callbackObj); + sp 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", diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp index 7226ef567cd12..393003d984629 100644 --- a/media/jni/android_media_MediaHTTPConnection.cpp +++ b/media/jni/android_media_MediaHTTPConnection.cpp @@ -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 conn = getObject(env, thiz); - if (size > JMediaHTTPConnection::kBufferSize) { size = JMediaHTTPConnection::kBufferSize; } diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index c6fa3790d73ad..59fb6d6f68591 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -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 callbackDataSource = new JMediaDataSource(env, dataSource); + process_media_retriever_call(env, retriever->setDataSource(callbackDataSource), "java/lang/RuntimeException", "setDataSourceCallback failed"); +} + template 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}, diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 3e4171663de4c..c2472201c7512 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -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 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 callbackDataSource = new JMediaDataSource(env, dataSource); + process_media_player_call(env, thiz, mp->setDataSource(callbackDataSource), "java/lang/RuntimeException", "setDataSourceCallback failed." ); +} + static sp 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},