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