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