diff options
-rw-r--r-- | include/media/IMediaPlayer.h | 17 | ||||
-rw-r--r-- | include/media/mediaplayer.h | 1 | ||||
-rw-r--r-- | media/java/android/media/MediaPlayer.java | 37 | ||||
-rw-r--r-- | media/java/android/media/Metadata.java | 13 | ||||
-rw-r--r-- | media/jni/android_media_MediaPlayer.cpp | 31 | ||||
-rw-r--r-- | media/libmedia/IMediaPlayer.cpp | 23 | ||||
-rw-r--r-- | media/libmedia/mediaplayer.cpp | 15 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.cpp | 10 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.h | 1 |
9 files changed, 140 insertions, 8 deletions
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 @@ public: // @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 @@ public: 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 class MediaPlayer */ 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 @@ public class MediaPlayer * @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.Date; 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 class Metadata 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 @@ public class Metadata /* 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 @@ android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject r 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 @@ static JNINativeMethod gMethods[] = { {"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 @@ enum { SET_VOLUME, INVOKE, SET_METADATA_FILTER, + GET_METADATA, }; class BpMediaPlayer: public BpInterface<IMediaPlayer> @@ -176,8 +177,7 @@ public: 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 @@ public: 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 @@ status_t BnMediaPlayer::onTransact( 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::invoke(const Parcel& request, Parcel *reply) 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 @@ status_t MediaPlayerService::Client::setMetadataFilter(const Parcel& filter) 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 @@ private: 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); |