blob: 09e697685f6c70bc10329c11c60f5ca7db67f5df [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"
33
34namespace android {
35
John Grossman44a7e422012-06-21 17:29:24 -070036Mutex MediaPlayerFactory::sLock;
37MediaPlayerFactory::tFactoryMap MediaPlayerFactory::sFactoryMap;
38bool MediaPlayerFactory::sInitComplete = false;
39
40status_t MediaPlayerFactory::registerFactory_l(IFactory* factory,
41 player_type type) {
42 if (NULL == factory) {
43 ALOGE("Failed to register MediaPlayerFactory of type %d, factory is"
44 " NULL.", type);
45 return BAD_VALUE;
46 }
47
48 if (sFactoryMap.indexOfKey(type) >= 0) {
49 ALOGE("Failed to register MediaPlayerFactory of type %d, type is"
50 " already registered.", type);
51 return ALREADY_EXISTS;
52 }
53
54 if (sFactoryMap.add(type, factory) < 0) {
55 ALOGE("Failed to register MediaPlayerFactory of type %d, failed to add"
56 " to map.", type);
57 return UNKNOWN_ERROR;
58 }
59
60 return OK;
61}
62
63player_type MediaPlayerFactory::getDefaultPlayerType() {
64 char value[PROPERTY_VALUE_MAX];
65 if (property_get("media.stagefright.use-nuplayer", value, NULL)
66 && (!strcmp("1", value) || !strcasecmp("true", value))) {
67 return NU_PLAYER;
68 }
69
70 return STAGEFRIGHT_PLAYER;
71}
72
73status_t MediaPlayerFactory::registerFactory(IFactory* factory,
74 player_type type) {
75 Mutex::Autolock lock_(&sLock);
76 return registerFactory_l(factory, type);
77}
78
79void MediaPlayerFactory::unregisterFactory(player_type type) {
80 Mutex::Autolock lock_(&sLock);
81 sFactoryMap.removeItem(type);
82}
83
84#define GET_PLAYER_TYPE_IMPL(a...) \
85 Mutex::Autolock lock_(&sLock); \
86 \
87 player_type ret = STAGEFRIGHT_PLAYER; \
88 float bestScore = 0.0; \
89 \
90 for (size_t i = 0; i < sFactoryMap.size(); ++i) { \
91 \
92 IFactory* v = sFactoryMap.valueAt(i); \
93 float thisScore; \
94 CHECK(v != NULL); \
95 thisScore = v->scoreFactory(a, bestScore); \
96 if (thisScore > bestScore) { \
97 ret = sFactoryMap.keyAt(i); \
98 bestScore = thisScore; \
99 } \
100 } \
101 \
102 if (0.0 == bestScore) { \
Andreas Huber27243b72013-02-05 13:16:39 -0800103 ret = getDefaultPlayerType(); \
John Grossman44a7e422012-06-21 17:29:24 -0700104 } \
105 \
106 return ret;
107
108player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
109 const char* url) {
110 GET_PLAYER_TYPE_IMPL(client, url);
111}
112
113player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
114 int fd,
115 int64_t offset,
116 int64_t length) {
117 GET_PLAYER_TYPE_IMPL(client, fd, offset, length);
118}
119
120player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
121 const sp<IStreamSource> &source) {
122 GET_PLAYER_TYPE_IMPL(client, source);
123}
124
125#undef GET_PLAYER_TYPE_IMPL
126
127sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
128 player_type playerType,
129 void* cookie,
130 notify_callback_f notifyFunc) {
131 sp<MediaPlayerBase> p;
132 IFactory* factory;
133 status_t init_result;
134 Mutex::Autolock lock_(&sLock);
135
136 if (sFactoryMap.indexOfKey(playerType) < 0) {
137 ALOGE("Failed to create player object of type %d, no registered"
138 " factory", playerType);
139 return p;
140 }
141
142 factory = sFactoryMap.valueFor(playerType);
143 CHECK(NULL != factory);
144 p = factory->createPlayer();
145
146 if (p == NULL) {
147 ALOGE("Failed to create player object of type %d, create failed",
148 playerType);
149 return p;
150 }
151
152 init_result = p->initCheck();
153 if (init_result == NO_ERROR) {
154 p->setNotifyCallback(cookie, notifyFunc);
155 } else {
156 ALOGE("Failed to create player object of type %d, initCheck failed"
157 " (res = %d)", playerType, init_result);
158 p.clear();
159 }
160
161 return p;
162}
163
164/*****************************************************************************
165 * *
166 * Built-In Factory Implementations *
167 * *
168 *****************************************************************************/
169
170class StagefrightPlayerFactory :
171 public MediaPlayerFactory::IFactory {
172 public:
Mark Salyzyn247d9eb2014-06-23 14:14:40 -0700173 virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
John Grossman44a7e422012-06-21 17:29:24 -0700174 int fd,
175 int64_t offset,
Mark Salyzyn247d9eb2014-06-23 14:14:40 -0700176 int64_t /*length*/,
177 float /*curScore*/) {
John Grossman44a7e422012-06-21 17:29:24 -0700178 char buf[20];
179 lseek(fd, offset, SEEK_SET);
180 read(fd, buf, sizeof(buf));
181 lseek(fd, offset, SEEK_SET);
182
183 long ident = *((long*)buf);
184
185 // Ogg vorbis?
186 if (ident == 0x5367674f) // 'OggS'
187 return 1.0;
188
189 return 0.0;
190 }
191
192 virtual sp<MediaPlayerBase> createPlayer() {
193 ALOGV(" create StagefrightPlayer");
194 return new StagefrightPlayer();
195 }
196};
197
198class NuPlayerFactory : public MediaPlayerFactory::IFactory {
199 public:
Mark Salyzyn247d9eb2014-06-23 14:14:40 -0700200 virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
John Grossman44a7e422012-06-21 17:29:24 -0700201 const char* url,
202 float curScore) {
203 static const float kOurScore = 0.8;
204
205 if (kOurScore <= curScore)
206 return 0.0;
207
208 if (!strncasecmp("http://", url, 7)
Andreas Huber7069bdf2013-04-01 14:28:31 -0700209 || !strncasecmp("https://", url, 8)
210 || !strncasecmp("file://", url, 7)) {
John Grossman44a7e422012-06-21 17:29:24 -0700211 size_t len = strlen(url);
212 if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
213 return kOurScore;
214 }
215
216 if (strstr(url,"m3u8")) {
217 return kOurScore;
218 }
Oscar Rydhé81dd60e2012-02-20 10:15:48 +0100219
220 if ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) || strstr(url, ".sdp?")) {
221 return kOurScore;
222 }
John Grossman44a7e422012-06-21 17:29:24 -0700223 }
224
225 if (!strncasecmp("rtsp://", url, 7)) {
226 return kOurScore;
227 }
228
229 return 0.0;
230 }
231
Mark Salyzyn247d9eb2014-06-23 14:14:40 -0700232 virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
233 const sp<IStreamSource>& /*source*/,
234 float /*curScore*/) {
John Grossman44a7e422012-06-21 17:29:24 -0700235 return 1.0;
236 }
237
238 virtual sp<MediaPlayerBase> createPlayer() {
239 ALOGV(" create NuPlayer");
240 return new NuPlayerDriver;
241 }
242};
243
244class SonivoxPlayerFactory : public MediaPlayerFactory::IFactory {
245 public:
Mark Salyzyn247d9eb2014-06-23 14:14:40 -0700246 virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
John Grossman44a7e422012-06-21 17:29:24 -0700247 const char* url,
248 float curScore) {
249 static const float kOurScore = 0.4;
250 static const char* const FILE_EXTS[] = { ".mid",
251 ".midi",
252 ".smf",
253 ".xmf",
Dongwon Kanga6932492012-09-05 19:37:13 +0900254 ".mxmf",
John Grossman44a7e422012-06-21 17:29:24 -0700255 ".imy",
256 ".rtttl",
257 ".rtx",
258 ".ota" };
259 if (kOurScore <= curScore)
260 return 0.0;
261
262 // use MidiFile for MIDI extensions
263 int lenURL = strlen(url);
264 for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
265 int len = strlen(FILE_EXTS[i]);
266 int start = lenURL - len;
267 if (start > 0) {
268 if (!strncasecmp(url + start, FILE_EXTS[i], len)) {
269 return kOurScore;
270 }
271 }
272 }
273
274 return 0.0;
275 }
276
Mark Salyzyn247d9eb2014-06-23 14:14:40 -0700277 virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
John Grossman44a7e422012-06-21 17:29:24 -0700278 int fd,
279 int64_t offset,
280 int64_t length,
281 float curScore) {
282 static const float kOurScore = 0.8;
283
284 if (kOurScore <= curScore)
285 return 0.0;
286
287 // Some kind of MIDI?
288 EAS_DATA_HANDLE easdata;
289 if (EAS_Init(&easdata) == EAS_SUCCESS) {
290 EAS_FILE locator;
291 locator.path = NULL;
292 locator.fd = fd;
293 locator.offset = offset;
294 locator.length = length;
295 EAS_HANDLE eashandle;
296 if (EAS_OpenFile(easdata, &locator, &eashandle) == EAS_SUCCESS) {
297 EAS_CloseFile(easdata, eashandle);
298 EAS_Shutdown(easdata);
299 return kOurScore;
300 }
301 EAS_Shutdown(easdata);
302 }
303
304 return 0.0;
305 }
306
307 virtual sp<MediaPlayerBase> createPlayer() {
308 ALOGV(" create MidiFile");
309 return new MidiFile();
310 }
311};
312
313class TestPlayerFactory : public MediaPlayerFactory::IFactory {
314 public:
Mark Salyzyn247d9eb2014-06-23 14:14:40 -0700315 virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
John Grossman44a7e422012-06-21 17:29:24 -0700316 const char* url,
Mark Salyzyn247d9eb2014-06-23 14:14:40 -0700317 float /*curScore*/) {
John Grossman44a7e422012-06-21 17:29:24 -0700318 if (TestPlayerStub::canBeUsed(url)) {
319 return 1.0;
320 }
321
322 return 0.0;
323 }
324
325 virtual sp<MediaPlayerBase> createPlayer() {
326 ALOGV("Create Test Player stub");
327 return new TestPlayerStub();
328 }
329};
330
John Grossman44a7e422012-06-21 17:29:24 -0700331void MediaPlayerFactory::registerBuiltinFactories() {
332 Mutex::Autolock lock_(&sLock);
333
334 if (sInitComplete)
335 return;
336
337 registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
338 registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
339 registerFactory_l(new SonivoxPlayerFactory(), SONIVOX_PLAYER);
340 registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
341
John Grossman44a7e422012-06-21 17:29:24 -0700342 sInitComplete = true;
343}
344
345} // namespace android