1 /*
2 **
3 ** Copyright 2008, 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_NDEBUG 0
19 #define LOG_TAG "MediaMetadataRetriever"
20
21 #include <binder/IServiceManager.h>
22 #include <binder/IPCThreadState.h>
23 #include <media/mediametadataretriever.h>
24 #include <media/IMediaPlayerService.h>
25 #include <utils/Log.h>
26 #include <dlfcn.h>
27
28 namespace android {
29
30 // client singleton for binder interface to service
31 Mutex MediaMetadataRetriever::sServiceLock;
32 sp<IMediaPlayerService> MediaMetadataRetriever::sService;
33 sp<MediaMetadataRetriever::DeathNotifier> MediaMetadataRetriever::sDeathNotifier;
34
getService()35 const sp<IMediaPlayerService>& MediaMetadataRetriever::getService()
36 {
37 Mutex::Autolock lock(sServiceLock);
38 if (sService == 0) {
39 sp<IServiceManager> sm = defaultServiceManager();
40 sp<IBinder> binder;
41 do {
42 binder = sm->getService(String16("media.player"));
43 if (binder != 0) {
44 break;
45 }
46 ALOGW("MediaPlayerService not published, waiting...");
47 usleep(500000); // 0.5 s
48 } while (true);
49 if (sDeathNotifier == NULL) {
50 sDeathNotifier = new DeathNotifier();
51 }
52 binder->linkToDeath(sDeathNotifier);
53 sService = interface_cast<IMediaPlayerService>(binder);
54 }
55 ALOGE_IF(sService == 0, "no MediaPlayerService!?");
56 return sService;
57 }
58
MediaMetadataRetriever()59 MediaMetadataRetriever::MediaMetadataRetriever()
60 {
61 ALOGV("constructor");
62 const sp<IMediaPlayerService>& service(getService());
63 if (service == 0) {
64 ALOGE("failed to obtain MediaMetadataRetrieverService");
65 return;
66 }
67 sp<IMediaMetadataRetriever> retriever(service->createMetadataRetriever(getpid()));
68 if (retriever == 0) {
69 ALOGE("failed to create IMediaMetadataRetriever object from server");
70 }
71 mRetriever = retriever;
72 }
73
~MediaMetadataRetriever()74 MediaMetadataRetriever::~MediaMetadataRetriever()
75 {
76 ALOGV("destructor");
77 disconnect();
78 IPCThreadState::self()->flushCommands();
79 }
80
disconnect()81 void MediaMetadataRetriever::disconnect()
82 {
83 ALOGV("disconnect");
84 sp<IMediaMetadataRetriever> retriever;
85 {
86 Mutex::Autolock _l(mLock);
87 retriever = mRetriever;
88 mRetriever.clear();
89 }
90 if (retriever != 0) {
91 retriever->disconnect();
92 }
93 }
94
setDataSource(const char * srcUrl,const KeyedVector<String8,String8> * headers)95 status_t MediaMetadataRetriever::setDataSource(
96 const char *srcUrl, const KeyedVector<String8, String8> *headers)
97 {
98 ALOGV("setDataSource");
99 Mutex::Autolock _l(mLock);
100 if (mRetriever == 0) {
101 ALOGE("retriever is not initialized");
102 return INVALID_OPERATION;
103 }
104 if (srcUrl == NULL) {
105 ALOGE("data source is a null pointer");
106 return UNKNOWN_ERROR;
107 }
108 ALOGV("data source (%s)", srcUrl);
109 return mRetriever->setDataSource(srcUrl, headers);
110 }
111
setDataSource(int fd,int64_t offset,int64_t length)112 status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
113 {
114 ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
115 Mutex::Autolock _l(mLock);
116 if (mRetriever == 0) {
117 ALOGE("retriever is not initialized");
118 return INVALID_OPERATION;
119 }
120 if (fd < 0 || offset < 0 || length < 0) {
121 ALOGE("Invalid negative argument");
122 return UNKNOWN_ERROR;
123 }
124 return mRetriever->setDataSource(fd, offset, length);
125 }
126
getFrameAtTime(int64_t timeUs,int option)127 sp<IMemory> MediaMetadataRetriever::getFrameAtTime(int64_t timeUs, int option)
128 {
129 ALOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
130 Mutex::Autolock _l(mLock);
131 if (mRetriever == 0) {
132 ALOGE("retriever is not initialized");
133 return NULL;
134 }
135 return mRetriever->getFrameAtTime(timeUs, option);
136 }
137
extractMetadata(int keyCode)138 const char* MediaMetadataRetriever::extractMetadata(int keyCode)
139 {
140 ALOGV("extractMetadata(%d)", keyCode);
141 Mutex::Autolock _l(mLock);
142 if (mRetriever == 0) {
143 ALOGE("retriever is not initialized");
144 return NULL;
145 }
146 return mRetriever->extractMetadata(keyCode);
147 }
148
extractAlbumArt()149 sp<IMemory> MediaMetadataRetriever::extractAlbumArt()
150 {
151 ALOGV("extractAlbumArt");
152 Mutex::Autolock _l(mLock);
153 if (mRetriever == 0) {
154 ALOGE("retriever is not initialized");
155 return NULL;
156 }
157 return mRetriever->extractAlbumArt();
158 }
159
binderDied(const wp<IBinder> & who)160 void MediaMetadataRetriever::DeathNotifier::binderDied(const wp<IBinder>& who) {
161 Mutex::Autolock lock(MediaMetadataRetriever::sServiceLock);
162 MediaMetadataRetriever::sService.clear();
163 ALOGW("MediaMetadataRetriever server died!");
164 }
165
~DeathNotifier()166 MediaMetadataRetriever::DeathNotifier::~DeathNotifier()
167 {
168 Mutex::Autolock lock(sServiceLock);
169 if (sService != 0) {
170 sService->asBinder()->unlinkToDeath(this);
171 }
172 }
173
174 }; // namespace android
175