summaryrefslogtreecommitdiffstats
path: root/media/libmediaplayerservice/MediaPlayerFactory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libmediaplayerservice/MediaPlayerFactory.cpp')
-rw-r--r--media/libmediaplayerservice/MediaPlayerFactory.cpp404
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