MediaPlayerFactory.cpp revision 247d9ebdbe7f165644f308745eee061fcbb77771
1/*
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
36Mutex 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) {                             \
103        ret = getDefaultPlayerType();                   \
104    }                                                   \
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:
173    virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
174                               int fd,
175                               int64_t offset,
176                               int64_t /*length*/,
177                               float /*curScore*/) {
178        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:
200    virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
201                               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)
209                || !strncasecmp("https://", url, 8)
210                || !strncasecmp("file://", url, 7)) {
211            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            }
219
220            if ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) || strstr(url, ".sdp?")) {
221                return kOurScore;
222            }
223        }
224
225        if (!strncasecmp("rtsp://", url, 7)) {
226            return kOurScore;
227        }
228
229        return 0.0;
230    }
231
232    virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
233                               const sp<IStreamSource>& /*source*/,
234                               float /*curScore*/) {
235        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:
246    virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
247                               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",
254                                                 ".mxmf",
255                                                 ".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
277    virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
278                               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:
315    virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
316                               const char* url,
317                               float /*curScore*/) {
318        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
331void 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
342    sInitComplete = true;
343}
344
345}  // namespace android
346