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