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/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, deprecated
40     READMULTIPLE,
41     RELEASE_BUFFER,
42     SUPPORT_NONBLOCKING_READ,
43 };
44 
45 enum {
46     NULL_BUFFER,
47     SHARED_BUFFER,
48     INLINE_BUFFER,
49     SHARED_BUFFER_INDEX,
50 };
51 
52 class RemoteMediaBufferWrapper : public MediaBuffer {
53 public:
RemoteMediaBufferWrapper(const sp<IMemory> & mem)54     RemoteMediaBufferWrapper(const sp<IMemory> &mem)
55         : MediaBuffer(mem) {
56         ALOGV("RemoteMediaBufferWrapper: creating %p", this);
57     }
58 
59 protected:
~RemoteMediaBufferWrapper()60     virtual ~RemoteMediaBufferWrapper() {
61         // Release our interest in the MediaBuffer's shared memory.
62         int32_t old = addRemoteRefcount(-1);
63         ALOGV("RemoteMediaBufferWrapper: releasing %p, refcount %d", this, old - 1);
64         mMemory.clear(); // don't set the dead object flag.
65     }
66 };
67 
68 class BpMediaSource : public BpInterface<IMediaSource> {
69 public:
BpMediaSource(const sp<IBinder> & impl)70     explicit BpMediaSource(const sp<IBinder>& impl)
71         : BpInterface<IMediaSource>(impl), mBuffersSinceStop(0)
72     {
73     }
74 
start(MetaData * params)75     virtual status_t start(MetaData *params) {
76         ALOGV("start");
77         Parcel data, reply;
78         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
79         if (params) {
80             params->writeToParcel(data);
81         }
82         status_t ret = remote()->transact(START, data, &reply);
83         if (ret == NO_ERROR && params) {
84             ALOGW("ignoring potentially modified MetaData from start");
85             ALOGW("input:");
86             params->dumpToLog();
87             sp<MetaData> meta = MetaData::createFromParcel(reply);
88             ALOGW("output:");
89             meta->dumpToLog();
90         }
91         return ret;
92     }
93 
stop()94     virtual status_t stop() {
95         ALOGV("stop");
96         Parcel data, reply;
97         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
98         status_t status = remote()->transact(STOP, data, &reply);
99         mMemoryCache.reset();
100         mBuffersSinceStop = 0;
101         return status;
102     }
103 
getFormat()104     virtual sp<MetaData> getFormat() {
105         ALOGV("getFormat");
106         Parcel data, reply;
107         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
108         status_t ret = remote()->transact(GETFORMAT, data, &reply);
109         if (ret == NO_ERROR) {
110             mMetaData = MetaData::createFromParcel(reply);
111             return mMetaData;
112         }
113         return NULL;
114     }
115 
read(MediaBufferBase ** buffer,const MediaSource::ReadOptions * options)116     virtual status_t read(MediaBufferBase **buffer,
117             const MediaSource::ReadOptions *options) {
118         Vector<MediaBufferBase *> buffers;
119         status_t ret = readMultiple(&buffers, 1 /* maxNumBuffers */, options);
120         *buffer = buffers.size() == 0 ? nullptr : buffers[0];
121         ALOGV("read status %d, bufferCount %u, sinceStop %u",
122                 ret, *buffer != nullptr, mBuffersSinceStop);
123         return ret;
124     }
125 
readMultiple(Vector<MediaBufferBase * > * buffers,uint32_t maxNumBuffers,const MediaSource::ReadOptions * options)126     virtual status_t readMultiple(
127             Vector<MediaBufferBase *> *buffers, uint32_t maxNumBuffers,
128             const MediaSource::ReadOptions *options) {
129         ALOGV("readMultiple");
130         if (buffers == NULL || !buffers->isEmpty()) {
131             return BAD_VALUE;
132         }
133         Parcel data, reply;
134         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
135         data.writeUint32(maxNumBuffers);
136         if (options != nullptr) {
137             data.writeByteArray(sizeof(*options), (uint8_t*) options);
138         }
139         status_t ret = remote()->transact(READMULTIPLE, data, &reply);
140         mMemoryCache.gc();
141         if (ret != NO_ERROR) {
142             return ret;
143         }
144         // wrap the returned data in a vector of MediaBuffers
145         int32_t buftype;
146         uint32_t bufferCount = 0;
147         while ((buftype = reply.readInt32()) != NULL_BUFFER) {
148             LOG_ALWAYS_FATAL_IF(bufferCount >= maxNumBuffers,
149                     "Received %u+ buffers and requested %u buffers",
150                     bufferCount + 1, maxNumBuffers);
151             MediaBuffer *buf;
152             if (buftype == SHARED_BUFFER || buftype == SHARED_BUFFER_INDEX) {
153                 uint64_t index = reply.readUint64();
154                 ALOGV("Received %s index %llu",
155                         buftype == SHARED_BUFFER ? "SHARED_BUFFER" : "SHARED_BUFFER_INDEX",
156                         (unsigned long long) index);
157                 sp<IMemory> mem;
158                 if (buftype == SHARED_BUFFER) {
159                     sp<IBinder> binder = reply.readStrongBinder();
160                     mem = interface_cast<IMemory>(binder);
161                     LOG_ALWAYS_FATAL_IF(mem.get() == nullptr,
162                             "Received NULL IMemory for shared buffer");
163                     mMemoryCache.insert(index, mem);
164                 } else {
165                     mem = mMemoryCache.lookup(index);
166                     LOG_ALWAYS_FATAL_IF(mem.get() == nullptr,
167                             "Received invalid IMemory index for shared buffer: %llu",
168                             (unsigned long long)index);
169                 }
170                 size_t offset = reply.readInt32();
171                 size_t length = reply.readInt32();
172                 buf = new RemoteMediaBufferWrapper(mem);
173                 buf->set_range(offset, length);
174                 buf->meta_data().updateFromParcel(reply);
175             } else { // INLINE_BUFFER
176                 int32_t len = reply.readInt32();
177                 ALOGV("INLINE_BUFFER status %d and len %d", ret, len);
178                 buf = new MediaBuffer(len);
179                 reply.read(buf->data(), len);
180                 buf->meta_data().updateFromParcel(reply);
181             }
182             buffers->push_back(buf);
183             ++bufferCount;
184             ++mBuffersSinceStop;
185         }
186         ret = reply.readInt32();
187         ALOGV("readMultiple status %d, bufferCount %u, sinceStop %u",
188                 ret, bufferCount, mBuffersSinceStop);
189         return ret;
190     }
191 
192     // Binder proxy adds readMultiple support.
supportReadMultiple()193     virtual bool supportReadMultiple() {
194         return true;
195     }
196 
supportNonblockingRead()197     virtual bool supportNonblockingRead() {
198         ALOGV("supportNonblockingRead");
199         Parcel data, reply;
200         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
201         status_t ret = remote()->transact(SUPPORT_NONBLOCKING_READ, data, &reply);
202         if (ret == NO_ERROR) {
203             return reply.readInt32() != 0;
204         }
205         return false;
206     }
207 
pause()208     virtual status_t pause() {
209         ALOGV("pause");
210         Parcel data, reply;
211         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
212         return remote()->transact(PAUSE, data, &reply);
213     }
214 
215 private:
216 
217     uint32_t mBuffersSinceStop; // Buffer tracking variable
218 
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;
222 
223     // Cache all IMemory objects received from MediaExtractor.
224     // We gc IMemory objects that are no longer active (referenced by a MediaBuffer).
225 
226     struct MemoryCache {
lookupandroid::BpMediaSource::MemoryCache227         sp<IMemory> lookup(uint64_t index) {
228             auto p = mIndexToMemory.find(index);
229             if (p == mIndexToMemory.end()) {
230                 ALOGE("cannot find index!");
231                 return nullptr;
232             }
233             return p->second;
234         }
235 
insertandroid::BpMediaSource::MemoryCache236         void insert(uint64_t index, const sp<IMemory> &mem) {
237             if (mIndexToMemory.find(index) != mIndexToMemory.end()) {
238                 ALOGE("index %llu already present", (unsigned long long)index);
239                 return;
240             }
241             (void)mIndexToMemory.emplace(index, mem);
242         }
243 
resetandroid::BpMediaSource::MemoryCache244         void reset() {
245             mIndexToMemory.clear();
246         }
247 
gcandroid::BpMediaSource::MemoryCache248         void gc() {
249             for (auto it = mIndexToMemory.begin(); it != mIndexToMemory.end(); ) {
250                 if (MediaBuffer::isDeadObject(it->second)) {
251                     it = mIndexToMemory.erase(it);
252                 } else {
253                     ++it;
254                 }
255             }
256         }
257     private:
258         // C++14 unordered_map erase on iterator is stable; C++11 has no guarantee.
259         std::map<uint64_t, sp<IMemory>> mIndexToMemory;
260     } mMemoryCache;
261 };
262 
263 IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
264 
265 #undef LOG_TAG
266 #define LOG_TAG "BnMediaSource"
267 
BnMediaSource()268 BnMediaSource::BnMediaSource()
269     : mBuffersSinceStop(0)
270     , mGroup(new MediaBufferGroup(kBinderMediaBuffers /* growthLimit */)) {
271 }
272 
~BnMediaSource()273 BnMediaSource::~BnMediaSource() {
274 }
275 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)276 status_t BnMediaSource::onTransact(
277     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
278 {
279     switch (code) {
280         case START: {
281             ALOGV("start");
282             CHECK_INTERFACE(IMediaSource, data, reply);
283             sp<MetaData> meta;
284             if (data.dataAvail()) {
285                 meta = MetaData::createFromParcel(data);
286             }
287             status_t ret = start(meta.get());
288             if (ret == NO_ERROR && meta != NULL) {
289                 meta->writeToParcel(*reply);
290             }
291             return ret;
292         }
293         case STOP: {
294             ALOGV("stop");
295             CHECK_INTERFACE(IMediaSource, data, reply);
296             mGroup->signalBufferReturned(nullptr);
297             status_t status = stop();
298             mIndexCache.reset();
299             mBuffersSinceStop = 0;
300             return status;
301         }
302         case PAUSE: {
303             ALOGV("pause");
304             CHECK_INTERFACE(IMediaSource, data, reply);
305             mGroup->signalBufferReturned(nullptr);
306             return pause();
307         }
308         case GETFORMAT: {
309             ALOGV("getFormat");
310             CHECK_INTERFACE(IMediaSource, data, reply);
311             sp<MetaData> meta = getFormat();
312             if (meta != NULL) {
313                 meta->writeToParcel(*reply);
314                 return NO_ERROR;
315             }
316             return UNKNOWN_ERROR;
317         }
318         case READMULTIPLE: {
319             ALOGV("readMultiple");
320             CHECK_INTERFACE(IMediaSource, data, reply);
321 
322             // Get max number of buffers to read.
323             uint32_t maxNumBuffers;
324             data.readUint32(&maxNumBuffers);
325             if (maxNumBuffers > kMaxNumReadMultiple) {
326                 maxNumBuffers = kMaxNumReadMultiple;
327             }
328 
329             // Get read options, if any.
330             MediaSource::ReadOptions opts;
331             uint32_t len;
332             const bool useOptions =
333                     data.readUint32(&len) == NO_ERROR
334                     && len == sizeof(opts)
335                     && data.read((void *)&opts, len) == NO_ERROR;
336 
337             mGroup->signalBufferReturned(nullptr);
338             mIndexCache.gc();
339             size_t inlineTransferSize = 0;
340             status_t ret = NO_ERROR;
341             uint32_t bufferCount = 0;
342             for (; bufferCount < maxNumBuffers; ++bufferCount, ++mBuffersSinceStop) {
343                 MediaBuffer *buf = nullptr;
344                 ret = read((MediaBufferBase **)&buf, useOptions ? &opts : nullptr);
345                 opts.clearNonPersistent(); // Remove options that only apply to first buffer.
346                 if (ret != NO_ERROR || buf == nullptr) {
347                     break;
348                 }
349 
350                 // Even if we're using shared memory, we might not want to use it, since for small
351                 // sizes it's faster to copy data through the Binder transaction
352                 // On the other hand, if the data size is large enough, it's better to use shared
353                 // memory. When data is too large, binder can't handle it.
354                 //
355                 // TODO: reduce MediaBuffer::kSharedMemThreshold
356                 MediaBuffer *transferBuf = nullptr;
357                 const size_t length = buf->range_length();
358                 size_t offset = buf->range_offset();
359                 if (length >= (supportNonblockingRead() && buf->mMemory != nullptr ?
360                         kTransferSharedAsSharedThreshold : kTransferInlineAsSharedThreshold)) {
361                     if (buf->mMemory != nullptr) {
362                         ALOGV("Use shared memory: %zu", length);
363                         transferBuf = buf;
364                     } else {
365                         ALOGD("Large buffer %zu without IMemory!", length);
366                         ret = mGroup->acquire_buffer(
367                                 (MediaBufferBase **)&transferBuf, false /* nonBlocking */, length);
368                         if (ret != OK
369                                 || transferBuf == nullptr
370                                 || transferBuf->mMemory == nullptr) {
371                             ALOGW("Failed to acquire shared memory, size %zu, ret %d",
372                                     length, ret);
373                             if (transferBuf != nullptr) {
374                                 transferBuf->release();
375                                 transferBuf = nullptr;
376                             }
377                             // Current buffer transmit inline; no more additional buffers.
378                             maxNumBuffers = 0;
379                         } else {
380                             memcpy(transferBuf->data(), (uint8_t*)buf->data() + offset, length);
381                             offset = 0;
382                             if (!mGroup->has_buffers()) {
383                                 maxNumBuffers = 0; // No more MediaBuffers, stop readMultiple.
384                             }
385                         }
386                     }
387                 }
388                 if (transferBuf != nullptr) { // Using shared buffers.
389                     if (!transferBuf->isObserved() && transferBuf != buf) {
390                         // Transfer buffer must be part of a MediaBufferGroup.
391                         ALOGV("adding shared memory buffer %p to local group", transferBuf);
392                         mGroup->add_buffer(transferBuf);
393                         transferBuf->add_ref(); // We have already acquired buffer.
394                     }
395                     uint64_t index = mIndexCache.lookup(transferBuf->mMemory);
396                     if (index == 0) {
397                         index = mIndexCache.insert(transferBuf->mMemory);
398                         reply->writeInt32(SHARED_BUFFER);
399                         reply->writeUint64(index);
400                         reply->writeStrongBinder(IInterface::asBinder(transferBuf->mMemory));
401                         ALOGV("SHARED_BUFFER(%p) %llu",
402                                 transferBuf, (unsigned long long)index);
403                     } else {
404                         reply->writeInt32(SHARED_BUFFER_INDEX);
405                         reply->writeUint64(index);
406                         ALOGV("SHARED_BUFFER_INDEX(%p) %llu",
407                                 transferBuf, (unsigned long long)index);
408                     }
409                     reply->writeInt32(offset);
410                     reply->writeInt32(length);
411                     buf->meta_data().writeToParcel(*reply);
412                     transferBuf->addRemoteRefcount(1);
413                     if (transferBuf != buf) {
414                         transferBuf->release(); // release local ref
415                     } else if (!supportNonblockingRead()) {
416                         maxNumBuffers = 0; // stop readMultiple with one shared buffer.
417                     }
418                 } else {
419                     ALOGV_IF(buf->mMemory != nullptr,
420                             "INLINE(%p) %zu shared mem available, but only %zu used",
421                             buf, buf->mMemory->size(), length);
422                     reply->writeInt32(INLINE_BUFFER);
423                     reply->writeByteArray(length, (uint8_t*)buf->data() + offset);
424                     buf->meta_data().writeToParcel(*reply);
425                     inlineTransferSize += length;
426                     if (inlineTransferSize > kInlineMaxTransfer) {
427                         maxNumBuffers = 0; // stop readMultiple if inline transfer is too large.
428                     }
429                 }
430                 buf->release();
431             }
432             reply->writeInt32(NULL_BUFFER); // Indicate no more MediaBuffers.
433             reply->writeInt32(ret);
434             ALOGV("readMultiple status %d, bufferCount %u, sinceStop %u",
435                     ret, bufferCount, mBuffersSinceStop);
436             return NO_ERROR;
437         }
438         case SUPPORT_NONBLOCKING_READ: {
439             ALOGV("supportNonblockingRead");
440             CHECK_INTERFACE(IMediaSource, data, reply);
441             reply->writeInt32((int32_t)supportNonblockingRead());
442             return NO_ERROR;
443         }
444         default:
445             return BBinder::onTransact(code, data, reply, flags);
446     }
447 }
448 
449 }  // namespace android
450 
451