blob: 1770fb8a5ec05f9adcb117c1585e6fe420c6415a [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 Nelissenafe2f272016-02-26 11:56:04 -080021#include <utils/CallStack.h>
22
Marco Nelissenb65990f2015-11-09 15:39:49 -080023#include <inttypes.h>
Marco Nelissenb2487f02015-09-01 13:23:23 -070024#include <stdint.h>
25#include <sys/types.h>
26
27#include <binder/Parcel.h>
28#include <media/IMediaSource.h>
29#include <media/stagefright/MediaBuffer.h>
Wei Jiae9a5b962016-02-12 11:38:27 -080030#include <media/stagefright/MediaBufferGroup.h>
Marco Nelissenb2487f02015-09-01 13:23:23 -070031#include <media/stagefright/MediaSource.h>
32#include <media/stagefright/MetaData.h>
33
34namespace android {
35
36enum {
37 START = IBinder::FIRST_CALL_TRANSACTION,
38 STOP,
39 PAUSE,
40 GETFORMAT,
Marco Nelissenb65990f2015-11-09 15:39:49 -080041 READ,
42 RELEASE_BUFFER
Marco Nelissenb2487f02015-09-01 13:23:23 -070043};
44
Marco Nelissenb65990f2015-11-09 15:39:49 -080045enum {
46 NULL_BUFFER,
47 SHARED_BUFFER,
48 INLINE_BUFFER
49};
50
51class RemoteMediaBufferReleaser : public BBinder {
52public:
Wei Jiae9a5b962016-02-12 11:38:27 -080053 RemoteMediaBufferReleaser(MediaBuffer *buf, sp<BnMediaSource> owner) {
Marco Nelissenb65990f2015-11-09 15:39:49 -080054 mBuf = buf;
Wei Jiae9a5b962016-02-12 11:38:27 -080055 mOwner = owner;
Marco Nelissenb65990f2015-11-09 15:39:49 -080056 }
57 ~RemoteMediaBufferReleaser() {
58 if (mBuf) {
59 ALOGW("RemoteMediaBufferReleaser dtor called while still holding buffer");
60 mBuf->release();
61 }
62 }
63 virtual status_t onTransact( uint32_t code,
64 const Parcel& data,
65 Parcel* reply,
66 uint32_t flags = 0) {
67 if (code == RELEASE_BUFFER) {
68 mBuf->release();
69 mBuf = NULL;
70 return OK;
71 } else {
72 return BBinder::onTransact(code, data, reply, flags);
73 }
74 }
75private:
76 MediaBuffer *mBuf;
Wei Jiae9a5b962016-02-12 11:38:27 -080077 // Keep a ref to ensure MediaBuffer is released before the owner, i.e., BnMediaSource,
78 // because BnMediaSource needs to delete MediaBufferGroup in its dtor and
79 // MediaBufferGroup dtor requires all MediaBuffer's have 0 ref count.
80 sp<BnMediaSource> mOwner;
Marco Nelissenb65990f2015-11-09 15:39:49 -080081};
82
83
84class RemoteMediaBufferWrapper : public MediaBuffer {
85public:
86 RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source);
87protected:
88 virtual ~RemoteMediaBufferWrapper();
89private:
90 sp<IMemory> mMemory;
91 sp<IBinder> mRemoteSource;
92};
93
94RemoteMediaBufferWrapper::RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source)
95: MediaBuffer(mem->pointer(), mem->size()) {
96 mMemory = mem;
97 mRemoteSource = source;
98}
99
100RemoteMediaBufferWrapper::~RemoteMediaBufferWrapper() {
101 mMemory.clear();
102 // Explicitly ask the remote side to release the buffer. We could also just clear
103 // mRemoteSource, but that doesn't immediately release the reference on the remote side.
104 Parcel data, reply;
105 mRemoteSource->transact(RELEASE_BUFFER, data, &reply);
106 mRemoteSource.clear();
107}
108
Marco Nelissenb2487f02015-09-01 13:23:23 -0700109class BpMediaSource : public BpInterface<IMediaSource> {
110public:
111 BpMediaSource(const sp<IBinder>& impl)
112 : BpInterface<IMediaSource>(impl)
113 {
Marco Nelissenafe2f272016-02-26 11:56:04 -0800114 mStarted = false;
Marco Nelissenb2487f02015-09-01 13:23:23 -0700115 }
116
117 virtual status_t start(MetaData *params) {
Marco Nelissenafe2f272016-02-26 11:56:04 -0800118 if (mStarted) {
119 ALOGD("Source was started previously from:");
120 mStartStack.log(LOG_TAG);
121 ALOGD("Now from:");
122 CallStack stack(LOG_TAG);
123 }
Marco Nelissenb2487f02015-09-01 13:23:23 -0700124 ALOGV("start");
125 Parcel data, reply;
126 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
127 if (params) {
128 params->writeToParcel(data);
129 }
130 status_t ret = remote()->transact(START, data, &reply);
Marco Nelissenafe2f272016-02-26 11:56:04 -0800131 if (ret == NO_ERROR) {
132 mStarted = true;
133 mStartStack.update();
134 }
Marco Nelissenb2487f02015-09-01 13:23:23 -0700135 if (ret == NO_ERROR && params) {
136 ALOGW("ignoring potentially modified MetaData from start");
137 ALOGW("input:");
138 params->dumpToLog();
139 sp<MetaData> meta = MetaData::createFromParcel(reply);
140 ALOGW("output:");
141 meta->dumpToLog();
142 }
143 return ret;
144 }
145
146 virtual status_t stop() {
Marco Nelissenafe2f272016-02-26 11:56:04 -0800147 mStarted = false;
Marco Nelissenb2487f02015-09-01 13:23:23 -0700148 ALOGV("stop");
149 Parcel data, reply;
150 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
151 return remote()->transact(STOP, data, &reply);
152 }
153
154 virtual sp<MetaData> getFormat() {
155 ALOGV("getFormat");
156 Parcel data, reply;
157 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
158 status_t ret = remote()->transact(GETFORMAT, data, &reply);
159 if (ret == NO_ERROR) {
160 mMetaData = MetaData::createFromParcel(reply);
161 return mMetaData;
162 }
163 return NULL;
164 }
165
166 virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
167 ALOGV("read");
168 Parcel data, reply;
169 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
170 if (options) {
171 data.writeByteArray(sizeof(*options), (uint8_t*) options);
172 }
173 status_t ret = remote()->transact(READ, data, &reply);
174 if (ret != NO_ERROR) {
175 return ret;
176 }
177 // wrap the returned data in a MediaBuffer
Marco Nelissenb2487f02015-09-01 13:23:23 -0700178 ret = reply.readInt32();
Marco Nelissenb65990f2015-11-09 15:39:49 -0800179 int32_t buftype = reply.readInt32();
180 if (buftype == SHARED_BUFFER) {
181 sp<IBinder> remote = reply.readStrongBinder();
182 sp<IBinder> binder = reply.readStrongBinder();
183 sp<IMemory> mem = interface_cast<IMemory>(binder);
184 if (mem == NULL) {
185 ALOGE("received NULL IMemory for shared buffer");
186 }
187 size_t offset = reply.readInt32();
188 size_t length = reply.readInt32();
189 MediaBuffer *buf = new RemoteMediaBufferWrapper(mem, remote);
190 buf->set_range(offset, length);
191 buf->meta_data()->updateFromParcel(reply);
192 *buffer = buf;
193 } else if (buftype == NULL_BUFFER) {
194 ALOGV("got status %d and NULL buffer", ret);
Marco Nelissenb2487f02015-09-01 13:23:23 -0700195 *buffer = NULL;
196 } else {
Marco Nelissenb65990f2015-11-09 15:39:49 -0800197 int32_t len = reply.readInt32();
Marco Nelissenb2487f02015-09-01 13:23:23 -0700198 ALOGV("got status %d and len %d", ret, len);
199 *buffer = new MediaBuffer(len);
200 reply.read((*buffer)->data(), len);
201 (*buffer)->meta_data()->updateFromParcel(reply);
202 }
203 return ret;
204 }
205
206 virtual status_t pause() {
207 ALOGV("pause");
208 Parcel data, reply;
209 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
210 return remote()->transact(PAUSE, data, &reply);
211 }
212
213 virtual status_t setBuffers(const Vector<MediaBuffer *> & buffers __unused) {
214 ALOGV("setBuffers NOT IMPLEMENTED");
215 return ERROR_UNSUPPORTED; // default
216 }
217
218private:
219 // NuPlayer passes pointers-to-metadata around, so we use this to keep the metadata alive
220 // XXX: could we use this for caching, or does metadata change on the fly?
221 sp<MetaData> mMetaData;
Marco Nelissenafe2f272016-02-26 11:56:04 -0800222 bool mStarted;
223 CallStack mStartStack;
Marco Nelissenb2487f02015-09-01 13:23:23 -0700224};
225
226IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
227
228#undef LOG_TAG
229#define LOG_TAG "BnMediaSource"
230
Wei Jiae9a5b962016-02-12 11:38:27 -0800231BnMediaSource::BnMediaSource()
232 : mGroup(NULL) {
233}
234
235BnMediaSource::~BnMediaSource() {
236 delete mGroup;
237 mGroup = NULL;
238}
239
Marco Nelissenb2487f02015-09-01 13:23:23 -0700240status_t BnMediaSource::onTransact(
241 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
242{
243 switch (code) {
244 case START: {
245 ALOGV("start");
246 CHECK_INTERFACE(IMediaSource, data, reply);
247 sp<MetaData> meta;
248 if (data.dataAvail()) {
249 meta = MetaData::createFromParcel(data);
250 }
251 status_t ret = start(meta.get());
252 if (ret == NO_ERROR && meta != NULL) {
253 meta->writeToParcel(*reply);
254 }
255 return ret;
256 }
257 case STOP: {
258 ALOGV("stop");
259 CHECK_INTERFACE(IMediaSource, data, reply);
260 return stop();
261 }
262 case PAUSE: {
263 ALOGV("pause");
264 CHECK_INTERFACE(IMediaSource, data, reply);
265 return pause();
266 }
267 case GETFORMAT: {
268 ALOGV("getFormat");
269 CHECK_INTERFACE(IMediaSource, data, reply);
270 sp<MetaData> meta = getFormat();
271 if (meta != NULL) {
272 meta->writeToParcel(*reply);
273 return NO_ERROR;
274 }
275 return UNKNOWN_ERROR;
276 }
277 case READ: {
278 ALOGV("read");
279 CHECK_INTERFACE(IMediaSource, data, reply);
280 status_t ret;
281 MediaBuffer *buf = NULL;
282 ReadOptions opts;
283 uint32_t len;
284 if (data.readUint32(&len) == NO_ERROR &&
285 len == sizeof(opts) && data.read((void*)&opts, len) == NO_ERROR) {
286 ret = read(&buf, &opts);
287 } else {
288 ret = read(&buf, NULL);
289 }
Marco Nelissenb65990f2015-11-09 15:39:49 -0800290
Marco Nelissenb2487f02015-09-01 13:23:23 -0700291 reply->writeInt32(ret);
292 if (buf != NULL) {
Marco Nelissenb65990f2015-11-09 15:39:49 -0800293 size_t usedSize = buf->range_length();
294 // even if we're using shared memory, we might not want to use it, since for small
295 // sizes it's faster to copy data through the Binder transaction
Wei Jiae9a5b962016-02-12 11:38:27 -0800296 // On the other hand, if the data size is large enough, it's better to use shared
297 // memory. When data is too large, binder can't handle it.
298 if (usedSize >= MediaBuffer::kSharedMemThreshold) {
299 ALOGV("use shared memory: %zu", usedSize);
300
301 MediaBuffer *transferBuf = buf;
302 size_t offset = buf->range_offset();
303 if (transferBuf->mMemory == NULL) {
304 if (mGroup == NULL) {
305 mGroup = new MediaBufferGroup;
306 size_t allocateSize = usedSize;
307 if (usedSize < SIZE_MAX / 3) {
308 allocateSize = usedSize * 3 / 2;
309 }
310 mGroup->add_buffer(new MediaBuffer(allocateSize));
311 }
312
313 ret = mGroup->acquire_buffer(
314 &transferBuf, false /* nonBlocking */, usedSize);
315 if (ret != OK || transferBuf == NULL || transferBuf->mMemory == NULL) {
316 ALOGW("failed to acquire shared memory, ret %d", ret);
317 reply->writeInt32(NULL_BUFFER);
318 return NO_ERROR;
319 }
320 memcpy(transferBuf->data(), (uint8_t*)buf->data() + buf->range_offset(),
321 buf->range_length());
322 offset = 0;
323 }
324
Marco Nelissenb65990f2015-11-09 15:39:49 -0800325 reply->writeInt32(SHARED_BUFFER);
Wei Jiae9a5b962016-02-12 11:38:27 -0800326 RemoteMediaBufferReleaser *wrapper =
327 new RemoteMediaBufferReleaser(transferBuf, this);
Marco Nelissenb65990f2015-11-09 15:39:49 -0800328 reply->writeStrongBinder(wrapper);
Wei Jiae9a5b962016-02-12 11:38:27 -0800329 reply->writeStrongBinder(IInterface::asBinder(transferBuf->mMemory));
330 reply->writeInt32(offset);
Marco Nelissenb65990f2015-11-09 15:39:49 -0800331 reply->writeInt32(usedSize);
332 buf->meta_data()->writeToParcel(*reply);
Wei Jia1d5a3062016-02-29 09:47:27 -0800333 if (buf->mMemory == NULL) {
334 buf->release();
335 }
Marco Nelissenb65990f2015-11-09 15:39:49 -0800336 } else {
Wei Jiae9a5b962016-02-12 11:38:27 -0800337 // buffer is small: copy it
Marco Nelissenb65990f2015-11-09 15:39:49 -0800338 if (buf->mMemory != NULL) {
339 ALOGV("%zu shared mem available, but only %zu used", buf->mMemory->size(), buf->range_length());
340 }
341 reply->writeInt32(INLINE_BUFFER);
342 reply->writeByteArray(buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
343 buf->meta_data()->writeToParcel(*reply);
344 buf->release();
345 }
Marco Nelissenb2487f02015-09-01 13:23:23 -0700346 } else {
347 ALOGV("ret %d, buf %p", ret, buf);
Marco Nelissenb65990f2015-11-09 15:39:49 -0800348 reply->writeInt32(NULL_BUFFER);
Marco Nelissenb2487f02015-09-01 13:23:23 -0700349 }
350 return NO_ERROR;
351 }
352 default:
353 return BBinder::onTransact(code, data, reply, flags);
354 }
355}
356
357////////////////////////////////////////////////////////////////////////////////
358
359IMediaSource::ReadOptions::ReadOptions() {
360 reset();
361}
362
363void IMediaSource::ReadOptions::reset() {
364 mOptions = 0;
365 mSeekTimeUs = 0;
366 mLatenessUs = 0;
367 mNonBlocking = false;
368}
369
370void IMediaSource::ReadOptions::setNonBlocking() {
371 mNonBlocking = true;
372}
373
374void IMediaSource::ReadOptions::clearNonBlocking() {
375 mNonBlocking = false;
376}
377
378bool IMediaSource::ReadOptions::getNonBlocking() const {
379 return mNonBlocking;
380}
381
382void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
383 mOptions |= kSeekTo_Option;
384 mSeekTimeUs = time_us;
385 mSeekMode = mode;
386}
387
388void IMediaSource::ReadOptions::clearSeekTo() {
389 mOptions &= ~kSeekTo_Option;
390 mSeekTimeUs = 0;
391 mSeekMode = SEEK_CLOSEST_SYNC;
392}
393
394bool IMediaSource::ReadOptions::getSeekTo(
395 int64_t *time_us, SeekMode *mode) const {
396 *time_us = mSeekTimeUs;
397 *mode = mSeekMode;
398 return (mOptions & kSeekTo_Option) != 0;
399}
400
401void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
402 mLatenessUs = lateness_us;
403}
404
405int64_t IMediaSource::ReadOptions::getLateBy() const {
406 return mLatenessUs;
407}
408
409
410} // namespace android
411