blob: 744af1be00fad3e0e1c36329ef273a71bce4a49f [file] [log] [blame]
Marco Nelissenb2487f02015-09-01 13:23:23 -07001/*
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
Marco Nelissenb65990f2015-11-09 15:39:49 -080017//#define LOG_NDEBUG 0
Marco Nelissenb2487f02015-09-01 13:23:23 -070018#define LOG_TAG "BpMediaExtractor"
19#include <utils/Log.h>
20
21#include <stdint.h>
22#include <sys/types.h>
23
Marco Nelissen69d3d8a2016-03-07 13:20:01 -080024#include <binder/IPCThreadState.h>
Marco Nelissenb2487f02015-09-01 13:23:23 -070025#include <binder/Parcel.h>
ray-cy.leeb596c342017-03-07 18:25:15 +080026#include <binder/PermissionCache.h>
Marco Nelissenb2487f02015-09-01 13:23:23 -070027#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 SETDRMFLAG,
39 GETDRMFLAG,
40 GETDRMTRACKINFO,
41 SETUID,
42 NAME
43};
44
45class BpMediaExtractor : public BpInterface<IMediaExtractor> {
46public:
47 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 uint32_t flags() const {
101 ALOGV("flags NOT IMPLEMENTED");
102 return 0;
103 }
104
105 virtual void setDrmFlag(bool flag __unused) {
106 ALOGV("setDrmFlag NOT IMPLEMENTED");
107 }
108 virtual bool getDrmFlag() {
109 ALOGV("getDrmFlag NOT IMPLEMENTED");
110 return false;
111 }
112 virtual char* getDrmTrackInfo(size_t trackID __unused, int *len __unused) {
113 ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
114 return NULL;
115 }
116 virtual void setUID(uid_t uid __unused) {
117 ALOGV("setUID NOT IMPLEMENTED");
118 }
119
120 virtual const char * name() {
121 ALOGV("name NOT IMPLEMENTED");
122 return NULL;
123 }
124};
125
126IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor");
127
128#undef LOG_TAG
129#define LOG_TAG "BnMediaExtractor"
130
131status_t BnMediaExtractor::onTransact(
132 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
133{
134 switch (code) {
135 case COUNTTRACKS: {
136 ALOGV("countTracks");
137 CHECK_INTERFACE(IMediaExtractor, data, reply);
138 size_t numTracks = countTracks();
139 if (numTracks > INT32_MAX) {
140 numTracks = 0;
141 }
142 reply->writeUint32(uint32_t(numTracks));
143 return NO_ERROR;
144 }
145 case GETTRACK: {
146 ALOGV("getTrack()");
147 CHECK_INTERFACE(IMediaExtractor, data, reply);
148 uint32_t idx;
149 if (data.readUint32(&idx) == NO_ERROR) {
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800150 const sp<IMediaSource> track = getTrack(size_t(idx));
151 registerMediaSource(this, track);
152 return reply->writeStrongBinder(IInterface::asBinder(track));
Marco Nelissenb2487f02015-09-01 13:23:23 -0700153 }
154 return UNKNOWN_ERROR;
155 }
156 case GETTRACKMETADATA: {
157 ALOGV("getTrackMetaData");
158 CHECK_INTERFACE(IMediaExtractor, data, reply);
159 uint32_t idx;
160 uint32_t flags;
161 if (data.readUint32(&idx) == NO_ERROR &&
162 data.readUint32(&flags) == NO_ERROR) {
163 sp<MetaData> meta = getTrackMetaData(idx, flags);
Marco Nelissen0d138242016-10-06 15:31:52 -0700164 if (meta == NULL) {
165 return UNKNOWN_ERROR;
166 }
Marco Nelissenb2487f02015-09-01 13:23:23 -0700167 meta->writeToParcel(*reply);
168 return NO_ERROR;
169 }
170 return UNKNOWN_ERROR;
171 }
172 case GETMETADATA: {
173 ALOGV("getMetaData");
174 CHECK_INTERFACE(IMediaExtractor, data, reply);
175 sp<MetaData> meta = getMetaData();
176 if (meta != NULL) {
177 meta->writeToParcel(*reply);
178 return NO_ERROR;
179 }
180 return UNKNOWN_ERROR;
181 }
182 default:
183 return BBinder::onTransact(code, data, reply, flags);
184 }
185}
186
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800187typedef struct {
188 String8 mime;
189 String8 name;
190 String8 sourceDescription;
191 pid_t owner;
192 wp<IMediaExtractor> extractor;
193 Vector<wp<IMediaSource>> tracks;
194 Vector<String8> trackDescriptions;
195 String8 toString() const;
196} ExtractorInstance;
197
198String8 ExtractorInstance::toString() const {
199 String8 str = name;
200 str.append(" for mime ");
201 str.append(mime);
202 str.append(", source ");
203 str.append(sourceDescription);
204 str.append(String8::format(", pid %d: ", owner));
205 if (extractor.promote() == NULL) {
206 str.append("deleted\n");
207 } else {
208 str.append("active\n");
209 }
210 for (size_t i = 0; i < tracks.size(); i++) {
211 const String8 desc = trackDescriptions.itemAt(i);
212 str.appendFormat(" track {%s} ", desc.string());
Marco Nelissen460b7e82016-12-19 14:06:30 -0800213 wp<IMediaSource> wSource = tracks.itemAt(i);
214 if (wSource == NULL) {
215 str.append(": null\n");
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800216 } else {
Marco Nelissen460b7e82016-12-19 14:06:30 -0800217 const sp<IMediaSource> source = wSource.promote();
218 if (source == NULL) {
219 str.append(": deleted\n");
220 } else {
221 str.appendFormat(": active\n");
222 }
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800223 }
224 }
225 return str;
226}
227
Marco Nelissen8d27f5e2016-04-14 08:06:26 -0700228static Vector<ExtractorInstance> sExtractors;
229static Mutex sExtractorsLock;
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800230
231void registerMediaSource(
232 const sp<IMediaExtractor> &ex,
233 const sp<IMediaSource> &source) {
Marco Nelissen8d27f5e2016-04-14 08:06:26 -0700234 Mutex::Autolock lock(sExtractorsLock);
235 for (size_t i = 0; i < sExtractors.size(); i++) {
236 ExtractorInstance &instance = sExtractors.editItemAt(i);
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800237 sp<IMediaExtractor> extractor = instance.extractor.promote();
238 if (extractor != NULL && extractor == ex) {
239 if (instance.tracks.size() > 5) {
240 instance.tracks.resize(5);
Marco Nelissen460b7e82016-12-19 14:06:30 -0800241 instance.trackDescriptions.resize(5);
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800242 }
243 instance.tracks.push_front(source);
Marco Nelissen460b7e82016-12-19 14:06:30 -0800244 if (source != NULL) {
245 instance.trackDescriptions.push_front(source->getFormat()->toString());
246 } else {
247 instance.trackDescriptions.push_front(String8::empty());
248 }
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800249 break;
250 }
251 }
252}
253
254void registerMediaExtractor(
255 const sp<IMediaExtractor> &extractor,
Marco Nelissena3214692016-05-06 10:57:20 -0700256 const sp<DataSource> &source,
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800257 const char *mime) {
258 ExtractorInstance ex;
259 ex.mime = mime == NULL ? "NULL" : mime;
260 ex.name = extractor->name();
261 ex.sourceDescription = source->toString();
262 ex.owner = IPCThreadState::self()->getCallingPid();
263 ex.extractor = extractor;
264
Marco Nelissen8d27f5e2016-04-14 08:06:26 -0700265 {
266 Mutex::Autolock lock(sExtractorsLock);
267 if (sExtractors.size() > 10) {
268 sExtractors.resize(10);
269 }
270 sExtractors.push_front(ex);
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800271 }
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800272}
273
274status_t dumpExtractors(int fd, const Vector<String16>&) {
275 String8 out;
ray-cy.leeb596c342017-03-07 18:25:15 +0800276 const IPCThreadState* ipc = IPCThreadState::self();
277 const int pid = ipc->getCallingPid();
278 const int uid = ipc->getCallingUid();
279 if (!PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
280 out.appendFormat("Permission Denial: "
281 "can't dump MediaExtractor from pid=%d, uid=%d\n", pid, uid);
282 } else {
283 out.append("Recent extractors, most recent first:\n");
284 {
285 Mutex::Autolock lock(sExtractorsLock);
286 for (size_t i = 0; i < sExtractors.size(); i++) {
287 const ExtractorInstance &instance = sExtractors.itemAt(i);
288 out.append(" ");
289 out.append(instance.toString());
290 }
Marco Nelissen8d27f5e2016-04-14 08:06:26 -0700291 }
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800292 }
293 write(fd, out.string(), out.size());
294 return OK;
295}
296
Marco Nelissenb2487f02015-09-01 13:23:23 -0700297
298} // namespace android
299