IMediaMetadataRetriever.cpp revision f888020c6e2735624f2b2a30e72aca24e17b8b4d
198a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall/* 298a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall** 398a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall** Copyright (C) 2008 The Android Open Source Project 498a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall** 598a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall** Licensed under the Apache License, Version 2.0 (the "License"); 698a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall** you may not use this file except in compliance with the License. 798a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall** You may obtain a copy of the License at 898a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall** 998a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall** http://www.apache.org/licenses/LICENSE-2.0 1098a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall** 1198a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall** Unless required by applicable law or agreed to in writing, software 1298a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall** distributed under the License is distributed on an "AS IS" BASIS, 1398a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1498a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall** See the License for the specific language governing permissions and 1598a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall** limitations under the License. 1698a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall*/ 1798a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall 1898a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall#include <inttypes.h> 1998a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall#include <stdint.h> 2098a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall#include <sys/types.h> 2198a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall 2298a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall#include <binder/Parcel.h> 2398a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall#include <media/IMediaHTTPService.h> 2498a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall#include <media/IMediaMetadataRetriever.h> 2598a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall#include <utils/String8.h> 2698a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall#include <utils/KeyedVector.h> 2798a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall 2898a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall// The binder is supposed to propagate the scheduler group across 2998a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall// the binder interface so that remote calls are executed with 3098a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall// the same priority as local calls. This is currently not working 3198a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall// so this change puts in a temporary hack to fix the issue with 3298a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall// metadata retrieval which can be a huge CPU hit if done on a 3398a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall// foreground thread. 3498a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall#ifndef DISABLE_GROUP_SCHEDULE_HACK 3598a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall 3698a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall#undef LOG_TAG 3798a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall#define LOG_TAG "IMediaMetadataRetriever" 3898671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier#include <utils/Log.h> 393762c311729fe9f3af085c14c5c1fb471d994c03Steve Block#include <cutils/sched_policy.h> 4098a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall 4198a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrallnamespace android { 4298a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall 4398a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrallstatic void sendSchedPolicy(Parcel& data) 4498a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall{ 4598a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall SchedPolicy policy; 4698a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall get_sched_policy(gettid(), &policy); 4798a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall data.writeInt32(policy); 4898a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall} 4998a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall 50f5df700e6ce056ebfa322314d970e52d6facc35aAshok Bhatstatic void setSchedPolicy(const Parcel& data) 51f5df700e6ce056ebfa322314d970e52d6facc35aAshok Bhat{ 5298a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall SchedPolicy policy = (SchedPolicy) data.readInt32(); 5398a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall set_sched_policy(gettid(), policy); 5498671c34fa00a79c62ff0d9d874428bed1f86e92Mathieu Chartier} 553762c311729fe9f3af085c14c5c1fb471d994c03Steve Blockstatic void restoreSchedPolicy() 5698a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall{ 5798a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall set_sched_policy(gettid(), SP_FOREGROUND); 5898a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall} 5998a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall}; // end namespace android 6098a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall#endif 6198a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall 6298a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrallnamespace android { 6398a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall 6498a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrallenum { 6598a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, 6698a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall SET_DATA_SOURCE_URL, 6798a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall SET_DATA_SOURCE_FD, 6898a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall GET_FRAME_AT_TIME, 6998a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall EXTRACT_ALBUM_ART, 7098a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall EXTRACT_METADATA, 7198a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall}; 7298a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall 7398a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrallclass BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever> 7498a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall{ 7598a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrallpublic: 7698a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall BpMediaMetadataRetriever(const sp<IBinder>& impl) 7798a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall : BpInterface<IMediaMetadataRetriever>(impl) 7898a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall { 7998a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall } 8098a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall 8198a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall // disconnect from media metadata retriever service 8298a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall void disconnect() 8398a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall { 8498a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall Parcel data, reply; 8598a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 8676f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micay remote()->transact(DISCONNECT, data, &reply); 8798a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall } 8898a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall 8998a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall status_t setDataSource( 9098a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall const sp<IMediaHTTPService> &httpService, 9198a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall const char *srcUrl, 9298a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall const KeyedVector<String8, String8> *headers) 9398a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall { 9498a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall Parcel data, reply; 9598a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 9698a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall data.writeInt32(httpService != NULL); 9798a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall if (httpService != NULL) { 98 data.writeStrongBinder(IInterface::asBinder(httpService)); 99 } 100 data.writeCString(srcUrl); 101 102 if (headers == NULL) { 103 data.writeInt32(0); 104 } else { 105 // serialize the headers 106 data.writeInt64(headers->size()); 107 for (size_t i = 0; i < headers->size(); ++i) { 108 data.writeString8(headers->keyAt(i)); 109 data.writeString8(headers->valueAt(i)); 110 } 111 } 112 113 remote()->transact(SET_DATA_SOURCE_URL, data, &reply); 114 return reply.readInt32(); 115 } 116 117 status_t setDataSource(int fd, int64_t offset, int64_t length) 118 { 119 Parcel data, reply; 120 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 121 data.writeFileDescriptor(fd); 122 data.writeInt64(offset); 123 data.writeInt64(length); 124 remote()->transact(SET_DATA_SOURCE_FD, data, &reply); 125 return reply.readInt32(); 126 } 127 128 sp<IMemory> getFrameAtTime(int64_t timeUs, int option) 129 { 130 ALOGV("getTimeAtTime: time(%" PRId64 " us) and option(%d)", timeUs, option); 131 Parcel data, reply; 132 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 133 data.writeInt64(timeUs); 134 data.writeInt32(option); 135#ifndef DISABLE_GROUP_SCHEDULE_HACK 136 sendSchedPolicy(data); 137#endif 138 remote()->transact(GET_FRAME_AT_TIME, data, &reply); 139 status_t ret = reply.readInt32(); 140 if (ret != NO_ERROR) { 141 return NULL; 142 } 143 return interface_cast<IMemory>(reply.readStrongBinder()); 144 } 145 146 sp<IMemory> extractAlbumArt() 147 { 148 Parcel data, reply; 149 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 150#ifndef DISABLE_GROUP_SCHEDULE_HACK 151 sendSchedPolicy(data); 152#endif 153 remote()->transact(EXTRACT_ALBUM_ART, data, &reply); 154 status_t ret = reply.readInt32(); 155 if (ret != NO_ERROR) { 156 return NULL; 157 } 158 return interface_cast<IMemory>(reply.readStrongBinder()); 159 } 160 161 const char* extractMetadata(int keyCode) 162 { 163 Parcel data, reply; 164 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 165#ifndef DISABLE_GROUP_SCHEDULE_HACK 166 sendSchedPolicy(data); 167#endif 168 data.writeInt32(keyCode); 169 remote()->transact(EXTRACT_METADATA, data, &reply); 170 status_t ret = reply.readInt32(); 171 if (ret != NO_ERROR) { 172 return NULL; 173 } 174 const char* str = reply.readCString(); 175 if (str != NULL) { 176 String8 value(str); 177 if (mMetadata.indexOfKey(keyCode) < 0) { 178 mMetadata.add(keyCode, value); 179 } else { 180 mMetadata.replaceValueFor(keyCode, value); 181 } 182 return mMetadata.valueFor(keyCode).string(); 183 } else { 184 return NULL; 185 } 186 } 187 188private: 189 KeyedVector<int, String8> mMetadata; 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 208 sp<IMediaHTTPService> httpService; 209 if (data.readInt32()) { 210 httpService = 211 interface_cast<IMediaHTTPService>(data.readStrongBinder()); 212 } 213 214 const char* srcUrl = data.readCString(); 215 216 KeyedVector<String8, String8> headers; 217 size_t numHeaders = (size_t) data.readInt64(); 218 for (size_t i = 0; i < numHeaders; ++i) { 219 String8 key = data.readString8(); 220 String8 value = data.readString8(); 221 headers.add(key, value); 222 } 223 224 reply->writeInt32( 225 setDataSource( 226 httpService, srcUrl, numHeaders > 0 ? &headers : NULL)); 227 228 return NO_ERROR; 229 } break; 230 case SET_DATA_SOURCE_FD: { 231 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 232 int fd = dup(data.readFileDescriptor()); 233 int64_t offset = data.readInt64(); 234 int64_t length = data.readInt64(); 235 reply->writeInt32(setDataSource(fd, offset, length)); 236 return NO_ERROR; 237 } break; 238 case GET_FRAME_AT_TIME: { 239 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 240 int64_t timeUs = data.readInt64(); 241 int option = data.readInt32(); 242 ALOGV("getTimeAtTime: time(%" PRId64 " us) and option(%d)", timeUs, option); 243#ifndef DISABLE_GROUP_SCHEDULE_HACK 244 setSchedPolicy(data); 245#endif 246 sp<IMemory> bitmap = getFrameAtTime(timeUs, option); 247 if (bitmap != 0) { // Don't send NULL across the binder interface 248 reply->writeInt32(NO_ERROR); 249 reply->writeStrongBinder(IInterface::asBinder(bitmap)); 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_ALBUM_ART: { 259 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 260#ifndef DISABLE_GROUP_SCHEDULE_HACK 261 setSchedPolicy(data); 262#endif 263 sp<IMemory> albumArt = extractAlbumArt(); 264 if (albumArt != 0) { // Don't send NULL across the binder interface 265 reply->writeInt32(NO_ERROR); 266 reply->writeStrongBinder(IInterface::asBinder(albumArt)); 267 } else { 268 reply->writeInt32(UNKNOWN_ERROR); 269 } 270#ifndef DISABLE_GROUP_SCHEDULE_HACK 271 restoreSchedPolicy(); 272#endif 273 return NO_ERROR; 274 } break; 275 case EXTRACT_METADATA: { 276 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 277#ifndef DISABLE_GROUP_SCHEDULE_HACK 278 setSchedPolicy(data); 279#endif 280 int keyCode = data.readInt32(); 281 const char* value = extractMetadata(keyCode); 282 if (value != NULL) { // Don't send NULL across the binder interface 283 reply->writeInt32(NO_ERROR); 284 reply->writeCString(value); 285 } else { 286 reply->writeInt32(UNKNOWN_ERROR); 287 } 288#ifndef DISABLE_GROUP_SCHEDULE_HACK 289 restoreSchedPolicy(); 290#endif 291 return NO_ERROR; 292 } break; 293 default: 294 return BBinder::onTransact(code, data, reply, flags); 295 } 296} 297 298// ---------------------------------------------------------------------------- 299 300}; // namespace android 301