blob: b1685b908b6058c81727d877963d830315a30fdb [file] [log] [blame]
John Grossman44a7e422012-06-21 17:29:24 -07001/*
2**
3** Copyright 2012, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define LOG_TAG "MediaPlayerFactory"
19#include <utils/Log.h>
20
21#include <cutils/properties.h>
22#include <media/IMediaPlayer.h>
23#include <media/stagefright/foundation/ADebug.h>
24#include <utils/Errors.h>
25#include <utils/misc.h>
26
27#include "MediaPlayerFactory.h"
28
29#include "MidiFile.h"
30#include "TestPlayerStub.h"
31#include "StagefrightPlayer.h"
32#include "nuplayer/NuPlayerDriver.h"
Ajit Khare821695d2013-01-07 23:23:39 -080033#include <dlfcn.h>
John Grossman44a7e422012-06-21 17:29:24 -070034
35namespace android {
36
John Grossman44a7e422012-06-21 17:29:24 -070037Mutex MediaPlayerFactory::sLock;
38MediaPlayerFactory::tFactoryMap MediaPlayerFactory::sFactoryMap;
39bool MediaPlayerFactory::sInitComplete = false;
40
41status_t MediaPlayerFactory::registerFactory_l(IFactory* factory,
42 player_type type) {
43 if (NULL == factory) {
44 ALOGE("Failed to register MediaPlayerFactory of type %d, factory is"
45 " NULL.", type);
46 return BAD_VALUE;
47 }
48
49 if (sFactoryMap.indexOfKey(type) >= 0) {
50 ALOGE("Failed to register MediaPlayerFactory of type %d, type is"
51 " already registered.", type);
52 return ALREADY_EXISTS;
53 }
54
55 if (sFactoryMap.add(type, factory) < 0) {
56 ALOGE("Failed to register MediaPlayerFactory of type %d, failed to add"
57 " to map.", type);
58 return UNKNOWN_ERROR;
59 }
60
61 return OK;
62}
63
64player_type MediaPlayerFactory::getDefaultPlayerType() {
65 char value[PROPERTY_VALUE_MAX];
66 if (property_get("media.stagefright.use-nuplayer", value, NULL)
67 && (!strcmp("1", value) || !strcasecmp("true", value))) {
68 return NU_PLAYER;
69 }
70
71 return STAGEFRIGHT_PLAYER;
72}
73
74status_t MediaPlayerFactory::registerFactory(IFactory* factory,
75 player_type type) {
76 Mutex::Autolock lock_(&sLock);
77 return registerFactory_l(factory, type);
78}
79
80void MediaPlayerFactory::unregisterFactory(player_type type) {
81 Mutex::Autolock lock_(&sLock);
82 sFactoryMap.removeItem(type);
83}
84
85#define GET_PLAYER_TYPE_IMPL(a...) \
86 Mutex::Autolock lock_(&sLock); \
87 \
88 player_type ret = STAGEFRIGHT_PLAYER; \
89 float bestScore = 0.0; \
90 \
91 for (size_t i = 0; i < sFactoryMap.size(); ++i) { \
92 \
93 IFactory* v = sFactoryMap.valueAt(i); \
94 float thisScore; \
95 CHECK(v != NULL); \
96 thisScore = v->scoreFactory(a, bestScore); \
97 if (thisScore > bestScore) { \
98 ret = sFactoryMap.keyAt(i); \
99 bestScore = thisScore; \
100 } \
101 } \
102 \
103 if (0.0 == bestScore) { \
Andreas Huber198a8932013-02-05 13:16:39 -0800104 ret = getDefaultPlayerType(); \
John Grossman44a7e422012-06-21 17:29:24 -0700105 } \
106 \
107 return ret;
108
109player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
110 const char* url) {
111 GET_PLAYER_TYPE_IMPL(client, url);
112}
113
114player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
115 int fd,
116 int64_t offset,
117 int64_t length) {
118 GET_PLAYER_TYPE_IMPL(client, fd, offset, length);
119}
120
121player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
122 const sp<IStreamSource> &source) {
123 GET_PLAYER_TYPE_IMPL(client, source);
124}
125
126#undef GET_PLAYER_TYPE_IMPL
127
128sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
129 player_type playerType,
130 void* cookie,
131 notify_callback_f notifyFunc) {
132 sp<MediaPlayerBase> p;
133 IFactory* factory;
134 status_t init_result;
135 Mutex::Autolock lock_(&sLock);
136
137 if (sFactoryMap.indexOfKey(playerType) < 0) {
138 ALOGE("Failed to create player object of type %d, no registered"
139 " factory", playerType);
140 return p;
141 }
142
143 factory = sFactoryMap.valueFor(playerType);
144 CHECK(NULL != factory);
145 p = factory->createPlayer();
146
147 if (p == NULL) {
148 ALOGE("Failed to create player object of type %d, create failed",
149 playerType);
150 return p;
151 }
152
153 init_result = p->initCheck();
154 if (init_result == NO_ERROR) {
155 p->setNotifyCallback(cookie, notifyFunc);
156 } else {
157 ALOGE("Failed to create player object of type %d, initCheck failed"
158 " (res = %d)", playerType, init_result);
159 p.clear();
160 }
161
162 return p;
163}
164
165/*****************************************************************************
166 * *
167 * Built-In Factory Implementations *
168 * *
169 *****************************************************************************/
170
171class StagefrightPlayerFactory :
172 public MediaPlayerFactory::IFactory {
173 public:
174 virtual float scoreFactory(const sp<IMediaPlayer>& client,
175 int fd,
176 int64_t offset,
177 int64_t length,
178 float curScore) {
179 char buf[20];
180 lseek(fd, offset, SEEK_SET);
181 read(fd, buf, sizeof(buf));
182 lseek(fd, offset, SEEK_SET);
183
184 long ident = *((long*)buf);
185
186 // Ogg vorbis?
187 if (ident == 0x5367674f) // 'OggS'
188 return 1.0;
189
190 return 0.0;
191 }
192
193 virtual sp<MediaPlayerBase> createPlayer() {
194 ALOGV(" create StagefrightPlayer");
195 return new StagefrightPlayer();
196 }
197};
198
199class NuPlayerFactory : public MediaPlayerFactory::IFactory {
200 public:
201 virtual float scoreFactory(const sp<IMediaPlayer>& client,
202 const char* url,
203 float curScore) {
204 static const float kOurScore = 0.8;
205
206 if (kOurScore <= curScore)
207 return 0.0;
208
209 if (!strncasecmp("http://", url, 7)
Andreas Huber99759402013-04-01 14:28:31 -0700210 || !strncasecmp("https://", url, 8)
211 || !strncasecmp("file://", url, 7)) {
John Grossman44a7e422012-06-21 17:29:24 -0700212 size_t len = strlen(url);
213 if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
214 return kOurScore;
215 }
216
217 if (strstr(url,"m3u8")) {
218 return kOurScore;
219 }
Oscar Rydhé7a33b772012-02-20 10:15:48 +0100220
221 if ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) || strstr(url, ".sdp?")) {
222 return kOurScore;
223 }
John Grossman44a7e422012-06-21 17:29:24 -0700224 }
225
226 if (!strncasecmp("rtsp://", url, 7)) {
227 return kOurScore;
228 }
229
230 return 0.0;
231 }
232
233 virtual float scoreFactory(const sp<IMediaPlayer>& client,
234 const sp<IStreamSource> &source,
235 float curScore) {
236 return 1.0;
237 }
238
239 virtual sp<MediaPlayerBase> createPlayer() {
240 ALOGV(" create NuPlayer");
241 return new NuPlayerDriver;
242 }
243};
244
245class SonivoxPlayerFactory : public MediaPlayerFactory::IFactory {
246 public:
247 virtual float scoreFactory(const sp<IMediaPlayer>& client,
248 const char* url,
249 float curScore) {
250 static const float kOurScore = 0.4;
251 static const char* const FILE_EXTS[] = { ".mid",
252 ".midi",
253 ".smf",
254 ".xmf",
Dongwon Kang5c5f8d92012-09-05 19:37:13 +0900255 ".mxmf",
John Grossman44a7e422012-06-21 17:29:24 -0700256 ".imy",
257 ".rtttl",
258 ".rtx",
259 ".ota" };
260 if (kOurScore <= curScore)
261 return 0.0;
262
263 // use MidiFile for MIDI extensions
264 int lenURL = strlen(url);
265 for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
266 int len = strlen(FILE_EXTS[i]);
267 int start = lenURL - len;
268 if (start > 0) {
269 if (!strncasecmp(url + start, FILE_EXTS[i], len)) {
270 return kOurScore;
271 }
272 }
273 }
274
275 return 0.0;
276 }
277
278 virtual float scoreFactory(const sp<IMediaPlayer>& client,
279 int fd,
280 int64_t offset,
281 int64_t length,
282 float curScore) {
283 static const float kOurScore = 0.8;
284
285 if (kOurScore <= curScore)
286 return 0.0;
287
288 // Some kind of MIDI?
289 EAS_DATA_HANDLE easdata;
290 if (EAS_Init(&easdata) == EAS_SUCCESS) {
291 EAS_FILE locator;
292 locator.path = NULL;
293 locator.fd = fd;
294 locator.offset = offset;
295 locator.length = length;
296 EAS_HANDLE eashandle;
297 if (EAS_OpenFile(easdata, &locator, &eashandle) == EAS_SUCCESS) {
298 EAS_CloseFile(easdata, eashandle);
299 EAS_Shutdown(easdata);
300 return kOurScore;
301 }
302 EAS_Shutdown(easdata);
303 }
304
305 return 0.0;
306 }
307
308 virtual sp<MediaPlayerBase> createPlayer() {
309 ALOGV(" create MidiFile");
310 return new MidiFile();
311 }
312};
313
314class TestPlayerFactory : public MediaPlayerFactory::IFactory {
315 public:
316 virtual float scoreFactory(const sp<IMediaPlayer>& client,
317 const char* url,
318 float curScore) {
319 if (TestPlayerStub::canBeUsed(url)) {
320 return 1.0;
321 }
322
323 return 0.0;
324 }
325
326 virtual sp<MediaPlayerBase> createPlayer() {
327 ALOGV("Create Test Player stub");
328 return new TestPlayerStub();
329 }
330};
331
John Grossman44a7e422012-06-21 17:29:24 -0700332void MediaPlayerFactory::registerBuiltinFactories() {
333 Mutex::Autolock lock_(&sLock);
334
335 if (sInitComplete)
336 return;
337
338 registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
339 registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
340 registerFactory_l(new SonivoxPlayerFactory(), SONIVOX_PLAYER);
341 registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
342
Ajit Khare821695d2013-01-07 23:23:39 -0800343 const char* FACTORY_LIB = "libdashplayer.so";
344 const char* FACTORY_CREATE_FN = "CreateDASHFactory";
345
346 MediaPlayerFactory::IFactory* pFactory = NULL;
347 void* pFactoryLib = NULL;
348 typedef MediaPlayerFactory::IFactory* (*CreateDASHDriverFn)();
349
350 pFactoryLib = ::dlopen(FACTORY_LIB, RTLD_LAZY);
Steve Kondik1bb22702013-04-08 02:24:19 -0700351 if (pFactoryLib != NULL) {
Ajit Khare821695d2013-01-07 23:23:39 -0800352 CreateDASHDriverFn pCreateFnPtr;
353 pCreateFnPtr = (CreateDASHDriverFn) dlsym(pFactoryLib, FACTORY_CREATE_FN);
354 if (pCreateFnPtr == NULL) {
355 ALOGE("Could not locate pCreateFnPtr");
356 } else {
357 pFactory = pCreateFnPtr();
358 if(pFactory == NULL) {
359 ALOGE("Failed to invoke CreateDASHDriverFn...");
360 } else {
361 registerFactory_l(pFactory,DASH_PLAYER);
362 }
363 }
364 }
John Grossman44a7e422012-06-21 17:29:24 -0700365 sInitComplete = true;
366}
367
368} // namespace android