IMediaMetadataRetriever.cpp revision f311c557729099d002f4aae37c402a8287912369
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_MODE, 86 CAPTURE_FRAME, 87 EXTRACT_ALBUM_ART, 88 EXTRACT_METADATA, 89}; 90 91class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever> 92{ 93public: 94 BpMediaMetadataRetriever(const sp<IBinder>& impl) 95 : BpInterface<IMediaMetadataRetriever>(impl) 96 { 97 } 98 99 // disconnect from media metadata retriever service 100 void disconnect() 101 { 102 Parcel data, reply; 103 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 104 remote()->transact(DISCONNECT, data, &reply); 105 } 106 107 status_t setDataSource(const char* srcUrl) 108 { 109 Parcel data, reply; 110 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 111 data.writeCString(srcUrl); 112 remote()->transact(SET_DATA_SOURCE_URL, data, &reply); 113 return reply.readInt32(); 114 } 115 116 status_t setDataSource(int fd, int64_t offset, int64_t length) 117 { 118 Parcel data, reply; 119 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 120 data.writeFileDescriptor(fd); 121 data.writeInt64(offset); 122 data.writeInt64(length); 123 remote()->transact(SET_DATA_SOURCE_FD, data, &reply); 124 return reply.readInt32(); 125 } 126 127 status_t setMode(int mode) 128 { 129 Parcel data, reply; 130 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 131 data.writeInt32(mode); 132 remote()->transact(SET_MODE, data, &reply); 133 return reply.readInt32(); 134 } 135 136 status_t getMode(int* mode) const 137 { 138 Parcel data, reply; 139 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 140 remote()->transact(GET_MODE, data, &reply); 141 *mode = reply.readInt32(); 142 return reply.readInt32(); 143 } 144 145 sp<IMemory> captureFrame() 146 { 147 Parcel data, reply; 148 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 149#ifndef DISABLE_GROUP_SCHEDULE_HACK 150 sendSchedPolicy(data); 151#endif 152 remote()->transact(CAPTURE_FRAME, data, &reply); 153 status_t ret = reply.readInt32(); 154 if (ret != NO_ERROR) { 155 return NULL; 156 } 157 return interface_cast<IMemory>(reply.readStrongBinder()); 158 } 159 160 sp<IMemory> extractAlbumArt() 161 { 162 Parcel data, reply; 163 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 164#ifndef DISABLE_GROUP_SCHEDULE_HACK 165 sendSchedPolicy(data); 166#endif 167 remote()->transact(EXTRACT_ALBUM_ART, data, &reply); 168 status_t ret = reply.readInt32(); 169 if (ret != NO_ERROR) { 170 return NULL; 171 } 172 return interface_cast<IMemory>(reply.readStrongBinder()); 173 } 174 175 const char* extractMetadata(int keyCode) 176 { 177 Parcel data, reply; 178 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 179#ifndef DISABLE_GROUP_SCHEDULE_HACK 180 sendSchedPolicy(data); 181#endif 182 data.writeInt32(keyCode); 183 remote()->transact(EXTRACT_METADATA, data, &reply); 184 status_t ret = reply.readInt32(); 185 if (ret != NO_ERROR) { 186 return NULL; 187 } 188 return reply.readCString(); 189 } 190}; 191 192IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever"); 193 194// ---------------------------------------------------------------------- 195 196status_t BnMediaMetadataRetriever::onTransact( 197 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 198{ 199 switch (code) { 200 case DISCONNECT: { 201 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 202 disconnect(); 203 return NO_ERROR; 204 } break; 205 case SET_DATA_SOURCE_URL: { 206 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 207 const char* srcUrl = data.readCString(); 208 reply->writeInt32(setDataSource(srcUrl)); 209 return NO_ERROR; 210 } break; 211 case SET_DATA_SOURCE_FD: { 212 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 213 int fd = dup(data.readFileDescriptor()); 214 int64_t offset = data.readInt64(); 215 int64_t length = data.readInt64(); 216 reply->writeInt32(setDataSource(fd, offset, length)); 217 return NO_ERROR; 218 } break; 219 case SET_MODE: { 220 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 221 int mode = data.readInt32(); 222 reply->writeInt32(setMode(mode)); 223 return NO_ERROR; 224 } break; 225 case GET_MODE: { 226 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 227 int mode; 228 status_t status = getMode(&mode); 229 reply->writeInt32(mode); 230 reply->writeInt32(status); 231 return NO_ERROR; 232 } break; 233 case CAPTURE_FRAME: { 234 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 235#ifndef DISABLE_GROUP_SCHEDULE_HACK 236 setSchedPolicy(data); 237#endif 238 sp<IMemory> bitmap = captureFrame(); 239 if (bitmap != 0) { // Don't send NULL across the binder interface 240 reply->writeInt32(NO_ERROR); 241 reply->writeStrongBinder(bitmap->asBinder()); 242 } else { 243 reply->writeInt32(UNKNOWN_ERROR); 244 } 245#ifndef DISABLE_GROUP_SCHEDULE_HACK 246 restoreSchedPolicy(); 247#endif 248 return NO_ERROR; 249 } break; 250 case EXTRACT_ALBUM_ART: { 251 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 252#ifndef DISABLE_GROUP_SCHEDULE_HACK 253 setSchedPolicy(data); 254#endif 255 sp<IMemory> albumArt = extractAlbumArt(); 256 if (albumArt != 0) { // Don't send NULL across the binder interface 257 reply->writeInt32(NO_ERROR); 258 reply->writeStrongBinder(albumArt->asBinder()); 259 } else { 260 reply->writeInt32(UNKNOWN_ERROR); 261 } 262#ifndef DISABLE_GROUP_SCHEDULE_HACK 263 restoreSchedPolicy(); 264#endif 265 return NO_ERROR; 266 } break; 267 case EXTRACT_METADATA: { 268 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 269#ifndef DISABLE_GROUP_SCHEDULE_HACK 270 setSchedPolicy(data); 271#endif 272 int keyCode = data.readInt32(); 273 const char* value = extractMetadata(keyCode); 274 if (value != NULL) { // Don't send NULL across the binder interface 275 reply->writeInt32(NO_ERROR); 276 reply->writeCString(value); 277 } else { 278 reply->writeInt32(UNKNOWN_ERROR); 279 } 280#ifndef DISABLE_GROUP_SCHEDULE_HACK 281 restoreSchedPolicy(); 282#endif 283 return NO_ERROR; 284 } break; 285 default: 286 return BBinder::onTransact(code, data, reply, flags); 287 } 288} 289 290// ---------------------------------------------------------------------------- 291 292}; // namespace android 293