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