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 <android/media/ICas.h> 25 #include <binder/IPCThreadState.h> 26 #include <binder/Parcel.h> 27 #include <media/IMediaExtractor.h> 28 #include <media/stagefright/MetaData.h> 29 30 namespace android { 31 32 enum { 33 COUNTTRACKS = IBinder::FIRST_CALL_TRANSACTION, 34 GETTRACK, 35 GETTRACKMETADATA, 36 GETMETADATA, 37 FLAGS, 38 GETDRMTRACKINFO, 39 SETMEDIACAS, 40 SETUID, 41 NAME, 42 GETMETRICS 43 }; 44 45 class BpMediaExtractor : public BpInterface<IMediaExtractor> { 46 public: 47 explicit BpMediaExtractor(const sp<IBinder>& impl) 48 : BpInterface<IMediaExtractor>(impl) 49 { 50 } 51 52 virtual size_t countTracks() { 53 ALOGV("countTracks"); 54 Parcel data, reply; 55 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); 56 status_t ret = remote()->transact(COUNTTRACKS, data, &reply); 57 size_t numTracks = 0; 58 if (ret == NO_ERROR) { 59 numTracks = reply.readUint32(); 60 } 61 return numTracks; 62 } 63 virtual sp<IMediaSource> getTrack(size_t index) { 64 ALOGV("getTrack(%zu)", index); 65 Parcel data, reply; 66 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); 67 data.writeUint32(index); 68 status_t ret = remote()->transact(GETTRACK, data, &reply); 69 if (ret == NO_ERROR) { 70 return interface_cast<IMediaSource>(reply.readStrongBinder()); 71 } 72 return NULL; 73 } 74 75 virtual sp<MetaData> getTrackMetaData( 76 size_t index, uint32_t flags) { 77 ALOGV("getTrackMetaData(%zu, %u)", index, flags); 78 Parcel data, reply; 79 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); 80 data.writeUint32(index); 81 data.writeUint32(flags); 82 status_t ret = remote()->transact(GETTRACKMETADATA, data, &reply); 83 if (ret == NO_ERROR) { 84 return MetaData::createFromParcel(reply); 85 } 86 return NULL; 87 } 88 89 virtual sp<MetaData> getMetaData() { 90 ALOGV("getMetaData"); 91 Parcel data, reply; 92 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); 93 status_t ret = remote()->transact(GETMETADATA, data, &reply); 94 if (ret == NO_ERROR) { 95 return MetaData::createFromParcel(reply); 96 } 97 return NULL; 98 } 99 100 virtual status_t getMetrics(Parcel * reply) { 101 Parcel data; 102 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); 103 status_t ret = remote()->transact(GETMETRICS, data, reply); 104 if (ret == NO_ERROR) { 105 return OK; 106 } 107 return UNKNOWN_ERROR; 108 } 109 110 virtual uint32_t flags() const { 111 ALOGV("flags NOT IMPLEMENTED"); 112 return 0; 113 } 114 115 virtual char* getDrmTrackInfo(size_t trackID __unused, int *len __unused) { 116 ALOGV("getDrmTrackInfo NOT IMPLEMENTED"); 117 return NULL; 118 } 119 120 virtual status_t setMediaCas(const sp<ICas> & cas) { 121 ALOGV("setMediaCas"); 122 123 Parcel data, reply; 124 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); 125 data.writeStrongBinder(IInterface::asBinder(cas)); 126 127 status_t err = remote()->transact(SETMEDIACAS, data, &reply); 128 if (err != NO_ERROR) { 129 return err; 130 } 131 return reply.readInt32(); 132 } 133 134 virtual void setUID(uid_t uid __unused) { 135 ALOGV("setUID NOT IMPLEMENTED"); 136 } 137 138 virtual const char * name() { 139 ALOGV("name NOT IMPLEMENTED"); 140 return NULL; 141 } 142 }; 143 144 IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor"); 145 146 #undef LOG_TAG 147 #define LOG_TAG "BnMediaExtractor" 148 149 status_t BnMediaExtractor::onTransact( 150 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 151 { 152 switch (code) { 153 case COUNTTRACKS: { 154 ALOGV("countTracks"); 155 CHECK_INTERFACE(IMediaExtractor, data, reply); 156 size_t numTracks = countTracks(); 157 if (numTracks > INT32_MAX) { 158 numTracks = 0; 159 } 160 reply->writeUint32(uint32_t(numTracks)); 161 return NO_ERROR; 162 } 163 case GETTRACK: { 164 ALOGV("getTrack()"); 165 CHECK_INTERFACE(IMediaExtractor, data, reply); 166 uint32_t idx; 167 if (data.readUint32(&idx) == NO_ERROR) { 168 const sp<IMediaSource> track = getTrack(size_t(idx)); 169 registerMediaSource(this, track); 170 return reply->writeStrongBinder(IInterface::asBinder(track)); 171 } 172 return UNKNOWN_ERROR; 173 } 174 case GETTRACKMETADATA: { 175 ALOGV("getTrackMetaData"); 176 CHECK_INTERFACE(IMediaExtractor, data, reply); 177 uint32_t idx; 178 uint32_t flags; 179 if (data.readUint32(&idx) == NO_ERROR && 180 data.readUint32(&flags) == NO_ERROR) { 181 sp<MetaData> meta = getTrackMetaData(idx, flags); 182 if (meta == NULL) { 183 return UNKNOWN_ERROR; 184 } 185 meta->writeToParcel(*reply); 186 return NO_ERROR; 187 } 188 return UNKNOWN_ERROR; 189 } 190 case GETMETADATA: { 191 ALOGV("getMetaData"); 192 CHECK_INTERFACE(IMediaExtractor, data, reply); 193 sp<MetaData> meta = getMetaData(); 194 if (meta != NULL) { 195 meta->writeToParcel(*reply); 196 return NO_ERROR; 197 } 198 return UNKNOWN_ERROR; 199 } 200 case GETMETRICS: { 201 CHECK_INTERFACE(IMediaExtractor, data, reply); 202 status_t ret = getMetrics(reply); 203 return ret; 204 } 205 case SETMEDIACAS: { 206 ALOGV("setMediaCas"); 207 CHECK_INTERFACE(IMediaExtractor, data, reply); 208 209 sp<IBinder> casBinder; 210 status_t err = data.readNullableStrongBinder(&casBinder); 211 if (err != NO_ERROR) { 212 ALOGE("Error reading cas from parcel"); 213 return err; 214 } 215 sp<ICas> cas = interface_cast<ICas>(casBinder); 216 217 reply->writeInt32(setMediaCas(cas)); 218 return OK; 219 } 220 default: 221 return BBinder::onTransact(code, data, reply, flags); 222 } 223 } 224 225 typedef struct { 226 String8 mime; 227 String8 name; 228 String8 sourceDescription; 229 pid_t owner; 230 wp<IMediaExtractor> extractor; 231 Vector<wp<IMediaSource>> tracks; 232 Vector<String8> trackDescriptions; 233 String8 toString() const; 234 } ExtractorInstance; 235 236 String8 ExtractorInstance::toString() const { 237 String8 str = name; 238 str.append(" for mime "); 239 str.append(mime); 240 str.append(", source "); 241 str.append(sourceDescription); 242 str.append(String8::format(", pid %d: ", owner)); 243 if (extractor.promote() == NULL) { 244 str.append("deleted\n"); 245 } else { 246 str.append("active\n"); 247 } 248 for (size_t i = 0; i < tracks.size(); i++) { 249 const String8 desc = trackDescriptions.itemAt(i); 250 str.appendFormat(" track {%s} ", desc.string()); 251 wp<IMediaSource> wSource = tracks.itemAt(i); 252 if (wSource == NULL) { 253 str.append(": null\n"); 254 } else { 255 const sp<IMediaSource> source = wSource.promote(); 256 if (source == NULL) { 257 str.append(": deleted\n"); 258 } else { 259 str.appendFormat(": active\n"); 260 } 261 } 262 } 263 return str; 264 } 265 266 static Vector<ExtractorInstance> sExtractors; 267 static Mutex sExtractorsLock; 268 269 void registerMediaSource( 270 const sp<IMediaExtractor> &ex, 271 const sp<IMediaSource> &source) { 272 Mutex::Autolock lock(sExtractorsLock); 273 for (size_t i = 0; i < sExtractors.size(); i++) { 274 ExtractorInstance &instance = sExtractors.editItemAt(i); 275 sp<IMediaExtractor> extractor = instance.extractor.promote(); 276 if (extractor != NULL && extractor == ex) { 277 if (instance.tracks.size() > 5) { 278 instance.tracks.resize(5); 279 instance.trackDescriptions.resize(5); 280 } 281 instance.tracks.push_front(source); 282 if (source != NULL) { 283 instance.trackDescriptions.push_front(source->getFormat()->toString()); 284 } else { 285 instance.trackDescriptions.push_front(String8::empty()); 286 } 287 break; 288 } 289 } 290 } 291 292 void registerMediaExtractor( 293 const sp<IMediaExtractor> &extractor, 294 const sp<DataSource> &source, 295 const char *mime) { 296 ExtractorInstance ex; 297 ex.mime = mime == NULL ? "NULL" : mime; 298 ex.name = extractor->name(); 299 ex.sourceDescription = source->toString(); 300 ex.owner = IPCThreadState::self()->getCallingPid(); 301 ex.extractor = extractor; 302 303 { 304 Mutex::Autolock lock(sExtractorsLock); 305 if (sExtractors.size() > 10) { 306 sExtractors.resize(10); 307 } 308 sExtractors.push_front(ex); 309 } 310 } 311 312 status_t dumpExtractors(int fd, const Vector<String16>&) { 313 String8 out; 314 out.append("Recent extractors, most recent first:\n"); 315 { 316 Mutex::Autolock lock(sExtractorsLock); 317 for (size_t i = 0; i < sExtractors.size(); i++) { 318 const ExtractorInstance &instance = sExtractors.itemAt(i); 319 out.append(" "); 320 out.append(instance.toString()); 321 } 322 } 323 write(fd, out.string(), out.size()); 324 return OK; 325 } 326 327 328 } // namespace android 329 330