1 /*
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 
21 #include <inttypes.h>
22 #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/MediaBufferGroup.h>
29 #include <media/stagefright/MediaSource.h>
30 #include <media/stagefright/MetaData.h>
31 
32 namespace android {
33 
34 enum {
35     START = IBinder::FIRST_CALL_TRANSACTION,
36     STOP,
37     PAUSE,
38     GETFORMAT,
39     READ,
40     READMULTIPLE,
41     RELEASE_BUFFER
42 };
43 
44 enum {
45     NULL_BUFFER,
46     SHARED_BUFFER,
47     INLINE_BUFFER
48 };
49 
50 class RemoteMediaBufferReleaser : public BBinder {
51 public:
RemoteMediaBufferReleaser(MediaBuffer * buf,sp<BnMediaSource> owner)52     RemoteMediaBufferReleaser(MediaBuffer *buf, sp<BnMediaSource> owner) {
53         mBuf = buf;
54         mOwner = owner;
55     }
~RemoteMediaBufferReleaser()56     ~RemoteMediaBufferReleaser() {
57         if (mBuf) {
58             ALOGW("RemoteMediaBufferReleaser dtor called while still holding buffer");
59             mBuf->release();
60         }
61     }
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags=0)62     virtual status_t    onTransact( uint32_t code,
63                                     const Parcel& data,
64                                     Parcel* reply,
65                                     uint32_t flags = 0) {
66         if (code == RELEASE_BUFFER) {
67             mBuf->release();
68             mBuf = NULL;
69             return OK;
70         } else {
71             return BBinder::onTransact(code, data, reply, flags);
72         }
73     }
74 private:
75     MediaBuffer *mBuf;
76     // Keep a ref to ensure MediaBuffer is released before the owner, i.e., BnMediaSource,
77     // because BnMediaSource needs to delete MediaBufferGroup in its dtor and
78     // MediaBufferGroup dtor requires all MediaBuffer's have 0 ref count.
79     sp<BnMediaSource> mOwner;
80 };
81 
82 
83 class RemoteMediaBufferWrapper : public MediaBuffer {
84 public:
85     RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source);
86 protected:
87     virtual ~RemoteMediaBufferWrapper();
88 private:
89     sp<IMemory> mMemory;
90     sp<IBinder> mRemoteSource;
91 };
92 
RemoteMediaBufferWrapper(sp<IMemory> mem,sp<IBinder> source)93 RemoteMediaBufferWrapper::RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source)
94 : MediaBuffer(mem->pointer(), mem->size()) {
95     mMemory = mem;
96     mRemoteSource = source;
97 }
98 
~RemoteMediaBufferWrapper()99 RemoteMediaBufferWrapper::~RemoteMediaBufferWrapper() {
100     mMemory.clear();
101     // Explicitly ask the remote side to release the buffer. We could also just clear
102     // mRemoteSource, but that doesn't immediately release the reference on the remote side.
103     Parcel data, reply;
104     mRemoteSource->transact(RELEASE_BUFFER, data, &reply);
105     mRemoteSource.clear();
106 }
107 
108 class BpMediaSource : public BpInterface<IMediaSource> {
109 public:
BpMediaSource(const sp<IBinder> & impl)110     BpMediaSource(const sp<IBinder>& impl)
111         : BpInterface<IMediaSource>(impl)
112     {
113     }
114 
start(MetaData * params)115     virtual status_t start(MetaData *params) {
116         ALOGV("start");
117         Parcel data, reply;
118         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
119         if (params) {
120             params->writeToParcel(data);
121         }
122         status_t ret = remote()->transact(START, data, &reply);
123         if (ret == NO_ERROR && params) {
124             ALOGW("ignoring potentially modified MetaData from start");
125             ALOGW("input:");
126             params->dumpToLog();
127             sp<MetaData> meta = MetaData::createFromParcel(reply);
128             ALOGW("output:");
129             meta->dumpToLog();
130         }
131         return ret;
132     }
133 
stop()134     virtual status_t stop() {
135         ALOGV("stop");
136         Parcel data, reply;
137         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
138         return remote()->transact(STOP, data, &reply);
139     }
140 
getFormat()141     virtual sp<MetaData> getFormat() {
142         ALOGV("getFormat");
143         Parcel data, reply;
144         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
145         status_t ret = remote()->transact(GETFORMAT, data, &reply);
146         if (ret == NO_ERROR) {
147             mMetaData = MetaData::createFromParcel(reply);
148             return mMetaData;
149         }
150         return NULL;
151     }
152 
read(MediaBuffer ** buffer,const ReadOptions * options)153     virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
154         ALOGV("read");
155         Parcel data, reply;
156         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
157         if (options) {
158             data.writeByteArray(sizeof(*options), (uint8_t*) options);
159         }
160         status_t ret = remote()->transact(READ, data, &reply);
161         if (ret != NO_ERROR) {
162             return ret;
163         }
164         // wrap the returned data in a MediaBuffer
165         ret = reply.readInt32();
166         int32_t buftype = reply.readInt32();
167         if (buftype == SHARED_BUFFER) {
168             sp<IBinder> remote = reply.readStrongBinder();
169             sp<IBinder> binder = reply.readStrongBinder();
170             sp<IMemory> mem = interface_cast<IMemory>(binder);
171             if (mem == NULL) {
172                 ALOGE("received NULL IMemory for shared buffer");
173             }
174             size_t offset = reply.readInt32();
175             size_t length = reply.readInt32();
176             MediaBuffer *buf = new RemoteMediaBufferWrapper(mem, remote);
177             buf->set_range(offset, length);
178             buf->meta_data()->updateFromParcel(reply);
179             *buffer = buf;
180         } else if (buftype == NULL_BUFFER) {
181             ALOGV("got status %d and NULL buffer", ret);
182             *buffer = NULL;
183         } else {
184             int32_t len = reply.readInt32();
185             ALOGV("got status %d and len %d", ret, len);
186             *buffer = new MediaBuffer(len);
187             reply.read((*buffer)->data(), len);
188             (*buffer)->meta_data()->updateFromParcel(reply);
189         }
190         return ret;
191     }
192 
readMultiple(Vector<MediaBuffer * > * buffers,uint32_t maxNumBuffers)193     virtual status_t readMultiple(Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers) {
194         ALOGV("readMultiple");
195         if (buffers == NULL || !buffers->isEmpty()) {
196             return BAD_VALUE;
197         }
198         Parcel data, reply;
199         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
200         data.writeUint32(maxNumBuffers);
201         status_t ret = remote()->transact(READMULTIPLE, data, &reply);
202         if (ret != NO_ERROR) {
203             return ret;
204         }
205         // wrap the returned data in a vector of MediaBuffers
206         int32_t bufCount = 0;
207         while (1) {
208             if (reply.readInt32() == 0) {
209                 break;
210             }
211             int32_t len = reply.readInt32();
212             ALOGV("got len %d", len);
213             MediaBuffer *buf = new MediaBuffer(len);
214             reply.read(buf->data(), len);
215             buf->meta_data()->updateFromParcel(reply);
216             buffers->push_back(buf);
217             ++bufCount;
218         }
219         ret = reply.readInt32();
220         ALOGV("got status %d, bufCount %d", ret, bufCount);
221         return ret;
222     }
223 
pause()224     virtual status_t pause() {
225         ALOGV("pause");
226         Parcel data, reply;
227         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
228         return remote()->transact(PAUSE, data, &reply);
229     }
230 
setBuffers(const Vector<MediaBuffer * > & buffers __unused)231     virtual status_t setBuffers(const Vector<MediaBuffer *> & buffers __unused) {
232         ALOGV("setBuffers NOT IMPLEMENTED");
233         return ERROR_UNSUPPORTED; // default
234     }
235 
236 private:
237     // NuPlayer passes pointers-to-metadata around, so we use this to keep the metadata alive
238     // XXX: could we use this for caching, or does metadata change on the fly?
239     sp<MetaData> mMetaData;
240 
241 };
242 
243 IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
244 
245 #undef LOG_TAG
246 #define LOG_TAG "BnMediaSource"
247 
BnMediaSource()248 BnMediaSource::BnMediaSource()
249     : mGroup(NULL) {
250 }
251 
~BnMediaSource()252 BnMediaSource::~BnMediaSource() {
253     delete mGroup;
254     mGroup = NULL;
255 }
256 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)257 status_t BnMediaSource::onTransact(
258     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
259 {
260     switch (code) {
261         case START: {
262             ALOGV("start");
263             CHECK_INTERFACE(IMediaSource, data, reply);
264             sp<MetaData> meta;
265             if (data.dataAvail()) {
266                 meta = MetaData::createFromParcel(data);
267             }
268             status_t ret = start(meta.get());
269             if (ret == NO_ERROR && meta != NULL) {
270                 meta->writeToParcel(*reply);
271             }
272             return ret;
273         }
274         case STOP: {
275             ALOGV("stop");
276             CHECK_INTERFACE(IMediaSource, data, reply);
277             return stop();
278         }
279         case PAUSE: {
280             ALOGV("pause");
281             CHECK_INTERFACE(IMediaSource, data, reply);
282             return pause();
283         }
284         case GETFORMAT: {
285             ALOGV("getFormat");
286             CHECK_INTERFACE(IMediaSource, data, reply);
287             sp<MetaData> meta = getFormat();
288             if (meta != NULL) {
289                 meta->writeToParcel(*reply);
290                 return NO_ERROR;
291             }
292             return UNKNOWN_ERROR;
293         }
294         case READ: {
295             ALOGV("read");
296             CHECK_INTERFACE(IMediaSource, data, reply);
297             status_t ret;
298             MediaBuffer *buf = NULL;
299             ReadOptions opts;
300             uint32_t len;
301             if (data.readUint32(&len) == NO_ERROR &&
302                     len == sizeof(opts) && data.read((void*)&opts, len) == NO_ERROR) {
303                 ret = read(&buf, &opts);
304             } else {
305                 ret = read(&buf, NULL);
306             }
307 
308             reply->writeInt32(ret);
309             if (buf != NULL) {
310                 size_t usedSize = buf->range_length();
311                 // even if we're using shared memory, we might not want to use it, since for small
312                 // sizes it's faster to copy data through the Binder transaction
313                 // On the other hand, if the data size is large enough, it's better to use shared
314                 // memory. When data is too large, binder can't handle it.
315                 if (usedSize >= MediaBuffer::kSharedMemThreshold) {
316                     ALOGV("use shared memory: %zu", usedSize);
317 
318                     MediaBuffer *transferBuf = buf;
319                     size_t offset = buf->range_offset();
320                     if (transferBuf->mMemory == NULL) {
321                         if (mGroup == NULL) {
322                             mGroup = new MediaBufferGroup;
323                             size_t allocateSize = usedSize;
324                             if (usedSize < SIZE_MAX / 3) {
325                                 allocateSize = usedSize * 3 / 2;
326                             }
327                             mGroup->add_buffer(new MediaBuffer(allocateSize));
328                         }
329 
330                         MediaBuffer *newBuf = NULL;
331                         ret = mGroup->acquire_buffer(
332                                 &newBuf, false /* nonBlocking */, usedSize);
333                         if (ret != OK || newBuf == NULL || newBuf->mMemory == NULL) {
334                             ALOGW("failed to acquire shared memory, ret %d", ret);
335                             buf->release();
336                             if (newBuf != NULL) {
337                                 newBuf->release();
338                             }
339                             reply->writeInt32(NULL_BUFFER);
340                             return NO_ERROR;
341                         }
342                         transferBuf = newBuf;
343                         memcpy(transferBuf->data(), (uint8_t*)buf->data() + buf->range_offset(),
344                                 buf->range_length());
345                         offset = 0;
346                     }
347 
348                     reply->writeInt32(SHARED_BUFFER);
349                     RemoteMediaBufferReleaser *wrapper =
350                         new RemoteMediaBufferReleaser(transferBuf, this);
351                     reply->writeStrongBinder(wrapper);
352                     reply->writeStrongBinder(IInterface::asBinder(transferBuf->mMemory));
353                     reply->writeInt32(offset);
354                     reply->writeInt32(usedSize);
355                     buf->meta_data()->writeToParcel(*reply);
356                     if (buf->mMemory == NULL) {
357                         buf->release();
358                     }
359                 } else {
360                     // buffer is small: copy it
361                     if (buf->mMemory != NULL) {
362                         ALOGV("%zu shared mem available, but only %zu used", buf->mMemory->size(), buf->range_length());
363                     }
364                     reply->writeInt32(INLINE_BUFFER);
365                     reply->writeByteArray(buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
366                     buf->meta_data()->writeToParcel(*reply);
367                     buf->release();
368                 }
369             } else {
370                 ALOGV("ret %d, buf %p", ret, buf);
371                 reply->writeInt32(NULL_BUFFER);
372             }
373             return NO_ERROR;
374         }
375         case READMULTIPLE: {
376             ALOGV("readmultiple");
377             CHECK_INTERFACE(IMediaSource, data, reply);
378             uint32_t maxNumBuffers;
379             data.readUint32(&maxNumBuffers);
380             status_t ret = NO_ERROR;
381             uint32_t bufferCount = 0;
382             if (maxNumBuffers > kMaxNumReadMultiple) {
383                 maxNumBuffers = kMaxNumReadMultiple;
384             }
385             while (bufferCount < maxNumBuffers) {
386                 if (reply->dataSize() >= MediaBuffer::kSharedMemThreshold) {
387                     break;
388                 }
389 
390                 MediaBuffer *buf = NULL;
391                 ret = read(&buf, NULL);
392                 if (ret != NO_ERROR || buf == NULL) {
393                     break;
394                 }
395                 ++bufferCount;
396                 reply->writeInt32(1);  // indicate one more MediaBuffer.
397                 reply->writeByteArray(
398                         buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
399                 buf->meta_data()->writeToParcel(*reply);
400                 buf->release();
401             }
402             reply->writeInt32(0);  // indicate no more MediaBuffer.
403             reply->writeInt32(ret);
404             return NO_ERROR;
405         }
406         default:
407             return BBinder::onTransact(code, data, reply, flags);
408     }
409 }
410 
411 ////////////////////////////////////////////////////////////////////////////////
412 
ReadOptions()413 IMediaSource::ReadOptions::ReadOptions() {
414     reset();
415 }
416 
reset()417 void IMediaSource::ReadOptions::reset() {
418     mOptions = 0;
419     mSeekTimeUs = 0;
420     mLatenessUs = 0;
421     mNonBlocking = false;
422 }
423 
setNonBlocking()424 void IMediaSource::ReadOptions::setNonBlocking() {
425     mNonBlocking = true;
426 }
427 
clearNonBlocking()428 void IMediaSource::ReadOptions::clearNonBlocking() {
429     mNonBlocking = false;
430 }
431 
getNonBlocking() const432 bool IMediaSource::ReadOptions::getNonBlocking() const {
433     return mNonBlocking;
434 }
435 
setSeekTo(int64_t time_us,SeekMode mode)436 void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
437     mOptions |= kSeekTo_Option;
438     mSeekTimeUs = time_us;
439     mSeekMode = mode;
440 }
441 
clearSeekTo()442 void IMediaSource::ReadOptions::clearSeekTo() {
443     mOptions &= ~kSeekTo_Option;
444     mSeekTimeUs = 0;
445     mSeekMode = SEEK_CLOSEST_SYNC;
446 }
447 
getSeekTo(int64_t * time_us,SeekMode * mode) const448 bool IMediaSource::ReadOptions::getSeekTo(
449         int64_t *time_us, SeekMode *mode) const {
450     *time_us = mSeekTimeUs;
451     *mode = mSeekMode;
452     return (mOptions & kSeekTo_Option) != 0;
453 }
454 
setLateBy(int64_t lateness_us)455 void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
456     mLatenessUs = lateness_us;
457 }
458 
getLateBy() const459 int64_t IMediaSource::ReadOptions::getLateBy() const {
460     return mLatenessUs;
461 }
462 
463 
464 }  // namespace android
465 
466