• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 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(mBpLock);
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 mBpLock;
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             AutoMutex _l(mBnLock);
305             mIndexCache.reset();
306             mBuffersSinceStop = 0;
307             return status;
308         }
309         case PAUSE: {
310             ALOGV("pause");
311             CHECK_INTERFACE(IMediaSource, data, reply);
312             mGroup->signalBufferReturned(nullptr);
313             return pause();
314         }
315         case GETFORMAT: {
316             ALOGV("getFormat");
317             CHECK_INTERFACE(IMediaSource, data, reply);
318             sp<MetaData> meta = getFormat();
319             if (meta != NULL) {
320                 meta->writeToParcel(*reply);
321                 return NO_ERROR;
322             }
323             return UNKNOWN_ERROR;
324         }
325         case READMULTIPLE: {
326             ALOGV("readMultiple");
327             CHECK_INTERFACE(IMediaSource, data, reply);
328 
329             // Get max number of buffers to read.
330             uint32_t maxNumBuffers;
331             data.readUint32(&maxNumBuffers);
332             if (maxNumBuffers > kMaxNumReadMultiple) {
333                 maxNumBuffers = kMaxNumReadMultiple;
334             }
335 
336             // Get read options, if any.
337             MediaSource::ReadOptions opts;
338             uint32_t len;
339             const bool useOptions =
340                     data.readUint32(&len) == NO_ERROR
341                     && len == sizeof(opts)
342                     && data.read((void *)&opts, len) == NO_ERROR;
343 
344             AutoMutex _l(mBnLock);
345             mGroup->signalBufferReturned(nullptr);
346             mIndexCache.gc();
347             size_t inlineTransferSize = 0;
348             status_t ret = NO_ERROR;
349             uint32_t bufferCount = 0;
350             for (; bufferCount < maxNumBuffers; ++bufferCount, ++mBuffersSinceStop) {
351                 MediaBuffer *buf = nullptr;
352                 ret = read((MediaBufferBase **)&buf, useOptions ? &opts : nullptr);
353                 opts.clearNonPersistent(); // Remove options that only apply to first buffer.
354                 if (ret != NO_ERROR || buf == nullptr) {
355                     break;
356                 }
357 
358                 // Even if we're using shared memory, we might not want to use it, since for small
359                 // sizes it's faster to copy data through the Binder transaction
360                 // On the other hand, if the data size is large enough, it's better to use shared
361                 // memory. When data is too large, binder can't handle it.
362                 //
363                 // TODO: reduce MediaBuffer::kSharedMemThreshold
364                 MediaBuffer *transferBuf = nullptr;
365                 const size_t length = buf->range_length();
366                 size_t offset = buf->range_offset();
367                 if (length >= (supportNonblockingRead() && buf->mMemory != nullptr ?
368                         kTransferSharedAsSharedThreshold : kTransferInlineAsSharedThreshold)) {
369                     if (buf->mMemory != nullptr) {
370                         ALOGV("Use shared memory: %zu", length);
371                         transferBuf = buf;
372                     } else {
373                         ALOGV("Large buffer %zu without IMemory!", length);
374                         ret = mGroup->acquire_buffer(
375                                 (MediaBufferBase **)&transferBuf, false /* nonBlocking */, length);
376                         if (ret != OK
377                                 || transferBuf == nullptr
378                                 || transferBuf->mMemory == nullptr) {
379                             ALOGV("Failed to acquire shared memory, size %zu, ret %d",
380                                     length, ret);
381                             if (transferBuf != nullptr) {
382                                 transferBuf->release();
383                                 transferBuf = nullptr;
384                             }
385                             // Current buffer transmit inline; no more additional buffers.
386                             maxNumBuffers = 0;
387                         } else {
388                             memcpy(transferBuf->data(), (uint8_t*)buf->data() + offset, length);
389                             offset = 0;
390                             if (!mGroup->has_buffers()) {
391                                 maxNumBuffers = 0; // No more MediaBuffers, stop readMultiple.
392                             }
393                         }
394                     }
395                 }
396                 if (transferBuf != nullptr) { // Using shared buffers.
397                     if (!transferBuf->isObserved() && transferBuf != buf) {
398                         // Transfer buffer must be part of a MediaBufferGroup.
399                         ALOGV("adding shared memory buffer %p to local group", transferBuf);
400                         mGroup->add_buffer(transferBuf);
401                         transferBuf->add_ref(); // We have already acquired buffer.
402                     }
403                     uint64_t index = mIndexCache.lookup(transferBuf->mMemory);
404                     if (index == 0) {
405                         index = mIndexCache.insert(transferBuf->mMemory);
406                         reply->writeInt32(SHARED_BUFFER);
407                         reply->writeUint64(index);
408                         reply->writeStrongBinder(IInterface::asBinder(transferBuf->mMemory));
409                         ALOGV("SHARED_BUFFER(%p) %llu",
410                                 transferBuf, (unsigned long long)index);
411                     } else {
412                         reply->writeInt32(SHARED_BUFFER_INDEX);
413                         reply->writeUint64(index);
414                         ALOGV("SHARED_BUFFER_INDEX(%p) %llu",
415                                 transferBuf, (unsigned long long)index);
416                     }
417                     reply->writeInt32(offset);
418                     reply->writeInt32(length);
419                     buf->meta_data().writeToParcel(*reply);
420                     transferBuf->addRemoteRefcount(1);
421                     if (transferBuf != buf) {
422                         transferBuf->release(); // release local ref
423                     } else if (!supportNonblockingRead()) {
424                         maxNumBuffers = 0; // stop readMultiple with one shared buffer.
425                     }
426                 } else {
427                     ALOGV_IF(buf->mMemory != nullptr,
428                             "INLINE(%p) %zu shared mem available, but only %zu used",
429                             buf, buf->mMemory->size(), length);
430                     reply->writeInt32(INLINE_BUFFER);
431                     reply->writeByteArray(length, (uint8_t*)buf->data() + offset);
432                     buf->meta_data().writeToParcel(*reply);
433                     inlineTransferSize += length;
434                     if (inlineTransferSize > kInlineMaxTransfer) {
435                         maxNumBuffers = 0; // stop readMultiple if inline transfer is too large.
436                     }
437                 }
438                 buf->release();
439             }
440             reply->writeInt32(NULL_BUFFER); // Indicate no more MediaBuffers.
441             reply->writeInt32(ret);
442             ALOGV("readMultiple status %d, bufferCount %u, sinceStop %u",
443                     ret, bufferCount, mBuffersSinceStop);
444             return NO_ERROR;
445         }
446         case SUPPORT_NONBLOCKING_READ: {
447             ALOGV("supportNonblockingRead");
448             CHECK_INTERFACE(IMediaSource, data, reply);
449             reply->writeInt32((int32_t)supportNonblockingRead());
450             return NO_ERROR;
451         }
452         default:
453             return BBinder::onTransact(code, data, reply, flags);
454     }
455 }
456 
457 }  // namespace android
458 
459