• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
BpMediaExtractor(const sp<IBinder> & impl)47     explicit BpMediaExtractor(const sp<IBinder>& impl)
48         : BpInterface<IMediaExtractor>(impl)
49     {
50     }
51 
countTracks()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     }
getTrack(size_t index)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 
getTrackMetaData(size_t index,uint32_t flags)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 
getMetaData()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 
getMetrics(Parcel * reply)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 
flags() const110     virtual uint32_t flags() const {
111         ALOGV("flags NOT IMPLEMENTED");
112         return 0;
113     }
114 
getDrmTrackInfo(size_t trackID __unused,int * len __unused)115     virtual char* getDrmTrackInfo(size_t trackID __unused, int *len __unused) {
116         ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
117         return NULL;
118     }
119 
setMediaCas(const sp<ICas> & cas)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 
setUID(uid_t uid __unused)134     virtual void setUID(uid_t uid __unused) {
135         ALOGV("setUID NOT IMPLEMENTED");
136     }
137 
name()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 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)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 
toString() const236 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 
registerMediaSource(const sp<IMediaExtractor> & ex,const sp<IMediaSource> & source)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 
registerMediaExtractor(const sp<IMediaExtractor> & extractor,const sp<DataSource> & source,const char * mime)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 
dumpExtractors(int fd,const Vector<String16> &)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