diff options
Diffstat (limited to 'media/libmediaplayerservice')
-rw-r--r-- | media/libmediaplayerservice/Android.mk | 21 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.cpp | 346 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.h | 60 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaRecorderClient.cpp | 8 | ||||
-rw-r--r-- | media/libmediaplayerservice/MetadataRetrieverClient.cpp | 10 | ||||
-rw-r--r-- | media/libmediaplayerservice/MetadataRetrieverClient.h | 7 | ||||
-rw-r--r-- | media/libmediaplayerservice/MidiFile.h | 8 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightPlayer.cpp | 213 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightPlayer.h | 63 | ||||
-rw-r--r-- | media/libmediaplayerservice/TestPlayerStub.cpp | 196 | ||||
-rw-r--r-- | media/libmediaplayerservice/TestPlayerStub.h | 123 | ||||
-rw-r--r-- | media/libmediaplayerservice/VorbisPlayer.h | 6 |
12 files changed, 1035 insertions, 26 deletions
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index f7f2490..f74ef3a 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -10,6 +10,7 @@ LOCAL_SRC_FILES:= \ MediaRecorderClient.cpp \ MediaPlayerService.cpp \ MetadataRetrieverClient.cpp \ + TestPlayerStub.cpp \ VorbisPlayer.cpp \ MidiFile.cpp @@ -20,6 +21,7 @@ endif LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ + libbinder \ libvorbisidec \ libsonivox \ libopencore_player \ @@ -27,10 +29,27 @@ LOCAL_SHARED_LIBRARIES := \ libmedia \ libandroid_runtime +ifneq ($(TARGET_SIMULATOR),true) +LOCAL_SHARED_LIBRARIES += libdl +endif + LOCAL_C_INCLUDES := external/tremor/Tremor \ - $(call include-path-for, graphics corecg) + $(call include-path-for, graphics corecg) \ + $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include LOCAL_MODULE:= libmediaplayerservice +ifeq ($(BUILD_WITH_STAGEFRIGHT),true) + LOCAL_SRC_FILES += StagefrightPlayer.cpp + + LOCAL_SHARED_LIBRARIES += \ + libstagefright \ + libstagefright_omx + + LOCAL_C_INCLUDES += $(TOP)/frameworks/base/media/libstagefright/omx + + LOCAL_CFLAGS += -DBUILD_WITH_STAGEFRIGHT -DUSE_STAGEFRIGHT +endif + include $(BUILD_SHARED_LIBRARY) diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 31eecac..5e62f9d 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -27,13 +27,21 @@ #include <unistd.h> #include <string.h> + #include <cutils/atomic.h> +#include <cutils/properties.h> // for property_get + +#include <utils/misc.h> #include <android_runtime/ActivityManager.h> -#include <utils/IPCThreadState.h> -#include <utils/IServiceManager.h> -#include <utils/MemoryHeapBase.h> -#include <utils/MemoryBase.h> + +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/MemoryHeapBase.h> +#include <binder/MemoryBase.h> +#include <utils/Errors.h> // for status_t +#include <utils/String8.h> +#include <utils/Vector.h> #include <cutils/properties.h> #include <media/MediaPlayerInterface.h> @@ -41,6 +49,8 @@ #include <media/MediaMetadataRetrieverInterface.h> #include <media/AudioTrack.h> +#include <utils/SortedVector.h> + #include "MediaRecorderClient.h" #include "MediaPlayerService.h" #include "MetadataRetrieverClient.h" @@ -48,6 +58,19 @@ #include "MidiFile.h" #include "VorbisPlayer.h" #include <media/PVPlayer.h> +#include "TestPlayerStub.h" + +#if USE_STAGEFRIGHT +#include "StagefrightPlayer.h" +#endif + +#ifdef BUILD_WITH_STAGEFRIGHT +#include <OMX.h> +#else +#include <media/IOMX.h> +#endif + + /* desktop Linux needs a little help with gettid() */ #if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS) @@ -61,6 +84,114 @@ 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::MetadataType; +using android::Parcel; +using android::SortedVector; + +// 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; + +const int32_t kMetaMarker = 0x4d455441; // 'M' 'E' 'T' 'A' + + +// 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, + SortedVector<MetadataType> *filter, + status_t *status) +{ + int32_t val; + if (p.readInt32(&val) != OK) + { + LOGE("Failed to read filter's length"); + *status = NOT_ENOUGH_DATA; + return false; + } + + if( val > kMaxFilterSize || val < 0) + { + LOGE("Invalid filter len %d", val); + *status = BAD_VALUE; + return false; + } + + const size_t num = val; + + filter->clear(); + filter->setCapacity(num); + + size_t size = num * sizeof(MetadataType); + + + if (p.dataAvail() < size) + { + LOGE("Filter too short expected %d but got %d", size, p.dataAvail()); + *status = NOT_ENOUGH_DATA; + return false; + } + + const MetadataType *data = static_cast<const MetadataType*>(p.readInplace(size)); + + 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 < num; ++i) + { + filter->add(*data); + ++data; + } + *status = OK; + return true; +} + +// @param filter Of metadata type. +// @param val To be searched. +// @return true if a match was found. +bool findMetadata(const SortedVector<MetadataType>& filter, const int32_t val) +{ + // Deal with empty and ANY right away + if (filter.isEmpty()) return false; + if (filter[0] == kAny) return true; + + return filter.indexOf(val) >= 0; +} + +} // anonymous namespace + namespace android { @@ -70,6 +201,10 @@ typedef struct { const player_type playertype; } extmap; extmap FILE_EXTS [] = { +#if USE_STAGEFRIGHT + {".mp4", STAGEFRIGHT_PLAYER}, + {".3gp", STAGEFRIGHT_PLAYER}, +#endif {".mid", SONIVOX_PLAYER}, {".midi", SONIVOX_PLAYER}, {".smf", SONIVOX_PLAYER}, @@ -105,7 +240,11 @@ MediaPlayerService::~MediaPlayerService() sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid) { +#ifndef NO_OPENCORE sp<MediaRecorderClient> recorder = new MediaRecorderClient(pid); +#else + sp<MediaRecorderClient> recorder = NULL; +#endif LOGV("Create new media recorder client from pid %d", pid); return recorder; } @@ -151,6 +290,14 @@ sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClie return c; } +sp<IOMX> MediaPlayerService::createOMX() { +#ifdef BUILD_WITH_STAGEFRIGHT + return new OMX; +#else + return NULL; +#endif +} + status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const { const size_t SIZE = 256; @@ -457,6 +604,7 @@ void MediaPlayerService::Client::disconnect() p = mPlayer; } mClient.clear(); + mPlayer.clear(); // clear the notification to prevent callbacks to dead client @@ -504,12 +652,19 @@ static player_type getPlayerType(int fd, int64_t offset, int64_t length) EAS_Shutdown(easdata); } +#if USE_STAGEFRIGHT + return STAGEFRIGHT_PLAYER; +#endif + // Fall through to PV return PV_PLAYER; } static player_type getPlayerType(const char* url) { + if (TestPlayerStub::canBeUsed(url)) { + return TEST_PLAYER; + } // use MidiFile for MIDI extensions int lenURL = strlen(url); @@ -523,6 +678,10 @@ static player_type getPlayerType(const char* url) } } +#if USE_STAGEFRIGHT + return STAGEFRIGHT_PLAYER; +#endif + // Fall through to PV return PV_PLAYER; } @@ -532,10 +691,12 @@ static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie, { sp<MediaPlayerBase> p; switch (playerType) { +#ifndef NO_OPENCORE case PV_PLAYER: LOGV(" create PVPlayer"); p = new PVPlayer(); break; +#endif case SONIVOX_PLAYER: LOGV(" create MidiFile"); p = new MidiFile(); @@ -544,6 +705,21 @@ static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie, LOGV(" create VorbisPlayer"); p = new VorbisPlayer(); break; +#if USE_STAGEFRIGHT + case STAGEFRIGHT_PLAYER: + LOGV(" create StagefrightPlayer"); + p = new StagefrightPlayer; + break; +#else + case STAGEFRIGHT_PLAYER: + LOG_ALWAYS_FATAL( + "Should not be here, stagefright player not enabled."); + break; +#endif + case TEST_PLAYER: + LOGV("Create Test Player stub"); + p = new TestPlayerStub(); + break; } if (p != NULL) { if (p->initCheck() == NO_ERROR) { @@ -608,7 +784,11 @@ status_t MediaPlayerService::Client::setDataSource(const char *url) // now set data source LOGV(" setDataSource"); mStatus = p->setDataSource(url); - if (mStatus == NO_ERROR) mPlayer = p; + if (mStatus == NO_ERROR) { + mPlayer = p; + } else { + LOGE(" error: %d", mStatus); + } return mStatus; } } @@ -665,6 +845,78 @@ status_t MediaPlayerService::Client::setVideoSurface(const sp<ISurface>& surface return p->setVideoSurface(surface); } +status_t MediaPlayerService::Client::invoke(const Parcel& request, + Parcel *reply) +{ + sp<MediaPlayerBase> p = getPlayer(); + if (p == NULL) return UNKNOWN_ERROR; + 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; + SortedVector<MetadataType> allow, drop; + + if (unmarshallFilter(filter, &allow, &status) && + unmarshallFilter(filter, &drop, &status)) { + Mutex::Autolock lock(mLock); + + mMetadataAllow = allow; + mMetadataDrop = drop; + } + return status; +} + +status_t MediaPlayerService::Client::getMetadata( + bool update_only, bool apply_filter, Parcel *reply) +{ + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + + status_t status; + // Placeholder for the return code, updated by the caller. + reply->writeInt32(-1); + + SortedVector<MetadataType> ids; + + // We don't block notifications while we fetch the data. We clear + // mMetadataUpdated first so we don't lose notifications happening + // during the rest of this call. + { + Mutex::Autolock lock(mLock); + if (update_only) { + ids = mMetadataUpdated; + } + mMetadataUpdated.clear(); + } + + const size_t begin = reply->dataPosition(); + reply->writeInt32(-1); // Placeholder for the length of the metadata + reply->writeInt32(kMetaMarker); + + status = p->getMetadata(ids, reply); + + if (status != OK) { + reply->setDataPosition(begin); + LOGE("getMetadata failed %d", status); + return status; + } + + // FIXME: Implement filtering on the result. Not critical since + // filtering takes place on the update notifications already. This + // would be when all the metadata are fetch and a filter is set. + + const size_t end = reply->dataPosition(); + + // Everything is fine, update the metadata length. + reply->setDataPosition(begin); + reply->writeInt32(end - begin); + reply->setDataPosition(end); + return OK; +} + status_t MediaPlayerService::Client::prepareAsync() { LOGV("[%d] prepareAsync", mConnId); @@ -784,13 +1036,51 @@ status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolu return NO_ERROR; } + 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) { + const MetadataType metadata_type = ext2; + + if(client->shouldDropMetadata(metadata_type)) { + return; + } + + // Update the list of metadata that have changed. getMetadata + // also access mMetadataUpdated and clears it. + client->addNewMetadataUpdate(metadata_type); + } LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2); client->mClient->notify(msg, ext1, ext2); } + +bool MediaPlayerService::Client::shouldDropMetadata(MetadataType code) const +{ + Mutex::Autolock lock(mLock); + + if (findMetadata(mMetadataDrop, code)) { + return true; + } + + if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) { + return false; + } else { + return true; + } +} + + +void MediaPlayerService::Client::addNewMetadataUpdate(MetadataType metadata_type) { + Mutex::Autolock lock(mLock); + if (mMetadataUpdated.indexOf(metadata_type) < 0) { + mMetadataUpdated.add(metadata_type); + } +} + #if CALLBACK_ANTAGONIZER const int Antagonizer::interval = 10000; // 10 msecs @@ -927,7 +1217,8 @@ Exit: #undef LOG_TAG #define LOG_TAG "AudioSink" MediaPlayerService::AudioOutput::AudioOutput() -{ + : mCallback(NULL), + mCallbackCookie(NULL) { mTrack = 0; mStreamType = AudioSystem::MUSIC; mLeftVolume = 1.0; @@ -997,8 +1288,13 @@ float MediaPlayerService::AudioOutput::msecsPerFrame() const return mMsecsPerFrame; } -status_t MediaPlayerService::AudioOutput::open(uint32_t sampleRate, int channelCount, int format, int bufferCount) +status_t MediaPlayerService::AudioOutput::open( + uint32_t sampleRate, int channelCount, int format, int bufferCount, + AudioCallback cb, void *cookie) { + mCallback = cb; + mCallbackCookie = cookie; + // Check argument "bufferCount" against the mininum buffer count if (bufferCount < mMinBufferCount) { LOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount); @@ -1019,7 +1315,17 @@ status_t MediaPlayerService::AudioOutput::open(uint32_t sampleRate, int channelC } frameCount = (sampleRate*afFrameCount*bufferCount)/afSampleRate; - AudioTrack *t = new AudioTrack(mStreamType, sampleRate, format, channelCount, frameCount); + + AudioTrack *t; + if (mCallback != NULL) { + t = new AudioTrack( + mStreamType, sampleRate, format, channelCount, frameCount, + 0 /* flags */, CallbackWrapper, this); + } else { + t = new AudioTrack( + mStreamType, sampleRate, format, channelCount, frameCount); + } + if ((t == 0) || (t->initCheck() != NO_ERROR)) { LOGE("Unable to create audio track"); delete t; @@ -1045,6 +1351,8 @@ void MediaPlayerService::AudioOutput::start() ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size) { + LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback."); + //LOGV("write(%p, %u)", buffer, size); if (mTrack) return mTrack->write(buffer, size); return NO_INIT; @@ -1085,6 +1393,20 @@ void MediaPlayerService::AudioOutput::setVolume(float left, float right) } } +// static +void MediaPlayerService::AudioOutput::CallbackWrapper( + int event, void *cookie, void *info) { + if (event != AudioTrack::EVENT_MORE_DATA) { + return; + } + + AudioOutput *me = (AudioOutput *)cookie; + AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info; + + (*me->mCallback)( + me, buffer->raw, buffer->size, me->mCallbackCookie); +} + #undef LOG_TAG #define LOG_TAG "AudioCache" MediaPlayerService::AudioCache::AudioCache(const char* name) : @@ -1105,8 +1427,14 @@ float MediaPlayerService::AudioCache::msecsPerFrame() const return mMsecsPerFrame; } -status_t MediaPlayerService::AudioCache::open(uint32_t sampleRate, int channelCount, int format, int bufferCount) +status_t MediaPlayerService::AudioCache::open( + uint32_t sampleRate, int channelCount, int format, int bufferCount, + AudioCallback cb, void *cookie) { + if (cb != NULL) { + return UNKNOWN_ERROR; // TODO: implement this. + } + LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount); if (mHeap->getHeapID() < 0) return NO_INIT; mSampleRate = sampleRate; diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index f138886..94cb917 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -18,17 +18,24 @@ #ifndef ANDROID_MEDIAPLAYERSERVICE_H #define ANDROID_MEDIAPLAYERSERVICE_H -#include <utils.h> +#include <utils/Log.h> +#include <utils/threads.h> +#include <utils/List.h> +#include <utils/Errors.h> #include <utils/KeyedVector.h> +#include <utils/SortedVector.h> +#include <utils/Vector.h> #include <ui/SurfaceComposerClient.h> #include <media/IMediaPlayerService.h> #include <media/MediaPlayerInterface.h> namespace android { +typedef int32_t MetadataType; class IMediaRecorder; class IMediaMetadataRetriever; +class IOMX; #define CALLBACK_ANTAGONIZER 0 #if CALLBACK_ANTAGONIZER @@ -69,7 +76,12 @@ class MediaPlayerService : public BnMediaPlayerService virtual ssize_t frameSize() const; virtual uint32_t latency() const; virtual float msecsPerFrame() const; - virtual status_t open(uint32_t sampleRate, int channelCount, int format, int bufferCount=4); + + virtual status_t open( + uint32_t sampleRate, int channelCount, + int format, int bufferCount, + AudioCallback cb, void *cookie); + virtual void start(); virtual ssize_t write(const void* buffer, size_t size); virtual void stop(); @@ -84,8 +96,12 @@ class MediaPlayerService : public BnMediaPlayerService static int getMinBufferCount(); private: static void setMinBufferCount(); + static void CallbackWrapper( + int event, void *me, void *info); AudioTrack* mTrack; + AudioCallback mCallback; + void * mCallbackCookie; int mStreamType; float mLeftVolume; float mRightVolume; @@ -113,7 +129,12 @@ class MediaPlayerService : public BnMediaPlayerService virtual ssize_t frameSize() const { return ssize_t(mChannelCount * ((mFormat == AudioSystem::PCM_16_BIT)?sizeof(int16_t):sizeof(u_int8_t))); } virtual uint32_t latency() const; virtual float msecsPerFrame() const; - virtual status_t open(uint32_t sampleRate, int channelCount, int format, int bufferCount=1); + + virtual status_t open( + uint32_t sampleRate, int channelCount, int format, + int bufferCount = 1, + AudioCallback cb = NULL, void *cookie = NULL); + virtual void start() {} virtual ssize_t write(const void* buffer, size_t size); virtual void stop() {} @@ -140,7 +161,7 @@ class MediaPlayerService : public BnMediaPlayerService sp<MemoryHeapBase> mHeap; float mMsecsPerFrame; uint16_t mChannelCount; - uint16_t mFormat; + uint16_t mFormat; ssize_t mFrameCount; uint32_t mSampleRate; uint32_t mSize; @@ -160,11 +181,13 @@ public: virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length); virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat); virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat); + virtual sp<IOMX> createOMX(); virtual status_t dump(int fd, const Vector<String16>& args); void removeClient(wp<Client> client); + private: class Client : public BnMediaPlayer { @@ -184,6 +207,11 @@ private: virtual status_t setAudioStreamType(int type); virtual status_t setLooping(int loop); 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 *reply); sp<MediaPlayerBase> createPlayer(player_type playerType); status_t setDataSource(const char *url); @@ -206,6 +234,18 @@ private: sp<MediaPlayerBase> getPlayer() const { Mutex::Autolock lock(mLock); return mPlayer; } + + + // @param type Of the metadata to be tested. + // @return true if the metadata should be dropped according to + // the filters. + bool shouldDropMetadata(MetadataType type) const; + + // Add a new element to the set of metadata updated. Noop if + // the element exists already. + // @param type Of the metadata to be recorded. + void addNewMetadataUpdate(MetadataType type); + mutable Mutex mLock; sp<MediaPlayerBase> mPlayer; sp<MediaPlayerService> mService; @@ -215,6 +255,17 @@ private: status_t mStatus; bool mLoop; int32_t mConnId; + + // Metadata filters. + SortedVector<int32_t> mMetadataAllow; // protected by mLock + SortedVector<int32_t> mMetadataDrop; // protected by mLock + + // Metadata updated. For each MEDIA_INFO_METADATA_UPDATE + // notification we try to update mMetadataUpdated which is a + // set: no duplicate. + // getMetadata clears this set. + SortedVector<int32_t> mMetadataUpdated; // protected by mLock + #if CALLBACK_ANTAGONIZER Antagonizer* mAntagonizer; #endif @@ -235,4 +286,3 @@ private: }; // namespace android #endif // ANDROID_MEDIAPLAYERSERVICE_H - diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp index 8bc410c..e54f20d 100644 --- a/media/libmediaplayerservice/MediaRecorderClient.cpp +++ b/media/libmediaplayerservice/MediaRecorderClient.cpp @@ -25,10 +25,10 @@ #include <string.h> #include <cutils/atomic.h> #include <android_runtime/ActivityManager.h> -#include <utils/IPCThreadState.h> -#include <utils/IServiceManager.h> -#include <utils/MemoryHeapBase.h> -#include <utils/MemoryBase.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/MemoryHeapBase.h> +#include <binder/MemoryBase.h> #include <media/PVMediaRecorder.h> #include <utils/String16.h> diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp index a320bd5..ba8d9a8 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp +++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp @@ -26,10 +26,10 @@ #include <string.h> #include <cutils/atomic.h> -#include <utils/MemoryDealer.h> +#include <binder/MemoryDealer.h> #include <android_runtime/ActivityManager.h> -#include <utils/IPCThreadState.h> -#include <utils/IServiceManager.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> #include <media/MediaMetadataRetrieverInterface.h> #include <media/MediaPlayerInterface.h> #include <media/PVMetadataRetriever.h> @@ -49,7 +49,11 @@ MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid) mThumbnail = NULL; mAlbumArt = NULL; +#ifndef NO_OPENCORE mRetriever = new PVMetadataRetriever(); +#else + mRetriever = NULL; +#endif if (mRetriever == NULL) { LOGE("failed to initialize the retriever"); } diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h index ce29c98..88d50bf 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.h +++ b/media/libmediaplayerservice/MetadataRetrieverClient.h @@ -18,9 +18,12 @@ #ifndef ANDROID_MEDIAMETADATARETRIEVERSERVICE_H #define ANDROID_MEDIAMETADATARETRIEVERSERVICE_H -#include <utils.h> +#include <utils/Log.h> +#include <utils/threads.h> +#include <utils/List.h> +#include <utils/Errors.h> #include <utils/KeyedVector.h> -#include <utils/IMemory.h> +#include <binder/IMemory.h> #include <media/MediaMetadataRetrieverInterface.h> diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h index 302f1cf..30b6a2e 100644 --- a/media/libmediaplayerservice/MidiFile.h +++ b/media/libmediaplayerservice/MidiFile.h @@ -46,6 +46,13 @@ public: virtual status_t reset(); virtual status_t setLooping(int loop); virtual player_type playerType() { return SONIVOX_PLAYER; } + virtual status_t invoke(const Parcel& request, Parcel *reply) { + return INVALID_OPERATION; + } + virtual status_t getMetadata(const SortedVector<MetadataType>& ids, + Parcel *records) { + return INVALID_OPERATION; + } private: status_t createOutputTrack(); @@ -74,4 +81,3 @@ private: }; // namespace android #endif // ANDROID_MIDIFILE_H - diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp new file mode 100644 index 0000000..8597275 --- /dev/null +++ b/media/libmediaplayerservice/StagefrightPlayer.cpp @@ -0,0 +1,213 @@ +//#define LOG_NDEBUG 0 +#define LOG_TAG "StagefrightPlayer" +#include <utils/Log.h> + +#include "StagefrightPlayer.h" +#include <media/stagefright/MediaPlayerImpl.h> + +namespace android { + +StagefrightPlayer::StagefrightPlayer() + : mPlayer(NULL) { + LOGV("StagefrightPlayer"); +} + +StagefrightPlayer::~StagefrightPlayer() { + LOGV("~StagefrightPlayer"); + reset(); + LOGV("~StagefrightPlayer done."); +} + +status_t StagefrightPlayer::initCheck() { + LOGV("initCheck"); + return OK; +} + +status_t StagefrightPlayer::setDataSource(const char *url) { + LOGV("setDataSource('%s')", url); + + reset(); + mPlayer = new MediaPlayerImpl(url); + + status_t err = mPlayer->initCheck(); + if (err != OK) { + delete mPlayer; + mPlayer = NULL; + } else { + mPlayer->setAudioSink(mAudioSink); + } + + return err; +} + +status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) { + LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); + + reset(); + mPlayer = new MediaPlayerImpl(fd, offset, length); + + status_t err = mPlayer->initCheck(); + if (err != OK) { + delete mPlayer; + mPlayer = NULL; + } else { + mPlayer->setAudioSink(mAudioSink); + } + + return err; +} + +status_t StagefrightPlayer::setVideoSurface(const sp<ISurface> &surface) { + LOGV("setVideoSurface"); + + if (mPlayer == NULL) { + return NO_INIT; + } + + mPlayer->setISurface(surface); + + return OK; +} + +status_t StagefrightPlayer::prepare() { + LOGV("prepare"); + + if (mPlayer == NULL) { + return NO_INIT; + } + + sendEvent( + MEDIA_SET_VIDEO_SIZE, + mPlayer->getWidth(), mPlayer->getHeight()); + + return OK; +} + +status_t StagefrightPlayer::prepareAsync() { + LOGV("prepareAsync"); + + status_t err = prepare(); + + if (err != OK) { + return err; + } + + sendEvent(MEDIA_PREPARED); + + return OK; +} + +status_t StagefrightPlayer::start() { + LOGV("start"); + + if (mPlayer == NULL) { + return NO_INIT; + } + + mPlayer->play(); + + return OK; +} + +status_t StagefrightPlayer::stop() { + LOGV("stop"); + + if (mPlayer == NULL) { + return NO_INIT; + } + + reset(); + + return OK; +} + +status_t StagefrightPlayer::pause() { + LOGV("pause"); + + if (mPlayer == NULL) { + return NO_INIT; + } + + mPlayer->pause(); + + return OK; +} + +bool StagefrightPlayer::isPlaying() { + LOGV("isPlaying"); + return mPlayer != NULL && mPlayer->isPlaying(); +} + +status_t StagefrightPlayer::seekTo(int msec) { + LOGV("seekTo"); + + if (mPlayer == NULL) { + return NO_INIT; + } + + status_t err = mPlayer->seekTo((int64_t)msec * 1000); + + sendEvent(MEDIA_SEEK_COMPLETE); + + return err; +} + +status_t StagefrightPlayer::getCurrentPosition(int *msec) { + LOGV("getCurrentPosition"); + + if (mPlayer == NULL) { + return NO_INIT; + } + + *msec = mPlayer->getPosition() / 1000; + return OK; +} + +status_t StagefrightPlayer::getDuration(int *msec) { + LOGV("getDuration"); + + if (mPlayer == NULL) { + return NO_INIT; + } + + *msec = mPlayer->getDuration() / 1000; + return OK; +} + +status_t StagefrightPlayer::reset() { + LOGV("reset"); + + delete mPlayer; + mPlayer = NULL; + + return OK; +} + +status_t StagefrightPlayer::setLooping(int loop) { + LOGV("setLooping"); + return UNKNOWN_ERROR; +} + +player_type StagefrightPlayer::playerType() { + LOGV("playerType"); + return STAGEFRIGHT_PLAYER; +} + +status_t StagefrightPlayer::invoke(const Parcel &request, Parcel *reply) { + return INVALID_OPERATION; +} + +void StagefrightPlayer::setAudioSink(const sp<AudioSink> &audioSink) { + MediaPlayerInterface::setAudioSink(audioSink); + + if (mPlayer != NULL) { + mPlayer->setAudioSink(audioSink); + } +} + +status_t StagefrightPlayer::getMetadata( + const SortedVector<MetadataType> &ids, Parcel *records) { + return INVALID_OPERATION; +} + +} // namespace android diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h new file mode 100644 index 0000000..f93c1f8 --- /dev/null +++ b/media/libmediaplayerservice/StagefrightPlayer.h @@ -0,0 +1,63 @@ +/* +** +** Copyright 2009, 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_STAGEFRIGHTPLAYER_H +#define ANDROID_STAGEFRIGHTPLAYER_H + +#include <media/MediaPlayerInterface.h> + +namespace android { + +class MediaPlayerImpl; + +class StagefrightPlayer : public MediaPlayerInterface { +public: + StagefrightPlayer(); + virtual ~StagefrightPlayer(); + + virtual status_t initCheck(); + virtual status_t setDataSource(const char *url); + virtual status_t setDataSource(int fd, int64_t offset, int64_t length); + virtual status_t setVideoSurface(const sp<ISurface> &surface); + virtual status_t prepare(); + virtual status_t prepareAsync(); + virtual status_t start(); + virtual status_t stop(); + virtual status_t pause(); + virtual bool isPlaying(); + virtual status_t seekTo(int msec); + virtual status_t getCurrentPosition(int *msec); + virtual status_t getDuration(int *msec); + virtual status_t reset(); + virtual status_t setLooping(int loop); + virtual player_type playerType(); + virtual status_t invoke(const Parcel &request, Parcel *reply); + virtual void setAudioSink(const sp<AudioSink> &audioSink); + + virtual status_t getMetadata( + const SortedVector<MetadataType> &ids, Parcel *records); + +private: + MediaPlayerImpl *mPlayer; + + StagefrightPlayer(const StagefrightPlayer &); + StagefrightPlayer &operator=(const StagefrightPlayer &); +}; + +} // namespace android + +#endif // ANDROID_STAGEFRIGHTPLAYER_H diff --git a/media/libmediaplayerservice/TestPlayerStub.cpp b/media/libmediaplayerservice/TestPlayerStub.cpp new file mode 100644 index 0000000..8627708 --- /dev/null +++ b/media/libmediaplayerservice/TestPlayerStub.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2009 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 "TestPlayerStub" +#include "utils/Log.h" + +#include "TestPlayerStub.h" + +#include <dlfcn.h> // for dlopen/dlclose +#include <stdlib.h> +#include <string.h> +#include <cutils/properties.h> +#include <utils/Errors.h> // for status_t + +#include "media/MediaPlayerInterface.h" + + +namespace { +using android::status_t; +using android::MediaPlayerBase; + +const char *kTestUrlScheme = "test:"; +const char *kUrlParam = "url="; + +const char *kBuildTypePropName = "ro.build.type"; +const char *kEngBuild = "eng"; +const char *kTestBuild = "test"; + +// @return true if the current build is 'eng' or 'test'. +bool isTestBuild() +{ + char prop[PROPERTY_VALUE_MAX] = { '\0', }; + + property_get(kBuildTypePropName, prop, '\0'); + return strcmp(prop, kEngBuild) == 0 || strcmp(prop, kTestBuild) == 0; +} + +// @return true if the url scheme is 'test:' +bool isTestUrl(const char *url) +{ + return url && strncmp(url, kTestUrlScheme, strlen(kTestUrlScheme)) == 0; +} + +} // anonymous namespace + +namespace android { + +TestPlayerStub::TestPlayerStub() + :mUrl(NULL), mFilename(NULL), mContentUrl(NULL), + mHandle(NULL), mNewPlayer(NULL), mDeletePlayer(NULL), + mPlayer(NULL) { } + +TestPlayerStub::~TestPlayerStub() +{ + resetInternal(); +} + +status_t TestPlayerStub::initCheck() +{ + return isTestBuild() ? OK : INVALID_OPERATION; +} + +// Parse mUrl to get: +// * The library to be dlopened. +// * The url to be passed to the real setDataSource impl. +// +// mUrl is expected to be in following format: +// +// test:<name of the .so>?url=<url for setDataSource> +// +// The value of the url parameter is treated as a string (no +// unescaping of illegal charaters). +status_t TestPlayerStub::parseUrl() +{ + if (strlen(mUrl) < strlen(kTestUrlScheme)) { + resetInternal(); + return BAD_VALUE; + } + + char *i = mUrl + strlen(kTestUrlScheme); + + mFilename = i; + + while (*i != '\0' && *i != '?') { + ++i; + } + + if (*i == '\0' || strncmp(i + 1, kUrlParam, strlen(kUrlParam)) != 0) { + resetInternal(); + return BAD_VALUE; + } + *i = '\0'; // replace '?' to nul-terminate mFilename + + mContentUrl = i + 1 + strlen(kUrlParam); + return OK; +} + +// Load the dynamic library. +// Create the test player. +// Call setDataSource on the test player with the url in param. +status_t TestPlayerStub::setDataSource(const char *url) +{ + if (!isTestUrl(url) || NULL != mHandle) { + return INVALID_OPERATION; + } + + mUrl = strdup(url); + + status_t status = parseUrl(); + + if (OK != status) { + resetInternal(); + return status; + } + + ::dlerror(); // Clears any pending error. + + // Load the test player from the url. dlopen will fail if the lib + // is not there. dls are under /system/lib + // None of the entry points should be NULL. + mHandle = ::dlopen(mFilename, RTLD_NOW | RTLD_GLOBAL); + if (!mHandle) { + LOGE("dlopen failed: %s", ::dlerror()); + resetInternal(); + return UNKNOWN_ERROR; + } + + // Load the 2 entry points to create and delete instances. + const char *err; + mNewPlayer = reinterpret_cast<NEW_PLAYER>(dlsym(mHandle, + "newPlayer")); + err = ::dlerror(); + if (err || mNewPlayer == NULL) { + // if err is NULL the string <null> is inserted in the logs => + // mNewPlayer was NULL. + LOGE("dlsym for newPlayer failed %s", err); + resetInternal(); + return UNKNOWN_ERROR; + } + + mDeletePlayer = reinterpret_cast<DELETE_PLAYER>(dlsym(mHandle, + "deletePlayer")); + err = ::dlerror(); + if (err || mDeletePlayer == NULL) { + LOGE("dlsym for deletePlayer failed %s", err); + resetInternal(); + return UNKNOWN_ERROR; + } + + mPlayer = (*mNewPlayer)(); + return mPlayer->setDataSource(mContentUrl); +} + +// Internal cleanup. +status_t TestPlayerStub::resetInternal() +{ + if(mUrl) { + free(mUrl); + mUrl = NULL; + } + mFilename = NULL; + mContentUrl = NULL; + + if (mPlayer) { + LOG_ASSERT(mDeletePlayer != NULL); + (*mDeletePlayer)(mPlayer); + mPlayer = NULL; + } + + if (mHandle) { + ::dlclose(mHandle); + mHandle = NULL; + } + return OK; +} + +/* static */ bool TestPlayerStub::canBeUsed(const char *url) +{ + return isTestBuild() && isTestUrl(url); +} + +} // namespace android diff --git a/media/libmediaplayerservice/TestPlayerStub.h b/media/libmediaplayerservice/TestPlayerStub.h new file mode 100644 index 0000000..339b108 --- /dev/null +++ b/media/libmediaplayerservice/TestPlayerStub.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2009 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_FRAMEWORKS_BASE_MEDIA_LIBMEDIAPLAYERSERVICE_TESTPLAYERSTUB_H__ +#define ANDROID_FRAMEWORKS_BASE_MEDIA_LIBMEDIAPLAYERSERVICE_TESTPLAYERSTUB_H__ + +#include <media/MediaPlayerInterface.h> +#include <utils/Errors.h> + +namespace android { +class MediaPlayerBase; // in media/MediaPlayerInterface.h + +// Wrapper around a test media player that gets dynamically loaded. +// +// The URL passed to setDataSource has this format: +// +// test:<name of the .so>?url=<url for the real setDataSource impl.> +// +// e.g: +// test:invoke_test_media_player.so?url=http://youtube.com/ +// test:invoke_test_media_player.so?url=speedtest +// +// TestPlayerStub::setDataSource loads the library in the test url. 2 +// entry points with C linkage are expected. One to create the test +// player and one to destroy it. +// +// extern "C" android::MediaPlayerBase* newPlayer(); +// extern "C" android::status_t deletePlayer(android::MediaPlayerBase *p); +// +// Once the test player has been loaded, its setDataSource +// implementation is called with the value of the 'url' parameter. +// +// typical usage in a java test: +// ============================ +// +// MediaPlayer p = new MediaPlayer(); +// p.setDataSource("test:invoke_mock_media_player.so?url=http://youtube.com"); +// p.prepare(); +// ... +// p.release(); + +class TestPlayerStub : public MediaPlayerInterface { + public: + typedef MediaPlayerBase* (*NEW_PLAYER)(); + typedef status_t (*DELETE_PLAYER)(MediaPlayerBase *); + + TestPlayerStub(); + virtual ~TestPlayerStub(); + + // Called right after the constructor. Check if the current build + // allows test players. + virtual status_t initCheck(); + + // @param url Should be a test url. See class comment. + virtual status_t setDataSource(const char* url); + + // Test player for a file descriptor source is not supported. + virtual status_t setDataSource(int, int64_t, int64_t) { + return INVALID_OPERATION; + } + + + // All the methods below wrap the mPlayer instance. + virtual status_t setVideoSurface(const android::sp<android::ISurface>& s) { + return mPlayer->setVideoSurface(s); + } + virtual status_t prepare() {return mPlayer->prepare();} + virtual status_t prepareAsync() {return mPlayer->prepareAsync();} + virtual status_t start() {return mPlayer->start();} + virtual status_t stop() {return mPlayer->stop();} + virtual status_t pause() {return mPlayer->pause();} + virtual bool isPlaying() {return mPlayer->isPlaying();} + virtual status_t seekTo(int msec) {return mPlayer->seekTo(msec);} + virtual status_t getCurrentPosition(int *p) { + return mPlayer->getCurrentPosition(p); + } + virtual status_t getDuration(int *d) {return mPlayer->getDuration(d);} + virtual status_t reset() {return mPlayer->reset();} + virtual status_t setLooping(int b) {return mPlayer->setLooping(b);} + virtual player_type playerType() {return mPlayer->playerType();} + virtual status_t invoke(const android::Parcel& in, android::Parcel *out) { + return mPlayer->invoke(in, out); + } + virtual status_t getMetadata(const SortedVector<MetadataType>& ids, + Parcel *records) { + return INVALID_OPERATION; + } + + + // @return true if the current build is 'eng' or 'test' and the + // url's scheme is 'test:' + static bool canBeUsed(const char *url); + + private: + // Release the player, dlclose the library. + status_t resetInternal(); + status_t parseUrl(); + + char *mUrl; // test:foo.so?url=http://bar + char *mFilename; // foo.so + char *mContentUrl; // http://bar + void *mHandle; // returned by dlopen + NEW_PLAYER mNewPlayer; + DELETE_PLAYER mDeletePlayer; + MediaPlayerBase *mPlayer; // wrapped player +}; + +} // namespace android + +#endif diff --git a/media/libmediaplayerservice/VorbisPlayer.h b/media/libmediaplayerservice/VorbisPlayer.h index c30dc1b..040eb36 100644 --- a/media/libmediaplayerservice/VorbisPlayer.h +++ b/media/libmediaplayerservice/VorbisPlayer.h @@ -53,6 +53,11 @@ public: virtual status_t reset(); virtual status_t setLooping(int loop); virtual player_type playerType() { return VORBIS_PLAYER; } + virtual status_t invoke(const Parcel& request, Parcel *reply) {return INVALID_OPERATION;} + virtual status_t getMetadata(const SortedVector<MetadataType>& ids, + Parcel *records) { + return INVALID_OPERATION; + } private: status_t setdatasource(const char *path, int fd, int64_t offset, int64_t length); @@ -88,4 +93,3 @@ private: }; // namespace android #endif // ANDROID_VORBISPLAYER_H - |