blob: 0f4f092f8f0c4cfba85b0863f338bd000dcdbd7c [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>
26#include <media/IMediaExtractor.h>
27#include <media/stagefright/MetaData.h>
28
29namespace android {
30
31enum {
32 COUNTTRACKS = IBinder::FIRST_CALL_TRANSACTION,
33 GETTRACK,
34 GETTRACKMETADATA,
35 GETMETADATA,
36 FLAGS,
Marco Nelissenb2487f02015-09-01 13:23:23 -070037 GETDRMTRACKINFO,
38 SETUID,
39 NAME
40};
41
42class BpMediaExtractor : public BpInterface<IMediaExtractor> {
43public:
Chih-Hung Hsieh64a28702016-05-03 09:52:51 -070044 explicit BpMediaExtractor(const sp<IBinder>& impl)
Marco Nelissenb2487f02015-09-01 13:23:23 -070045 : BpInterface<IMediaExtractor>(impl)
46 {
47 }
48
49 virtual size_t countTracks() {
50 ALOGV("countTracks");
51 Parcel data, reply;
52 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
53 status_t ret = remote()->transact(COUNTTRACKS, data, &reply);
54 size_t numTracks = 0;
55 if (ret == NO_ERROR) {
56 numTracks = reply.readUint32();
57 }
58 return numTracks;
59 }
60 virtual sp<IMediaSource> getTrack(size_t index) {
61 ALOGV("getTrack(%zu)", index);
62 Parcel data, reply;
63 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
64 data.writeUint32(index);
65 status_t ret = remote()->transact(GETTRACK, data, &reply);
66 if (ret == NO_ERROR) {
67 return interface_cast<IMediaSource>(reply.readStrongBinder());
68 }
69 return NULL;
70 }
71
72 virtual sp<MetaData> getTrackMetaData(
73 size_t index, uint32_t flags) {
74 ALOGV("getTrackMetaData(%zu, %u)", index, flags);
75 Parcel data, reply;
76 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
77 data.writeUint32(index);
78 data.writeUint32(flags);
79 status_t ret = remote()->transact(GETTRACKMETADATA, data, &reply);
80 if (ret == NO_ERROR) {
81 return MetaData::createFromParcel(reply);
82 }
83 return NULL;
84 }
85
86 virtual sp<MetaData> getMetaData() {
87 ALOGV("getMetaData");
88 Parcel data, reply;
89 data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
90 status_t ret = remote()->transact(GETMETADATA, data, &reply);
91 if (ret == NO_ERROR) {
92 return MetaData::createFromParcel(reply);
93 }
94 return NULL;
95 }
96
97 virtual uint32_t flags() const {
98 ALOGV("flags NOT IMPLEMENTED");
99 return 0;
100 }
101
Marco Nelissenb2487f02015-09-01 13:23:23 -0700102 virtual char* getDrmTrackInfo(size_t trackID __unused, int *len __unused) {
103 ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
104 return NULL;
105 }
106 virtual void setUID(uid_t uid __unused) {
107 ALOGV("setUID NOT IMPLEMENTED");
108 }
109
110 virtual const char * name() {
111 ALOGV("name NOT IMPLEMENTED");
112 return NULL;
113 }
114};
115
116IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor");
117
118#undef LOG_TAG
119#define LOG_TAG "BnMediaExtractor"
120
121status_t BnMediaExtractor::onTransact(
122 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
123{
124 switch (code) {
125 case COUNTTRACKS: {
126 ALOGV("countTracks");
127 CHECK_INTERFACE(IMediaExtractor, data, reply);
128 size_t numTracks = countTracks();
129 if (numTracks > INT32_MAX) {
130 numTracks = 0;
131 }
132 reply->writeUint32(uint32_t(numTracks));
133 return NO_ERROR;
134 }
135 case GETTRACK: {
136 ALOGV("getTrack()");
137 CHECK_INTERFACE(IMediaExtractor, data, reply);
138 uint32_t idx;
139 if (data.readUint32(&idx) == NO_ERROR) {
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800140 const sp<IMediaSource> track = getTrack(size_t(idx));
141 registerMediaSource(this, track);
142 return reply->writeStrongBinder(IInterface::asBinder(track));
Marco Nelissenb2487f02015-09-01 13:23:23 -0700143 }
144 return UNKNOWN_ERROR;
145 }
146 case GETTRACKMETADATA: {
147 ALOGV("getTrackMetaData");
148 CHECK_INTERFACE(IMediaExtractor, data, reply);
149 uint32_t idx;
150 uint32_t flags;
151 if (data.readUint32(&idx) == NO_ERROR &&
152 data.readUint32(&flags) == NO_ERROR) {
153 sp<MetaData> meta = getTrackMetaData(idx, flags);
Marco Nelissen0d138242016-10-06 15:31:52 -0700154 if (meta == NULL) {
155 return UNKNOWN_ERROR;
156 }
Marco Nelissenb2487f02015-09-01 13:23:23 -0700157 meta->writeToParcel(*reply);
158 return NO_ERROR;
159 }
160 return UNKNOWN_ERROR;
161 }
162 case GETMETADATA: {
163 ALOGV("getMetaData");
164 CHECK_INTERFACE(IMediaExtractor, data, reply);
165 sp<MetaData> meta = getMetaData();
166 if (meta != NULL) {
167 meta->writeToParcel(*reply);
168 return NO_ERROR;
169 }
170 return UNKNOWN_ERROR;
171 }
172 default:
173 return BBinder::onTransact(code, data, reply, flags);
174 }
175}
176
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800177typedef struct {
178 String8 mime;
179 String8 name;
180 String8 sourceDescription;
181 pid_t owner;
182 wp<IMediaExtractor> extractor;
183 Vector<wp<IMediaSource>> tracks;
184 Vector<String8> trackDescriptions;
185 String8 toString() const;
186} ExtractorInstance;
187
188String8 ExtractorInstance::toString() const {
189 String8 str = name;
190 str.append(" for mime ");
191 str.append(mime);
192 str.append(", source ");
193 str.append(sourceDescription);
194 str.append(String8::format(", pid %d: ", owner));
195 if (extractor.promote() == NULL) {
196 str.append("deleted\n");
197 } else {
198 str.append("active\n");
199 }
200 for (size_t i = 0; i < tracks.size(); i++) {
201 const String8 desc = trackDescriptions.itemAt(i);
202 str.appendFormat(" track {%s} ", desc.string());
Marco Nelissen460b7e82016-12-19 14:06:30 -0800203 wp<IMediaSource> wSource = tracks.itemAt(i);
204 if (wSource == NULL) {
205 str.append(": null\n");
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800206 } else {
Marco Nelissen460b7e82016-12-19 14:06:30 -0800207 const sp<IMediaSource> source = wSource.promote();
208 if (source == NULL) {
209 str.append(": deleted\n");
210 } else {
211 str.appendFormat(": active\n");
212 }
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800213 }
214 }
215 return str;
216}
217
Marco Nelissen8d27f5e2016-04-14 08:06:26 -0700218static Vector<ExtractorInstance> sExtractors;
219static Mutex sExtractorsLock;
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800220
221void registerMediaSource(
222 const sp<IMediaExtractor> &ex,
223 const sp<IMediaSource> &source) {
Marco Nelissen8d27f5e2016-04-14 08:06:26 -0700224 Mutex::Autolock lock(sExtractorsLock);
225 for (size_t i = 0; i < sExtractors.size(); i++) {
226 ExtractorInstance &instance = sExtractors.editItemAt(i);
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800227 sp<IMediaExtractor> extractor = instance.extractor.promote();
228 if (extractor != NULL && extractor == ex) {
229 if (instance.tracks.size() > 5) {
230 instance.tracks.resize(5);
Marco Nelissen460b7e82016-12-19 14:06:30 -0800231 instance.trackDescriptions.resize(5);
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800232 }
233 instance.tracks.push_front(source);
Marco Nelissen460b7e82016-12-19 14:06:30 -0800234 if (source != NULL) {
235 instance.trackDescriptions.push_front(source->getFormat()->toString());
236 } else {
237 instance.trackDescriptions.push_front(String8::empty());
238 }
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800239 break;
240 }
241 }
242}
243
244void registerMediaExtractor(
245 const sp<IMediaExtractor> &extractor,
Marco Nelissena3214692016-05-06 10:57:20 -0700246 const sp<DataSource> &source,
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800247 const char *mime) {
248 ExtractorInstance ex;
249 ex.mime = mime == NULL ? "NULL" : mime;
250 ex.name = extractor->name();
251 ex.sourceDescription = source->toString();
252 ex.owner = IPCThreadState::self()->getCallingPid();
253 ex.extractor = extractor;
254
Marco Nelissen8d27f5e2016-04-14 08:06:26 -0700255 {
256 Mutex::Autolock lock(sExtractorsLock);
257 if (sExtractors.size() > 10) {
258 sExtractors.resize(10);
259 }
260 sExtractors.push_front(ex);
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800261 }
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800262}
263
264status_t dumpExtractors(int fd, const Vector<String16>&) {
265 String8 out;
266 out.append("Recent extractors, most recent first:\n");
Marco Nelissen8d27f5e2016-04-14 08:06:26 -0700267 {
268 Mutex::Autolock lock(sExtractorsLock);
269 for (size_t i = 0; i < sExtractors.size(); i++) {
270 const ExtractorInstance &instance = sExtractors.itemAt(i);
271 out.append(" ");
272 out.append(instance.toString());
273 }
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800274 }
275 write(fd, out.string(), out.size());
276 return OK;
277}
278
Marco Nelissenb2487f02015-09-01 13:23:23 -0700279
280} // namespace android
281