diff options
Diffstat (limited to 'media/libmediaplayerservice/MediaPlayerFactory.cpp')
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerFactory.cpp | 404 |
1 files changed, 404 insertions, 0 deletions
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp new file mode 100644 index 0000000..dcb347f --- /dev/null +++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp @@ -0,0 +1,404 @@ +/* +** +** Copyright 2012, 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_TAG "MediaPlayerFactory" +#include <utils/Log.h> + +#include <cutils/properties.h> +#include <media/IMediaPlayer.h> +#include <media/stagefright/foundation/ADebug.h> +#include <utils/Errors.h> +#include <utils/misc.h> + +#include "MediaPlayerFactory.h" + +#include "MidiFile.h" +#include "TestPlayerStub.h" +#include "StagefrightPlayer.h" +#include "nuplayer/NuPlayerDriver.h" + +namespace android { + +extern sp<MediaPlayerBase> createAAH_TXPlayer(); +extern sp<MediaPlayerBase> createAAH_RXPlayer(); + +Mutex MediaPlayerFactory::sLock; +MediaPlayerFactory::tFactoryMap MediaPlayerFactory::sFactoryMap; +bool MediaPlayerFactory::sInitComplete = false; + +status_t MediaPlayerFactory::registerFactory_l(IFactory* factory, + player_type type) { + if (NULL == factory) { + ALOGE("Failed to register MediaPlayerFactory of type %d, factory is" + " NULL.", type); + return BAD_VALUE; + } + + if (sFactoryMap.indexOfKey(type) >= 0) { + ALOGE("Failed to register MediaPlayerFactory of type %d, type is" + " already registered.", type); + return ALREADY_EXISTS; + } + + if (sFactoryMap.add(type, factory) < 0) { + ALOGE("Failed to register MediaPlayerFactory of type %d, failed to add" + " to map.", type); + return UNKNOWN_ERROR; + } + + return OK; +} + +player_type MediaPlayerFactory::getDefaultPlayerType() { + char value[PROPERTY_VALUE_MAX]; + if (property_get("media.stagefright.use-nuplayer", value, NULL) + && (!strcmp("1", value) || !strcasecmp("true", value))) { + return NU_PLAYER; + } + + return STAGEFRIGHT_PLAYER; +} + +status_t MediaPlayerFactory::registerFactory(IFactory* factory, + player_type type) { + Mutex::Autolock lock_(&sLock); + return registerFactory_l(factory, type); +} + +void MediaPlayerFactory::unregisterFactory(player_type type) { + Mutex::Autolock lock_(&sLock); + sFactoryMap.removeItem(type); +} + +#define GET_PLAYER_TYPE_IMPL(a...) \ + Mutex::Autolock lock_(&sLock); \ + \ + player_type ret = STAGEFRIGHT_PLAYER; \ + float bestScore = 0.0; \ + \ + for (size_t i = 0; i < sFactoryMap.size(); ++i) { \ + \ + IFactory* v = sFactoryMap.valueAt(i); \ + float thisScore; \ + CHECK(v != NULL); \ + thisScore = v->scoreFactory(a, bestScore); \ + if (thisScore > bestScore) { \ + ret = sFactoryMap.keyAt(i); \ + bestScore = thisScore; \ + } \ + } \ + \ + if (0.0 == bestScore) { \ + bestScore = getDefaultPlayerType(); \ + } \ + \ + return ret; + +player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client, + const char* url) { + GET_PLAYER_TYPE_IMPL(client, url); +} + +player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client, + int fd, + int64_t offset, + int64_t length) { + GET_PLAYER_TYPE_IMPL(client, fd, offset, length); +} + +player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client, + const sp<IStreamSource> &source) { + GET_PLAYER_TYPE_IMPL(client, source); +} + +#undef GET_PLAYER_TYPE_IMPL + +sp<MediaPlayerBase> MediaPlayerFactory::createPlayer( + player_type playerType, + void* cookie, + notify_callback_f notifyFunc) { + sp<MediaPlayerBase> p; + IFactory* factory; + status_t init_result; + Mutex::Autolock lock_(&sLock); + + if (sFactoryMap.indexOfKey(playerType) < 0) { + ALOGE("Failed to create player object of type %d, no registered" + " factory", playerType); + return p; + } + + factory = sFactoryMap.valueFor(playerType); + CHECK(NULL != factory); + p = factory->createPlayer(); + + if (p == NULL) { + ALOGE("Failed to create player object of type %d, create failed", + playerType); + return p; + } + + init_result = p->initCheck(); + if (init_result == NO_ERROR) { + p->setNotifyCallback(cookie, notifyFunc); + } else { + ALOGE("Failed to create player object of type %d, initCheck failed" + " (res = %d)", playerType, init_result); + p.clear(); + } + + return p; +} + +/***************************************************************************** + * * + * Built-In Factory Implementations * + * * + *****************************************************************************/ + +class StagefrightPlayerFactory : + public MediaPlayerFactory::IFactory { + public: + virtual float scoreFactory(const sp<IMediaPlayer>& client, + int fd, + int64_t offset, + int64_t length, + float curScore) { + char buf[20]; + lseek(fd, offset, SEEK_SET); + read(fd, buf, sizeof(buf)); + lseek(fd, offset, SEEK_SET); + + long ident = *((long*)buf); + + // Ogg vorbis? + if (ident == 0x5367674f) // 'OggS' + return 1.0; + + return 0.0; + } + + virtual sp<MediaPlayerBase> createPlayer() { + ALOGV(" create StagefrightPlayer"); + return new StagefrightPlayer(); + } +}; + +class NuPlayerFactory : public MediaPlayerFactory::IFactory { + public: + virtual float scoreFactory(const sp<IMediaPlayer>& client, + const char* url, + float curScore) { + static const float kOurScore = 0.8; + + if (kOurScore <= curScore) + return 0.0; + + if (!strncasecmp("http://", url, 7) + || !strncasecmp("https://", url, 8)) { + size_t len = strlen(url); + if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) { + return kOurScore; + } + + if (strstr(url,"m3u8")) { + return kOurScore; + } + } + + if (!strncasecmp("rtsp://", url, 7)) { + return kOurScore; + } + + return 0.0; + } + + virtual float scoreFactory(const sp<IMediaPlayer>& client, + const sp<IStreamSource> &source, + float curScore) { + return 1.0; + } + + virtual sp<MediaPlayerBase> createPlayer() { + ALOGV(" create NuPlayer"); + return new NuPlayerDriver; + } +}; + +class SonivoxPlayerFactory : public MediaPlayerFactory::IFactory { + public: + virtual float scoreFactory(const sp<IMediaPlayer>& client, + const char* url, + float curScore) { + static const float kOurScore = 0.4; + static const char* const FILE_EXTS[] = { ".mid", + ".midi", + ".smf", + ".xmf", + ".imy", + ".rtttl", + ".rtx", + ".ota" }; + if (kOurScore <= curScore) + return 0.0; + + // use MidiFile for MIDI extensions + int lenURL = strlen(url); + for (int i = 0; i < NELEM(FILE_EXTS); ++i) { + int len = strlen(FILE_EXTS[i]); + int start = lenURL - len; + if (start > 0) { + if (!strncasecmp(url + start, FILE_EXTS[i], len)) { + return kOurScore; + } + } + } + + return 0.0; + } + + virtual float scoreFactory(const sp<IMediaPlayer>& client, + int fd, + int64_t offset, + int64_t length, + float curScore) { + static const float kOurScore = 0.8; + + if (kOurScore <= curScore) + return 0.0; + + // Some kind of MIDI? + EAS_DATA_HANDLE easdata; + if (EAS_Init(&easdata) == EAS_SUCCESS) { + EAS_FILE locator; + locator.path = NULL; + locator.fd = fd; + locator.offset = offset; + locator.length = length; + EAS_HANDLE eashandle; + if (EAS_OpenFile(easdata, &locator, &eashandle) == EAS_SUCCESS) { + EAS_CloseFile(easdata, eashandle); + EAS_Shutdown(easdata); + return kOurScore; + } + EAS_Shutdown(easdata); + } + + return 0.0; + } + + virtual sp<MediaPlayerBase> createPlayer() { + ALOGV(" create MidiFile"); + return new MidiFile(); + } +}; + +class TestPlayerFactory : public MediaPlayerFactory::IFactory { + public: + virtual float scoreFactory(const sp<IMediaPlayer>& client, + const char* url, + float curScore) { + if (TestPlayerStub::canBeUsed(url)) { + return 1.0; + } + + return 0.0; + } + + virtual sp<MediaPlayerBase> createPlayer() { + ALOGV("Create Test Player stub"); + return new TestPlayerStub(); + } +}; + +class AAH_RX_PlayerFactory : public MediaPlayerFactory::IFactory { + public: + virtual float scoreFactory(const sp<IMediaPlayer>& client, + const char* url, + float curScore) { + static const float kOurScore = 0.6; + + if (kOurScore <= curScore) + return 0.0; + + if (!strncasecmp("aahRX://", url, 8)) { + return kOurScore; + } + + return 0.0; + } + + virtual sp<MediaPlayerBase> createPlayer() { + ALOGV(" create A@H RX Player"); + return createAAH_RXPlayer(); + } +}; + +class AAH_TX_PlayerFactory : public MediaPlayerFactory::IFactory { + public: + virtual float scoreFactory(const sp<IMediaPlayer>& client, + const char* url, + float curScore) { + return checkRetransmitEndpoint(client) ? 1.1 : 0.0; + } + + virtual float scoreFactory(const sp<IMediaPlayer>& client, + int fd, + int64_t offset, + int64_t length, + float curScore) { + return checkRetransmitEndpoint(client) ? 1.1 : 0.0; + } + + virtual sp<MediaPlayerBase> createPlayer() { + ALOGV(" create A@H TX Player"); + return createAAH_TXPlayer(); + } + + private: + bool checkRetransmitEndpoint(const sp<IMediaPlayer>& client) { + if (client == NULL) + return false; + + struct sockaddr_in junk; + if (OK != client->getRetransmitEndpoint(&junk)) + return false; + + return true; + } +}; + +void MediaPlayerFactory::registerBuiltinFactories() { + Mutex::Autolock lock_(&sLock); + + if (sInitComplete) + return; + + registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER); + registerFactory_l(new NuPlayerFactory(), NU_PLAYER); + registerFactory_l(new SonivoxPlayerFactory(), SONIVOX_PLAYER); + registerFactory_l(new TestPlayerFactory(), TEST_PLAYER); + + // TODO: remove this once AAH players have been relocated from + // framework/base and into vendor/google_devices/phantasm + registerFactory_l(new AAH_RX_PlayerFactory(), AAH_RX_PLAYER); + registerFactory_l(new AAH_TX_PlayerFactory(), AAH_TX_PLAYER); + + sInitComplete = true; +} + +} // namespace android |