/* ** ** 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 #include #include #include #include #include #include "MediaPlayerFactory.h" #include "MidiFile.h" #include "TestPlayerStub.h" #include "StagefrightPlayer.h" #include "nuplayer/NuPlayerDriver.h" namespace android { 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) { \ ret = getDefaultPlayerType(); \ } \ \ return ret; player_type MediaPlayerFactory::getPlayerType(const sp& client, const char* url) { GET_PLAYER_TYPE_IMPL(client, url); } player_type MediaPlayerFactory::getPlayerType(const sp& client, int fd, int64_t offset, int64_t length) { GET_PLAYER_TYPE_IMPL(client, fd, offset, length); } player_type MediaPlayerFactory::getPlayerType(const sp& client, const sp &source) { GET_PLAYER_TYPE_IMPL(client, source); } #undef GET_PLAYER_TYPE_IMPL sp MediaPlayerFactory::createPlayer( player_type playerType, void* cookie, notify_callback_f notifyFunc) { sp 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& /*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 createPlayer() { ALOGV(" create StagefrightPlayer"); return new StagefrightPlayer(); } }; class NuPlayerFactory : public MediaPlayerFactory::IFactory { public: virtual float scoreFactory(const sp& /*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) || !strncasecmp("file://", url, 7)) { size_t len = strlen(url); if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) { return kOurScore; } if (strstr(url,"m3u8")) { return kOurScore; } if ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) || strstr(url, ".sdp?")) { return kOurScore; } } if (!strncasecmp("rtsp://", url, 7)) { return kOurScore; } return 0.0; } virtual float scoreFactory(const sp& /*client*/, const sp& /*source*/, float /*curScore*/) { return 1.0; } virtual sp createPlayer() { ALOGV(" create NuPlayer"); return new NuPlayerDriver; } }; class SonivoxPlayerFactory : public MediaPlayerFactory::IFactory { public: virtual float scoreFactory(const sp& /*client*/, const char* url, float curScore) { static const float kOurScore = 0.4; static const char* const FILE_EXTS[] = { ".mid", ".midi", ".smf", ".xmf", ".mxmf", ".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& /*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 createPlayer() { ALOGV(" create MidiFile"); return new MidiFile(); } }; class TestPlayerFactory : public MediaPlayerFactory::IFactory { public: virtual float scoreFactory(const sp& /*client*/, const char* url, float /*curScore*/) { if (TestPlayerStub::canBeUsed(url)) { return 1.0; } return 0.0; } virtual sp createPlayer() { ALOGV("Create Test Player stub"); return new TestPlayerStub(); } }; 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); sInitComplete = true; } } // namespace android