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