blob: 8376c0a97fee45aaf7eed925c8805b793aa93497 [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>
Wei Jiae9a5b962016-02-12 11:38:27 -080028#include <media/stagefright/MediaBufferGroup.h>
Marco Nelissenb2487f02015-09-01 13:23:23 -070029#include <media/stagefright/MediaSource.h>
30#include <media/stagefright/MetaData.h>
31
32namespace android {
33
34enum {
35 START = IBinder::FIRST_CALL_TRANSACTION,
36 STOP,
37 PAUSE,
38 GETFORMAT,
Marco Nelissenb65990f2015-11-09 15:39:49 -080039 READ,
40 RELEASE_BUFFER
Marco Nelissenb2487f02015-09-01 13:23:23 -070041};
42
Marco Nelissenb65990f2015-11-09 15:39:49 -080043enum {
44 NULL_BUFFER,
45 SHARED_BUFFER,
46 INLINE_BUFFER
47};
48
49class RemoteMediaBufferReleaser : public BBinder {
50public:
Wei Jiae9a5b962016-02-12 11:38:27 -080051 RemoteMediaBufferReleaser(MediaBuffer *buf, sp<BnMediaSource> owner) {
Marco Nelissenb65990f2015-11-09 15:39:49 -080052 mBuf = buf;
Wei Jiae9a5b962016-02-12 11:38:27 -080053 mOwner = owner;
Marco Nelissenb65990f2015-11-09 15:39:49 -080054 }
55 ~RemoteMediaBufferReleaser() {
56 if (mBuf) {
57 ALOGW("RemoteMediaBufferReleaser dtor called while still holding buffer");
58 mBuf->release();
59 }
60 }
61 virtual status_t onTransact( uint32_t code,
62 const Parcel& data,
63 Parcel* reply,
64 uint32_t flags = 0) {
65 if (code == RELEASE_BUFFER) {
66 mBuf->release();
67 mBuf = NULL;
68 return OK;
69 } else {
70 return BBinder::onTransact(code, data, reply, flags);
71 }
72 }
73private:
74 MediaBuffer *mBuf;
Wei Jiae9a5b962016-02-12 11:38:27 -080075 // Keep a ref to ensure MediaBuffer is released before the owner, i.e., BnMediaSource,
76 // because BnMediaSource needs to delete MediaBufferGroup in its dtor and
77 // MediaBufferGroup dtor requires all MediaBuffer's have 0 ref count.
78 sp<BnMediaSource> mOwner;
Marco Nelissenb65990f2015-11-09 15:39:49 -080079};
80
81
82class RemoteMediaBufferWrapper : public MediaBuffer {
83public:
84 RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source);
85protected:
86 virtual ~RemoteMediaBufferWrapper();
87private:
88 sp<IMemory> mMemory;
89 sp<IBinder> mRemoteSource;
90};
91
92RemoteMediaBufferWrapper::RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source)
93: MediaBuffer(mem->pointer(), mem->size()) {
94 mMemory = mem;
95 mRemoteSource = source;
96}
97
98RemoteMediaBufferWrapper::~RemoteMediaBufferWrapper() {
99 mMemory.clear();
100 // Explicitly ask the remote side to release the buffer. We could also just clear
101 // mRemoteSource, but that doesn't immediately release the reference on the remote side.
102 Parcel data, reply;
103 mRemoteSource->transact(RELEASE_BUFFER, data, &reply);
104 mRemoteSource.clear();
105}
106
Marco Nelissenb2487f02015-09-01 13:23:23 -0700107class BpMediaSource : public BpInterface<IMediaSource> {
108public:
109 BpMediaSource(const sp<IBinder>& impl)
110 : BpInterface<IMediaSource>(impl)
111 {
112 }
113
114 virtual status_t start(MetaData *params) {
115 ALOGV("start");
116 Parcel data, reply;
117 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
118 if (params) {
119 params->writeToParcel(data);
120 }
121 status_t ret = remote()->transact(START, data, &reply);
122 if (ret == NO_ERROR && params) {
123 ALOGW("ignoring potentially modified MetaData from start");
124 ALOGW("input:");
125 params->dumpToLog();
126 sp<MetaData> meta = MetaData::createFromParcel(reply);
127 ALOGW("output:");
128 meta->dumpToLog();
129 }
130 return ret;
131 }
132
133 virtual status_t stop() {
134 ALOGV("stop");
135 Parcel data, reply;
136 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
137 return remote()->transact(STOP, data, &reply);
138 }
139
140 virtual sp<MetaData> getFormat() {
141 ALOGV("getFormat");
142 Parcel data, reply;
143 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
144 status_t ret = remote()->transact(GETFORMAT, data, &reply);
145 if (ret == NO_ERROR) {
146 mMetaData = MetaData::createFromParcel(reply);
147 return mMetaData;
148 }
149 return NULL;
150 }
151
152 virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
153 ALOGV("read");
154 Parcel data, reply;
155 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
156 if (options) {
157 data.writeByteArray(sizeof(*options), (uint8_t*) options);
158 }
159 status_t ret = remote()->transact(READ, data, &reply);
160 if (ret != NO_ERROR) {
161 return ret;
162 }
163 // wrap the returned data in a MediaBuffer
Marco Nelissenb2487f02015-09-01 13:23:23 -0700164 ret = reply.readInt32();
Marco Nelissenb65990f2015-11-09 15:39:49 -0800165 int32_t buftype = reply.readInt32();
166 if (buftype == SHARED_BUFFER) {
167 sp<IBinder> remote = reply.readStrongBinder();
168 sp<IBinder> binder = reply.readStrongBinder();
169 sp<IMemory> mem = interface_cast<IMemory>(binder);
170 if (mem == NULL) {
171 ALOGE("received NULL IMemory for shared buffer");
172 }
173 size_t offset = reply.readInt32();
174 size_t length = reply.readInt32();
175 MediaBuffer *buf = new RemoteMediaBufferWrapper(mem, remote);
176 buf->set_range(offset, length);
177 buf->meta_data()->updateFromParcel(reply);
178 *buffer = buf;
179 } else if (buftype == NULL_BUFFER) {
180 ALOGV("got status %d and NULL buffer", ret);
Marco Nelissenb2487f02015-09-01 13:23:23 -0700181 *buffer = NULL;
182 } else {
Marco Nelissenb65990f2015-11-09 15:39:49 -0800183 int32_t len = reply.readInt32();
Marco Nelissenb2487f02015-09-01 13:23:23 -0700184 ALOGV("got status %d and len %d", ret, len);
185 *buffer = new MediaBuffer(len);
186 reply.read((*buffer)->data(), len);
187 (*buffer)->meta_data()->updateFromParcel(reply);
188 }
189 return ret;
190 }
191
192 virtual status_t pause() {
193 ALOGV("pause");
194 Parcel data, reply;
195 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
196 return remote()->transact(PAUSE, data, &reply);
197 }
198
199 virtual status_t setBuffers(const Vector<MediaBuffer *> & buffers __unused) {
200 ALOGV("setBuffers NOT IMPLEMENTED");
201 return ERROR_UNSUPPORTED; // default
202 }
203
204private:
205 // NuPlayer passes pointers-to-metadata around, so we use this to keep the metadata alive
206 // XXX: could we use this for caching, or does metadata change on the fly?
207 sp<MetaData> mMetaData;
208
209};
210
211IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
212
213#undef LOG_TAG
214#define LOG_TAG "BnMediaSource"
215
Wei Jiae9a5b962016-02-12 11:38:27 -0800216BnMediaSource::BnMediaSource()
217 : mGroup(NULL) {
218}
219
220BnMediaSource::~BnMediaSource() {
221 delete mGroup;
222 mGroup = NULL;
223}
224
Marco Nelissenb2487f02015-09-01 13:23:23 -0700225status_t BnMediaSource::onTransact(
226 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
227{
228 switch (code) {
229 case START: {
230 ALOGV("start");
231 CHECK_INTERFACE(IMediaSource, data, reply);
232 sp<MetaData> meta;
233 if (data.dataAvail()) {
234 meta = MetaData::createFromParcel(data);
235 }
236 status_t ret = start(meta.get());
237 if (ret == NO_ERROR && meta != NULL) {
238 meta->writeToParcel(*reply);
239 }
240 return ret;
241 }
242 case STOP: {
243 ALOGV("stop");
244 CHECK_INTERFACE(IMediaSource, data, reply);
245 return stop();
246 }
247 case PAUSE: {
248 ALOGV("pause");
249 CHECK_INTERFACE(IMediaSource, data, reply);
250 return pause();
251 }
252 case GETFORMAT: {
253 ALOGV("getFormat");
254 CHECK_INTERFACE(IMediaSource, data, reply);
255 sp<MetaData> meta = getFormat();
256 if (meta != NULL) {
257 meta->writeToParcel(*reply);
258 return NO_ERROR;
259 }
260 return UNKNOWN_ERROR;
261 }
262 case READ: {
263 ALOGV("read");
264 CHECK_INTERFACE(IMediaSource, data, reply);
265 status_t ret;
266 MediaBuffer *buf = NULL;
267 ReadOptions opts;
268 uint32_t len;
269 if (data.readUint32(&len) == NO_ERROR &&
270 len == sizeof(opts) && data.read((void*)&opts, len) == NO_ERROR) {
271 ret = read(&buf, &opts);
272 } else {
273 ret = read(&buf, NULL);
274 }
Marco Nelissenb65990f2015-11-09 15:39:49 -0800275
Marco Nelissenb2487f02015-09-01 13:23:23 -0700276 reply->writeInt32(ret);
277 if (buf != NULL) {
Marco Nelissenb65990f2015-11-09 15:39:49 -0800278 size_t usedSize = buf->range_length();
279 // even if we're using shared memory, we might not want to use it, since for small
280 // sizes it's faster to copy data through the Binder transaction
Wei Jiae9a5b962016-02-12 11:38:27 -0800281 // On the other hand, if the data size is large enough, it's better to use shared
282 // memory. When data is too large, binder can't handle it.
283 if (usedSize >= MediaBuffer::kSharedMemThreshold) {
284 ALOGV("use shared memory: %zu", usedSize);
285
286 MediaBuffer *transferBuf = buf;
287 size_t offset = buf->range_offset();
288 if (transferBuf->mMemory == NULL) {
289 if (mGroup == NULL) {
290 mGroup = new MediaBufferGroup;
291 size_t allocateSize = usedSize;
292 if (usedSize < SIZE_MAX / 3) {
293 allocateSize = usedSize * 3 / 2;
294 }
295 mGroup->add_buffer(new MediaBuffer(allocateSize));
296 }
297
298 ret = mGroup->acquire_buffer(
299 &transferBuf, false /* nonBlocking */, usedSize);
300 if (ret != OK || transferBuf == NULL || transferBuf->mMemory == NULL) {
301 ALOGW("failed to acquire shared memory, ret %d", ret);
302 reply->writeInt32(NULL_BUFFER);
303 return NO_ERROR;
304 }
305 memcpy(transferBuf->data(), (uint8_t*)buf->data() + buf->range_offset(),
306 buf->range_length());
307 offset = 0;
308 }
309
Marco Nelissenb65990f2015-11-09 15:39:49 -0800310 reply->writeInt32(SHARED_BUFFER);
Wei Jiae9a5b962016-02-12 11:38:27 -0800311 RemoteMediaBufferReleaser *wrapper =
312 new RemoteMediaBufferReleaser(transferBuf, this);
Marco Nelissenb65990f2015-11-09 15:39:49 -0800313 reply->writeStrongBinder(wrapper);
Wei Jiae9a5b962016-02-12 11:38:27 -0800314 reply->writeStrongBinder(IInterface::asBinder(transferBuf->mMemory));
315 reply->writeInt32(offset);
Marco Nelissenb65990f2015-11-09 15:39:49 -0800316 reply->writeInt32(usedSize);
317 buf->meta_data()->writeToParcel(*reply);
Wei Jia1d5a3062016-02-29 09:47:27 -0800318 if (buf->mMemory == NULL) {
319 buf->release();
320 }
Marco Nelissenb65990f2015-11-09 15:39:49 -0800321 } else {
Wei Jiae9a5b962016-02-12 11:38:27 -0800322 // buffer is small: copy it
Marco Nelissenb65990f2015-11-09 15:39:49 -0800323 if (buf->mMemory != NULL) {
324 ALOGV("%zu shared mem available, but only %zu used", buf->mMemory->size(), buf->range_length());
325 }
326 reply->writeInt32(INLINE_BUFFER);
327 reply->writeByteArray(buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
328 buf->meta_data()->writeToParcel(*reply);
329 buf->release();
330 }
Marco Nelissenb2487f02015-09-01 13:23:23 -0700331 } else {
332 ALOGV("ret %d, buf %p", ret, buf);
Marco Nelissenb65990f2015-11-09 15:39:49 -0800333 reply->writeInt32(NULL_BUFFER);
Marco Nelissenb2487f02015-09-01 13:23:23 -0700334 }
335 return NO_ERROR;
336 }
337 default:
338 return BBinder::onTransact(code, data, reply, flags);
339 }
340}
341
342////////////////////////////////////////////////////////////////////////////////
343
344IMediaSource::ReadOptions::ReadOptions() {
345 reset();
346}
347
348void IMediaSource::ReadOptions::reset() {
349 mOptions = 0;
350 mSeekTimeUs = 0;
351 mLatenessUs = 0;
352 mNonBlocking = false;
353}
354
355void IMediaSource::ReadOptions::setNonBlocking() {
356 mNonBlocking = true;
357}
358
359void IMediaSource::ReadOptions::clearNonBlocking() {
360 mNonBlocking = false;
361}
362
363bool IMediaSource::ReadOptions::getNonBlocking() const {
364 return mNonBlocking;
365}
366
367void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
368 mOptions |= kSeekTo_Option;
369 mSeekTimeUs = time_us;
370 mSeekMode = mode;
371}
372
373void IMediaSource::ReadOptions::clearSeekTo() {
374 mOptions &= ~kSeekTo_Option;
375 mSeekTimeUs = 0;
376 mSeekMode = SEEK_CLOSEST_SYNC;
377}
378
379bool IMediaSource::ReadOptions::getSeekTo(
380 int64_t *time_us, SeekMode *mode) const {
381 *time_us = mSeekTimeUs;
382 *mode = mSeekMode;
383 return (mOptions & kSeekTo_Option) != 0;
384}
385
386void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
387 mLatenessUs = lateness_us;
388}
389
390int64_t IMediaSource::ReadOptions::getLateBy() const {
391 return mLatenessUs;
392}
393
394
395} // namespace android
396