GenericSource: Allow multiple buffer reads for video

Bug: 29125703
Change-Id: I23490a65ad3968d7be561805c9fa742320b5c78a
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index 2adce19..dd94ccf 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -38,7 +38,8 @@
     GETFORMAT,
     // READ, deprecated
     READMULTIPLE,
-    RELEASE_BUFFER
+    RELEASE_BUFFER,
+    SUPPORT_NONBLOCKING_READ,
 };
 
 enum {
@@ -186,10 +187,22 @@
         return ret;
     }
 
-    bool supportReadMultiple() {
+    // Binder proxy adds readMultiple support.
+    virtual bool supportReadMultiple() {
         return true;
     }
 
+    virtual bool supportNonblockingRead() {
+        ALOGV("supportNonblockingRead");
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+        status_t ret = remote()->transact(SUPPORT_NONBLOCKING_READ, data, &reply);
+        if (ret == NO_ERROR) {
+            return reply.readInt32() != 0;
+        }
+        return false;
+    }
+
     virtual status_t pause() {
         ALOGV("pause");
         Parcel data, reply;
@@ -325,6 +338,7 @@
 
             mGroup->gc(kBinderMediaBuffers /* freeBuffers */);
             mIndexCache.gc();
+            size_t inlineTransferSize = 0;
             status_t ret = NO_ERROR;
             uint32_t bufferCount = 0;
             for (; bufferCount < maxNumBuffers; ++bufferCount, ++mBuffersSinceStop) {
@@ -344,7 +358,8 @@
                 MediaBuffer *transferBuf = nullptr;
                 const size_t length = buf->range_length();
                 size_t offset = buf->range_offset();
-                if (length >= MediaBuffer::kSharedMemThreshold) {
+                if (length >= (supportNonblockingRead() && buf->mMemory != nullptr ?
+                        kTransferSharedAsSharedThreshold : kTransferInlineAsSharedThreshold)) {
                     if (buf->mMemory != nullptr) {
                         ALOGV("Use shared memory: %zu", length);
                         transferBuf = buf;
@@ -366,6 +381,9 @@
                         } else {
                             memcpy(transferBuf->data(), (uint8_t*)buf->data() + offset, length);
                             offset = 0;
+                            if (!mGroup->has_buffers()) {
+                                maxNumBuffers = 0; // No more MediaBuffers, stop readMultiple.
+                            }
                         }
                     }
                 }
@@ -395,6 +413,8 @@
                     buf->meta_data()->writeToParcel(*reply);
                     if (transferBuf != buf) {
                         buf->release();
+                    } else if (!supportNonblockingRead()) {
+                        maxNumBuffers = 0; // stop readMultiple with one shared buffer.
                     }
                 } else {
                     ALOGV_IF(buf->mMemory != nullptr,
@@ -404,6 +424,10 @@
                     reply->writeByteArray(length, (uint8_t*)buf->data() + offset);
                     buf->meta_data()->writeToParcel(*reply);
                     buf->release();
+                    inlineTransferSize += length;
+                    if (inlineTransferSize > kInlineMaxTransfer) {
+                        maxNumBuffers = 0; // stop readMultiple if inline transfer is too large.
+                    }
                 }
             }
             reply->writeInt32(NULL_BUFFER); // Indicate no more MediaBuffers.
@@ -412,6 +436,12 @@
                     ret, bufferCount, mBuffersSinceStop);
             return NO_ERROR;
         }
+        case SUPPORT_NONBLOCKING_READ: {
+            ALOGV("supportNonblockingRead");
+            CHECK_INTERFACE(IMediaSource, data, reply);
+            reply->writeInt32((int32_t)supportNonblockingRead());
+            return NO_ERROR;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }