Merge "Add caching mechanism to speed up midi file reading speed." am: 145a0becf0 am: be670f474b

Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/1429788

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Id5a6ebfb5f08180cad4657c256ad152a5390d936
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
index da272e3..f682b6e 100644
--- a/media/libmedia/MidiIoWrapper.cpp
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -21,6 +21,7 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <algorithm>
 
 #include <media/MidiIoWrapper.h>
 #include <media/MediaExtractorPluginApi.h>
@@ -33,6 +34,8 @@
 }
 
 namespace android {
+int MidiIoWrapper::sCacheBufferSize = 0;
+Mutex MidiIoWrapper::mCacheLock;
 
 MidiIoWrapper::MidiIoWrapper(const char *path) {
     ALOGV("MidiIoWrapper(%s)", path);
@@ -40,6 +43,8 @@
     mBase = 0;
     mLength = lseek(mFd, 0, SEEK_END);
     mDataSource = nullptr;
+    mCacheBuffer = NULL;
+    mCacheBufRangeLength = 0;
 }
 
 MidiIoWrapper::MidiIoWrapper(int fd, off64_t offset, int64_t size) {
@@ -48,6 +53,8 @@
     mBase = offset;
     mLength = size;
     mDataSource = nullptr;
+    mCacheBuffer = NULL;
+    mCacheBufRangeLength = 0;
 }
 
 class MidiIoWrapper::DataSourceUnwrapper {
@@ -97,6 +104,8 @@
     } else {
         mLength = 0;
     }
+    mCacheBuffer = NULL;
+    mCacheBufRangeLength = 0;
 }
 
 MidiIoWrapper::~MidiIoWrapper() {
@@ -105,11 +114,80 @@
         close(mFd);
     }
     delete mDataSource;
+
+    if (NULL != mCacheBuffer) {
+        delete [] mCacheBuffer;
+        mCacheBuffer = NULL;
+        {
+            Mutex::Autolock _l(mCacheLock);
+            sCacheBufferSize -= mLength;
+        }
+    }
 }
 
 int MidiIoWrapper::readAt(void *buffer, int offset, int size) {
     ALOGV("readAt(%p, %d, %d)", buffer, offset, size);
 
+    if (offset < 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    if (offset + size > mLength) {
+        size = mLength - offset;
+    }
+
+    if (mCacheBuffer == NULL) {
+        Mutex::Autolock _l(mCacheLock);
+        if (sCacheBufferSize + mLength <= kTotalCacheSize) {
+            mCacheBuffer = new (std::nothrow) unsigned char[mLength];
+            if (NULL != mCacheBuffer) {
+                sCacheBufferSize += mLength;
+                ALOGV("sCacheBufferSize : %d", sCacheBufferSize);
+            } else {
+                ALOGE("failed to allocate memory for mCacheBuffer");
+            }
+        } else {
+            ALOGV("not allocate memory for mCacheBuffer");
+        }
+    }
+
+    if (mCacheBuffer != NULL) {
+        if (mCacheBufRangeLength > 0 && mCacheBufRangeLength >= (offset + size)) {
+            /* Use buffered data */
+            memcpy(buffer, (void*)(mCacheBuffer + offset), size);
+            return size;
+        } else {
+            /* Buffer new data */
+            int64_t beyondCacheBufRangeLength = (offset + size) - mCacheBufRangeLength;
+            int64_t numRequiredBytesToCache =
+                  std::max((int64_t)kSingleCacheSize, beyondCacheBufRangeLength);
+            int64_t availableReadLength = mLength - mCacheBufRangeLength;
+            int64_t readSize = std::min(availableReadLength, numRequiredBytesToCache);
+            int actualNumBytesRead =
+                unbufferedReadAt(mCacheBuffer + mCacheBufRangeLength,
+                        mCacheBufRangeLength, readSize);
+            if(actualNumBytesRead > 0) {
+                mCacheBufRangeLength += actualNumBytesRead;
+                if (offset >= mCacheBufRangeLength) {
+                    return 0;
+                } else if (offset + size >= mCacheBufRangeLength) {
+                    memcpy(buffer, (void*)(mCacheBuffer + offset), mCacheBufRangeLength - offset);
+                    return mCacheBufRangeLength - offset;
+                } else {
+                    memcpy(buffer, (void*)(mCacheBuffer + offset), size);
+                    return size;
+                }
+            } else {
+                return actualNumBytesRead;
+            }
+        }
+    } else {
+        return unbufferedReadAt(buffer, offset, size);
+    }
+}
+
+int MidiIoWrapper::unbufferedReadAt(void *buffer, int offset, int size) {
+    ALOGV("unbufferedReadAt(%p, %d, %d)", buffer, offset, size);
     if (mDataSource != NULL) {
         return mDataSource->readAt(offset, buffer, size);
     }
diff --git a/media/libmedia/include/media/MidiIoWrapper.h b/media/libmedia/include/media/MidiIoWrapper.h
index 0cdd4ad..5fa745c 100644
--- a/media/libmedia/include/media/MidiIoWrapper.h
+++ b/media/libmedia/include/media/MidiIoWrapper.h
@@ -18,6 +18,7 @@
 #define MIDI_IO_WRAPPER_H_
 
 #include <libsonivox/eas_types.h>
+#include <utils/Mutex.h>
 
 namespace android {
 
@@ -32,17 +33,27 @@
     ~MidiIoWrapper();
 
     int readAt(void *buffer, int offset, int size);
+    int unbufferedReadAt(void *buffer, int offset, int size);
     int size();
 
     EAS_FILE_LOCATOR getLocator();
 
 private:
+    enum {
+        kTotalCacheSize      = 1024 * 1024 + 512 * 1024,
+        kSingleCacheSize     = 65536,
+    };
+
     int mFd;
     off64_t mBase;
     int64_t  mLength;
     class DataSourceUnwrapper;
     DataSourceUnwrapper *mDataSource;
     EAS_FILE mEasFile;
+    unsigned char *mCacheBuffer;
+    int64_t mCacheBufRangeLength;
+    static int sCacheBufferSize;
+    static Mutex mCacheLock;
 };