blob: fc9a123576bacb875d09f72732fc93c3813c5e2e [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
17//#define LOG_NDEBUG 0
18#define LOG_TAG "BpMediaSource"
19#include <utils/Log.h>
20
Marco Nelissenb65990f2015-11-09 15:39:49 -080021#include <inttypes.h>
Marco Nelissenb2487f02015-09-01 13:23:23 -070022#include <stdint.h>
23#include <sys/types.h>
24
25#include <binder/Parcel.h>
26#include <media/IMediaSource.h>
27#include <media/stagefright/MediaBuffer.h>
28#include <media/stagefright/MediaSource.h>
29#include <media/stagefright/MetaData.h>
30
31namespace android {
32
33enum {
34 START = IBinder::FIRST_CALL_TRANSACTION,
35 STOP,
36 PAUSE,
37 GETFORMAT,
Marco Nelissenb65990f2015-11-09 15:39:49 -080038 READ,
39 RELEASE_BUFFER
Marco Nelissenb2487f02015-09-01 13:23:23 -070040};
41
Marco Nelissenb65990f2015-11-09 15:39:49 -080042enum {
43 NULL_BUFFER,
44 SHARED_BUFFER,
45 INLINE_BUFFER
46};
47
48class RemoteMediaBufferReleaser : public BBinder {
49public:
50 RemoteMediaBufferReleaser(MediaBuffer *buf) {
51 mBuf = buf;
52 }
53 ~RemoteMediaBufferReleaser() {
54 if (mBuf) {
55 ALOGW("RemoteMediaBufferReleaser dtor called while still holding buffer");
56 mBuf->release();
57 }
58 }
59 virtual status_t onTransact( uint32_t code,
60 const Parcel& data,
61 Parcel* reply,
62 uint32_t flags = 0) {
63 if (code == RELEASE_BUFFER) {
64 mBuf->release();
65 mBuf = NULL;
66 return OK;
67 } else {
68 return BBinder::onTransact(code, data, reply, flags);
69 }
70 }
71private:
72 MediaBuffer *mBuf;
73};
74
75
76class RemoteMediaBufferWrapper : public MediaBuffer {
77public:
78 RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source);
79protected:
80 virtual ~RemoteMediaBufferWrapper();
81private:
82 sp<IMemory> mMemory;
83 sp<IBinder> mRemoteSource;
84};
85
86RemoteMediaBufferWrapper::RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source)
87: MediaBuffer(mem->pointer(), mem->size()) {
88 mMemory = mem;
89 mRemoteSource = source;
90}
91
92RemoteMediaBufferWrapper::~RemoteMediaBufferWrapper() {
93 mMemory.clear();
94 // Explicitly ask the remote side to release the buffer. We could also just clear
95 // mRemoteSource, but that doesn't immediately release the reference on the remote side.
96 Parcel data, reply;
97 mRemoteSource->transact(RELEASE_BUFFER, data, &reply);
98 mRemoteSource.clear();
99}
100
Marco Nelissenb2487f02015-09-01 13:23:23 -0700101class BpMediaSource : public BpInterface<IMediaSource> {
102public:
103 BpMediaSource(const sp<IBinder>& impl)
104 : BpInterface<IMediaSource>(impl)
105 {
106 }
107
108 virtual status_t start(MetaData *params) {
109 ALOGV("start");
110 Parcel data, reply;
111 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
112 if (params) {
113 params->writeToParcel(data);
114 }
115 status_t ret = remote()->transact(START, data, &reply);
116 if (ret == NO_ERROR && params) {
117 ALOGW("ignoring potentially modified MetaData from start");
118 ALOGW("input:");
119 params->dumpToLog();
120 sp<MetaData> meta = MetaData::createFromParcel(reply);
121 ALOGW("output:");
122 meta->dumpToLog();
123 }
124 return ret;
125 }
126
127 virtual status_t stop() {
128 ALOGV("stop");
129 Parcel data, reply;
130 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
131 return remote()->transact(STOP, data, &reply);
132 }
133
134 virtual sp<MetaData> getFormat() {
135 ALOGV("getFormat");
136 Parcel data, reply;
137 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
138 status_t ret = remote()->transact(GETFORMAT, data, &reply);
139 if (ret == NO_ERROR) {
140 mMetaData = MetaData::createFromParcel(reply);
141 return mMetaData;
142 }
143 return NULL;
144 }
145
146 virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
147 ALOGV("read");
148 Parcel data, reply;
149 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
150 if (options) {
151 data.writeByteArray(sizeof(*options), (uint8_t*) options);
152 }
153 status_t ret = remote()->transact(READ, data, &reply);
154 if (ret != NO_ERROR) {
155 return ret;
156 }
157 // wrap the returned data in a MediaBuffer
Marco Nelissenb2487f02015-09-01 13:23:23 -0700158 ret = reply.readInt32();
Marco Nelissenb65990f2015-11-09 15:39:49 -0800159 int32_t buftype = reply.readInt32();
160 if (buftype == SHARED_BUFFER) {
161 sp<IBinder> remote = reply.readStrongBinder();
162 sp<IBinder> binder = reply.readStrongBinder();
163 sp<IMemory> mem = interface_cast<IMemory>(binder);
164 if (mem == NULL) {
165 ALOGE("received NULL IMemory for shared buffer");
166 }
167 size_t offset = reply.readInt32();
168 size_t length = reply.readInt32();
169 MediaBuffer *buf = new RemoteMediaBufferWrapper(mem, remote);
170 buf->set_range(offset, length);
171 buf->meta_data()->updateFromParcel(reply);
172 *buffer = buf;
173 } else if (buftype == NULL_BUFFER) {
174 ALOGV("got status %d and NULL buffer", ret);
Marco Nelissenb2487f02015-09-01 13:23:23 -0700175 *buffer = NULL;
176 } else {
Marco Nelissenb65990f2015-11-09 15:39:49 -0800177 int32_t len = reply.readInt32();
Marco Nelissenb2487f02015-09-01 13:23:23 -0700178 ALOGV("got status %d and len %d", ret, len);
179 *buffer = new MediaBuffer(len);
180 reply.read((*buffer)->data(), len);
181 (*buffer)->meta_data()->updateFromParcel(reply);
182 }
183 return ret;
184 }
185
186 virtual status_t pause() {
187 ALOGV("pause");
188 Parcel data, reply;
189 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
190 return remote()->transact(PAUSE, data, &reply);
191 }
192
193 virtual status_t setBuffers(const Vector<MediaBuffer *> & buffers __unused) {
194 ALOGV("setBuffers NOT IMPLEMENTED");
195 return ERROR_UNSUPPORTED; // default
196 }
197
198private:
199 // NuPlayer passes pointers-to-metadata around, so we use this to keep the metadata alive
200 // XXX: could we use this for caching, or does metadata change on the fly?
201 sp<MetaData> mMetaData;
202
203};
204
205IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
206
207#undef LOG_TAG
208#define LOG_TAG "BnMediaSource"
209
210status_t BnMediaSource::onTransact(
211 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
212{
213 switch (code) {
214 case START: {
215 ALOGV("start");
216 CHECK_INTERFACE(IMediaSource, data, reply);
217 sp<MetaData> meta;
218 if (data.dataAvail()) {
219 meta = MetaData::createFromParcel(data);
220 }
221 status_t ret = start(meta.get());
222 if (ret == NO_ERROR && meta != NULL) {
223 meta->writeToParcel(*reply);
224 }
225 return ret;
226 }
227 case STOP: {
228 ALOGV("stop");
229 CHECK_INTERFACE(IMediaSource, data, reply);
230 return stop();
231 }
232 case PAUSE: {
233 ALOGV("pause");
234 CHECK_INTERFACE(IMediaSource, data, reply);
235 return pause();
236 }
237 case GETFORMAT: {
238 ALOGV("getFormat");
239 CHECK_INTERFACE(IMediaSource, data, reply);
240 sp<MetaData> meta = getFormat();
241 if (meta != NULL) {
242 meta->writeToParcel(*reply);
243 return NO_ERROR;
244 }
245 return UNKNOWN_ERROR;
246 }
247 case READ: {
248 ALOGV("read");
249 CHECK_INTERFACE(IMediaSource, data, reply);
250 status_t ret;
251 MediaBuffer *buf = NULL;
252 ReadOptions opts;
253 uint32_t len;
254 if (data.readUint32(&len) == NO_ERROR &&
255 len == sizeof(opts) && data.read((void*)&opts, len) == NO_ERROR) {
256 ret = read(&buf, &opts);
257 } else {
258 ret = read(&buf, NULL);
259 }
Marco Nelissenb65990f2015-11-09 15:39:49 -0800260
Marco Nelissenb2487f02015-09-01 13:23:23 -0700261 reply->writeInt32(ret);
262 if (buf != NULL) {
Marco Nelissenb65990f2015-11-09 15:39:49 -0800263 size_t usedSize = buf->range_length();
264 // even if we're using shared memory, we might not want to use it, since for small
265 // sizes it's faster to copy data through the Binder transaction
266 if (buf->mMemory != NULL && usedSize >= 64 * 1024) {
267 ALOGV("buffer is using shared memory: %zu", usedSize);
268 reply->writeInt32(SHARED_BUFFER);
269 RemoteMediaBufferReleaser *wrapper = new RemoteMediaBufferReleaser(buf);
270 reply->writeStrongBinder(wrapper);
271 reply->writeStrongBinder(IInterface::asBinder(buf->mMemory));
272 reply->writeInt32(buf->range_offset());
273 reply->writeInt32(usedSize);
274 buf->meta_data()->writeToParcel(*reply);
275 } else {
276 // buffer is not in shared memory, or is small: copy it
277 if (buf->mMemory != NULL) {
278 ALOGV("%zu shared mem available, but only %zu used", buf->mMemory->size(), buf->range_length());
279 }
280 reply->writeInt32(INLINE_BUFFER);
281 reply->writeByteArray(buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
282 buf->meta_data()->writeToParcel(*reply);
283 buf->release();
284 }
Marco Nelissenb2487f02015-09-01 13:23:23 -0700285 } else {
286 ALOGV("ret %d, buf %p", ret, buf);
Marco Nelissenb65990f2015-11-09 15:39:49 -0800287 reply->writeInt32(NULL_BUFFER);
Marco Nelissenb2487f02015-09-01 13:23:23 -0700288 }
289 return NO_ERROR;
290 }
291 default:
292 return BBinder::onTransact(code, data, reply, flags);
293 }
294}
295
296////////////////////////////////////////////////////////////////////////////////
297
298IMediaSource::ReadOptions::ReadOptions() {
299 reset();
300}
301
302void IMediaSource::ReadOptions::reset() {
303 mOptions = 0;
304 mSeekTimeUs = 0;
305 mLatenessUs = 0;
306 mNonBlocking = false;
307}
308
309void IMediaSource::ReadOptions::setNonBlocking() {
310 mNonBlocking = true;
311}
312
313void IMediaSource::ReadOptions::clearNonBlocking() {
314 mNonBlocking = false;
315}
316
317bool IMediaSource::ReadOptions::getNonBlocking() const {
318 return mNonBlocking;
319}
320
321void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
322 mOptions |= kSeekTo_Option;
323 mSeekTimeUs = time_us;
324 mSeekMode = mode;
325}
326
327void IMediaSource::ReadOptions::clearSeekTo() {
328 mOptions &= ~kSeekTo_Option;
329 mSeekTimeUs = 0;
330 mSeekMode = SEEK_CLOSEST_SYNC;
331}
332
333bool IMediaSource::ReadOptions::getSeekTo(
334 int64_t *time_us, SeekMode *mode) const {
335 *time_us = mSeekTimeUs;
336 *mode = mSeekMode;
337 return (mOptions & kSeekTo_Option) != 0;
338}
339
340void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
341 mLatenessUs = lateness_us;
342}
343
344int64_t IMediaSource::ReadOptions::getLateBy() const {
345 return mLatenessUs;
346}
347
348
349} // namespace android
350