Basic plumbing to retrieve metadata from the native player.
IMediaPlayer.h
Added a getMetadata method that mirrors the on in MediaPlayer.java.
MediaPlayer.java
Added a native method to get the metadata from the native player.
Parse the parcel into a Metadata object.
Metadata.java
Added a stub to parse the Parcel returned by the native player into
a set of metadata.
android_media_MediaPlayer.cpp
JNI call to forward the getMetadata call.
MediaPlayerService.cpp
MediaPlayerService::Client implements the new getMetadata method added in IMediaPlayer.h
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index 074125f..b6f654f 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -59,6 +59,23 @@
// @param filter A set of allow and drop rules serialized in a Parcel.
// @return OK if the invocation was made successfully.
virtual status_t setMetadataFilter(const Parcel& filter) = 0;
+
+ // Retrieve a set of metadata.
+ // @param update_only Include only the metadata that have changed
+ // since the last invocation of getMetadata.
+ // The set is built using the unfiltered
+ // notifications the native player sent to the
+ // MediaPlayerService during that period of
+ // time. If false, all the metadatas are considered.
+ // @param apply_filter If true, once the metadata set has been built based
+ // on the value update_only, the current filter is
+ // applied.
+ // @param[out] metadata On exit contains a set (possibly empty) of metadata.
+ // Valid only if the call returned OK.
+ // @return OK if the invocation was made successfully.
+ virtual status_t getMetadata(bool update_only,
+ bool apply_filter,
+ Parcel *metadata) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 8326a21..26b054bd 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -155,6 +155,7 @@
static sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
status_t invoke(const Parcel& request, Parcel *reply);
status_t setMetadataFilter(const Parcel& filter);
+ status_t getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
private:
void clear_l();
status_t seekTo_l(int msec);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 306ea81..a23f535 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -930,8 +930,21 @@
*/
public Metadata getMetadata(final boolean update_only,
final boolean apply_filter) {
- // FIXME: Implement.
- return new Metadata();
+ Parcel reply = Parcel.obtain();
+ Metadata data = new Metadata();
+
+ if (!native_getMetadata(update_only, apply_filter, reply)) {
+ reply.recycle();
+ return null;
+ }
+
+ // Metadata takes over the parcel, don't recycle it unless
+ // there is an error.
+ if (!data.parse(reply)) {
+ reply.recycle();
+ return null;
+ }
+ return data;
}
/**
@@ -1064,11 +1077,29 @@
* @param request Parcel destinated to the media player. The
* Interface token must be set to the IMediaPlayer
* one to be routed correctly through the system.
- * @param reply Parcel that will contain the reply.
+ * @param reply[out] Parcel that will contain the reply.
* @return The status code.
*/
private native final int native_invoke(Parcel request, Parcel reply);
+
+ /**
+ * @param update_only If true fetch only the set of metadata that have
+ * changed since the last invocation of getMetadata.
+ * The set is built using the unfiltered
+ * notifications the native player sent to the
+ * MediaPlayerService during that period of
+ * time. If false, all the metadatas are considered.
+ * @param apply_filter If true, once the metadata set has been built based on
+ * the value update_only, the current filter is applied.
+ * @param reply[out] On return contains the serialized
+ * metadata. Valid only if the call was successful.
+ * @return The status code.
+ */
+ private native final boolean native_getMetadata(boolean update_only,
+ boolean apply_filter,
+ Parcel reply);
+
/**
* @param request Parcel with the 2 serialized lists of allowed
* metadata types followed by the one to be
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
index 7bc4e9c..6525109 100644
--- a/media/java/android/media/Metadata.java
+++ b/media/java/android/media/Metadata.java
@@ -17,6 +17,7 @@
package android.media;
import android.graphics.Bitmap;
+import android.os.Parcel;
import android.util.Log;
import java.util.Collections;
@@ -24,6 +25,7 @@
import java.util.Iterator;
import java.util.Set;
+
/**
Class to hold the media's metadata. Metadata are used
for human consumption and can be embedded in the media (e.g
@@ -100,6 +102,12 @@
public static final Set<Integer> MATCH_NONE = Collections.EMPTY_SET;
public static final Set<Integer> MATCH_ALL = Collections.singleton(ANY);
+ private static final int STRING_VAL = 1;
+ private static final int INTEGER_VAL = 2;
+ private static final int LONG_VAL = 3;
+ private static final int DOUBLE_VAL = 4;
+ private static final int TIMED_TEXT_VAL = 2;
+
/**
* Helper class to hold a pair (time, text). Can be used to implement caption.
*/
@@ -119,6 +127,11 @@
/* package */ Metadata() {}
+ /* package */ boolean parse(Parcel data) {
+ // FIXME: Implement.
+ return true;
+ }
+
/**
* @return the number of element in this metadata set.
*/
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 19a2a41..b173129 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -479,9 +479,39 @@
Parcel *filter = parcelForJavaObject(env, request);
+ if (filter == NULL ) {
+ jniThrowException(env, "java/lang/RuntimeException", "Filter is null");
+ return UNKNOWN_ERROR;
+ }
+
return media_player->setMetadataFilter(*filter);
}
+static jboolean
+android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only,
+ jboolean apply_filter, jobject reply)
+{
+ sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
+ if (media_player == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return false;
+ }
+
+ Parcel *metadata = parcelForJavaObject(env, reply);
+
+ if (metadata == NULL ) {
+ jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null");
+ return false;
+ }
+
+ metadata->freeData();
+ // On return metadata is positioned at the beginning of the
+ // metadata. Note however that the parcel actually starts with the
+ // return code so you should not rewind the parcel using
+ // setDataPosition(0).
+ return media_player->getMetadata(update_only, apply_filter, metadata) == OK;
+}
+
static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
@@ -546,6 +576,7 @@
{"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt},
{"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
{"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter},
+ {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata},
{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
};
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 131e510..5d9db10 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -42,6 +42,7 @@
SET_VOLUME,
INVOKE,
SET_METADATA_FILTER,
+ GET_METADATA,
};
class BpMediaPlayer: public BpInterface<IMediaPlayer>
@@ -176,8 +177,7 @@
status_t invoke(const Parcel& request, Parcel *reply)
{ // Avoid doing any extra copy. The interface descriptor should
// have been set by MediaPlayer.java.
- status_t retcode = remote()->transact(INVOKE, request, reply);
- return retcode;
+ return remote()->transact(INVOKE, request, reply);
}
status_t setMetadataFilter(const Parcel& request)
@@ -188,6 +188,17 @@
remote()->transact(SET_METADATA_FILTER, request, &reply);
return reply.readInt32();
}
+
+ status_t getMetadata(bool update_only, bool apply_filter, Parcel *reply)
+ {
+ Parcel request;
+ request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ // TODO: Burning 2 ints for 2 boolean. Should probably use flags in an int here.
+ request.writeInt32(update_only);
+ request.writeInt32(apply_filter);
+ remote()->transact(GET_METADATA, request, reply);
+ return reply->readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -288,6 +299,14 @@
reply->writeInt32(setMetadataFilter(data));
return NO_ERROR;
} break;
+ case GET_METADATA: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ const status_t retcode = getMetadata(data.readInt32(), data.readInt32(), reply);
+ reply->setDataPosition(0);
+ reply->writeInt32(retcode);
+ reply->setDataPosition(0);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index d8c622f..6b35fa7 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -211,14 +211,23 @@
status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
{
LOGD("setMetadataFilter");
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL)
- {
+ Mutex::Autolock lock(mLock);
+ if (mPlayer == NULL) {
return NO_INIT;
}
return mPlayer->setMetadataFilter(filter);
}
+status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
+{
+ LOGD("getMetadata");
+ Mutex::Autolock lock(mLock);
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+ return mPlayer->getMetadata(update_only, apply_filter, metadata);
+}
+
status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
{
LOGV("setVideoSurface");
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 3adbfac..04aab81 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -846,6 +846,16 @@
return status;
}
+status_t MediaPlayerService::Client::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
+{
+ status_t status;
+ metadata->writeInt32(-1); // Placeholder for the return code
+
+ // FIXME: Implement, query the native player and do the optional filtering, etc...
+ status = OK;
+ return status;
+}
+
status_t MediaPlayerService::Client::prepareAsync()
{
LOGV("[%d] prepareAsync", mConnId);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index b915e86..7920559 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -191,6 +191,7 @@
virtual status_t setVolume(float leftVolume, float rightVolume);
virtual status_t invoke(const Parcel& request, Parcel *reply);
virtual status_t setMetadataFilter(const Parcel& filter);
+ virtual status_t getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
sp<MediaPlayerBase> createPlayer(player_type playerType);
status_t setDataSource(const char *url);