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:
RemoteMediaBufferWrapper(const sp<IMemory> & mem)54 RemoteMediaBufferWrapper(const sp<IMemory> &mem)
55 : MediaBuffer(mem) {
56 ALOGV("RemoteMediaBufferWrapper: creating %p", this);
57 }
58
59 protected:
~RemoteMediaBufferWrapper()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:
BpMediaSource(const sp<IBinder> & impl)70 BpMediaSource(const sp<IBinder>& impl)
71 : BpInterface<IMediaSource>(impl), mBuffersSinceStop(0)
72 {
73 }
74
start(MetaData * params)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
stop()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
getFormat()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
read(MediaBuffer ** buffer,const ReadOptions * options)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
readMultiple(Vector<MediaBuffer * > * buffers,uint32_t maxNumBuffers,const ReadOptions * options)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.
supportReadMultiple()191 virtual bool supportReadMultiple() {
192 return true;
193 }
194
supportNonblockingRead()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
pause()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
setBuffers(const Vector<MediaBuffer * > & buffers __unused)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 {
lookupandroid::BpMediaSource::MemoryCache230 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
insertandroid::BpMediaSource::MemoryCache239 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
resetandroid::BpMediaSource::MemoryCache247 void reset() {
248 mIndexToMemory.clear();
249 }
250
gcandroid::BpMediaSource::MemoryCache251 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
BnMediaSource()271 BnMediaSource::BnMediaSource()
272 : mBuffersSinceStop(0)
273 , mGroup(new MediaBufferGroup(kBinderMediaBuffers /* growthLimit */)) {
274 }
275
~BnMediaSource()276 BnMediaSource::~BnMediaSource() {
277 }
278
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)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
ReadOptions()452 IMediaSource::ReadOptions::ReadOptions() {
453 reset();
454 }
455
reset()456 void IMediaSource::ReadOptions::reset() {
457 mOptions = 0;
458 mSeekTimeUs = 0;
459 mLatenessUs = 0;
460 mNonBlocking = false;
461 }
462
setNonBlocking()463 void IMediaSource::ReadOptions::setNonBlocking() {
464 mNonBlocking = true;
465 }
466
clearNonBlocking()467 void IMediaSource::ReadOptions::clearNonBlocking() {
468 mNonBlocking = false;
469 }
470
getNonBlocking() const471 bool IMediaSource::ReadOptions::getNonBlocking() const {
472 return mNonBlocking;
473 }
474
setSeekTo(int64_t time_us,SeekMode mode)475 void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
476 mOptions |= kSeekTo_Option;
477 mSeekTimeUs = time_us;
478 mSeekMode = mode;
479 }
480
clearSeekTo()481 void IMediaSource::ReadOptions::clearSeekTo() {
482 mOptions &= ~kSeekTo_Option;
483 mSeekTimeUs = 0;
484 mSeekMode = SEEK_CLOSEST_SYNC;
485 }
486
getSeekTo(int64_t * time_us,SeekMode * mode) const487 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
setLateBy(int64_t lateness_us)494 void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
495 mLatenessUs = lateness_us;
496 }
497
getLateBy() const498 int64_t IMediaSource::ReadOptions::getLateBy() const {
499 return mLatenessUs;
500 }
501
502
503 } // namespace android
504
505