MetadataRetrieverClient.cpp revision 827f3004421aacb6bceaf772ac825d4f2d3006e4
1/* 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 <sys/resource.h> 25#include <dirent.h> 26#include <unistd.h> 27 28#include <string.h> 29#include <cutils/atomic.h> 30#include <binder/MemoryDealer.h> 31#include <android_runtime/ActivityManager.h> 32#include <binder/IPCThreadState.h> 33#include <binder/IServiceManager.h> 34#include <media/MediaMetadataRetrieverInterface.h> 35#include <media/MediaPlayerInterface.h> 36#include <media/PVMetadataRetriever.h> 37#include <private/media/VideoFrame.h> 38#include "VorbisMetadataRetriever.h" 39#include "MidiMetadataRetriever.h" 40#include "MetadataRetrieverClient.h" 41#include "StagefrightMetadataRetriever.h" 42 43/* 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 55namespace android { 56 57extern player_type getPlayerType(const char* url); 58extern player_type getPlayerType(int fd, int64_t offset, int64_t length); 59 60MetadataRetrieverClient::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; 68 mRetriever = NULL; 69 mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL; 70} 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"); 84 snprintf(buffer, 255, " pid(%d) mode(%d)\n", mPid, mMode); 85 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(); 100 mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL; 101 IPCThreadState::self()->flushCommands(); 102} 103 104static 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; 122#if BUILD_WITH_FULL_STAGEFRIGHT 123 case STAGEFRIGHT_PLAYER: 124 LOGV("create StagefrightMetadataRetriever"); 125 p = new StagefrightMetadataRetriever; 126 break; 127#endif 128 default: 129 // TODO: 130 // support for TEST_PLAYER 131 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 140status_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 } 147 player_type playerType = getPlayerType(url); 148 LOGV("player type = %d", playerType); 149 sp<MediaMetadataRetrieverBase> p = createRetriever(playerType); 150 if (p == NULL) return NO_INIT; 151 status_t ret = p->setMode(mMode); 152 if (ret == NO_ERROR) { 153 ret = p->setDataSource(url); 154 } 155 if (ret == NO_ERROR) mRetriever = p; 156 return ret; 157} 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); 163 struct stat sb; 164 int ret = fstat(fd, &sb); 165 if (ret != 0) { 166 LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno)); 167 return BAD_VALUE; 168 } 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); 178 return BAD_VALUE; 179 } 180 if (offset + length > sb.st_size) { 181 length = sb.st_size - offset; 182 LOGV("calculated length = %lld", length); 183 } 184 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 } 192 status_t status = p->setMode(mMode); 193 if (status == NO_ERROR) { 194 p->setDataSource(fd, offset, length); 195 } 196 if (status == NO_ERROR) mRetriever = p; 197 ::close(fd); 198 return status; 199} 200 201status_t MetadataRetrieverClient::setMode(int mode) 202{ 203 LOGV("setMode"); 204 Mutex::Autolock lock(mLock); 205 if (mode < METADATA_MODE_NOOP || 206 mode > METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL) { 207 LOGE("invalid mode %d", mode); 208 return BAD_VALUE; 209 } 210 mMode = mode; 211 return NO_ERROR; 212} 213 214status_t MetadataRetrieverClient::getMode(int* mode) const 215{ 216 LOGV("getMode"); 217 Mutex::Autolock lock(mLock); 218 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 223 if (mRetriever == NULL) { 224 *mode = mMode; 225 } else { 226 mRetriever->getMode(mode); 227 } 228 return NO_ERROR; 229} 230 231sp<IMemory> MetadataRetrieverClient::captureFrame() 232{ 233 LOGV("captureFrame"); 234 Mutex::Autolock lock(mLock); 235 mThumbnail.clear(); 236 mThumbnailDealer.clear(); 237 if (mRetriever == NULL) { 238 LOGE("retriever is not initialized"); 239 return NULL; 240 } 241 VideoFrame *frame = mRetriever->captureFrame(); 242 if (frame == NULL) { 243 LOGE("failed to capture a video frame"); 244 return NULL; 245 } 246 size_t size = sizeof(VideoFrame) + frame->mSize; 247 mThumbnailDealer = new MemoryDealer(size); 248 if (mThumbnailDealer == NULL) { 249 LOGE("failed to create MemoryDealer"); 250 delete frame; 251 return NULL; 252 } 253 mThumbnail = mThumbnailDealer->allocate(size); 254 if (mThumbnail == NULL) { 255 LOGE("not enough memory for VideoFrame size=%u", size); 256 mThumbnailDealer.clear(); 257 delete frame; 258 return NULL; 259 } 260 VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer()); 261 frameCopy->mWidth = frame->mWidth; 262 frameCopy->mHeight = frame->mHeight; 263 frameCopy->mDisplayWidth = frame->mDisplayWidth; 264 frameCopy->mDisplayHeight = frame->mDisplayHeight; 265 frameCopy->mSize = frame->mSize; 266 frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame); 267 memcpy(frameCopy->mData, frame->mData, frame->mSize); 268 delete frame; // Fix memory leakage 269 return mThumbnail; 270} 271 272sp<IMemory> MetadataRetrieverClient::extractAlbumArt() 273{ 274 LOGV("extractAlbumArt"); 275 Mutex::Autolock lock(mLock); 276 mAlbumArt.clear(); 277 mAlbumArtDealer.clear(); 278 if (mRetriever == NULL) { 279 LOGE("retriever is not initialized"); 280 return NULL; 281 } 282 MediaAlbumArt *albumArt = mRetriever->extractAlbumArt(); 283 if (albumArt == NULL) { 284 LOGE("failed to extract an album art"); 285 return NULL; 286 } 287 size_t size = sizeof(MediaAlbumArt) + albumArt->mSize; 288 mAlbumArtDealer = new MemoryDealer(size); 289 if (mAlbumArtDealer == NULL) { 290 LOGE("failed to create MemoryDealer object"); 291 delete albumArt; 292 return NULL; 293 } 294 mAlbumArt = mAlbumArtDealer->allocate(size); 295 if (mAlbumArt == NULL) { 296 LOGE("not enough memory for MediaAlbumArt size=%u", size); 297 mAlbumArtDealer.clear(); 298 delete albumArt; 299 return NULL; 300 } 301 MediaAlbumArt *albumArtCopy = static_cast<MediaAlbumArt *>(mAlbumArt->pointer()); 302 albumArtCopy->mSize = albumArt->mSize; 303 albumArtCopy->mData = (uint8_t *)albumArtCopy + sizeof(MediaAlbumArt); 304 memcpy(albumArtCopy->mData, albumArt->mData, albumArt->mSize); 305 delete albumArt; // Fix memory leakage 306 return mAlbumArt; 307} 308 309const char* MetadataRetrieverClient::extractMetadata(int keyCode) 310{ 311 LOGV("extractMetadata"); 312 Mutex::Autolock lock(mLock); 313 if (mRetriever == NULL) { 314 LOGE("retriever is not initialized"); 315 return NULL; 316 } 317 return mRetriever->extractMetadata(keyCode); 318} 319 320}; // namespace android 321