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 <cutils/properties.h> 31 #include <binder/MemoryBase.h> 32 #include <binder/MemoryHeapBase.h> 33 #include <android_runtime/ActivityManager.h> 34 #include <binder/IPCThreadState.h> 35 #include <binder/IServiceManager.h> 36 #include <media/MediaMetadataRetrieverInterface.h> 37 #include <media/MediaPlayerInterface.h> 38 #include <media/PVMetadataRetriever.h> 39 #include <private/media/VideoFrame.h> 40 #include "MidiMetadataRetriever.h" 41 #include "MetadataRetrieverClient.h" 42 #include "StagefrightMetadataRetriever.h" 43 44 /* desktop Linux needs a little help with gettid() */ 45 #if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS) 46 #define __KERNEL__ 47 # include <linux/unistd.h> 48 #ifdef _syscall0 49 _syscall0(pid_t,gettid) 50 #else 51 pid_t gettid() { return syscall(__NR_gettid);} 52 #endif 53 #undef __KERNEL__ 54 #endif 55 56 namespace android { 57 58 extern player_type getPlayerType(const char* url); 59 extern player_type getPlayerType(int fd, int64_t offset, int64_t length); 60 61 MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid) 62 { 63 LOGV("MetadataRetrieverClient constructor pid(%d)", pid); 64 mPid = pid; 65 mThumbnail = NULL; 66 mAlbumArt = NULL; 67 mRetriever = NULL; 68 } 69 70 MetadataRetrieverClient::~MetadataRetrieverClient() 71 { 72 LOGV("MetadataRetrieverClient destructor"); 73 disconnect(); 74 } 75 76 status_t MetadataRetrieverClient::dump(int fd, const Vector<String16>& args) const 77 { 78 const size_t SIZE = 256; 79 char buffer[SIZE]; 80 String8 result; 81 result.append(" MetadataRetrieverClient\n"); 82 snprintf(buffer, 255, " pid(%d)\n", mPid); 83 result.append(buffer); 84 write(fd, result.string(), result.size()); 85 write(fd, "\n", 1); 86 return NO_ERROR; 87 } 88 89 void MetadataRetrieverClient::disconnect() 90 { 91 LOGV("disconnect from pid %d", mPid); 92 Mutex::Autolock lock(mLock); 93 mRetriever.clear(); 94 mThumbnail.clear(); 95 mAlbumArt.clear(); 96 IPCThreadState::self()->flushCommands(); 97 } 98 99 static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType) 100 { 101 sp<MediaMetadataRetrieverBase> p; 102 switch (playerType) { 103 case STAGEFRIGHT_PLAYER: 104 { 105 p = new StagefrightMetadataRetriever; 106 break; 107 } 108 #ifndef NO_OPENCORE 109 case PV_PLAYER: 110 LOGV("create pv metadata retriever"); 111 p = new PVMetadataRetriever(); 112 break; 113 #endif 114 case SONIVOX_PLAYER: 115 LOGV("create midi metadata retriever"); 116 p = new MidiMetadataRetriever(); 117 break; 118 default: 119 // TODO: 120 // support for TEST_PLAYER 121 LOGE("player type %d is not supported", playerType); 122 break; 123 } 124 if (p == NULL) { 125 LOGE("failed to create a retriever object"); 126 } 127 return p; 128 } 129 130 status_t MetadataRetrieverClient::setDataSource(const char *url) 131 { 132 LOGV("setDataSource(%s)", url); 133 Mutex::Autolock lock(mLock); 134 if (url == NULL) { 135 return UNKNOWN_ERROR; 136 } 137 player_type playerType = getPlayerType(url); 138 LOGV("player type = %d", playerType); 139 sp<MediaMetadataRetrieverBase> p = createRetriever(playerType); 140 if (p == NULL) return NO_INIT; 141 status_t ret = p->setDataSource(url); 142 if (ret == NO_ERROR) mRetriever = p; 143 return ret; 144 } 145 146 status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length) 147 { 148 LOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length); 149 Mutex::Autolock lock(mLock); 150 struct stat sb; 151 int ret = fstat(fd, &sb); 152 if (ret != 0) { 153 LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno)); 154 return BAD_VALUE; 155 } 156 LOGV("st_dev = %llu", sb.st_dev); 157 LOGV("st_mode = %u", sb.st_mode); 158 LOGV("st_uid = %lu", sb.st_uid); 159 LOGV("st_gid = %lu", sb.st_gid); 160 LOGV("st_size = %llu", sb.st_size); 161 162 if (offset >= sb.st_size) { 163 LOGE("offset (%lld) bigger than file size (%llu)", offset, sb.st_size); 164 ::close(fd); 165 return BAD_VALUE; 166 } 167 if (offset + length > sb.st_size) { 168 length = sb.st_size - offset; 169 LOGV("calculated length = %lld", length); 170 } 171 172 player_type playerType = getPlayerType(fd, offset, length); 173 LOGV("player type = %d", playerType); 174 sp<MediaMetadataRetrieverBase> p = createRetriever(playerType); 175 if (p == NULL) { 176 ::close(fd); 177 return NO_INIT; 178 } 179 status_t status = p->setDataSource(fd, offset, length); 180 if (status == NO_ERROR) mRetriever = p; 181 ::close(fd); 182 return status; 183 } 184 185 sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option) 186 { 187 LOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option); 188 Mutex::Autolock lock(mLock); 189 mThumbnail.clear(); 190 if (mRetriever == NULL) { 191 LOGE("retriever is not initialized"); 192 return NULL; 193 } 194 VideoFrame *frame = mRetriever->getFrameAtTime(timeUs, option); 195 if (frame == NULL) { 196 LOGE("failed to capture a video frame"); 197 return NULL; 198 } 199 size_t size = sizeof(VideoFrame) + frame->mSize; 200 sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient"); 201 if (heap == NULL) { 202 LOGE("failed to create MemoryDealer"); 203 delete frame; 204 return NULL; 205 } 206 mThumbnail = new MemoryBase(heap, 0, size); 207 if (mThumbnail == NULL) { 208 LOGE("not enough memory for VideoFrame size=%u", size); 209 delete frame; 210 return NULL; 211 } 212 VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer()); 213 frameCopy->mWidth = frame->mWidth; 214 frameCopy->mHeight = frame->mHeight; 215 frameCopy->mDisplayWidth = frame->mDisplayWidth; 216 frameCopy->mDisplayHeight = frame->mDisplayHeight; 217 frameCopy->mSize = frame->mSize; 218 frameCopy->mRotationAngle = frame->mRotationAngle; 219 LOGV("rotation: %d", frameCopy->mRotationAngle); 220 frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame); 221 memcpy(frameCopy->mData, frame->mData, frame->mSize); 222 delete frame; // Fix memory leakage 223 return mThumbnail; 224 } 225 226 sp<IMemory> MetadataRetrieverClient::extractAlbumArt() 227 { 228 LOGV("extractAlbumArt"); 229 Mutex::Autolock lock(mLock); 230 mAlbumArt.clear(); 231 if (mRetriever == NULL) { 232 LOGE("retriever is not initialized"); 233 return NULL; 234 } 235 MediaAlbumArt *albumArt = mRetriever->extractAlbumArt(); 236 if (albumArt == NULL) { 237 LOGE("failed to extract an album art"); 238 return NULL; 239 } 240 size_t size = sizeof(MediaAlbumArt) + albumArt->mSize; 241 sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient"); 242 if (heap == NULL) { 243 LOGE("failed to create MemoryDealer object"); 244 delete albumArt; 245 return NULL; 246 } 247 mAlbumArt = new MemoryBase(heap, 0, size); 248 if (mAlbumArt == NULL) { 249 LOGE("not enough memory for MediaAlbumArt size=%u", size); 250 delete albumArt; 251 return NULL; 252 } 253 MediaAlbumArt *albumArtCopy = static_cast<MediaAlbumArt *>(mAlbumArt->pointer()); 254 albumArtCopy->mSize = albumArt->mSize; 255 albumArtCopy->mData = (uint8_t *)albumArtCopy + sizeof(MediaAlbumArt); 256 memcpy(albumArtCopy->mData, albumArt->mData, albumArt->mSize); 257 delete albumArt; // Fix memory leakage 258 return mAlbumArt; 259 } 260 261 const char* MetadataRetrieverClient::extractMetadata(int keyCode) 262 { 263 LOGV("extractMetadata"); 264 Mutex::Autolock lock(mLock); 265 if (mRetriever == NULL) { 266 LOGE("retriever is not initialized"); 267 return NULL; 268 } 269 return mRetriever->extractMetadata(keyCode); 270 } 271 272 }; // namespace android 273