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/include/media/IMediaSource.h b/include/media/IMediaSource.h
index f7586a7..709f425 100644
--- a/include/media/IMediaSource.h
+++ b/include/media/IMediaSource.h
@@ -32,6 +32,11 @@
public:
DECLARE_META_INTERFACE(MediaSource);
+ enum {
+ // Maximum number of buffers would be read in readMultiple.
+ kMaxNumReadMultiple = 128,
+ };
+
// To be called before any other methods on this object, except
// getFormat().
virtual status_t start(MetaData *params = NULL) = 0;
@@ -87,7 +92,7 @@
};
// Returns a new buffer of data. Call blocks until a
- // buffer is available, an error is encountered of the end of the stream
+ // buffer is available, an error is encountered or the end of the stream
// is reached.
// End of stream is signalled by a result of ERROR_END_OF_STREAM.
// A result of INFO_FORMAT_CHANGED indicates that the format of this
@@ -96,6 +101,19 @@
virtual status_t read(
MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
+ // Returns a vector of new buffers of data. The vector size could be
+ // <= |maxNumBuffers|. Used for buffers with small size
+ // since all buffer data are passed back by binder, not shared memory.
+ // Call blocks until an error is encountered, or the end of the stream is
+ // reached, or format change is hit, or |kMaxNumReadMultiple| buffers have
+ // been read.
+ // End of stream is signalled by a result of ERROR_END_OF_STREAM.
+ // A result of INFO_FORMAT_CHANGED indicates that the format of this
+ // MediaSource has changed mid-stream, the client can continue reading
+ // but should be prepared for buffers of the new configuration.
+ virtual status_t readMultiple(
+ Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers = 1) = 0;
+
// Causes this source to suspend pulling data from its upstream source
// until a subsequent read-with-seek. Currently only supported by
// OMXCodec.
@@ -126,6 +144,10 @@
return ERROR_UNSUPPORTED;
}
+ virtual status_t readMultiple(
+ Vector<MediaBuffer *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */) {
+ return ERROR_UNSUPPORTED;
+ }
protected:
virtual ~BnMediaSource();
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;