blob: ddd4e24d9b7edd7c204d785e6c954cb13359d38b [file] [log] [blame]
The Android Open Source Project7b5eb022008-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>
24#include <dirent.h>
25#include <unistd.h>
26
27#include <string.h>
28#include <cutils/atomic.h>
Mathias Agopian75624082009-05-19 19:08:10 -070029#include <binder/MemoryDealer.h>
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080030#include <android_runtime/ActivityManager.h>
Mathias Agopian75624082009-05-19 19:08:10 -070031#include <binder/IPCThreadState.h>
32#include <binder/IServiceManager.h>
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080033#include <media/MediaMetadataRetrieverInterface.h>
34#include <media/MediaPlayerInterface.h>
35#include <media/PVMetadataRetriever.h>
36#include <private/media/VideoFrame.h>
James Dong148c1a22009-09-06 14:29:45 -070037#include "VorbisMetadataRetriever.h"
38#include "MidiMetadataRetriever.h"
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080039#include "MetadataRetrieverClient.h"
40
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080041namespace android {
42
James Dong148c1a22009-09-06 14:29:45 -070043extern player_type getPlayerType(const char* url);
44extern player_type getPlayerType(int fd, int64_t offset, int64_t length);
45
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080046MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
47{
48 LOGV("MetadataRetrieverClient constructor pid(%d)", pid);
49 mPid = pid;
50 mThumbnailDealer = NULL;
51 mAlbumArtDealer = NULL;
52 mThumbnail = NULL;
53 mAlbumArt = NULL;
Jean-Baptiste Queru6c5b2102009-03-21 11:40:18 -070054 mRetriever = NULL;
James Donga569aeb2009-09-29 10:45:27 -070055 mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080056}
57
58MetadataRetrieverClient::~MetadataRetrieverClient()
59{
60 LOGV("MetadataRetrieverClient destructor");
61 disconnect();
62}
63
64status_t MetadataRetrieverClient::dump(int fd, const Vector<String16>& args) const
65{
66 const size_t SIZE = 256;
67 char buffer[SIZE];
68 String8 result;
69 result.append(" MetadataRetrieverClient\n");
James Donga569aeb2009-09-29 10:45:27 -070070 snprintf(buffer, 255, " pid(%d) mode(%d)\n", mPid, mMode);
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080071 result.append(buffer);
72 write(fd, result.string(), result.size());
73 write(fd, "\n", 1);
74 return NO_ERROR;
75}
76
77void MetadataRetrieverClient::disconnect()
78{
79 LOGV("disconnect from pid %d", mPid);
80 Mutex::Autolock lock(mLock);
81 mRetriever.clear();
82 mThumbnailDealer.clear();
83 mAlbumArtDealer.clear();
84 mThumbnail.clear();
85 mAlbumArt.clear();
James Donga569aeb2009-09-29 10:45:27 -070086 mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -080087 IPCThreadState::self()->flushCommands();
88}
89
James Dong148c1a22009-09-06 14:29:45 -070090static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType)
91{
92 sp<MediaMetadataRetrieverBase> p;
93 switch (playerType) {
94#ifndef NO_OPENCORE
95 case PV_PLAYER:
96 LOGV("create pv metadata retriever");
97 p = new PVMetadataRetriever();
98 break;
99#endif
100 case VORBIS_PLAYER:
101 LOGV("create vorbis metadata retriever");
102 p = new VorbisMetadataRetriever();
103 break;
104 case SONIVOX_PLAYER:
105 LOGV("create midi metadata retriever");
106 p = new MidiMetadataRetriever();
107 break;
108 default:
109 // TODO:
110 // support for STAGEFRIGHT_PLAYER and TEST_PLAYER
111 LOGE("player type %d is not supported", playerType);
112 break;
113 }
114 if (p == NULL) {
115 LOGE("failed to create a retriever object");
116 }
117 return p;
118}
119
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800120status_t MetadataRetrieverClient::setDataSource(const char *url)
121{
122 LOGV("setDataSource(%s)", url);
123 Mutex::Autolock lock(mLock);
124 if (url == NULL) {
125 return UNKNOWN_ERROR;
126 }
James Dong148c1a22009-09-06 14:29:45 -0700127 player_type playerType = getPlayerType(url);
128 LOGV("player type = %d", playerType);
129 sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
130 if (p == NULL) return NO_INIT;
James Donga569aeb2009-09-29 10:45:27 -0700131 status_t ret = p->setMode(mMode);
132 if (ret == NO_ERROR) {
133 ret = p->setDataSource(url);
134 }
James Dong148c1a22009-09-06 14:29:45 -0700135 if (ret == NO_ERROR) mRetriever = p;
136 return ret;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800137}
138
139status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length)
140{
141 LOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
142 Mutex::Autolock lock(mLock);
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800143 struct stat sb;
144 int ret = fstat(fd, &sb);
145 if (ret != 0) {
146 LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
James Dong148c1a22009-09-06 14:29:45 -0700147 return BAD_VALUE;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800148 }
149 LOGV("st_dev = %llu", sb.st_dev);
150 LOGV("st_mode = %u", sb.st_mode);
151 LOGV("st_uid = %lu", sb.st_uid);
152 LOGV("st_gid = %lu", sb.st_gid);
153 LOGV("st_size = %llu", sb.st_size);
154
155 if (offset >= sb.st_size) {
156 LOGE("offset (%lld) bigger than file size (%llu)", offset, sb.st_size);
157 ::close(fd);
James Dong148c1a22009-09-06 14:29:45 -0700158 return BAD_VALUE;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800159 }
160 if (offset + length > sb.st_size) {
161 length = sb.st_size - offset;
James Dong148c1a22009-09-06 14:29:45 -0700162 LOGV("calculated length = %lld", length);
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800163 }
James Dong148c1a22009-09-06 14:29:45 -0700164
165 player_type playerType = getPlayerType(fd, offset, length);
166 LOGV("player type = %d", playerType);
167 sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
168 if (p == NULL) {
169 ::close(fd);
170 return NO_INIT;
171 }
James Donga569aeb2009-09-29 10:45:27 -0700172 status_t status = p->setMode(mMode);
173 if (status == NO_ERROR) {
174 p->setDataSource(fd, offset, length);
175 }
James Dong148c1a22009-09-06 14:29:45 -0700176 if (status == NO_ERROR) mRetriever = p;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800177 ::close(fd);
178 return status;
179}
180
181status_t MetadataRetrieverClient::setMode(int mode)
182{
183 LOGV("setMode");
184 Mutex::Autolock lock(mLock);
James Donga569aeb2009-09-29 10:45:27 -0700185 if (mode < METADATA_MODE_NOOP ||
186 mode > METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL) {
187 LOGE("invalid mode %d", mode);
188 return BAD_VALUE;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800189 }
James Donga569aeb2009-09-29 10:45:27 -0700190 mMode = mode;
191 return NO_ERROR;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800192}
193
194status_t MetadataRetrieverClient::getMode(int* mode) const
195{
196 LOGV("getMode");
197 Mutex::Autolock lock(mLock);
James Donga569aeb2009-09-29 10:45:27 -0700198
199 // TODO:
200 // This may not be necessary.
201 // If setDataSource() has not been called, return the cached value
202 // otherwise, return the value retrieved from the retriever
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800203 if (mRetriever == NULL) {
James Donga569aeb2009-09-29 10:45:27 -0700204 *mode = mMode;
205 } else {
206 mRetriever->getMode(mode);
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800207 }
James Donga569aeb2009-09-29 10:45:27 -0700208 return NO_ERROR;
The Android Open Source Project7b5eb022008-12-17 18:05:43 -0800209}
210
211sp<IMemory> MetadataRetrieverClient::captureFrame()
212{
213 LOGV("captureFrame");
214 Mutex::Autolock lock(mLock);
215 mThumbnail.clear();
216 mThumbnailDealer.clear();
217 if (mRetriever == NULL) {
218 LOGE("retriever is not initialized");
219 return NULL;
220 }
221 VideoFrame *frame = mRetriever->captureFrame();
222 if (frame == NULL) {
223 LOGE("failed to capture a video frame");
224 return NULL;
225 }
226 size_t size = sizeof(VideoFrame) + frame->mSize;
227 mThumbnailDealer = new MemoryDealer(size);
228 if (mThumbnailDealer == NULL) {
229 LOGE("failed to create MemoryDealer");
230 delete frame;
231 return NULL;
232 }
233 mThumbnail = mThumbnailDealer->allocate(size);
234 if (mThumbnail == NULL) {
235 LOGE("not enough memory for VideoFrame size=%u", size);
236 mThumbnailDealer.clear();
237 delete frame;
238 return NULL;
239 }
240 VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer());
241 frameCopy->mWidth = frame->mWidth;
242 frameCopy->mHeight = frame->mHeight;
243 frameCopy->mDisplayWidth = frame->mDisplayWidth;
244 frameCopy->mDisplayHeight = frame->mDisplayHeight;
245 frameCopy->mSize = frame->mSize;
246 frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame);
247 memcpy(frameCopy->mData, frame->mData, frame->mSize);
248 delete frame; // Fix memory leakage
249 return mThumbnail;
250}
251
252sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
253{
254 LOGV("extractAlbumArt");
255 Mutex::Autolock lock(mLock);
256 mAlbumArt.clear();
257 mAlbumArtDealer.clear();
258 if (mRetriever == NULL) {
259 LOGE("retriever is not initialized");
260 return NULL;
261 }
262 MediaAlbumArt *albumArt = mRetriever->extractAlbumArt();
263 if (albumArt == NULL) {
264 LOGE("failed to extract an album art");
265 return NULL;
266 }
267 size_t size = sizeof(MediaAlbumArt) + albumArt->mSize;
268 mAlbumArtDealer = new MemoryDealer(size);
269 if (mAlbumArtDealer == NULL) {
270 LOGE("failed to create MemoryDealer object");
271 delete albumArt;
272 return NULL;
273 }
274 mAlbumArt = mAlbumArtDealer->allocate(size);
275 if (mAlbumArt == NULL) {
276 LOGE("not enough memory for MediaAlbumArt size=%u", size);
277 mAlbumArtDealer.clear();
278 delete albumArt;
279 return NULL;
280 }
281 MediaAlbumArt *albumArtCopy = static_cast<MediaAlbumArt *>(mAlbumArt->pointer());
282 albumArtCopy->mSize = albumArt->mSize;
283 albumArtCopy->mData = (uint8_t *)albumArtCopy + sizeof(MediaAlbumArt);
284 memcpy(albumArtCopy->mData, albumArt->mData, albumArt->mSize);
285 delete albumArt; // Fix memory leakage
286 return mAlbumArt;
287}
288
289const char* MetadataRetrieverClient::extractMetadata(int keyCode)
290{
291 LOGV("extractMetadata");
292 Mutex::Autolock lock(mLock);
293 if (mRetriever == NULL) {
294 LOGE("retriever is not initialized");
295 return NULL;
296 }
297 return mRetriever->extractMetadata(keyCode);
298}
299
300}; // namespace android