Loading include/media/IMediaPlayer.h +6 −1 Original line number Diff line number Diff line Loading @@ -52,8 +52,13 @@ public: // @param request Parcel that must start with the media player // interface token. // @param[out] reply Parcel to hold the reply data. Cannot be null. // @return OK if the invocation was made. PERMISSION_DENIED otherwise. // @return OK if the invocation was made successfully. virtual status_t invoke(const Parcel& request, Parcel *reply) = 0; // Set a new metadata filter. // @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; }; // ---------------------------------------------------------------------------- Loading include/media/mediaplayer.h +3 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,8 @@ enum media_info_type { MEDIA_INFO_BAD_INTERLEAVING = 800, // The media is not seekable (e.g live stream). MEDIA_INFO_NOT_SEEKABLE = 801, // New media metadata is available. MEDIA_INFO_METADATA_UPDATE = 802, }; Loading Loading @@ -152,6 +154,7 @@ public: static sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat); 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); private: void clear_l(); status_t seekTo_l(int msec); Loading media/libmedia/IMediaPlayer.cpp +15 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ enum { SET_LOOPING, SET_VOLUME, INVOKE, SET_METADATA_FILTER, }; class BpMediaPlayer: public BpInterface<IMediaPlayer> Loading Loading @@ -178,6 +179,15 @@ public: status_t retcode = remote()->transact(INVOKE, request, reply); return retcode; } status_t setMetadataFilter(const Parcel& request) { Parcel reply; // Avoid doing any extra copy of the request. The interface // descriptor should have been set by MediaPlayer.java. remote()->transact(SET_METADATA_FILTER, request, &reply); return reply.readInt32(); } }; IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer"); Loading Loading @@ -273,6 +283,11 @@ status_t BnMediaPlayer::onTransact( invoke(data, reply); return NO_ERROR; } break; case SET_METADATA_FILTER: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(setMetadataFilter(data)); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } Loading media/libmedia/mediaplayer.cpp +10 −1 Original line number Diff line number Diff line Loading @@ -208,7 +208,16 @@ status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply) return INVALID_OPERATION; } status_t MediaPlayer::setMetadataFilter(const Parcel& filter) { LOGD("setMetadataFilter"); Mutex::Autolock _l(mLock); if (mPlayer == NULL) { return NO_INIT; } return mPlayer->setMetadataFilter(filter); } status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface) { Loading media/libmediaplayerservice/MediaPlayerService.cpp +185 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,150 @@ pid_t gettid() { return syscall(__NR_gettid);} #undef __KERNEL__ #endif namespace { using android::status_t; using android::OK; using android::BAD_VALUE; using android::NOT_ENOUGH_DATA; using android::Parcel; using android::Vector; // Max number of entries in the filter. const int kMaxFilterSize = 64; // I pulled that out of thin air. // Keep in sync with ANY in Metadata.java const int32_t kAny = 0; // To order the metadata types in the vector-filter. int lessThan(const int32_t *lhs, const int32_t *rhs) { return *lhs < *rhs ? 0 : 1; } // Unmarshall a filter from a Parcel. // Filter format in a parcel: // // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | number of entries (n) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | metadata type 1 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | metadata type 2 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // .... // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | metadata type n | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // // @param p Parcel that should start with a filter. // @param[out] filter On exit contains the list of metadata type to be // filtered. // @param[out] status On exit contains the status code to be returned. // @return true if the parcel starts with a valid filter. bool unmarshallFilter(const Parcel& p, Vector<int32_t> *filter, status_t *status) { int32_t s; if (p.readInt32(&s) != OK) { LOGE("Failed to read filter's length"); *status = NOT_ENOUGH_DATA; return false; } if( s > kMaxFilterSize || s < 0) { LOGE("Invalid filter len %d", s); *status = BAD_VALUE; return false; } size_t size = s; filter->clear(); filter->setCapacity(size); s *= sizeof(int32_t); if (p.dataAvail() < static_cast<size_t>(s)) { LOGE("Filter too short expected %d but got %d", s, p.dataAvail()); *status = NOT_ENOUGH_DATA; return false; } const int32_t *data = static_cast<const int32_t*>(p.readInplace(s)); if (NULL == data ) { LOGE("Filter had no data"); *status = BAD_VALUE; return false; } // TODO: The stl impl of vector would be more efficient here // because it degenerates into a memcpy on pod types. Try to // replace later or use stl::set. for (size_t i = 0; i < size; ++i) { filter->push(*data); ++data; } *status = OK; return true; } bool unmarshallBothFilters(const Parcel& p, Vector<int32_t> *allow, Vector<int32_t> *block, status_t *status) { if (!(unmarshallFilter(p, allow, status) && unmarshallFilter(p, block, status))) { return false; } allow->sort(lessThan); block->sort(lessThan); return true; } // @param filter Should be sorted in ascending order. // @param val To be searched. // @return true if a match was found. bool findMetadata(const Vector<int32_t> filter, const int32_t val) { // Deal with empty and ANY right away if (filter.isEmpty()) return false; if (filter[0] == kAny) return true; ssize_t min = 0; ssize_t max = filter.size() - 1; ssize_t mid; do { mid = (min + max) / 2; if (val > filter[mid]) { min = mid + 1; } else { max = mid - 1; } if (filter[mid] == val) { return true; } } while(min <= max); return false; } } // anonymous namespace namespace android { // TODO: Temp hack until we can register players Loading Loading @@ -686,6 +830,22 @@ status_t MediaPlayerService::Client::invoke(const Parcel& request, return p->invoke(request, reply); } // This call doesn't need to access the native player. status_t MediaPlayerService::Client::setMetadataFilter(const Parcel& filter) { status_t status; Vector<int32_t> allow, drop; if (unmarshallBothFilters(filter, &allow, &drop, &status)) { Mutex::Autolock l(mLock); mMetadataAllow = allow; mMetadataDrop = drop; } return status; } status_t MediaPlayerService::Client::prepareAsync() { LOGV("[%d] prepareAsync", mConnId); Loading Loading @@ -808,10 +968,35 @@ status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolu void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2) { Client* client = static_cast<Client*>(cookie); if (MEDIA_INFO == msg && MEDIA_INFO_METADATA_UPDATE == ext1 && client->shouldDropMetadata(ext2 /* metadata type */)) { return; } LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2); client->mClient->notify(msg, ext1, ext2); } bool MediaPlayerService::Client::shouldDropMetadata(int code) const { Mutex::Autolock l(mLock); if (findMetadata(mMetadataDrop, code)) { return true; } if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) { return false; } else { return true; } } #if CALLBACK_ANTAGONIZER const int Antagonizer::interval = 10000; // 10 msecs Loading Loading
include/media/IMediaPlayer.h +6 −1 Original line number Diff line number Diff line Loading @@ -52,8 +52,13 @@ public: // @param request Parcel that must start with the media player // interface token. // @param[out] reply Parcel to hold the reply data. Cannot be null. // @return OK if the invocation was made. PERMISSION_DENIED otherwise. // @return OK if the invocation was made successfully. virtual status_t invoke(const Parcel& request, Parcel *reply) = 0; // Set a new metadata filter. // @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; }; // ---------------------------------------------------------------------------- Loading
include/media/mediaplayer.h +3 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,8 @@ enum media_info_type { MEDIA_INFO_BAD_INTERLEAVING = 800, // The media is not seekable (e.g live stream). MEDIA_INFO_NOT_SEEKABLE = 801, // New media metadata is available. MEDIA_INFO_METADATA_UPDATE = 802, }; Loading Loading @@ -152,6 +154,7 @@ public: static sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat); 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); private: void clear_l(); status_t seekTo_l(int msec); Loading
media/libmedia/IMediaPlayer.cpp +15 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ enum { SET_LOOPING, SET_VOLUME, INVOKE, SET_METADATA_FILTER, }; class BpMediaPlayer: public BpInterface<IMediaPlayer> Loading Loading @@ -178,6 +179,15 @@ public: status_t retcode = remote()->transact(INVOKE, request, reply); return retcode; } status_t setMetadataFilter(const Parcel& request) { Parcel reply; // Avoid doing any extra copy of the request. The interface // descriptor should have been set by MediaPlayer.java. remote()->transact(SET_METADATA_FILTER, request, &reply); return reply.readInt32(); } }; IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer"); Loading Loading @@ -273,6 +283,11 @@ status_t BnMediaPlayer::onTransact( invoke(data, reply); return NO_ERROR; } break; case SET_METADATA_FILTER: { CHECK_INTERFACE(IMediaPlayer, data, reply); reply->writeInt32(setMetadataFilter(data)); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } Loading
media/libmedia/mediaplayer.cpp +10 −1 Original line number Diff line number Diff line Loading @@ -208,7 +208,16 @@ status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply) return INVALID_OPERATION; } status_t MediaPlayer::setMetadataFilter(const Parcel& filter) { LOGD("setMetadataFilter"); Mutex::Autolock _l(mLock); if (mPlayer == NULL) { return NO_INIT; } return mPlayer->setMetadataFilter(filter); } status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface) { Loading
media/libmediaplayerservice/MediaPlayerService.cpp +185 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,150 @@ pid_t gettid() { return syscall(__NR_gettid);} #undef __KERNEL__ #endif namespace { using android::status_t; using android::OK; using android::BAD_VALUE; using android::NOT_ENOUGH_DATA; using android::Parcel; using android::Vector; // Max number of entries in the filter. const int kMaxFilterSize = 64; // I pulled that out of thin air. // Keep in sync with ANY in Metadata.java const int32_t kAny = 0; // To order the metadata types in the vector-filter. int lessThan(const int32_t *lhs, const int32_t *rhs) { return *lhs < *rhs ? 0 : 1; } // Unmarshall a filter from a Parcel. // Filter format in a parcel: // // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | number of entries (n) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | metadata type 1 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | metadata type 2 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // .... // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | metadata type n | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // // @param p Parcel that should start with a filter. // @param[out] filter On exit contains the list of metadata type to be // filtered. // @param[out] status On exit contains the status code to be returned. // @return true if the parcel starts with a valid filter. bool unmarshallFilter(const Parcel& p, Vector<int32_t> *filter, status_t *status) { int32_t s; if (p.readInt32(&s) != OK) { LOGE("Failed to read filter's length"); *status = NOT_ENOUGH_DATA; return false; } if( s > kMaxFilterSize || s < 0) { LOGE("Invalid filter len %d", s); *status = BAD_VALUE; return false; } size_t size = s; filter->clear(); filter->setCapacity(size); s *= sizeof(int32_t); if (p.dataAvail() < static_cast<size_t>(s)) { LOGE("Filter too short expected %d but got %d", s, p.dataAvail()); *status = NOT_ENOUGH_DATA; return false; } const int32_t *data = static_cast<const int32_t*>(p.readInplace(s)); if (NULL == data ) { LOGE("Filter had no data"); *status = BAD_VALUE; return false; } // TODO: The stl impl of vector would be more efficient here // because it degenerates into a memcpy on pod types. Try to // replace later or use stl::set. for (size_t i = 0; i < size; ++i) { filter->push(*data); ++data; } *status = OK; return true; } bool unmarshallBothFilters(const Parcel& p, Vector<int32_t> *allow, Vector<int32_t> *block, status_t *status) { if (!(unmarshallFilter(p, allow, status) && unmarshallFilter(p, block, status))) { return false; } allow->sort(lessThan); block->sort(lessThan); return true; } // @param filter Should be sorted in ascending order. // @param val To be searched. // @return true if a match was found. bool findMetadata(const Vector<int32_t> filter, const int32_t val) { // Deal with empty and ANY right away if (filter.isEmpty()) return false; if (filter[0] == kAny) return true; ssize_t min = 0; ssize_t max = filter.size() - 1; ssize_t mid; do { mid = (min + max) / 2; if (val > filter[mid]) { min = mid + 1; } else { max = mid - 1; } if (filter[mid] == val) { return true; } } while(min <= max); return false; } } // anonymous namespace namespace android { // TODO: Temp hack until we can register players Loading Loading @@ -686,6 +830,22 @@ status_t MediaPlayerService::Client::invoke(const Parcel& request, return p->invoke(request, reply); } // This call doesn't need to access the native player. status_t MediaPlayerService::Client::setMetadataFilter(const Parcel& filter) { status_t status; Vector<int32_t> allow, drop; if (unmarshallBothFilters(filter, &allow, &drop, &status)) { Mutex::Autolock l(mLock); mMetadataAllow = allow; mMetadataDrop = drop; } return status; } status_t MediaPlayerService::Client::prepareAsync() { LOGV("[%d] prepareAsync", mConnId); Loading Loading @@ -808,10 +968,35 @@ status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolu void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2) { Client* client = static_cast<Client*>(cookie); if (MEDIA_INFO == msg && MEDIA_INFO_METADATA_UPDATE == ext1 && client->shouldDropMetadata(ext2 /* metadata type */)) { return; } LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2); client->mClient->notify(msg, ext1, ext2); } bool MediaPlayerService::Client::shouldDropMetadata(int code) const { Mutex::Autolock l(mLock); if (findMetadata(mMetadataDrop, code)) { return true; } if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) { return false; } else { return true; } } #if CALLBACK_ANTAGONIZER const int Antagonizer::interval = 10000; // 10 msecs Loading