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 // Release our interest in the MediaBuffer's shared memory.
62 int32_t old = addRemoteRefcount(-1);
63 ALOGV("RemoteMediaBufferWrapper: releasing %p, refcount %d", this, old - 1);
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 explicit 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 AutoMutex _l(mBpLock);
111 mMetaData = MetaData::createFromParcel(reply);
112 return mMetaData;
113 }
114 return NULL;
115 }
116
read(MediaBufferBase ** buffer,const MediaSource::ReadOptions * options)117 virtual status_t read(MediaBufferBase **buffer,
118 const MediaSource::ReadOptions *options) {
119 Vector<MediaBufferBase *> buffers;
120 status_t ret = readMultiple(&buffers, 1 /* maxNumBuffers */, options);
121 *buffer = buffers.size() == 0 ? nullptr : buffers[0];
122 ALOGV("read status %d, bufferCount %u, sinceStop %u",
123 ret, *buffer != nullptr, mBuffersSinceStop);
124 return ret;
125 }
126
readMultiple(Vector<MediaBufferBase * > * buffers,uint32_t maxNumBuffers,const MediaSource::ReadOptions * options)127 virtual status_t readMultiple(
128 Vector<MediaBufferBase *> *buffers, uint32_t maxNumBuffers,
129 const MediaSource::ReadOptions *options) {
130 ALOGV("readMultiple");
131 if (buffers == NULL || !buffers->isEmpty()) {
132 return BAD_VALUE;
133 }
134 Parcel data, reply;
135 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
136 data.writeUint32(maxNumBuffers);
137 if (options != nullptr) {
138 data.writeByteArray(sizeof(*options), (uint8_t*) options);
139 }
140 status_t ret = remote()->transact(READMULTIPLE, data, &reply);
141 mMemoryCache.gc();
142 if (ret != NO_ERROR) {
143 return ret;
144 }
145 // wrap the returned data in a vector of MediaBuffers
146 int32_t buftype;
147 uint32_t bufferCount = 0;
148 while ((buftype = reply.readInt32()) != NULL_BUFFER) {
149 LOG_ALWAYS_FATAL_IF(bufferCount >= maxNumBuffers,
150 "Received %u+ buffers and requested %u buffers",
151 bufferCount + 1, maxNumBuffers);
152 MediaBuffer *buf;
153 if (buftype == SHARED_BUFFER || buftype == SHARED_BUFFER_INDEX) {
154 uint64_t index = reply.readUint64();
155 ALOGV("Received %s index %llu",
156 buftype == SHARED_BUFFER ? "SHARED_BUFFER" : "SHARED_BUFFER_INDEX",
157 (unsigned long long) index);
158 sp<IMemory> mem;
159 if (buftype == SHARED_BUFFER) {
160 sp<IBinder> binder = reply.readStrongBinder();
161 mem = interface_cast<IMemory>(binder);
162 LOG_ALWAYS_FATAL_IF(mem.get() == nullptr,
163 "Received NULL IMemory for shared buffer");
164 mMemoryCache.insert(index, mem);
165 } else {
166 mem = mMemoryCache.lookup(index);
167 LOG_ALWAYS_FATAL_IF(mem.get() == nullptr,
168 "Received invalid IMemory index for shared buffer: %llu",
169 (unsigned long long)index);
170 }
171 size_t offset = reply.readInt32();
172 size_t length = reply.readInt32();
173 buf = new RemoteMediaBufferWrapper(mem);
174 buf->set_range(offset, length);
175 buf->meta_data().updateFromParcel(reply);
176 } else { // INLINE_BUFFER
177 int32_t len = reply.readInt32();
178 ALOGV("INLINE_BUFFER status %d and len %d", ret, len);
179 buf = new MediaBuffer(len);
180 reply.read(buf->data(), len);
181 buf->meta_data().updateFromParcel(reply);
182 }
183 buffers->push_back(buf);
184 ++bufferCount;
185 ++mBuffersSinceStop;
186 }
187 ret = reply.readInt32();
188 ALOGV("readMultiple status %d, bufferCount %u, sinceStop %u",
189 ret, bufferCount, mBuffersSinceStop);
190 if (bufferCount && ret == WOULD_BLOCK) {
191 ret = OK;
192 }
193 return ret;
194 }
195
196 // Binder proxy adds readMultiple support.
supportReadMultiple()197 virtual bool supportReadMultiple() {
198 return true;
199 }
200
supportNonblockingRead()201 virtual bool supportNonblockingRead() {
202 ALOGV("supportNonblockingRead");
203 Parcel data, reply;
204 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
205 status_t ret = remote()->transact(SUPPORT_NONBLOCKING_READ, data, &reply);
206 if (ret == NO_ERROR) {
207 return reply.readInt32() != 0;
208 }
209 return false;
210 }
211
pause()212 virtual status_t pause() {
213 ALOGV("pause");
214 Parcel data, reply;
215 data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
216 return remote()->transact(PAUSE, data, &reply);
217 }
218
219 private:
220
221 uint32_t mBuffersSinceStop; // Buffer tracking variable
222
223 // NuPlayer passes pointers-to-metadata around, so we use this to keep the metadata alive
224 // XXX: could we use this for caching, or does metadata change on the fly?
225 sp<MetaData> mMetaData;
226 // ensure synchronize access to mMetaData
227 Mutex mBpLock;
228
229 // Cache all IMemory objects received from MediaExtractor.
230 // We gc IMemory objects that are no longer active (referenced by a MediaBuffer).
231
232 struct MemoryCache {
lookupandroid::BpMediaSource::MemoryCache233 sp<IMemory> lookup(uint64_t index) {
234 auto p = mIndexToMemory.find(index);
235 if (p == mIndexToMemory.end()) {
236 ALOGE("cannot find index!");
237 return nullptr;
238 }
239 return p->second;
240 }
241
insertandroid::BpMediaSource::MemoryCache242 void insert(uint64_t index, const sp<IMemory> &mem) {
243 if (mIndexToMemory.find(index) != mIndexToMemory.end()) {
244 ALOGE("index %llu already present", (unsigned long long)index);
245 return;
246 }
247 (void)mIndexToMemory.emplace(index, mem);
248 }
249
resetandroid::BpMediaSource::MemoryCache250 void reset() {
251 mIndexToMemory.clear();
252 }
253
gcandroid::BpMediaSource::MemoryCache254 void gc() {
255 for (auto it = mIndexToMemory.begin(); it != mIndexToMemory.end(); ) {
256 if (MediaBuffer::isDeadObject(it->second)) {
257 it = mIndexToMemory.erase(it);
258 } else {
259 ++it;
260 }
261 }
262 }
263 private:
264 // C++14 unordered_map erase on iterator is stable; C++11 has no guarantee.
265 std::map<uint64_t, sp<IMemory>> mIndexToMemory;
266 } mMemoryCache;
267 };
268
269 IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
270
271 #undef LOG_TAG
272 #define LOG_TAG "BnMediaSource"
273
BnMediaSource()274 BnMediaSource::BnMediaSource()
275 : mBuffersSinceStop(0)
276 , mGroup(new MediaBufferGroup(kBinderMediaBuffers /* growthLimit */)) {
277 }
278
~BnMediaSource()279 BnMediaSource::~BnMediaSource() {
280 }
281
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)282 status_t BnMediaSource::onTransact(
283 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
284 {
285 switch (code) {
286 case START: {
287 ALOGV("start");
288 CHECK_INTERFACE(IMediaSource, data, reply);
289 sp<MetaData> meta;
290 if (data.dataAvail()) {
291 meta = MetaData::createFromParcel(data);
292 }
293 status_t ret = start(meta.get());
294 if (ret == NO_ERROR && meta != NULL) {
295 meta->writeToParcel(*reply);
296 }
297 return ret;
298 }
299 case STOP: {
300 ALOGV("stop");
301 CHECK_INTERFACE(IMediaSource, data, reply);
302 mGroup->signalBufferReturned(nullptr);
303 status_t status = stop();
304 AutoMutex _l(mBnLock);
305 mIndexCache.reset();
306 mBuffersSinceStop = 0;
307 return status;
308 }
309 case PAUSE: {
310 ALOGV("pause");
311 CHECK_INTERFACE(IMediaSource, data, reply);
312 mGroup->signalBufferReturned(nullptr);
313 return pause();
314 }
315 case GETFORMAT: {
316 ALOGV("getFormat");
317 CHECK_INTERFACE(IMediaSource, data, reply);
318 sp<MetaData> meta = getFormat();
319 if (meta != NULL) {
320 meta->writeToParcel(*reply);
321 return NO_ERROR;
322 }
323 return UNKNOWN_ERROR;
324 }
325 case READMULTIPLE: {
326 ALOGV("readMultiple");
327 CHECK_INTERFACE(IMediaSource, data, reply);
328
329 // Get max number of buffers to read.
330 uint32_t maxNumBuffers;
331 data.readUint32(&maxNumBuffers);
332 if (maxNumBuffers > kMaxNumReadMultiple) {
333 maxNumBuffers = kMaxNumReadMultiple;
334 }
335
336 // Get read options, if any.
337 MediaSource::ReadOptions opts;
338 uint32_t len;
339 const bool useOptions =
340 data.readUint32(&len) == NO_ERROR
341 && len == sizeof(opts)
342 && data.read((void *)&opts, len) == NO_ERROR;
343
344 AutoMutex _l(mBnLock);
345 mGroup->signalBufferReturned(nullptr);
346 mIndexCache.gc();
347 size_t inlineTransferSize = 0;
348 status_t ret = NO_ERROR;
349 uint32_t bufferCount = 0;
350 for (; bufferCount < maxNumBuffers; ++bufferCount, ++mBuffersSinceStop) {
351 MediaBuffer *buf = nullptr;
352 ret = read((MediaBufferBase **)&buf, useOptions ? &opts : nullptr);
353 opts.clearNonPersistent(); // Remove options that only apply to first buffer.
354 if (ret != NO_ERROR || buf == nullptr) {
355 break;
356 }
357
358 // Even if we're using shared memory, we might not want to use it, since for small
359 // sizes it's faster to copy data through the Binder transaction
360 // On the other hand, if the data size is large enough, it's better to use shared
361 // memory. When data is too large, binder can't handle it.
362 //
363 // TODO: reduce MediaBuffer::kSharedMemThreshold
364 MediaBuffer *transferBuf = nullptr;
365 const size_t length = buf->range_length();
366 size_t offset = buf->range_offset();
367 if (length >= (supportNonblockingRead() && buf->mMemory != nullptr ?
368 kTransferSharedAsSharedThreshold : kTransferInlineAsSharedThreshold)) {
369 if (buf->mMemory != nullptr) {
370 ALOGV("Use shared memory: %zu", length);
371 transferBuf = buf;
372 } else {
373 ALOGV("Large buffer %zu without IMemory!", length);
374 ret = mGroup->acquire_buffer(
375 (MediaBufferBase **)&transferBuf, false /* nonBlocking */, length);
376 if (ret != OK
377 || transferBuf == nullptr
378 || transferBuf->mMemory == nullptr) {
379 ALOGV("Failed to acquire shared memory, size %zu, ret %d",
380 length, ret);
381 if (transferBuf != nullptr) {
382 transferBuf->release();
383 transferBuf = nullptr;
384 }
385 // Current buffer transmit inline; no more additional buffers.
386 maxNumBuffers = 0;
387 } else {
388 memcpy(transferBuf->data(), (uint8_t*)buf->data() + offset, length);
389 offset = 0;
390 if (!mGroup->has_buffers()) {
391 maxNumBuffers = 0; // No more MediaBuffers, stop readMultiple.
392 }
393 }
394 }
395 }
396 if (transferBuf != nullptr) { // Using shared buffers.
397 if (!transferBuf->isObserved() && transferBuf != buf) {
398 // Transfer buffer must be part of a MediaBufferGroup.
399 ALOGV("adding shared memory buffer %p to local group", transferBuf);
400 mGroup->add_buffer(transferBuf);
401 transferBuf->add_ref(); // We have already acquired buffer.
402 }
403 uint64_t index = mIndexCache.lookup(transferBuf->mMemory);
404 if (index == 0) {
405 index = mIndexCache.insert(transferBuf->mMemory);
406 reply->writeInt32(SHARED_BUFFER);
407 reply->writeUint64(index);
408 reply->writeStrongBinder(IInterface::asBinder(transferBuf->mMemory));
409 ALOGV("SHARED_BUFFER(%p) %llu",
410 transferBuf, (unsigned long long)index);
411 } else {
412 reply->writeInt32(SHARED_BUFFER_INDEX);
413 reply->writeUint64(index);
414 ALOGV("SHARED_BUFFER_INDEX(%p) %llu",
415 transferBuf, (unsigned long long)index);
416 }
417 reply->writeInt32(offset);
418 reply->writeInt32(length);
419 buf->meta_data().writeToParcel(*reply);
420 transferBuf->addRemoteRefcount(1);
421 if (transferBuf != buf) {
422 transferBuf->release(); // release local ref
423 } else if (!supportNonblockingRead()) {
424 maxNumBuffers = 0; // stop readMultiple with one shared buffer.
425 }
426 } else {
427 ALOGV_IF(buf->mMemory != nullptr,
428 "INLINE(%p) %zu shared mem available, but only %zu used",
429 buf, buf->mMemory->size(), length);
430 reply->writeInt32(INLINE_BUFFER);
431 reply->writeByteArray(length, (uint8_t*)buf->data() + offset);
432 buf->meta_data().writeToParcel(*reply);
433 inlineTransferSize += length;
434 if (inlineTransferSize > kInlineMaxTransfer) {
435 maxNumBuffers = 0; // stop readMultiple if inline transfer is too large.
436 }
437 }
438 buf->release();
439 }
440 reply->writeInt32(NULL_BUFFER); // Indicate no more MediaBuffers.
441 reply->writeInt32(ret);
442 ALOGV("readMultiple status %d, bufferCount %u, sinceStop %u",
443 ret, bufferCount, mBuffersSinceStop);
444 return NO_ERROR;
445 }
446 case SUPPORT_NONBLOCKING_READ: {
447 ALOGV("supportNonblockingRead");
448 CHECK_INTERFACE(IMediaSource, data, reply);
449 reply->writeInt32((int32_t)supportNonblockingRead());
450 return NO_ERROR;
451 }
452 default:
453 return BBinder::onTransact(code, data, reply, flags);
454 }
455 }
456
457 } // namespace android
458
459