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
This commit is contained in:
Nicolas Catania
2009-07-09 09:21:33 -07:00
parent 2eedb2515b
commit 5d55c71198
9 changed files with 140 additions and 8 deletions

View File

@@ -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;
};
// ----------------------------------------------------------------------------

View File

@@ -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);

View File

@@ -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

View File

@@ -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.
*/

View File

@@ -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},
};

View File

@@ -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);
}

View File

@@ -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");

View File

@@ -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);

View File

@@ -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);