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
32namespace android {
33
34enum {
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
45enum {
46    NULL_BUFFER,
47    SHARED_BUFFER,
48    INLINE_BUFFER,
49    SHARED_BUFFER_INDEX,
50};
51
52class RemoteMediaBufferWrapper : public MediaBuffer {
53public:
54    RemoteMediaBufferWrapper(const sp<IMemory> &mem)
55        : MediaBuffer(mem) {
56        ALOGV("RemoteMediaBufferWrapper: creating %p", this);
57    }
58
59protected:
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
68class BpMediaSource : public BpInterface<IMediaSource> {
69public:
70    explicit BpMediaSource(const sp<IBinder>& impl)
71        : BpInterface<IMediaSource>(impl), mBuffersSinceStop(0)
72    {
73    }
74
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
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
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
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
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.
193    virtual bool supportReadMultiple() {
194        return true;
195    }
196
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
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
215private:
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 {
227        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
236        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
244        void reset() {
245            mIndexToMemory.clear();
246        }
247
248        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
263IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
264
265#undef LOG_TAG
266#define LOG_TAG "BnMediaSource"
267
268BnMediaSource::BnMediaSource()
269    : mBuffersSinceStop(0)
270    , mGroup(new MediaBufferGroup(kBinderMediaBuffers /* growthLimit */)) {
271}
272
273BnMediaSource::~BnMediaSource() {
274}
275
276status_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