IMediaSource: add readMultiple API to speed up inter-process reading.

GenericSource: use readMultiple for audio track.
Bug: 28545177
Bug: 22775369
Change-Id: If26b80e75eba4212105d51140c4bfce85ec664f8
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index 84f1181..7e40e4f 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -37,6 +37,7 @@
     PAUSE,
     GETFORMAT,
     READ,
+    READMULTIPLE,
     RELEASE_BUFFER
 };
 
@@ -189,6 +190,37 @@
         return ret;
     }
 
+    virtual status_t readMultiple(Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers) {
+        ALOGV("readMultiple");
+        if (buffers == NULL || !buffers->isEmpty()) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+        data.writeUint32(maxNumBuffers);
+        status_t ret = remote()->transact(READMULTIPLE, data, &reply);
+        if (ret != NO_ERROR) {
+            return ret;
+        }
+        // wrap the returned data in a vector of MediaBuffers
+        int32_t bufCount = 0;
+        while (1) {
+            if (reply.readInt32() == 0) {
+                break;
+            }
+            int32_t len = reply.readInt32();
+            ALOGV("got len %d", len);
+            MediaBuffer *buf = new MediaBuffer(len);
+            reply.read(buf->data(), len);
+            buf->meta_data()->updateFromParcel(reply);
+            buffers->push_back(buf);
+            ++bufCount;
+        }
+        ret = reply.readInt32();
+        ALOGV("got status %d, bufCount %d", ret, bufCount);
+        return ret;
+    }
+
     virtual status_t pause() {
         ALOGV("pause");
         Parcel data, reply;
@@ -340,6 +372,37 @@
             }
             return NO_ERROR;
         }
+        case READMULTIPLE: {
+            ALOGV("readmultiple");
+            CHECK_INTERFACE(IMediaSource, data, reply);
+            uint32_t maxNumBuffers;
+            data.readUint32(&maxNumBuffers);
+            status_t ret = NO_ERROR;
+            uint32_t bufferCount = 0;
+            if (maxNumBuffers > kMaxNumReadMultiple) {
+                maxNumBuffers = kMaxNumReadMultiple;
+            }
+            while (bufferCount < maxNumBuffers) {
+                if (reply->dataSize() >= MediaBuffer::kSharedMemThreshold) {
+                    break;
+                }
+
+                MediaBuffer *buf = NULL;
+                ret = read(&buf, NULL);
+                if (ret != NO_ERROR || buf == NULL) {
+                    break;
+                }
+                ++bufferCount;
+                reply->writeInt32(1);  // indicate one more MediaBuffer.
+                reply->writeByteArray(
+                        buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
+                buf->meta_data()->writeToParcel(*reply);
+                buf->release();
+            }
+            reply->writeInt32(0);  // indicate no more MediaBuffer.
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 9e33cb5..56042d4 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -1420,14 +1420,28 @@
         options.setNonBlocking();
     }
 
+    bool couldReadMultiple = (!mIsWidevine && trackType == MEDIA_TRACK_TYPE_AUDIO);
     for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
-        MediaBuffer *mbuf;
-        status_t err = track->mSource->read(&mbuf, &options);
+        Vector<MediaBuffer *> mediaBuffers;
+        status_t err = NO_ERROR;
+
+        if (!seeking && couldReadMultiple) {
+            err = track->mSource->readMultiple(&mediaBuffers, (maxBuffers - numBuffers));
+        } else {
+            MediaBuffer *mbuf = NULL;
+            err = track->mSource->read(&mbuf, &options);
+            if (err == OK && mbuf != NULL) {
+                mediaBuffers.push_back(mbuf);
+            }
+        }
 
         options.clearSeekTo();
 
-        if (err == OK) {
+        size_t id = 0;
+        size_t count = mediaBuffers.size();
+        for (; id < count; ++id) {
             int64_t timeUs;
+            MediaBuffer *mbuf = mediaBuffers[id];
             if (!mbuf->meta_data()->findInt64(kKeyTime, &timeUs)) {
                 mbuf->meta_data()->dumpToLog();
                 track->mPackets->signalEOS(ERROR_MALFORMED);
@@ -1450,7 +1464,16 @@
             formatChange = false;
             seeking = false;
             ++numBuffers;
-        } else if (err == WOULD_BLOCK) {
+        }
+        if (id < count) {
+            // Error, some mediaBuffer doesn't have kKeyTime.
+            for (; id < count; ++id) {
+                mediaBuffers[id]->release();
+            }
+            break;
+        }
+
+        if (err == WOULD_BLOCK) {
             break;
         } else if (err == INFO_FORMAT_CHANGED) {
 #if 0
@@ -1459,7 +1482,7 @@
                     NULL,
                     false /* discard */);
 #endif
-        } else {
+        } else if (err != OK) {
             queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
             track->mPackets->signalEOS(err);
             break;