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