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,
     40     READMULTIPLE,
     41     RELEASE_BUFFER
     42 };
     43 
     44 enum {
     45     NULL_BUFFER,
     46     SHARED_BUFFER,
     47     INLINE_BUFFER
     48 };
     49 
     50 class RemoteMediaBufferReleaser : public BBinder {
     51 public:
     52     RemoteMediaBufferReleaser(MediaBuffer *buf, sp<BnMediaSource> owner) {
     53         mBuf = buf;
     54         mOwner = owner;
     55     }
     56     ~RemoteMediaBufferReleaser() {
     57         if (mBuf) {
     58             ALOGW("RemoteMediaBufferReleaser dtor called while still holding buffer");
     59             mBuf->release();
     60         }
     61     }
     62     virtual status_t    onTransact( uint32_t code,
     63                                     const Parcel& data,
     64                                     Parcel* reply,
     65                                     uint32_t flags = 0) {
     66         if (code == RELEASE_BUFFER) {
     67             mBuf->release();
     68             mBuf = NULL;
     69             return OK;
     70         } else {
     71             return BBinder::onTransact(code, data, reply, flags);
     72         }
     73     }
     74 private:
     75     MediaBuffer *mBuf;
     76     // Keep a ref to ensure MediaBuffer is released before the owner, i.e., BnMediaSource,
     77     // because BnMediaSource needs to delete MediaBufferGroup in its dtor and
     78     // MediaBufferGroup dtor requires all MediaBuffer's have 0 ref count.
     79     sp<BnMediaSource> mOwner;
     80 };
     81 
     82 
     83 class RemoteMediaBufferWrapper : public MediaBuffer {
     84 public:
     85     RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source);
     86 protected:
     87     virtual ~RemoteMediaBufferWrapper();
     88 private:
     89     sp<IMemory> mMemory;
     90     sp<IBinder> mRemoteSource;
     91 };
     92 
     93 RemoteMediaBufferWrapper::RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source)
     94 : MediaBuffer(mem->pointer(), mem->size()) {
     95     mMemory = mem;
     96     mRemoteSource = source;
     97 }
     98 
     99 RemoteMediaBufferWrapper::~RemoteMediaBufferWrapper() {
    100     mMemory.clear();
    101     // Explicitly ask the remote side to release the buffer. We could also just clear
    102     // mRemoteSource, but that doesn't immediately release the reference on the remote side.
    103     Parcel data, reply;
    104     mRemoteSource->transact(RELEASE_BUFFER, data, &reply);
    105     mRemoteSource.clear();
    106 }
    107 
    108 class BpMediaSource : public BpInterface<IMediaSource> {
    109 public:
    110     BpMediaSource(const sp<IBinder>& impl)
    111         : BpInterface<IMediaSource>(impl)
    112     {
    113     }
    114 
    115     virtual status_t start(MetaData *params) {
    116         ALOGV("start");
    117         Parcel data, reply;
    118         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
    119         if (params) {
    120             params->writeToParcel(data);
    121         }
    122         status_t ret = remote()->transact(START, data, &reply);
    123         if (ret == NO_ERROR && params) {
    124             ALOGW("ignoring potentially modified MetaData from start");
    125             ALOGW("input:");
    126             params->dumpToLog();
    127             sp<MetaData> meta = MetaData::createFromParcel(reply);
    128             ALOGW("output:");
    129             meta->dumpToLog();
    130         }
    131         return ret;
    132     }
    133 
    134     virtual status_t stop() {
    135         ALOGV("stop");
    136         Parcel data, reply;
    137         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
    138         return remote()->transact(STOP, data, &reply);
    139     }
    140 
    141     virtual sp<MetaData> getFormat() {
    142         ALOGV("getFormat");
    143         Parcel data, reply;
    144         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
    145         status_t ret = remote()->transact(GETFORMAT, data, &reply);
    146         if (ret == NO_ERROR) {
    147             mMetaData = MetaData::createFromParcel(reply);
    148             return mMetaData;
    149         }
    150         return NULL;
    151     }
    152 
    153     virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
    154         ALOGV("read");
    155         Parcel data, reply;
    156         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
    157         if (options) {
    158             data.writeByteArray(sizeof(*options), (uint8_t*) options);
    159         }
    160         status_t ret = remote()->transact(READ, data, &reply);
    161         if (ret != NO_ERROR) {
    162             return ret;
    163         }
    164         // wrap the returned data in a MediaBuffer
    165         ret = reply.readInt32();
    166         int32_t buftype = reply.readInt32();
    167         if (buftype == SHARED_BUFFER) {
    168             sp<IBinder> remote = reply.readStrongBinder();
    169             sp<IBinder> binder = reply.readStrongBinder();
    170             sp<IMemory> mem = interface_cast<IMemory>(binder);
    171             if (mem == NULL) {
    172                 ALOGE("received NULL IMemory for shared buffer");
    173             }
    174             size_t offset = reply.readInt32();
    175             size_t length = reply.readInt32();
    176             MediaBuffer *buf = new RemoteMediaBufferWrapper(mem, remote);
    177             buf->set_range(offset, length);
    178             buf->meta_data()->updateFromParcel(reply);
    179             *buffer = buf;
    180         } else if (buftype == NULL_BUFFER) {
    181             ALOGV("got status %d and NULL buffer", ret);
    182             *buffer = NULL;
    183         } else {
    184             int32_t len = reply.readInt32();
    185             ALOGV("got status %d and len %d", ret, len);
    186             *buffer = new MediaBuffer(len);
    187             reply.read((*buffer)->data(), len);
    188             (*buffer)->meta_data()->updateFromParcel(reply);
    189         }
    190         return ret;
    191     }
    192 
    193     virtual status_t readMultiple(Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers) {
    194         ALOGV("readMultiple");
    195         if (buffers == NULL || !buffers->isEmpty()) {
    196             return BAD_VALUE;
    197         }
    198         Parcel data, reply;
    199         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
    200         data.writeUint32(maxNumBuffers);
    201         status_t ret = remote()->transact(READMULTIPLE, data, &reply);
    202         if (ret != NO_ERROR) {
    203             return ret;
    204         }
    205         // wrap the returned data in a vector of MediaBuffers
    206         int32_t bufCount = 0;
    207         while (1) {
    208             if (reply.readInt32() == 0) {
    209                 break;
    210             }
    211             int32_t len = reply.readInt32();
    212             ALOGV("got len %d", len);
    213             MediaBuffer *buf = new MediaBuffer(len);
    214             reply.read(buf->data(), len);
    215             buf->meta_data()->updateFromParcel(reply);
    216             buffers->push_back(buf);
    217             ++bufCount;
    218         }
    219         ret = reply.readInt32();
    220         ALOGV("got status %d, bufCount %d", ret, bufCount);
    221         return ret;
    222     }
    223 
    224     virtual status_t pause() {
    225         ALOGV("pause");
    226         Parcel data, reply;
    227         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
    228         return remote()->transact(PAUSE, data, &reply);
    229     }
    230 
    231     virtual status_t setBuffers(const Vector<MediaBuffer *> & buffers __unused) {
    232         ALOGV("setBuffers NOT IMPLEMENTED");
    233         return ERROR_UNSUPPORTED; // default
    234     }
    235 
    236 private:
    237     // NuPlayer passes pointers-to-metadata around, so we use this to keep the metadata alive
    238     // XXX: could we use this for caching, or does metadata change on the fly?
    239     sp<MetaData> mMetaData;
    240 
    241 };
    242 
    243 IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
    244 
    245 #undef LOG_TAG
    246 #define LOG_TAG "BnMediaSource"
    247 
    248 BnMediaSource::BnMediaSource()
    249     : mGroup(NULL) {
    250 }
    251 
    252 BnMediaSource::~BnMediaSource() {
    253     delete mGroup;
    254     mGroup = NULL;
    255 }
    256 
    257 status_t BnMediaSource::onTransact(
    258     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    259 {
    260     switch (code) {
    261         case START: {
    262             ALOGV("start");
    263             CHECK_INTERFACE(IMediaSource, data, reply);
    264             sp<MetaData> meta;
    265             if (data.dataAvail()) {
    266                 meta = MetaData::createFromParcel(data);
    267             }
    268             status_t ret = start(meta.get());
    269             if (ret == NO_ERROR && meta != NULL) {
    270                 meta->writeToParcel(*reply);
    271             }
    272             return ret;
    273         }
    274         case STOP: {
    275             ALOGV("stop");
    276             CHECK_INTERFACE(IMediaSource, data, reply);
    277             return stop();
    278         }
    279         case PAUSE: {
    280             ALOGV("pause");
    281             CHECK_INTERFACE(IMediaSource, data, reply);
    282             return pause();
    283         }
    284         case GETFORMAT: {
    285             ALOGV("getFormat");
    286             CHECK_INTERFACE(IMediaSource, data, reply);
    287             sp<MetaData> meta = getFormat();
    288             if (meta != NULL) {
    289                 meta->writeToParcel(*reply);
    290                 return NO_ERROR;
    291             }
    292             return UNKNOWN_ERROR;
    293         }
    294         case READ: {
    295             ALOGV("read");
    296             CHECK_INTERFACE(IMediaSource, data, reply);
    297             status_t ret;
    298             MediaBuffer *buf = NULL;
    299             ReadOptions opts;
    300             uint32_t len;
    301             if (data.readUint32(&len) == NO_ERROR &&
    302                     len == sizeof(opts) && data.read((void*)&opts, len) == NO_ERROR) {
    303                 ret = read(&buf, &opts);
    304             } else {
    305                 ret = read(&buf, NULL);
    306             }
    307 
    308             reply->writeInt32(ret);
    309             if (buf != NULL) {
    310                 size_t usedSize = buf->range_length();
    311                 // even if we're using shared memory, we might not want to use it, since for small
    312                 // sizes it's faster to copy data through the Binder transaction
    313                 // On the other hand, if the data size is large enough, it's better to use shared
    314                 // memory. When data is too large, binder can't handle it.
    315                 if (usedSize >= MediaBuffer::kSharedMemThreshold) {
    316                     ALOGV("use shared memory: %zu", usedSize);
    317 
    318                     MediaBuffer *transferBuf = buf;
    319                     size_t offset = buf->range_offset();
    320                     if (transferBuf->mMemory == NULL) {
    321                         if (mGroup == NULL) {
    322                             mGroup = new MediaBufferGroup;
    323                             size_t allocateSize = usedSize;
    324                             if (usedSize < SIZE_MAX / 3) {
    325                                 allocateSize = usedSize * 3 / 2;
    326                             }
    327                             mGroup->add_buffer(new MediaBuffer(allocateSize));
    328                         }
    329 
    330                         MediaBuffer *newBuf = NULL;
    331                         ret = mGroup->acquire_buffer(
    332                                 &newBuf, false /* nonBlocking */, usedSize);
    333                         if (ret != OK || newBuf == NULL || newBuf->mMemory == NULL) {
    334                             ALOGW("failed to acquire shared memory, ret %d", ret);
    335                             buf->release();
    336                             if (newBuf != NULL) {
    337                                 newBuf->release();
    338                             }
    339                             reply->writeInt32(NULL_BUFFER);
    340                             return NO_ERROR;
    341                         }
    342                         transferBuf = newBuf;
    343                         memcpy(transferBuf->data(), (uint8_t*)buf->data() + buf->range_offset(),
    344                                 buf->range_length());
    345                         offset = 0;
    346                     }
    347 
    348                     reply->writeInt32(SHARED_BUFFER);
    349                     RemoteMediaBufferReleaser *wrapper =
    350                         new RemoteMediaBufferReleaser(transferBuf, this);
    351                     reply->writeStrongBinder(wrapper);
    352                     reply->writeStrongBinder(IInterface::asBinder(transferBuf->mMemory));
    353                     reply->writeInt32(offset);
    354                     reply->writeInt32(usedSize);
    355                     buf->meta_data()->writeToParcel(*reply);
    356                     if (buf->mMemory == NULL) {
    357                         buf->release();
    358                     }
    359                 } else {
    360                     // buffer is small: copy it
    361                     if (buf->mMemory != NULL) {
    362                         ALOGV("%zu shared mem available, but only %zu used", buf->mMemory->size(), buf->range_length());
    363                     }
    364                     reply->writeInt32(INLINE_BUFFER);
    365                     reply->writeByteArray(buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
    366                     buf->meta_data()->writeToParcel(*reply);
    367                     buf->release();
    368                 }
    369             } else {
    370                 ALOGV("ret %d, buf %p", ret, buf);
    371                 reply->writeInt32(NULL_BUFFER);
    372             }
    373             return NO_ERROR;
    374         }
    375         case READMULTIPLE: {
    376             ALOGV("readmultiple");
    377             CHECK_INTERFACE(IMediaSource, data, reply);
    378             uint32_t maxNumBuffers;
    379             data.readUint32(&maxNumBuffers);
    380             status_t ret = NO_ERROR;
    381             uint32_t bufferCount = 0;
    382             if (maxNumBuffers > kMaxNumReadMultiple) {
    383                 maxNumBuffers = kMaxNumReadMultiple;
    384             }
    385             while (bufferCount < maxNumBuffers) {
    386                 if (reply->dataSize() >= MediaBuffer::kSharedMemThreshold) {
    387                     break;
    388                 }
    389 
    390                 MediaBuffer *buf = NULL;
    391                 ret = read(&buf, NULL);
    392                 if (ret != NO_ERROR || buf == NULL) {
    393                     break;
    394                 }
    395                 ++bufferCount;
    396                 reply->writeInt32(1);  // indicate one more MediaBuffer.
    397                 reply->writeByteArray(
    398                         buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
    399                 buf->meta_data()->writeToParcel(*reply);
    400                 buf->release();
    401             }
    402             reply->writeInt32(0);  // indicate no more MediaBuffer.
    403             reply->writeInt32(ret);
    404             return NO_ERROR;
    405         }
    406         default:
    407             return BBinder::onTransact(code, data, reply, flags);
    408     }
    409 }
    410 
    411 ////////////////////////////////////////////////////////////////////////////////
    412 
    413 IMediaSource::ReadOptions::ReadOptions() {
    414     reset();
    415 }
    416 
    417 void IMediaSource::ReadOptions::reset() {
    418     mOptions = 0;
    419     mSeekTimeUs = 0;
    420     mLatenessUs = 0;
    421     mNonBlocking = false;
    422 }
    423 
    424 void IMediaSource::ReadOptions::setNonBlocking() {
    425     mNonBlocking = true;
    426 }
    427 
    428 void IMediaSource::ReadOptions::clearNonBlocking() {
    429     mNonBlocking = false;
    430 }
    431 
    432 bool IMediaSource::ReadOptions::getNonBlocking() const {
    433     return mNonBlocking;
    434 }
    435 
    436 void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
    437     mOptions |= kSeekTo_Option;
    438     mSeekTimeUs = time_us;
    439     mSeekMode = mode;
    440 }
    441 
    442 void IMediaSource::ReadOptions::clearSeekTo() {
    443     mOptions &= ~kSeekTo_Option;
    444     mSeekTimeUs = 0;
    445     mSeekMode = SEEK_CLOSEST_SYNC;
    446 }
    447 
    448 bool IMediaSource::ReadOptions::getSeekTo(
    449         int64_t *time_us, SeekMode *mode) const {
    450     *time_us = mSeekTimeUs;
    451     *mode = mSeekMode;
    452     return (mOptions & kSeekTo_Option) != 0;
    453 }
    454 
    455 void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
    456     mLatenessUs = lateness_us;
    457 }
    458 
    459 int64_t IMediaSource::ReadOptions::getLateBy() const {
    460     return mLatenessUs;
    461 }
    462 
    463 
    464 }  // namespace android
    465 
    466