IMediaMetadataRetriever.cpp revision 16afe2fb439cab6125bb46a07a8078d4ce1c1ea5
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#include <stdint.h> 19#include <sys/types.h> 20#include <binder/Parcel.h> 21#include <SkBitmap.h> 22#include <media/IMediaMetadataRetriever.h> 23 24// The binder is supposed to propagate the scheduler group across 25// the binder interface so that remote calls are executed with 26// the same priority as local calls. This is currently not working 27// so this change puts in a temporary hack to fix the issue with 28// metadata retrieval which can be a huge CPU hit if done on a 29// foreground thread. 30#ifndef DISABLE_GROUP_SCHEDULE_HACK 31 32/* desktop Linux needs a little help with gettid() */ 33#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS) 34#define __KERNEL__ 35# include <linux/unistd.h> 36#ifdef _syscall0 37_syscall0(pid_t,gettid) 38#else 39pid_t gettid() { return syscall(__NR_gettid);} 40#endif 41#undef __KERNEL__ 42#endif 43 44static int myTid() { 45#ifdef HAVE_GETTID 46 return gettid(); 47#else 48 return getpid(); 49#endif 50} 51 52#undef LOG_TAG 53#define LOG_TAG "IMediaMetadataRetriever" 54#include <utils/Log.h> 55#include <cutils/sched_policy.h> 56 57namespace android { 58 59static void sendSchedPolicy(Parcel& data) 60{ 61 SchedPolicy policy; 62 get_sched_policy(myTid(), &policy); 63 data.writeInt32(policy); 64} 65 66static void setSchedPolicy(const Parcel& data) 67{ 68 SchedPolicy policy = (SchedPolicy) data.readInt32(); 69 set_sched_policy(myTid(), policy); 70} 71static void restoreSchedPolicy() 72{ 73 set_sched_policy(myTid(), SP_FOREGROUND); 74} 75}; // end namespace android 76#endif 77 78namespace android { 79 80enum { 81 DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, 82 SET_DATA_SOURCE_URL, 83 SET_DATA_SOURCE_FD, 84 SET_MODE, 85 GET_FRAME_AT_TIME, 86 EXTRACT_ALBUM_ART, 87 EXTRACT_METADATA, 88}; 89 90class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever> 91{ 92public: 93 BpMediaMetadataRetriever(const sp<IBinder>& impl) 94 : BpInterface<IMediaMetadataRetriever>(impl) 95 { 96 } 97 98 // disconnect from media metadata retriever service 99 void disconnect() 100 { 101 Parcel data, reply; 102 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 103 remote()->transact(DISCONNECT, data, &reply); 104 } 105 106 status_t setDataSource(const char* srcUrl) 107 { 108 Parcel data, reply; 109 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 110 data.writeCString(srcUrl); 111 remote()->transact(SET_DATA_SOURCE_URL, data, &reply); 112 return reply.readInt32(); 113 } 114 115 status_t setDataSource(int fd, int64_t offset, int64_t length) 116 { 117 Parcel data, reply; 118 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 119 data.writeFileDescriptor(fd); 120 data.writeInt64(offset); 121 data.writeInt64(length); 122 remote()->transact(SET_DATA_SOURCE_FD, data, &reply); 123 return reply.readInt32(); 124 } 125 126 status_t setMode(int mode) 127 { 128 Parcel data, reply; 129 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 130 data.writeInt32(mode); 131 remote()->transact(SET_MODE, data, &reply); 132 return reply.readInt32(); 133 } 134 135 sp<IMemory> getFrameAtTime(int64_t timeUs, int option) 136 { 137 LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option); 138 Parcel data, reply; 139 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 140 data.writeInt64(timeUs); 141 data.writeInt32(option); 142#ifndef DISABLE_GROUP_SCHEDULE_HACK 143 sendSchedPolicy(data); 144#endif 145 remote()->transact(GET_FRAME_AT_TIME, data, &reply); 146 status_t ret = reply.readInt32(); 147 if (ret != NO_ERROR) { 148 return NULL; 149 } 150 return interface_cast<IMemory>(reply.readStrongBinder()); 151 } 152 153 sp<IMemory> extractAlbumArt() 154 { 155 Parcel data, reply; 156 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 157#ifndef DISABLE_GROUP_SCHEDULE_HACK 158 sendSchedPolicy(data); 159#endif 160 remote()->transact(EXTRACT_ALBUM_ART, data, &reply); 161 status_t ret = reply.readInt32(); 162 if (ret != NO_ERROR) { 163 return NULL; 164 } 165 return interface_cast<IMemory>(reply.readStrongBinder()); 166 } 167 168 const char* extractMetadata(int keyCode) 169 { 170 Parcel data, reply; 171 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 172#ifndef DISABLE_GROUP_SCHEDULE_HACK 173 sendSchedPolicy(data); 174#endif 175 data.writeInt32(keyCode); 176 remote()->transact(EXTRACT_METADATA, data, &reply); 177 status_t ret = reply.readInt32(); 178 if (ret != NO_ERROR) { 179 return NULL; 180 } 181 return reply.readCString(); 182 } 183}; 184 185IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever"); 186 187// ---------------------------------------------------------------------- 188 189status_t BnMediaMetadataRetriever::onTransact( 190 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 191{ 192 switch (code) { 193 case DISCONNECT: { 194 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 195 disconnect(); 196 return NO_ERROR; 197 } break; 198 case SET_DATA_SOURCE_URL: { 199 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 200 const char* srcUrl = data.readCString(); 201 reply->writeInt32(setDataSource(srcUrl)); 202 return NO_ERROR; 203 } break; 204 case SET_DATA_SOURCE_FD: { 205 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 206 int fd = dup(data.readFileDescriptor()); 207 int64_t offset = data.readInt64(); 208 int64_t length = data.readInt64(); 209 reply->writeInt32(setDataSource(fd, offset, length)); 210 return NO_ERROR; 211 } break; 212 case SET_MODE: { 213 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 214 int mode = data.readInt32(); 215 reply->writeInt32(setMode(mode)); 216 return NO_ERROR; 217 } break; 218 case GET_FRAME_AT_TIME: { 219 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 220 int64_t timeUs = data.readInt64(); 221 int option = data.readInt32(); 222 LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option); 223#ifndef DISABLE_GROUP_SCHEDULE_HACK 224 setSchedPolicy(data); 225#endif 226 sp<IMemory> bitmap = getFrameAtTime(timeUs, option); 227 if (bitmap != 0) { // Don't send NULL across the binder interface 228 reply->writeInt32(NO_ERROR); 229 reply->writeStrongBinder(bitmap->asBinder()); 230 } else { 231 reply->writeInt32(UNKNOWN_ERROR); 232 } 233#ifndef DISABLE_GROUP_SCHEDULE_HACK 234 restoreSchedPolicy(); 235#endif 236 return NO_ERROR; 237 } break; 238 case EXTRACT_ALBUM_ART: { 239 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 240#ifndef DISABLE_GROUP_SCHEDULE_HACK 241 setSchedPolicy(data); 242#endif 243 sp<IMemory> albumArt = extractAlbumArt(); 244 if (albumArt != 0) { // Don't send NULL across the binder interface 245 reply->writeInt32(NO_ERROR); 246 reply->writeStrongBinder(albumArt->asBinder()); 247 } else { 248 reply->writeInt32(UNKNOWN_ERROR); 249 } 250#ifndef DISABLE_GROUP_SCHEDULE_HACK 251 restoreSchedPolicy(); 252#endif 253 return NO_ERROR; 254 } break; 255 case EXTRACT_METADATA: { 256 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 257#ifndef DISABLE_GROUP_SCHEDULE_HACK 258 setSchedPolicy(data); 259#endif 260 int keyCode = data.readInt32(); 261 const char* value = extractMetadata(keyCode); 262 if (value != NULL) { // Don't send NULL across the binder interface 263 reply->writeInt32(NO_ERROR); 264 reply->writeCString(value); 265 } else { 266 reply->writeInt32(UNKNOWN_ERROR); 267 } 268#ifndef DISABLE_GROUP_SCHEDULE_HACK 269 restoreSchedPolicy(); 270#endif 271 return NO_ERROR; 272 } break; 273 default: 274 return BBinder::onTransact(code, data, reply, flags); 275 } 276} 277 278// ---------------------------------------------------------------------------- 279 280}; // namespace android 281