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