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 READMULTIPLE, 41 RELEASE_BUFFER 42}; 43 44enum { 45 NULL_BUFFER, 46 SHARED_BUFFER, 47 INLINE_BUFFER 48}; 49 50class RemoteMediaBufferReleaser : public BBinder { 51public: 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 } 74private: 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 83class RemoteMediaBufferWrapper : public MediaBuffer { 84public: 85 RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source); 86protected: 87 virtual ~RemoteMediaBufferWrapper(); 88private: 89 sp<IMemory> mMemory; 90 sp<IBinder> mRemoteSource; 91}; 92 93RemoteMediaBufferWrapper::RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source) 94: MediaBuffer(mem->pointer(), mem->size()) { 95 mMemory = mem; 96 mRemoteSource = source; 97} 98 99RemoteMediaBufferWrapper::~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 108class BpMediaSource : public BpInterface<IMediaSource> { 109public: 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 236private: 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 243IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource"); 244 245#undef LOG_TAG 246#define LOG_TAG "BnMediaSource" 247 248BnMediaSource::BnMediaSource() 249 : mGroup(NULL) { 250} 251 252BnMediaSource::~BnMediaSource() { 253 delete mGroup; 254 mGroup = NULL; 255} 256 257status_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 413IMediaSource::ReadOptions::ReadOptions() { 414 reset(); 415} 416 417void IMediaSource::ReadOptions::reset() { 418 mOptions = 0; 419 mSeekTimeUs = 0; 420 mLatenessUs = 0; 421 mNonBlocking = false; 422} 423 424void IMediaSource::ReadOptions::setNonBlocking() { 425 mNonBlocking = true; 426} 427 428void IMediaSource::ReadOptions::clearNonBlocking() { 429 mNonBlocking = false; 430} 431 432bool IMediaSource::ReadOptions::getNonBlocking() const { 433 return mNonBlocking; 434} 435 436void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) { 437 mOptions |= kSeekTo_Option; 438 mSeekTimeUs = time_us; 439 mSeekMode = mode; 440} 441 442void IMediaSource::ReadOptions::clearSeekTo() { 443 mOptions &= ~kSeekTo_Option; 444 mSeekTimeUs = 0; 445 mSeekMode = SEEK_CLOSEST_SYNC; 446} 447 448bool 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 455void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) { 456 mLatenessUs = lateness_us; 457} 458 459int64_t IMediaSource::ReadOptions::getLateBy() const { 460 return mLatenessUs; 461} 462 463 464} // namespace android 465 466