Camera3: Implement dynamic buffer un-mapping

 Every output buffer by framework should
 be subsequently un-mapped before it
 returns to client. Both camera backend
 needs to be notified and ION resources
 need to be released.

Bug: 19674986
Change-Id: I0ffe789b3392c2948584f56a561fac3f086e2a6e
diff --git a/camera/QCamera2/HAL3/QCamera3Channel.cpp b/camera/QCamera2/HAL3/QCamera3Channel.cpp
index 6b09df9..753d1c1 100644
--- a/camera/QCamera2/HAL3/QCamera3Channel.cpp
+++ b/camera/QCamera2/HAL3/QCamera3Channel.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2012-2015, The Linux Foundataion. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -799,6 +799,11 @@
     int32_t resultFrameNumber;
     camera3_stream_buffer_t result;
 
+    if (NULL == stream) {
+        ALOGE("%s: Invalid stream", __func__);
+        return;
+    }
+
     if(!super_frame) {
          ALOGE("%s: Invalid Super buffer",__func__);
          return;
@@ -817,9 +822,7 @@
     frameIndex = (uint8_t)super_frame->bufs[0]->buf_idx;
     if(frameIndex >= mNumBufs) {
          ALOGE("%s: Error, Invalid index for buffer",__func__);
-         if(stream) {
-             stream->bufDone(frameIndex);
-         }
+         stream->bufDone(frameIndex);
          return;
     }
 
@@ -832,6 +835,17 @@
     result.status = CAMERA3_BUFFER_STATUS_OK;
     result.acquire_fence = -1;
     result.release_fence = -1;
+    int32_t rc = stream->bufRelease(frameIndex);
+    if (NO_ERROR != rc) {
+        ALOGE("%s: Error %d releasing stream buffer %d",
+                __func__, rc, frameIndex);
+    }
+
+    rc = mMemory.unregisterBuffer(frameIndex);
+    if (NO_ERROR != rc) {
+        ALOGE("%s: Error %d unregistering stream buffer %d",
+                __func__, rc, frameIndex);
+    }
 
     mChannelCB(NULL, &result, resultFrameNumber, mUserData);
     free(super_frame);
@@ -1411,6 +1425,11 @@
         ////Use below data to issue framework callback
         resultBuffer = (buffer_handle_t *)obj->mMemory.getBufferHandle(bufIdx);
         resultFrameNumber = obj->mMemory.getFrameNumber(bufIdx);
+        int32_t rc = obj->mMemory.unregisterBuffer(bufIdx);
+        if (NO_ERROR != rc) {
+            ALOGE("%s: Error %d unregistering stream buffer %d",
+                    __func__, rc, bufIdx);
+        }
 
         result.stream = obj->mCamera3Stream;
         result.buffer = resultBuffer;
diff --git a/camera/QCamera2/HAL3/QCamera3HWI.cpp b/camera/QCamera2/HAL3/QCamera3HWI.cpp
index f59e2a5..6086adb 100644
--- a/camera/QCamera2/HAL3/QCamera3HWI.cpp
+++ b/camera/QCamera2/HAL3/QCamera3HWI.cpp
@@ -54,8 +54,6 @@
 
 namespace qcamera {
 
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-
 #define DATA_PTR(MEM_OBJ,INDEX) MEM_OBJ->getPtr( INDEX )
 
 #define EMPTY_PIPELINE_DELAY 2
diff --git a/camera/QCamera2/HAL3/QCamera3HWI.h b/camera/QCamera2/HAL3/QCamera3HWI.h
index ed8c558..c2ac724 100644
--- a/camera/QCamera2/HAL3/QCamera3HWI.h
+++ b/camera/QCamera2/HAL3/QCamera3HWI.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2012-2015, The Linux Foundataion. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -66,6 +66,9 @@
 #define FALSE 0
 #endif
 
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
 /* Time related macros */
 typedef int64_t nsecs_t;
 #define NSEC_PER_SEC 1000000000LL
diff --git a/camera/QCamera2/HAL3/QCamera3Mem.cpp b/camera/QCamera2/HAL3/QCamera3Mem.cpp
index 9ec6f79..d4416ef 100644
--- a/camera/QCamera2/HAL3/QCamera3Mem.cpp
+++ b/camera/QCamera2/HAL3/QCamera3Mem.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2012-2015, The Linux Foundataion. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -97,12 +97,20 @@
  *==========================================================================*/
 int QCamera3Memory::cacheOpsInternal(int index, unsigned int cmd, void *vaddr)
 {
+    Mutex::Autolock lock(mLock);
+
     struct ion_flush_data cache_inv_data;
     struct ion_custom_data custom_data;
     int ret = OK;
 
-    if (index >= mBufferCount) {
-        ALOGE("%s: index %d out of bound [0, %d)", __func__, index, mBufferCount);
+    if (MM_CAMERA_MAX_NUM_FRAMES <= index) {
+        ALOGE("%s: index %d out of bound [0, %d)",
+                __func__, index, MM_CAMERA_MAX_NUM_FRAMES);
+        return BAD_INDEX;
+    }
+
+    if (0 == mMemInfo[index].handle) {
+        ALOGE("%s: Buffer at %d not registered", __func__, index);
         return BAD_INDEX;
     }
 
@@ -136,10 +144,17 @@
  *
  * RETURN     : file descriptor
  *==========================================================================*/
-int QCamera3Memory::getFd(int index) const
+int QCamera3Memory::getFd(int index)
 {
-    if (index >= mBufferCount)
+    Mutex::Autolock lock(mLock);
+
+    if (MM_CAMERA_MAX_NUM_FRAMES <= index) {
         return BAD_INDEX;
+    }
+
+    if (0 == mMemInfo[index].handle) {
+        return BAD_INDEX;
+    }
 
     return mMemInfo[index].fd;
 }
@@ -154,10 +169,17 @@
  *
  * RETURN     : buffer size
  *==========================================================================*/
-int QCamera3Memory::getSize(int index) const
+int QCamera3Memory::getSize(int index)
 {
-    if (index >= mBufferCount)
+    Mutex::Autolock lock(mLock);
+
+    if (MM_CAMERA_MAX_NUM_FRAMES <= index) {
         return BAD_INDEX;
+    }
+
+    if (0 == mMemInfo[index].handle) {
+        return BAD_INDEX;
+    }
 
     return (int)mMemInfo[index].size;
 }
@@ -171,8 +193,10 @@
  *
  * RETURN     : number of buffers allocated
  *==========================================================================*/
-int QCamera3Memory::getCnt() const
+int QCamera3Memory::getCnt()
 {
+    Mutex::Autolock lock(mLock);
+
     return mBufferCount;
 }
 
@@ -191,8 +215,10 @@
  *              none-zero failure code
  *==========================================================================*/
 int32_t QCamera3Memory::getBufDef(const cam_frame_len_offset_t &offset,
-        mm_camera_buf_def_t &bufDef, int index) const
+        mm_camera_buf_def_t &bufDef, int index)
 {
+    Mutex::Autolock lock(mLock);
+
     if (!mBufferCount) {
         ALOGE("Memory not allocated");
         return NO_INIT;
@@ -202,7 +228,7 @@
     bufDef.frame_len = mMemInfo[index].size;
     bufDef.mem_info = (void *)this;
     bufDef.num_planes = offset.num_planes;
-    bufDef.buffer = getPtr(index);
+    bufDef.buffer = getPtrLocked(index);
     bufDef.buf_idx = index;
 
     /* Plane 0 needs to be set separately. Set other planes in a loop */
@@ -401,16 +427,16 @@
 }
 
 /*===========================================================================
- * FUNCTION   : getPtr
+ * FUNCTION   : getPtrLocked
  *
- * DESCRIPTION: return buffer pointer
+ * DESCRIPTION: Return buffer pointer.
  *
  * PARAMETERS :
  *   @index   : index of the buffer
  *
  * RETURN     : buffer ptr
  *==========================================================================*/
-void *QCamera3HeapMemory::getPtr(int index) const
+void *QCamera3HeapMemory::getPtrLocked(int index)
 {
     if (index >= mBufferCount) {
         ALOGE("index out of bound");
@@ -420,6 +446,21 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : getPtr
+ *
+ * DESCRIPTION: Return buffer pointer
+ *
+ * PARAMETERS :
+ *   @index   : index of the buffer
+ *
+ * RETURN     : buffer ptr
+ *==========================================================================*/
+void *QCamera3HeapMemory::getPtr(int index)
+{
+    return getPtrLocked(index);
+}
+
+/*===========================================================================
  * FUNCTION   : allocate
  *
  * DESCRIPTION: allocate requested number of buffers of certain size
@@ -513,7 +554,7 @@
  *              NO_ERROR  -- success
  *              none-zero failure code
  *==========================================================================*/
-int QCamera3HeapMemory::getRegFlags(uint8_t * regFlags) const
+int QCamera3HeapMemory::getRegFlags(uint8_t * regFlags)
 {
     int i;
     for (i = 0; i < mBufferCount; i ++)
@@ -607,61 +648,69 @@
     status_t ret = NO_ERROR;
     struct ion_fd_data ion_info_fd;
     void *vaddr = NULL;
+
+    int32_t idx = -1;
+
     CDBG(" %s : E ", __FUNCTION__);
 
     memset(&ion_info_fd, 0, sizeof(ion_info_fd));
 
-    if (mBufferCount >= (MM_CAMERA_MAX_NUM_FRAMES - 1)) {
-        ALOGE("%s: Number of buffers %d greater than what's supported %d",
-            __func__, mBufferCount, MM_CAMERA_MAX_NUM_FRAMES);
-        return -EINVAL;
-    }
-
     if (0 <= getMatchBufIndex((void *) buffer)) {
         ALOGV("%s: Buffer already registered", __func__);
         return ALREADY_EXISTS;
     }
 
-    mBufferHandle[mBufferCount] = buffer;
-    mPrivateHandle[mBufferCount] =
-        (struct private_handle_t *)(*mBufferHandle[mBufferCount]);
+    Mutex::Autolock lock(mLock);
+    if (mBufferCount >= (MM_CAMERA_MAX_NUM_FRAMES - 1)) {
+        ALOGE("%s: Number of buffers %d greater than what's supported %d",
+                __func__, mBufferCount, MM_CAMERA_MAX_NUM_FRAMES);
+        return BAD_INDEX;
+    }
 
-    setMetaData(mPrivateHandle[mBufferCount], UPDATE_COLOR_SPACE, &mColorSpace);
+    idx = getFreeIndexLocked();
+    if (0 > idx) {
+        ALOGE("%s: No available memory slots", __func__);
+        return BAD_INDEX;
+    }
 
-    mMemInfo[mBufferCount].main_ion_fd = open("/dev/ion", O_RDONLY);
-    if (mMemInfo[mBufferCount].main_ion_fd < 0) {
+    mBufferHandle[idx] = buffer;
+    mPrivateHandle[idx] = (struct private_handle_t *)(*mBufferHandle[idx]);
+
+    setMetaData(mPrivateHandle[idx], UPDATE_COLOR_SPACE, &mColorSpace);
+
+    mMemInfo[idx].main_ion_fd = open("/dev/ion", O_RDONLY);
+    if (mMemInfo[idx].main_ion_fd < 0) {
         ALOGE("%s: failed: could not open ion device", __func__);
         ret = NO_MEMORY;
         goto end;
     } else {
-        ion_info_fd.fd = mPrivateHandle[mBufferCount]->fd;
-        if (ioctl(mMemInfo[mBufferCount].main_ion_fd,
+        ion_info_fd.fd = mPrivateHandle[idx]->fd;
+        if (ioctl(mMemInfo[idx].main_ion_fd,
                   ION_IOC_IMPORT, &ion_info_fd) < 0) {
             ALOGE("%s: ION import failed\n", __func__);
-            close(mMemInfo[mBufferCount].main_ion_fd);
+            close(mMemInfo[idx].main_ion_fd);
             ret = NO_MEMORY;
             goto end;
         }
     }
     ALOGV("%s: idx = %d, fd = %d, size = %d, offset = %d",
-            __func__, mBufferCount, mPrivateHandle[mBufferCount]->fd,
-            mPrivateHandle[mBufferCount]->size,
-            mPrivateHandle[mBufferCount]->offset);
-    mMemInfo[mBufferCount].fd =
-            mPrivateHandle[mBufferCount]->fd;
-    mMemInfo[mBufferCount].size =
-            mPrivateHandle[mBufferCount]->size;
-    mMemInfo[mBufferCount].handle = ion_info_fd.handle;
+            __func__, idx, mPrivateHandle[idx]->fd,
+            mPrivateHandle[idx]->size,
+            mPrivateHandle[idx]->offset);
+    mMemInfo[idx].fd = mPrivateHandle[idx]->fd;
+    mMemInfo[idx].size = mPrivateHandle[idx]->size;
+    mMemInfo[idx].handle = ion_info_fd.handle;
 
     vaddr = mmap(NULL,
-            mMemInfo[mBufferCount].size,
+            mMemInfo[idx].size,
             PROT_READ | PROT_WRITE,
             MAP_SHARED,
-            mMemInfo[mBufferCount].fd, 0);
+            mMemInfo[idx].fd, 0);
     if (vaddr == MAP_FAILED) {
+        mMemInfo[idx].handle = 0;
         ret = NO_MEMORY;
     } else {
-        mPtr[mBufferCount] = vaddr;
+        mPtr[idx] = vaddr;
         mBufferCount++;
     }
 
@@ -671,6 +720,77 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : unregisterBufferLocked
+ *
+ * DESCRIPTION: Unregister buffer. Please note that this method has to be
+ *              called with 'mLock' acquired.
+ *
+ * PARAMETERS :
+ *   @idx     : unregister buffer at index 'idx'
+ *
+ * RETURN     : int32_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int32_t QCamera3GrallocMemory::unregisterBufferLocked(size_t idx)
+{
+    munmap(mPtr[idx], mMemInfo[idx].size);
+    mPtr[idx] = NULL;
+
+    struct ion_handle_data ion_handle;
+    memset(&ion_handle, 0, sizeof(ion_handle));
+    ion_handle.handle = mMemInfo[idx].handle;
+    if (ioctl(mMemInfo[idx].main_ion_fd, ION_IOC_FREE, &ion_handle) < 0) {
+        ALOGE("ion free failed");
+    }
+    close(mMemInfo[idx].main_ion_fd);
+    memset(&mMemInfo[idx], 0, sizeof(struct QCamera3MemInfo));
+    mBufferHandle[idx] = NULL;
+    mPrivateHandle[idx] = NULL;
+    mBufferCount--;
+
+    return NO_ERROR;
+}
+
+/*===========================================================================
+ * FUNCTION   : unregisterBuffer
+ *
+ * DESCRIPTION: unregister buffer
+ *
+ * PARAMETERS :
+ *   @idx     : unregister buffer at index 'idx'
+ *
+ * RETURN     : int32_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int32_t QCamera3GrallocMemory::unregisterBuffer(size_t idx)
+{
+    int32_t rc = NO_ERROR;
+    Mutex::Autolock lock(mLock);
+
+    CDBG("%s: E ", __FUNCTION__);
+
+    if (MM_CAMERA_MAX_NUM_FRAMES <= idx) {
+        ALOGE("%s: Buffer index %d greater than what is supported %d",
+                __func__, idx, MM_CAMERA_MAX_NUM_FRAMES);
+        return BAD_VALUE;
+    }
+
+    if (0 == mMemInfo[idx].handle) {
+        ALOGE("%s: Trying to unregister buffer at %d which still not registered",
+                __func__, idx);
+        return BAD_VALUE;
+    }
+
+    rc = unregisterBufferLocked(idx);
+
+    CDBG(" %s : X ",__FUNCTION__);
+
+    return rc;
+}
+
+/*===========================================================================
  * FUNCTION   : unregisterBuffers
  *
  * DESCRIPTION: unregister buffers
@@ -681,20 +801,20 @@
  *==========================================================================*/
 void QCamera3GrallocMemory::unregisterBuffers()
 {
+    int err = NO_ERROR;
+    Mutex::Autolock lock(mLock);
+
     CDBG("%s: E ", __FUNCTION__);
 
-    for (int cnt = 0; cnt < mBufferCount; cnt++) {
-        munmap(mPtr[cnt], mMemInfo[cnt].size);
-        mPtr[cnt] = NULL;
-
-        struct ion_handle_data ion_handle;
-        memset(&ion_handle, 0, sizeof(ion_handle));
-        ion_handle.handle = mMemInfo[cnt].handle;
-        if (ioctl(mMemInfo[cnt].main_ion_fd, ION_IOC_FREE, &ion_handle) < 0) {
-            ALOGE("ion free failed");
+    for (size_t cnt = 0; cnt < MM_CAMERA_MAX_NUM_FRAMES; cnt++) {
+        if (0 == mMemInfo[cnt].handle) {
+            continue;
         }
-        close(mMemInfo[cnt].main_ion_fd);
-        CDBG_HIGH("put buffer %d successfully", cnt);
+        err = unregisterBufferLocked(cnt);
+        if (NO_ERROR != err) {
+            ALOGE("%s: Error unregistering buffer %d error %d",
+                    __func__, cnt, err);
+        }
     }
     mBufferCount = 0;
     CDBG(" %s : X ",__FUNCTION__);
@@ -718,10 +838,18 @@
  *==========================================================================*/
 int32_t QCamera3GrallocMemory::markFrameNumber(int index, uint32_t frameNumber)
 {
-    if(index >= mBufferCount || index >= MM_CAMERA_MAX_NUM_FRAMES) {
+    Mutex::Autolock lock(mLock);
+
+    if (index >= MM_CAMERA_MAX_NUM_FRAMES) {
         ALOGE("%s: Index out of bounds",__func__);
         return BAD_INDEX;
     }
+
+    if (0 == mMemInfo[index].handle) {
+        ALOGE("%s: Buffer at %d not registered",__func__, index);
+        return BAD_INDEX;
+    }
+
     mCurrentFrameNumbers[index] = frameNumber;
     return NO_ERROR;
 }
@@ -737,16 +865,23 @@
  *   @index   : index of the buffer
  *
  * RETURN     : int32_t frameNumber
- *              postive/zero  -- success
- *              negetive failure
+ *              positive/zero  -- success
+ *              negative failure
  *==========================================================================*/
 int32_t QCamera3GrallocMemory::getFrameNumber(int index)
 {
-    if(index >= mBufferCount || index >= MM_CAMERA_MAX_NUM_FRAMES) {
+    Mutex::Autolock lock(mLock);
+
+    if (index >= MM_CAMERA_MAX_NUM_FRAMES) {
         ALOGE("%s: Index out of bounds",__func__);
         return -1;
     }
 
+    if (0 == mMemInfo[index].handle) {
+        ALOGE("%s: Buffer at %d not registered",__func__, index);
+        return -1;
+    }
+
     return mCurrentFrameNumbers[index];
 }
 
@@ -765,8 +900,6 @@
  *==========================================================================*/
 int QCamera3GrallocMemory::cacheOps(int index, unsigned int cmd)
 {
-    if (index >= mBufferCount)
-        return BAD_INDEX;
     return cacheOpsInternal(index, cmd, mPtr[index]);
 }
 
@@ -782,11 +915,14 @@
  *              NO_ERROR  -- success
  *              none-zero failure code
  *==========================================================================*/
-int QCamera3GrallocMemory::getRegFlags(uint8_t *regFlags) const
+int QCamera3GrallocMemory::getRegFlags(uint8_t *regFlags)
 {
+    Mutex::Autolock lock(mLock);
+
     int i;
     for (i = 0; i < mBufferCount; i ++)
         regFlags[i] = 0;
+
     return NO_ERROR;
 }
 
@@ -803,40 +939,98 @@
  *==========================================================================*/
 int QCamera3GrallocMemory::getMatchBufIndex(void *object)
 {
+    Mutex::Autolock lock(mLock);
+
     int index = -1;
     buffer_handle_t *key = (buffer_handle_t*) object;
     if (!key) {
         return BAD_VALUE;
     }
-    for (int i = 0; i < mBufferCount; i++) {
+    for (int i = 0; i < MM_CAMERA_MAX_NUM_FRAMES; i++) {
         if (mBufferHandle[i] == key) {
             index = i;
             break;
         }
     }
+
     return index;
 }
 
 /*===========================================================================
- * FUNCTION   : getPtr
+ * FUNCTION   : getFreeIndexLocked
  *
- * DESCRIPTION: return buffer pointer
+ * DESCRIPTION: Find free index slot. Note 'mLock' needs to be acquired
+ *              before calling this method.
+ *
+ * PARAMETERS : None
+ *
+ * RETURN     : free buffer index if found,
+ *              -1 if failed
+ *==========================================================================*/
+int QCamera3GrallocMemory::getFreeIndexLocked()
+{
+    int index = -1;
+
+    if (mBufferCount >= (MM_CAMERA_MAX_NUM_FRAMES - 1)) {
+        ALOGE("%s: Number of buffers %d greater than what's supported %d",
+            __func__, mBufferCount, MM_CAMERA_MAX_NUM_FRAMES);
+        return index;
+    }
+
+    for (size_t i = 0; i < MM_CAMERA_MAX_NUM_FRAMES; i++) {
+        if (0 == mMemInfo[i].handle) {
+            index = i;
+            break;
+        }
+    }
+
+    return index;
+}
+
+/*===========================================================================
+ * FUNCTION   : getPtrLocked
+ *
+ * DESCRIPTION: Return buffer pointer. Please note 'mLock' must be acquired
+ *              before calling this method.
  *
  * PARAMETERS :
  *   @index   : index of the buffer
  *
  * RETURN     : buffer ptr
  *==========================================================================*/
-void *QCamera3GrallocMemory::getPtr(int index) const
+void *QCamera3GrallocMemory::getPtrLocked(int index)
 {
-    if (index >= mBufferCount) {
-        ALOGE("index out of bound");
-        return (void *)BAD_INDEX;
+    if (MM_CAMERA_MAX_NUM_FRAMES <= index) {
+        ALOGE("%s: index %d out of bound [0, %d)",
+                __func__, index, MM_CAMERA_MAX_NUM_FRAMES);
+        return NULL;
     }
+
+    if (0 == mMemInfo[index].handle) {
+        ALOGE("%s: Buffer at %d not registered", __func__, index);
+        return NULL;
+    }
+
     return mPtr[index];
 }
 
 /*===========================================================================
+ * FUNCTION   : getPtr
+ *
+ * DESCRIPTION: Return buffer pointer.
+ *
+ * PARAMETERS :
+ *   @index   : index of the buffer
+ *
+ * RETURN     : buffer ptr
+ *==========================================================================*/
+void *QCamera3GrallocMemory::getPtr(int index)
+{
+    Mutex::Autolock lock(mLock);
+    return getPtrLocked(index);
+}
+
+/*===========================================================================
  * FUNCTION   : getBufferHandle
  *
  * DESCRIPTION: return framework pointer
@@ -849,10 +1043,19 @@
  *==========================================================================*/
 void *QCamera3GrallocMemory::getBufferHandle(int index)
 {
-    if (index >= mBufferCount) {
-        ALOGE("index out of bound");
+    Mutex::Autolock lock(mLock);
+
+    if (MM_CAMERA_MAX_NUM_FRAMES <= index) {
+        ALOGE("%s: index %d out of bound [0, %d)",
+                __func__, index, MM_CAMERA_MAX_NUM_FRAMES);
         return NULL;
     }
+
+    if (0 == mMemInfo[index].handle) {
+        ALOGE("%s: Buffer at %d not registered", __func__, index);
+        return NULL;
+    }
+
     return mBufferHandle[index];
 }
 
diff --git a/camera/QCamera2/HAL3/QCamera3Mem.h b/camera/QCamera2/HAL3/QCamera3Mem.h
index a9af447..08dfcb2 100644
--- a/camera/QCamera2/HAL3/QCamera3Mem.h
+++ b/camera/QCamera2/HAL3/QCamera3Mem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2012-2015, The Linux Foundataion. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -39,6 +39,8 @@
 #include <mm_camera_interface.h>
 }
 
+using namespace android;
+
 namespace qcamera {
 
 // Base class for all memory types. Abstract.
@@ -48,20 +50,20 @@
     int cleanCache(int index) {return cacheOps(index, ION_IOC_CLEAN_CACHES);}
     int invalidateCache(int index) {return cacheOps(index, ION_IOC_INV_CACHES);}
     int cleanInvalidateCache(int index) {return cacheOps(index, ION_IOC_CLEAN_INV_CACHES);}
-    int getFd(int index) const;
-    int getSize(int index) const;
-    int getCnt() const;
+    int getFd(int index);
+    int getSize(int index);
+    int getCnt();
 
     virtual int cacheOps(int index, unsigned int cmd) = 0;
-    virtual int getRegFlags(uint8_t *regFlags) const = 0;
+    virtual int getRegFlags(uint8_t *regFlags) = 0;
     virtual int getMatchBufIndex(void *object) = 0;
-    virtual void *getPtr(int index) const= 0;
+    virtual void *getPtr(int index) = 0;
 
     QCamera3Memory();
     virtual ~QCamera3Memory();
 
     int32_t getBufDef(const cam_frame_len_offset_t &offset,
-                mm_camera_buf_def_t &bufDef, int index) const;
+                mm_camera_buf_def_t &bufDef, int index);
 
 protected:
     struct QCamera3MemInfo {
@@ -72,10 +74,12 @@
     };
 
     int cacheOpsInternal(int index, unsigned int cmd, void *vaddr);
+    virtual void *getPtrLocked(int index) = 0;
 
     int mBufferCount;
     struct QCamera3MemInfo mMemInfo[MM_CAMERA_MAX_NUM_FRAMES];
     void *mPtr[MM_CAMERA_MAX_NUM_FRAMES];
+    Mutex mLock;
 };
 
 // Internal heap memory is used for memories used internally
@@ -90,9 +94,11 @@
     void deallocate();
 
     virtual int cacheOps(int index, unsigned int cmd);
-    virtual int getRegFlags(uint8_t *regFlags) const;
+    virtual int getRegFlags(uint8_t *regFlags);
     virtual int getMatchBufIndex(void *object);
-    virtual void *getPtr(int index) const;
+    virtual void *getPtr(int index);
+protected:
+    virtual void *getPtrLocked(int index);
 private:
     int alloc(int count, int size, int heap_id);
     void dealloc();
@@ -109,16 +115,21 @@
     virtual ~QCamera3GrallocMemory();
 
     int registerBuffer(buffer_handle_t *buffer);
+    int32_t unregisterBuffer(size_t idx);
     void unregisterBuffers();
     virtual int cacheOps(int index, unsigned int cmd);
-    virtual int getRegFlags(uint8_t *regFlags) const;
+    virtual int getRegFlags(uint8_t *regFlags);
     virtual int getMatchBufIndex(void *object);
-    virtual void *getPtr(int index) const;
+    virtual void *getPtr(int index);
     int32_t markFrameNumber(int index, uint32_t frameNumber);
     int32_t getFrameNumber(int index);
     void *getBufferHandle(int index);
     int32_t setColorSpace(uint8_t intent);
+protected:
+    virtual void *getPtrLocked(int index);
 private:
+    int32_t unregisterBufferLocked(size_t idx);
+    int32_t getFreeIndexLocked();
     buffer_handle_t *mBufferHandle[MM_CAMERA_MAX_NUM_FRAMES];
     struct private_handle_t *mPrivateHandle[MM_CAMERA_MAX_NUM_FRAMES];
     uint32_t mCurrentFrameNumbers[MM_CAMERA_MAX_NUM_FRAMES];
diff --git a/camera/QCamera2/HAL3/QCamera3PostProc.cpp b/camera/QCamera2/HAL3/QCamera3PostProc.cpp
index 272757a..9fada4a 100644
--- a/camera/QCamera2/HAL3/QCamera3PostProc.cpp
+++ b/camera/QCamera2/HAL3/QCamera3PostProc.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2012-2015, The Linux Foundataion. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -384,7 +384,7 @@
         ret = BAD_VALUE;
         goto on_error;
     }
-    encode_parm.num_src_bufs = pStreamMem->getCnt();
+    encode_parm.num_src_bufs = MIN(pStreamMem->getCnt(), MM_JPEG_MAX_BUF);
     for (uint32_t i = 0; i < encode_parm.num_src_bufs; i++) {
         if (pStreamMem != NULL) {
             encode_parm.src_main_buf[i].index = i;
@@ -408,8 +408,8 @@
         cam_frame_len_offset_t thumb_offset;
         memset(&thumb_offset, 0, sizeof(cam_frame_len_offset_t));
         main_stream->getFrameOffset(thumb_offset);
-        encode_parm.num_tmb_bufs = pStreamMem->getCnt();
-        for (int i = 0; i < pStreamMem->getCnt(); i++) {
+        encode_parm.num_tmb_bufs = MIN(pStreamMem->getCnt(), MM_JPEG_MAX_BUF);
+        for (size_t i = 0; i < encode_parm.num_tmb_bufs; i++) {
             if (pStreamMem != NULL) {
                 encode_parm.src_thumb_buf[i].index = i;
                 encode_parm.src_thumb_buf[i].buf_size = pStreamMem->getSize(i);
diff --git a/camera/QCamera2/HAL3/QCamera3Stream.cpp b/camera/QCamera2/HAL3/QCamera3Stream.cpp
index 638bac8..04242d8 100644
--- a/camera/QCamera2/HAL3/QCamera3Stream.cpp
+++ b/camera/QCamera2/HAL3/QCamera3Stream.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2012-2015, The Linux Foundataion. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -203,7 +203,7 @@
         int rc = mCamOps->unmap_stream_buf(mCamHandle,
                     mChannelHandle, mHandle, CAM_MAPPING_BUF_TYPE_STREAM_INFO, 0, -1);
         if (rc < 0) {
-            ALOGE("Failed to map stream info buffer");
+            ALOGE("Failed to un-map stream info buffer");
         }
         mStreamInfoBuf->deallocate();
         delete mStreamInfoBuf;
@@ -496,36 +496,6 @@
 }
 
 /*===========================================================================
- * FUNCTION   : getInternalFormatBuffer
- *
- * DESCRIPTION: return buffer in the internal format structure
- *
- * PARAMETERS :
- *   @index   : index of buffer to be returned
- *
- * RETURN     : int32_t type of status
- *              NO_ERROR  -- success
- *              none-zero failure code
- *==========================================================================*/
-mm_camera_buf_def_t* QCamera3Stream::getInternalFormatBuffer(int index)
-{
-    mm_camera_buf_def_t *rc = NULL;
-    if ((index >= mNumBufs) || (mBufDefs == NULL) ||
-            (NULL == mBufDefs[index].mem_info)) {
-        ALOGE("%s:Index out of range/no internal buffers yet", __func__);
-        return NULL;
-    }
-
-    rc = (mm_camera_buf_def_t*)malloc(sizeof(mm_camera_buf_def_t));
-    if(rc) {
-        memcpy(rc, &mBufDefs[index], sizeof(mm_camera_buf_def_t));
-    } else {
-        ALOGE("%s: Failed to allocate memory",__func__);
-    }
-    return rc;
-}
-
-/*===========================================================================
  * FUNCTION   : bufDone
  *
  * DESCRIPTION: return stream buffer to kernel
@@ -540,9 +510,11 @@
 int32_t QCamera3Stream::bufDone(int index)
 {
     int32_t rc = NO_ERROR;
+    Mutex::Autolock lock(mLock);
 
-    if (index >= mNumBufs || mBufDefs == NULL)
+    if ((index >= mNumBufs) || (mBufDefs == NULL)) {
         return BAD_INDEX;
+    }
 
     if( NULL == mBufDefs[index].mem_info) {
         if (NULL == mMemOps) {
@@ -566,8 +538,51 @@
     }
 
     rc = mCamOps->qbuf(mCamHandle, mChannelHandle, &mBufDefs[index]);
-    if (rc < 0)
+    if (rc < 0) {
         return FAILED_TRANSACTION;
+    }
+
+    return rc;
+}
+
+/*===========================================================================
+ * FUNCTION   : bufRelease
+ *
+ * DESCRIPTION: release all resources associated with this buffer
+ *
+ * PARAMETERS :
+ *   @index   : index of buffer to be released
+ *
+ * RETURN     : int32_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int32_t QCamera3Stream::bufRelease(int32_t index)
+{
+    int32_t rc = NO_ERROR;
+    Mutex::Autolock lock(mLock);
+
+    if ((index >= mNumBufs) || (mBufDefs == NULL)) {
+        return BAD_INDEX;
+    }
+
+    if (NULL != mBufDefs[index].mem_info) {
+        if (NULL == mMemOps) {
+            ALOGE("%s: Camera operations not initialized", __func__);
+            return NO_INIT;
+        }
+
+        rc = mMemOps->unmap_ops(index, -1, mMemOps->userdata);
+        if (rc < 0) {
+            ALOGE("%s: Failed to un-map camera buffer %d", __func__, index);
+            return rc;
+        }
+
+        mBufDefs[index].mem_info = NULL;
+    } else {
+        ALOGE("%s: Buffer at index %d not registered", __func__);
+        return BAD_INDEX;
+    }
 
     return rc;
 }
@@ -597,6 +612,7 @@
 {
     int rc = NO_ERROR;
     uint8_t *regFlags;
+    Mutex::Autolock lock(mLock);
 
     if (!ops_tbl) {
         ALOGE("%s: ops_tbl is NULL", __func__);
@@ -685,11 +701,13 @@
 int32_t QCamera3Stream::putBufs(mm_camera_map_unmap_ops_tbl_t *ops_tbl)
 {
     int rc = NO_ERROR;
+    Mutex::Autolock lock(mLock);
+
     for (int i = 0; i < mNumBufs; i++) {
         if (NULL != mBufDefs[i].mem_info) {
             rc = ops_tbl->unmap_ops(i, -1, ops_tbl->userdata);
             if (rc < 0) {
-                ALOGE("%s: map_stream_buf failed: %d", __func__, rc);
+                ALOGE("%s: un-map stream buf failed: %d", __func__, rc);
             }
         }
     }
diff --git a/camera/QCamera2/HAL3/QCamera3Stream.h b/camera/QCamera2/HAL3/QCamera3Stream.h
index c06cb12..0a6a917 100644
--- a/camera/QCamera2/HAL3/QCamera3Stream.h
+++ b/camera/QCamera2/HAL3/QCamera3Stream.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2012-2015, The Linux Foundataion. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -31,6 +31,7 @@
 #define __QCAMERA3_STREAM_H__
 
 #include <hardware/camera3.h>
+#include "utils/Mutex.h"
 #include "QCameraCmdThread.h"
 #include "QCamera3Mem.h"
 
@@ -66,6 +67,7 @@
                          hal3_stream_cb_routine stream_cb,
                          void *userdata);
     virtual int32_t bufDone(int index);
+    virtual int32_t bufRelease(int32_t index);
     virtual int32_t processDataNotify(mm_camera_super_buf_t *bufs);
     virtual int32_t start();
     virtual int32_t stop();
@@ -77,7 +79,6 @@
     int32_t getFrameOffset(cam_frame_len_offset_t &offset);
     int32_t getFrameDimension(cam_dimension_t &dim);
     int32_t getFormat(cam_format_t &fmt);
-    mm_camera_buf_def_t* getInternalFormatBuffer(int index);
     QCamera3Memory *getStreamBufs() {return mStreamBufs;};
     uint32_t getMyServerID();
 
@@ -109,6 +110,7 @@
     cam_frame_len_offset_t mFrameLenOffset;
     cam_padding_info_t mPaddingInfo;
     QCamera3Channel *mChannel;
+    Mutex mLock;    //Lock controlling access to 'mBufDefs'
 
     static int32_t get_bufs(
                      cam_frame_len_offset_t *offset,