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