Home | History | Annotate | Download | only in libmedia
      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:
     54     RemoteMediaBufferWrapper(const sp<IMemory> &mem)
     55         : MediaBuffer(mem) {
     56         ALOGV("RemoteMediaBufferWrapper: creating %p", this);
     57     }
     58 
     59 protected:
     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:
     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(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 
    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.
    191     virtual bool supportReadMultiple() {
    192         return true;
    193     }
    194 
    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 
    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 
    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 {
    230         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 
    239         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 
    247         void reset() {
    248             mIndexToMemory.clear();
    249         }
    250 
    251         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 
    271 BnMediaSource::BnMediaSource()
    272     : mBuffersSinceStop(0)
    273     , mGroup(new MediaBufferGroup(kBinderMediaBuffers /* growthLimit */)) {
    274 }
    275 
    276 BnMediaSource::~BnMediaSource() {
    277 }
    278 
    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             mGroup->signalBufferReturned(nullptr);
    300             status_t status = stop();
    301             mIndexCache.reset();
    302             mBuffersSinceStop = 0;
    303             return status;
    304         }
    305         case PAUSE: {
    306             ALOGV("pause");
    307             CHECK_INTERFACE(IMediaSource, data, reply);
    308             mGroup->signalBufferReturned(nullptr);
    309             return pause();
    310         }
    311         case GETFORMAT: {
    312             ALOGV("getFormat");
    313             CHECK_INTERFACE(IMediaSource, data, reply);
    314             sp<MetaData> meta = getFormat();
    315             if (meta != NULL) {
    316                 meta->writeToParcel(*reply);
    317                 return NO_ERROR;
    318             }
    319             return UNKNOWN_ERROR;
    320         }
    321         case READMULTIPLE: {
    322             ALOGV("readMultiple");
    323             CHECK_INTERFACE(IMediaSource, data, reply);
    324 
    325             // Get max number of buffers to read.
    326             uint32_t maxNumBuffers;
    327             data.readUint32(&maxNumBuffers);
    328             if (maxNumBuffers > kMaxNumReadMultiple) {
    329                 maxNumBuffers = kMaxNumReadMultiple;
    330             }
    331 
    332             // Get read options, if any.
    333             ReadOptions opts;
    334             uint32_t len;
    335             const bool useOptions =
    336                     data.readUint32(&len) == NO_ERROR
    337                     && len == sizeof(opts)
    338                     && data.read((void *)&opts, len) == NO_ERROR;
    339 
    340             mGroup->signalBufferReturned(nullptr);
    341             mIndexCache.gc();
    342             size_t inlineTransferSize = 0;
    343             status_t ret = NO_ERROR;
    344             uint32_t bufferCount = 0;
    345             for (; bufferCount < maxNumBuffers; ++bufferCount, ++mBuffersSinceStop) {
    346                 MediaBuffer *buf = nullptr;
    347                 ret = read(&buf, useOptions ? &opts : nullptr);
    348                 opts.clearNonPersistent(); // Remove options that only apply to first buffer.
    349                 if (ret != NO_ERROR || buf == nullptr) {
    350                     break;
    351                 }
    352 
    353                 // Even if we're using shared memory, we might not want to use it, since for small
    354                 // sizes it's faster to copy data through the Binder transaction
    355                 // On the other hand, if the data size is large enough, it's better to use shared
    356                 // memory. When data is too large, binder can't handle it.
    357                 //
    358                 // TODO: reduce MediaBuffer::kSharedMemThreshold
    359                 MediaBuffer *transferBuf = nullptr;
    360                 const size_t length = buf->range_length();
    361                 size_t offset = buf->range_offset();
    362                 if (length >= (supportNonblockingRead() && buf->mMemory != nullptr ?
    363                         kTransferSharedAsSharedThreshold : kTransferInlineAsSharedThreshold)) {
    364                     if (buf->mMemory != nullptr) {
    365                         ALOGV("Use shared memory: %zu", length);
    366                         transferBuf = buf;
    367                     } else {
    368                         ALOGD("Large buffer %zu without IMemory!", length);
    369                         ret = mGroup->acquire_buffer(
    370                                 &transferBuf, false /* nonBlocking */, length);
    371                         if (ret != OK
    372                                 || transferBuf == nullptr
    373                                 || transferBuf->mMemory == nullptr) {
    374                             ALOGW("Failed to acquire shared memory, size %zu, ret %d",
    375                                     length, ret);
    376                             if (transferBuf != nullptr) {
    377                                 transferBuf->release();
    378                                 transferBuf = nullptr;
    379                             }
    380                             // Current buffer transmit inline; no more additional buffers.
    381                             maxNumBuffers = 0;
    382                         } else {
    383                             memcpy(transferBuf->data(), (uint8_t*)buf->data() + offset, length);
    384                             offset = 0;
    385                             if (!mGroup->has_buffers()) {
    386                                 maxNumBuffers = 0; // No more MediaBuffers, stop readMultiple.
    387                             }
    388                         }
    389                     }
    390                 }
    391                 if (transferBuf != nullptr) { // Using shared buffers.
    392                     if (!transferBuf->isObserved() && transferBuf != buf) {
    393                         // Transfer buffer must be part of a MediaBufferGroup.
    394                         ALOGV("adding shared memory buffer %p to local group", transferBuf);
    395                         mGroup->add_buffer(transferBuf);
    396                         transferBuf->add_ref(); // We have already acquired buffer.
    397                     }
    398                     uint64_t index = mIndexCache.lookup(transferBuf->mMemory);
    399                     if (index == 0) {
    400                         index = mIndexCache.insert(transferBuf->mMemory);
    401                         reply->writeInt32(SHARED_BUFFER);
    402                         reply->writeUint64(index);
    403                         reply->writeStrongBinder(IInterface::asBinder(transferBuf->mMemory));
    404                         ALOGV("SHARED_BUFFER(%p) %llu",
    405                                 transferBuf, (unsigned long long)index);
    406                     } else {
    407                         reply->writeInt32(SHARED_BUFFER_INDEX);
    408                         reply->writeUint64(index);
    409                         ALOGV("SHARED_BUFFER_INDEX(%p) %llu",
    410                                 transferBuf, (unsigned long long)index);
    411                     }
    412                     reply->writeInt32(offset);
    413                     reply->writeInt32(length);
    414                     buf->meta_data()->writeToParcel(*reply);
    415                     transferBuf->addRemoteRefcount(1);
    416                     if (transferBuf != buf) {
    417                         transferBuf->release(); // release local ref
    418                     } else if (!supportNonblockingRead()) {
    419                         maxNumBuffers = 0; // stop readMultiple with one shared buffer.
    420                     }
    421                 } else {
    422                     ALOGV_IF(buf->mMemory != nullptr,
    423                             "INLINE(%p) %zu shared mem available, but only %zu used",
    424                             buf, buf->mMemory->size(), length);
    425                     reply->writeInt32(INLINE_BUFFER);
    426                     reply->writeByteArray(length, (uint8_t*)buf->data() + offset);
    427                     buf->meta_data()->writeToParcel(*reply);
    428                     inlineTransferSize += length;
    429                     if (inlineTransferSize > kInlineMaxTransfer) {
    430                         maxNumBuffers = 0; // stop readMultiple if inline transfer is too large.
    431                     }
    432                 }
    433                 buf->release();
    434             }
    435             reply->writeInt32(NULL_BUFFER); // Indicate no more MediaBuffers.
    436             reply->writeInt32(ret);
    437             ALOGV("readMultiple status %d, bufferCount %u, sinceStop %u",
    438                     ret, bufferCount, mBuffersSinceStop);
    439             return NO_ERROR;
    440         }
    441         case SUPPORT_NONBLOCKING_READ: {
    442             ALOGV("supportNonblockingRead");
    443             CHECK_INTERFACE(IMediaSource, data, reply);
    444             reply->writeInt32((int32_t)supportNonblockingRead());
    445             return NO_ERROR;
    446         }
    447         default:
    448             return BBinder::onTransact(code, data, reply, flags);
    449     }
    450 }
    451 
    452 ////////////////////////////////////////////////////////////////////////////////
    453 
    454 IMediaSource::ReadOptions::ReadOptions() {
    455     reset();
    456 }
    457 
    458 void IMediaSource::ReadOptions::reset() {
    459     mOptions = 0;
    460     mSeekTimeUs = 0;
    461     mLatenessUs = 0;
    462     mNonBlocking = false;
    463 }
    464 
    465 void IMediaSource::ReadOptions::setNonBlocking() {
    466     mNonBlocking = true;
    467 }
    468 
    469 void IMediaSource::ReadOptions::clearNonBlocking() {
    470     mNonBlocking = false;
    471 }
    472 
    473 bool IMediaSource::ReadOptions::getNonBlocking() const {
    474     return mNonBlocking;
    475 }
    476 
    477 void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
    478     mOptions |= kSeekTo_Option;
    479     mSeekTimeUs = time_us;
    480     mSeekMode = mode;
    481 }
    482 
    483 void IMediaSource::ReadOptions::clearSeekTo() {
    484     mOptions &= ~kSeekTo_Option;
    485     mSeekTimeUs = 0;
    486     mSeekMode = SEEK_CLOSEST_SYNC;
    487 }
    488 
    489 bool IMediaSource::ReadOptions::getSeekTo(
    490         int64_t *time_us, SeekMode *mode) const {
    491     *time_us = mSeekTimeUs;
    492     *mode = mSeekMode;
    493     return (mOptions & kSeekTo_Option) != 0;
    494 }
    495 
    496 void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
    497     mLatenessUs = lateness_us;
    498 }
    499 
    500 int64_t IMediaSource::ReadOptions::getLateBy() const {
    501     return mLatenessUs;
    502 }
    503 
    504 
    505 }  // namespace android
    506 
    507