1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "BpMediaExtractor" 19#include <utils/Log.h> 20 21#include <stdint.h> 22#include <sys/types.h> 23 24#include <binder/IPCThreadState.h> 25#include <binder/Parcel.h> 26#include <binder/PermissionCache.h> 27#include <media/IMediaExtractor.h> 28#include <media/stagefright/MetaData.h> 29 30namespace android { 31 32enum { 33 COUNTTRACKS = IBinder::FIRST_CALL_TRANSACTION, 34 GETTRACK, 35 GETTRACKMETADATA, 36 GETMETADATA, 37 FLAGS, 38 SETMEDIACAS, 39 NAME, 40 GETMETRICS 41}; 42 43class BpMediaExtractor : public BpInterface<IMediaExtractor> { 44public: 45 explicit BpMediaExtractor(const sp<IBinder>& impl) 46 : BpInterface<IMediaExtractor>(impl) 47 { 48 } 49 50 virtual size_t countTracks() { 51 ALOGV("countTracks"); 52 Parcel data, reply; 53 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); 54 status_t ret = remote()->transact(COUNTTRACKS, data, &reply); 55 size_t numTracks = 0; 56 if (ret == NO_ERROR) { 57 numTracks = reply.readUint32(); 58 } 59 return numTracks; 60 } 61 virtual sp<IMediaSource> getTrack(size_t index) { 62 ALOGV("getTrack(%zu)", index); 63 Parcel data, reply; 64 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); 65 data.writeUint32(index); 66 status_t ret = remote()->transact(GETTRACK, data, &reply); 67 if (ret == NO_ERROR) { 68 return interface_cast<IMediaSource>(reply.readStrongBinder()); 69 } 70 return NULL; 71 } 72 73 virtual sp<MetaData> getTrackMetaData( 74 size_t index, uint32_t flags) { 75 ALOGV("getTrackMetaData(%zu, %u)", index, flags); 76 Parcel data, reply; 77 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); 78 data.writeUint32(index); 79 data.writeUint32(flags); 80 status_t ret = remote()->transact(GETTRACKMETADATA, data, &reply); 81 if (ret == NO_ERROR) { 82 return MetaData::createFromParcel(reply); 83 } 84 return NULL; 85 } 86 87 virtual sp<MetaData> getMetaData() { 88 ALOGV("getMetaData"); 89 Parcel data, reply; 90 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); 91 status_t ret = remote()->transact(GETMETADATA, data, &reply); 92 if (ret == NO_ERROR) { 93 return MetaData::createFromParcel(reply); 94 } 95 return NULL; 96 } 97 98 virtual status_t getMetrics(Parcel * reply) { 99 Parcel data; 100 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); 101 status_t ret = remote()->transact(GETMETRICS, data, reply); 102 if (ret == NO_ERROR) { 103 return OK; 104 } 105 return UNKNOWN_ERROR; 106 } 107 108 virtual uint32_t flags() const { 109 ALOGV("flags NOT IMPLEMENTED"); 110 return 0; 111 } 112 113 virtual status_t setMediaCas(const HInterfaceToken &casToken) { 114 ALOGV("setMediaCas"); 115 116 Parcel data, reply; 117 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); 118 data.writeByteVector(casToken); 119 120 status_t err = remote()->transact(SETMEDIACAS, data, &reply); 121 if (err != NO_ERROR) { 122 return err; 123 } 124 return reply.readInt32(); 125 } 126 127 virtual const char * name() { 128 ALOGV("name NOT IMPLEMENTED"); 129 return NULL; 130 } 131}; 132 133IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor"); 134 135#undef LOG_TAG 136#define LOG_TAG "BnMediaExtractor" 137 138status_t BnMediaExtractor::onTransact( 139 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 140{ 141 switch (code) { 142 case COUNTTRACKS: { 143 ALOGV("countTracks"); 144 CHECK_INTERFACE(IMediaExtractor, data, reply); 145 size_t numTracks = countTracks(); 146 if (numTracks > INT32_MAX) { 147 numTracks = 0; 148 } 149 reply->writeUint32(uint32_t(numTracks)); 150 return NO_ERROR; 151 } 152 case GETTRACK: { 153 ALOGV("getTrack()"); 154 CHECK_INTERFACE(IMediaExtractor, data, reply); 155 uint32_t idx; 156 if (data.readUint32(&idx) == NO_ERROR) { 157 const sp<IMediaSource> track = getTrack(size_t(idx)); 158 registerMediaSource(this, track); 159 return reply->writeStrongBinder(IInterface::asBinder(track)); 160 } 161 return UNKNOWN_ERROR; 162 } 163 case GETTRACKMETADATA: { 164 ALOGV("getTrackMetaData"); 165 CHECK_INTERFACE(IMediaExtractor, data, reply); 166 uint32_t idx; 167 uint32_t flags; 168 if (data.readUint32(&idx) == NO_ERROR && 169 data.readUint32(&flags) == NO_ERROR) { 170 sp<MetaData> meta = getTrackMetaData(idx, flags); 171 if (meta == NULL) { 172 return UNKNOWN_ERROR; 173 } 174 meta->writeToParcel(*reply); 175 return NO_ERROR; 176 } 177 return UNKNOWN_ERROR; 178 } 179 case GETMETADATA: { 180 ALOGV("getMetaData"); 181 CHECK_INTERFACE(IMediaExtractor, data, reply); 182 sp<MetaData> meta = getMetaData(); 183 if (meta != NULL) { 184 meta->writeToParcel(*reply); 185 return NO_ERROR; 186 } 187 return UNKNOWN_ERROR; 188 } 189 case GETMETRICS: { 190 CHECK_INTERFACE(IMediaExtractor, data, reply); 191 status_t ret = getMetrics(reply); 192 return ret; 193 } 194 case SETMEDIACAS: { 195 ALOGV("setMediaCas"); 196 CHECK_INTERFACE(IMediaExtractor, data, reply); 197 198 HInterfaceToken casToken; 199 status_t err = data.readByteVector(&casToken); 200 if (err != NO_ERROR) { 201 ALOGE("Error reading casToken from parcel"); 202 return err; 203 } 204 205 reply->writeInt32(setMediaCas(casToken)); 206 return OK; 207 } 208 default: 209 return BBinder::onTransact(code, data, reply, flags); 210 } 211} 212 213typedef struct { 214 String8 mime; 215 String8 name; 216 String8 sourceDescription; 217 pid_t owner; 218 wp<IMediaExtractor> extractor; 219 Vector<wp<IMediaSource>> tracks; 220 Vector<String8> trackDescriptions; 221 String8 toString() const; 222} ExtractorInstance; 223 224String8 ExtractorInstance::toString() const { 225 String8 str = name; 226 str.append(" for mime "); 227 str.append(mime); 228 str.append(", source "); 229 str.append(sourceDescription); 230 str.append(String8::format(", pid %d: ", owner)); 231 if (extractor.promote() == NULL) { 232 str.append("deleted\n"); 233 } else { 234 str.append("active\n"); 235 } 236 for (size_t i = 0; i < tracks.size(); i++) { 237 const String8 desc = trackDescriptions.itemAt(i); 238 str.appendFormat(" track {%s} ", desc.string()); 239 wp<IMediaSource> wSource = tracks.itemAt(i); 240 if (wSource == NULL) { 241 str.append(": null\n"); 242 } else { 243 const sp<IMediaSource> source = wSource.promote(); 244 if (source == NULL) { 245 str.append(": deleted\n"); 246 } else { 247 str.appendFormat(": active\n"); 248 } 249 } 250 } 251 return str; 252} 253 254static Vector<ExtractorInstance> sExtractors; 255static Mutex sExtractorsLock; 256 257void registerMediaSource( 258 const sp<IMediaExtractor> &ex, 259 const sp<IMediaSource> &source) { 260 Mutex::Autolock lock(sExtractorsLock); 261 for (size_t i = 0; i < sExtractors.size(); i++) { 262 ExtractorInstance &instance = sExtractors.editItemAt(i); 263 sp<IMediaExtractor> extractor = instance.extractor.promote(); 264 if (extractor != NULL && extractor == ex) { 265 if (instance.tracks.size() > 5) { 266 instance.tracks.resize(5); 267 instance.trackDescriptions.resize(5); 268 } 269 instance.tracks.push_front(source); 270 if (source != NULL) { 271 instance.trackDescriptions.push_front(source->getFormat()->toString()); 272 } else { 273 instance.trackDescriptions.push_front(String8::empty()); 274 } 275 break; 276 } 277 } 278} 279 280void registerMediaExtractor( 281 const sp<IMediaExtractor> &extractor, 282 const sp<DataSource> &source, 283 const char *mime) { 284 ExtractorInstance ex; 285 ex.mime = mime == NULL ? "NULL" : mime; 286 ex.name = extractor->name(); 287 ex.sourceDescription = source->toString(); 288 ex.owner = IPCThreadState::self()->getCallingPid(); 289 ex.extractor = extractor; 290 291 { 292 Mutex::Autolock lock(sExtractorsLock); 293 if (sExtractors.size() > 10) { 294 sExtractors.resize(10); 295 } 296 sExtractors.push_front(ex); 297 } 298} 299 300status_t dumpExtractors(int fd, const Vector<String16>&) { 301 String8 out; 302 const IPCThreadState* ipc = IPCThreadState::self(); 303 const int pid = ipc->getCallingPid(); 304 const int uid = ipc->getCallingUid(); 305 if (!PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) { 306 out.appendFormat("Permission Denial: " 307 "can't dump MediaExtractor from pid=%d, uid=%d\n", pid, uid); 308 } else { 309 out.append("Recent extractors, most recent first:\n"); 310 { 311 Mutex::Autolock lock(sExtractorsLock); 312 for (size_t i = 0; i < sExtractors.size(); i++) { 313 const ExtractorInstance &instance = sExtractors.itemAt(i); 314 out.append(" "); 315 out.append(instance.toString()); 316 } 317 } 318 } 319 write(fd, out.string(), out.size()); 320 return OK; 321} 322 323 324} // namespace android 325 326