blob: 866c7bd55ce3e9d32fadac165975d124b5c4ffd3 [file] [log] [blame]
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001/*
2**
3** Copyright (C) 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 "MetadataRetrieverClient"
20#include <utils/Log.h>
21
22#include <sys/types.h>
23#include <sys/stat.h>
Dave Sparks7c0d20a2009-10-26 16:28:26 -070024#include <sys/resource.h>
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080025#include <dirent.h>
26#include <unistd.h>
27
28#include <string.h>
29#include <cutils/atomic.h>
Mathias Agopian07952722009-05-19 19:08:10 -070030#include <binder/MemoryDealer.h>
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080031#include <android_runtime/ActivityManager.h>
Mathias Agopian07952722009-05-19 19:08:10 -070032#include <binder/IPCThreadState.h>
33#include <binder/IServiceManager.h>
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080034#include <media/MediaMetadataRetrieverInterface.h>
35#include <media/MediaPlayerInterface.h>
36#include <media/PVMetadataRetriever.h>
37#include <private/media/VideoFrame.h>
James Dong392ff3b2009-09-06 14:29:45 -070038#include "VorbisMetadataRetriever.h"
39#include "MidiMetadataRetriever.h"
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080040#include "MetadataRetrieverClient.h"
Andreas Huber53a76bd2009-10-06 16:20:44 -070041#include "StagefrightMetadataRetriever.h"
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080042
Dave Sparks7c0d20a2009-10-26 16:28:26 -070043/* desktop Linux needs a little help with gettid() */
44#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
45#define __KERNEL__
46# include <linux/unistd.h>
47#ifdef _syscall0
48_syscall0(pid_t,gettid)
49#else
50pid_t gettid() { return syscall(__NR_gettid);}
51#endif
52#undef __KERNEL__
53#endif
54
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080055namespace android {
56
James Dong392ff3b2009-09-06 14:29:45 -070057extern player_type getPlayerType(const char* url);
58extern player_type getPlayerType(int fd, int64_t offset, int64_t length);
59
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080060MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
61{
62 LOGV("MetadataRetrieverClient constructor pid(%d)", pid);
63 mPid = pid;
64 mThumbnailDealer = NULL;
65 mAlbumArtDealer = NULL;
66 mThumbnail = NULL;
67 mAlbumArt = NULL;
Jean-Baptiste Queru680f8c72009-03-21 11:40:18 -070068 mRetriever = NULL;
James Dong67fc2342009-09-29 10:45:27 -070069 mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080070}
71
72MetadataRetrieverClient::~MetadataRetrieverClient()
73{
74 LOGV("MetadataRetrieverClient destructor");
75 disconnect();
76}
77
78status_t MetadataRetrieverClient::dump(int fd, const Vector<String16>& args) const
79{
80 const size_t SIZE = 256;
81 char buffer[SIZE];
82 String8 result;
83 result.append(" MetadataRetrieverClient\n");
James Dong67fc2342009-09-29 10:45:27 -070084 snprintf(buffer, 255, " pid(%d) mode(%d)\n", mPid, mMode);
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080085 result.append(buffer);
86 write(fd, result.string(), result.size());
87 write(fd, "\n", 1);
88 return NO_ERROR;
89}
90
91void MetadataRetrieverClient::disconnect()
92{
93 LOGV("disconnect from pid %d", mPid);
94 Mutex::Autolock lock(mLock);
95 mRetriever.clear();
96 mThumbnailDealer.clear();
97 mAlbumArtDealer.clear();
98 mThumbnail.clear();
99 mAlbumArt.clear();
James Dong67fc2342009-09-29 10:45:27 -0700100 mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800101 IPCThreadState::self()->flushCommands();
102}
103
James Dong392ff3b2009-09-06 14:29:45 -0700104static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType)
105{
106 sp<MediaMetadataRetrieverBase> p;
107 switch (playerType) {
108#ifndef NO_OPENCORE
109 case PV_PLAYER:
110 LOGV("create pv metadata retriever");
111 p = new PVMetadataRetriever();
112 break;
113#endif
114 case VORBIS_PLAYER:
115 LOGV("create vorbis metadata retriever");
116 p = new VorbisMetadataRetriever();
117 break;
118 case SONIVOX_PLAYER:
119 LOGV("create midi metadata retriever");
120 p = new MidiMetadataRetriever();
121 break;
Andreas Huber53a76bd2009-10-06 16:20:44 -0700122#if BUILD_WITH_FULL_STAGEFRIGHT
123 case STAGEFRIGHT_PLAYER:
124 LOGV("create StagefrightMetadataRetriever");
125 p = new StagefrightMetadataRetriever;
126 break;
127#endif
James Dong392ff3b2009-09-06 14:29:45 -0700128 default:
129 // TODO:
Andreas Huber53a76bd2009-10-06 16:20:44 -0700130 // support for TEST_PLAYER
James Dong392ff3b2009-09-06 14:29:45 -0700131 LOGE("player type %d is not supported", playerType);
132 break;
133 }
134 if (p == NULL) {
135 LOGE("failed to create a retriever object");
136 }
137 return p;
138}
139
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800140status_t MetadataRetrieverClient::setDataSource(const char *url)
141{
142 LOGV("setDataSource(%s)", url);
143 Mutex::Autolock lock(mLock);
144 if (url == NULL) {
145 return UNKNOWN_ERROR;
146 }
James Dong392ff3b2009-09-06 14:29:45 -0700147 player_type playerType = getPlayerType(url);
148 LOGV("player type = %d", playerType);
149 sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
150 if (p == NULL) return NO_INIT;
James Dong67fc2342009-09-29 10:45:27 -0700151 status_t ret = p->setMode(mMode);
152 if (ret == NO_ERROR) {
153 ret = p->setDataSource(url);
154 }
James Dong392ff3b2009-09-06 14:29:45 -0700155 if (ret == NO_ERROR) mRetriever = p;
156 return ret;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800157}
158
159status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length)
160{
161 LOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
162 Mutex::Autolock lock(mLock);
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800163 struct stat sb;
164 int ret = fstat(fd, &sb);
165 if (ret != 0) {
166 LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
James Dong392ff3b2009-09-06 14:29:45 -0700167 return BAD_VALUE;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800168 }
169 LOGV("st_dev = %llu", sb.st_dev);
170 LOGV("st_mode = %u", sb.st_mode);
171 LOGV("st_uid = %lu", sb.st_uid);
172 LOGV("st_gid = %lu", sb.st_gid);
173 LOGV("st_size = %llu", sb.st_size);
174
175 if (offset >= sb.st_size) {
176 LOGE("offset (%lld) bigger than file size (%llu)", offset, sb.st_size);
177 ::close(fd);
James Dong392ff3b2009-09-06 14:29:45 -0700178 return BAD_VALUE;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800179 }
180 if (offset + length > sb.st_size) {
181 length = sb.st_size - offset;
James Dong392ff3b2009-09-06 14:29:45 -0700182 LOGV("calculated length = %lld", length);
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800183 }
James Dong392ff3b2009-09-06 14:29:45 -0700184
185 player_type playerType = getPlayerType(fd, offset, length);
186 LOGV("player type = %d", playerType);
187 sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
188 if (p == NULL) {
189 ::close(fd);
190 return NO_INIT;
191 }
James Dong67fc2342009-09-29 10:45:27 -0700192 status_t status = p->setMode(mMode);
193 if (status == NO_ERROR) {
194 p->setDataSource(fd, offset, length);
195 }
James Dong392ff3b2009-09-06 14:29:45 -0700196 if (status == NO_ERROR) mRetriever = p;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800197 ::close(fd);
198 return status;
199}
200
201status_t MetadataRetrieverClient::setMode(int mode)
202{
203 LOGV("setMode");
204 Mutex::Autolock lock(mLock);
James Dong67fc2342009-09-29 10:45:27 -0700205 if (mode < METADATA_MODE_NOOP ||
206 mode > METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL) {
207 LOGE("invalid mode %d", mode);
208 return BAD_VALUE;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800209 }
James Dong67fc2342009-09-29 10:45:27 -0700210 mMode = mode;
211 return NO_ERROR;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800212}
213
214status_t MetadataRetrieverClient::getMode(int* mode) const
215{
216 LOGV("getMode");
217 Mutex::Autolock lock(mLock);
James Dong67fc2342009-09-29 10:45:27 -0700218
219 // TODO:
220 // This may not be necessary.
221 // If setDataSource() has not been called, return the cached value
222 // otherwise, return the value retrieved from the retriever
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800223 if (mRetriever == NULL) {
James Dong67fc2342009-09-29 10:45:27 -0700224 *mode = mMode;
225 } else {
226 mRetriever->getMode(mode);
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800227 }
James Dong67fc2342009-09-29 10:45:27 -0700228 return NO_ERROR;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800229}
230
231sp<IMemory> MetadataRetrieverClient::captureFrame()
232{
233 LOGV("captureFrame");
234 Mutex::Autolock lock(mLock);
Dave Sparks7c0d20a2009-10-26 16:28:26 -0700235 Priority priority(ANDROID_PRIORITY_BACKGROUND);
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800236 mThumbnail.clear();
237 mThumbnailDealer.clear();
238 if (mRetriever == NULL) {
239 LOGE("retriever is not initialized");
240 return NULL;
241 }
242 VideoFrame *frame = mRetriever->captureFrame();
243 if (frame == NULL) {
244 LOGE("failed to capture a video frame");
245 return NULL;
246 }
247 size_t size = sizeof(VideoFrame) + frame->mSize;
248 mThumbnailDealer = new MemoryDealer(size);
249 if (mThumbnailDealer == NULL) {
250 LOGE("failed to create MemoryDealer");
251 delete frame;
252 return NULL;
253 }
254 mThumbnail = mThumbnailDealer->allocate(size);
255 if (mThumbnail == NULL) {
256 LOGE("not enough memory for VideoFrame size=%u", size);
257 mThumbnailDealer.clear();
258 delete frame;
259 return NULL;
260 }
261 VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer());
262 frameCopy->mWidth = frame->mWidth;
263 frameCopy->mHeight = frame->mHeight;
264 frameCopy->mDisplayWidth = frame->mDisplayWidth;
265 frameCopy->mDisplayHeight = frame->mDisplayHeight;
266 frameCopy->mSize = frame->mSize;
267 frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame);
268 memcpy(frameCopy->mData, frame->mData, frame->mSize);
269 delete frame; // Fix memory leakage
270 return mThumbnail;
271}
272
273sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
274{
275 LOGV("extractAlbumArt");
276 Mutex::Autolock lock(mLock);
Dave Sparks7c0d20a2009-10-26 16:28:26 -0700277 Priority priority(ANDROID_PRIORITY_BACKGROUND);
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800278 mAlbumArt.clear();
279 mAlbumArtDealer.clear();
280 if (mRetriever == NULL) {
281 LOGE("retriever is not initialized");
282 return NULL;
283 }
284 MediaAlbumArt *albumArt = mRetriever->extractAlbumArt();
285 if (albumArt == NULL) {
286 LOGE("failed to extract an album art");
287 return NULL;
288 }
289 size_t size = sizeof(MediaAlbumArt) + albumArt->mSize;
290 mAlbumArtDealer = new MemoryDealer(size);
291 if (mAlbumArtDealer == NULL) {
292 LOGE("failed to create MemoryDealer object");
293 delete albumArt;
294 return NULL;
295 }
296 mAlbumArt = mAlbumArtDealer->allocate(size);
297 if (mAlbumArt == NULL) {
298 LOGE("not enough memory for MediaAlbumArt size=%u", size);
299 mAlbumArtDealer.clear();
300 delete albumArt;
301 return NULL;
302 }
303 MediaAlbumArt *albumArtCopy = static_cast<MediaAlbumArt *>(mAlbumArt->pointer());
304 albumArtCopy->mSize = albumArt->mSize;
305 albumArtCopy->mData = (uint8_t *)albumArtCopy + sizeof(MediaAlbumArt);
306 memcpy(albumArtCopy->mData, albumArt->mData, albumArt->mSize);
307 delete albumArt; // Fix memory leakage
308 return mAlbumArt;
309}
310
311const char* MetadataRetrieverClient::extractMetadata(int keyCode)
312{
313 LOGV("extractMetadata");
314 Mutex::Autolock lock(mLock);
315 if (mRetriever == NULL) {
316 LOGE("retriever is not initialized");
317 return NULL;
318 }
Dave Sparks7c0d20a2009-10-26 16:28:26 -0700319 Priority priority(ANDROID_PRIORITY_BACKGROUND);
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800320 return mRetriever->extractMetadata(keyCode);
321}
322
Dave Sparks7c0d20a2009-10-26 16:28:26 -0700323MetadataRetrieverClient::Priority::Priority(int newPriority)
324{
325 mOldPriority = getpriority(PRIO_PROCESS, 0);
326 setpriority(PRIO_PROCESS, 0, newPriority);
327}
328
329MetadataRetrieverClient::Priority::~Priority()
330{
331 setpriority(PRIO_PROCESS, 0, mOldPriority);
332}
333
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800334}; // namespace android