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 <media/IMediaExtractor.h> 27 #include <media/stagefright/MetaData.h> 28 29 namespace android { 30 31 enum { 32 COUNTTRACKS = IBinder::FIRST_CALL_TRANSACTION, 33 GETTRACK, 34 GETTRACKMETADATA, 35 GETMETADATA, 36 FLAGS, 37 GETDRMTRACKINFO, 38 SETMEDIACAS, 39 SETUID, 40 NAME, 41 GETMETRICS, 42 RELEASE, 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 HInterfaceToken &casToken) { 121 ALOGV("setMediaCas"); 122 123 Parcel data, reply; 124 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); 125 data.writeByteVector(casToken); 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 virtual void release() { 144 ALOGV("release"); 145 Parcel data, reply; 146 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor()); 147 remote()->transact(RELEASE, data, &reply); 148 } 149 }; 150 151 IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor"); 152 153 #undef LOG_TAG 154 #define LOG_TAG "BnMediaExtractor" 155 156 status_t BnMediaExtractor::onTransact( 157 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 158 { 159 switch (code) { 160 case COUNTTRACKS: { 161 ALOGV("countTracks"); 162 CHECK_INTERFACE(IMediaExtractor, data, reply); 163 size_t numTracks = countTracks(); 164 if (numTracks > INT32_MAX) { 165 numTracks = 0; 166 } 167 reply->writeUint32(uint32_t(numTracks)); 168 return NO_ERROR; 169 } 170 case GETTRACK: { 171 ALOGV("getTrack()"); 172 CHECK_INTERFACE(IMediaExtractor, data, reply); 173 uint32_t idx; 174 if (data.readUint32(&idx) == NO_ERROR) { 175 const sp<IMediaSource> track = getTrack(size_t(idx)); 176 registerMediaSource(this, track); 177 return reply->writeStrongBinder(IInterface::asBinder(track)); 178 } 179 return UNKNOWN_ERROR; 180 } 181 case GETTRACKMETADATA: { 182 ALOGV("getTrackMetaData"); 183 CHECK_INTERFACE(IMediaExtractor, data, reply); 184 uint32_t idx; 185 uint32_t flags; 186 if (data.readUint32(&idx) == NO_ERROR && 187 data.readUint32(&flags) == NO_ERROR) { 188 sp<MetaData> meta = getTrackMetaData(idx, flags); 189 if (meta == NULL) { 190 return UNKNOWN_ERROR; 191 } 192 meta->writeToParcel(*reply); 193 return NO_ERROR; 194 } 195 return UNKNOWN_ERROR; 196 } 197 case GETMETADATA: { 198 ALOGV("getMetaData"); 199 CHECK_INTERFACE(IMediaExtractor, data, reply); 200 sp<MetaData> meta = getMetaData(); 201 if (meta != NULL) { 202 meta->writeToParcel(*reply); 203 return NO_ERROR; 204 } 205 return UNKNOWN_ERROR; 206 } 207 case GETMETRICS: { 208 CHECK_INTERFACE(IMediaExtractor, data, reply); 209 status_t ret = getMetrics(reply); 210 return ret; 211 } 212 case SETMEDIACAS: { 213 ALOGV("setMediaCas"); 214 CHECK_INTERFACE(IMediaExtractor, data, reply); 215 216 HInterfaceToken casToken; 217 status_t err = data.readByteVector(&casToken); 218 if (err != NO_ERROR) { 219 ALOGE("Error reading casToken from parcel"); 220 return err; 221 } 222 223 reply->writeInt32(setMediaCas(casToken)); 224 return OK; 225 } 226 case RELEASE: { 227 ALOGV("release"); 228 CHECK_INTERFACE(IMediaExtractor, data, reply); 229 release(); 230 return OK; 231 } 232 default: 233 return BBinder::onTransact(code, data, reply, flags); 234 } 235 } 236 237 typedef struct { 238 String8 mime; 239 String8 name; 240 String8 sourceDescription; 241 pid_t owner; 242 wp<IMediaExtractor> extractor; 243 Vector<wp<IMediaSource>> tracks; 244 Vector<String8> trackDescriptions; 245 String8 toString() const; 246 } ExtractorInstance; 247 248 String8 ExtractorInstance::toString() const { 249 String8 str = name; 250 str.append(" for mime "); 251 str.append(mime); 252 str.append(", source "); 253 str.append(sourceDescription); 254 str.append(String8::format(", pid %d: ", owner)); 255 if (extractor.promote() == NULL) { 256 str.append("deleted\n"); 257 } else { 258 str.append("active\n"); 259 } 260 for (size_t i = 0; i < tracks.size(); i++) { 261 const String8 desc = trackDescriptions.itemAt(i); 262 str.appendFormat(" track {%s} ", desc.string()); 263 wp<IMediaSource> wSource = tracks.itemAt(i); 264 if (wSource == NULL) { 265 str.append(": null\n"); 266 } else { 267 const sp<IMediaSource> source = wSource.promote(); 268 if (source == NULL) { 269 str.append(": deleted\n"); 270 } else { 271 str.appendFormat(": active\n"); 272 } 273 } 274 } 275 return str; 276 } 277 278 static Vector<ExtractorInstance> sExtractors; 279 static Mutex sExtractorsLock; 280 281 void registerMediaSource( 282 const sp<IMediaExtractor> &ex, 283 const sp<IMediaSource> &source) { 284 Mutex::Autolock lock(sExtractorsLock); 285 for (size_t i = 0; i < sExtractors.size(); i++) { 286 ExtractorInstance &instance = sExtractors.editItemAt(i); 287 sp<IMediaExtractor> extractor = instance.extractor.promote(); 288 if (extractor != NULL && extractor == ex) { 289 if (instance.tracks.size() > 5) { 290 instance.tracks.resize(5); 291 instance.trackDescriptions.resize(5); 292 } 293 instance.tracks.push_front(source); 294 if (source != NULL) { 295 instance.trackDescriptions.push_front(source->getFormat()->toString()); 296 } else { 297 instance.trackDescriptions.push_front(String8::empty()); 298 } 299 break; 300 } 301 } 302 } 303 304 void registerMediaExtractor( 305 const sp<IMediaExtractor> &extractor, 306 const sp<DataSource> &source, 307 const char *mime) { 308 ExtractorInstance ex; 309 ex.mime = mime == NULL ? "NULL" : mime; 310 ex.name = extractor->name(); 311 ex.sourceDescription = source->toString(); 312 ex.owner = IPCThreadState::self()->getCallingPid(); 313 ex.extractor = extractor; 314 315 { 316 Mutex::Autolock lock(sExtractorsLock); 317 if (sExtractors.size() > 10) { 318 sExtractors.resize(10); 319 } 320 sExtractors.push_front(ex); 321 } 322 } 323 324 status_t dumpExtractors(int fd, const Vector<String16>&) { 325 String8 out; 326 out.append("Recent extractors, most recent first:\n"); 327 { 328 Mutex::Autolock lock(sExtractorsLock); 329 for (size_t i = 0; i < sExtractors.size(); i++) { 330 const ExtractorInstance &instance = sExtractors.itemAt(i); 331 out.append(" "); 332 out.append(instance.toString()); 333 } 334 } 335 write(fd, out.string(), out.size()); 336 return OK; 337 } 338 339 340 } // namespace android 341 342