mm-video: vidc: Add support for dynamic buffer mode
The OMX Component will support dynamic buffer mode
for capture port. With static buffer mode, all the
output buffers are pre-registered with firmware
before stream-on. In dynamic buffer mode, there will
be no pre-registeration of output buffers with
firmware. This mode is primarily for streaming
use case, to save on video start-up latency.
Change-Id: I108f3f832167b7000ef4d25a38c8f5006507c864
diff --git a/mm-video-v4l2/vidc/vdec/src/omx_vdec_msm8974.cpp b/mm-video-v4l2/vidc/vdec/src/omx_vdec_msm8974.cpp
index add623c..1d07edb 100644
--- a/mm-video-v4l2/vidc/vdec/src/omx_vdec_msm8974.cpp
+++ b/mm-video-v4l2/vidc/vdec/src/omx_vdec_msm8974.cpp
@@ -49,6 +49,9 @@
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
+#ifdef META_DATA_MODE_SUPPORTED
+#include <media/hardware/HardwareAPI.h>
+#endif
#include <media/msm_media_info.h>
#ifndef _ANDROID_
@@ -230,7 +233,39 @@
DEBUG_PRINT_HIGH("\n async_message_thread Exited \n");
break;
}
- } else {
+ }
+#ifdef META_DATA_MODE_SUPPORTED
+ else if (dqevent.type == V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE) {
+ unsigned int *ptr = (unsigned int *)dqevent.u.data;
+ DEBUG_PRINT_LOW("REFERENCE RELEASE EVENT RECVD fd = %d offset = %d\n", ptr[0], ptr[1]);
+ omx->buf_ref_remove(ptr[0], ptr[1]);
+ } else if (dqevent.type == V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER) {
+ unsigned int *ptr = (unsigned int *)dqevent.u.data;
+ struct vdec_msginfo vdec_msg;
+
+ DEBUG_PRINT_LOW("Release unqueued buffer event recvd fd = %d offset = %d\n", ptr[0], ptr[1]);
+
+ v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ v4l2_buf.memory = V4L2_MEMORY_USERPTR;
+ v4l2_buf.length = omx->drv_ctx.num_planes;
+ v4l2_buf.m.planes = plane;
+ v4l2_buf.index = ptr[5];
+ v4l2_buf.flags = 0;
+
+ vdec_msg.msgcode = VDEC_MSG_RESP_OUTPUT_BUFFER_DONE;
+ vdec_msg.status_code = VDEC_S_SUCCESS;
+ vdec_msg.msgdata.output_frame.client_data = (void*)&v4l2_buf;
+ vdec_msg.msgdata.output_frame.len = 0;
+ vdec_msg.msgdata.output_frame.bufferaddr = (void*)ptr[2];
+ vdec_msg.msgdata.output_frame.time_stamp = ((uint64_t)ptr[3] * (uint64_t)1000000) +
+ (uint64_t)ptr[4];
+ if (omx->async_message_process(input,&vdec_msg) < 0) {
+ DEBUG_PRINT_HIGH("\n async_message_thread Exited \n");
+ break;
+ }
+ }
+#endif
+ else {
DEBUG_PRINT_HIGH("\n VIDC Some Event recieved \n");
continue;
}
@@ -609,12 +644,20 @@
#endif
m_fill_output_msg = OMX_COMPONENT_GENERATE_FTB;
client_buffers.set_vdec_client(this);
+#ifdef META_DATA_MODE_SUPPORTED
+ dynamic_buf_mode = false;
+ out_dynamic_list = NULL;
+#endif
}
static const int event_type[] = {
V4L2_EVENT_MSM_VIDC_FLUSH_DONE,
V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT,
V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT,
+#ifdef META_DATA_MODE_SUPPORTED
+ V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE,
+ V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER,
+#endif
V4L2_EVENT_MSM_VIDC_CLOSE_DONE,
V4L2_EVENT_MSM_VIDC_SYS_ERROR
};
@@ -3356,6 +3399,7 @@
break;
}
+#ifdef META_DATA_MODE_SUPPORTED
case OMX_QcomIndexParamVideoMetaBufferMode:
{
StoreMetaDataInBuffersParams *metabuffer =
@@ -3379,6 +3423,7 @@
if (!rc) {
DEBUG_PRINT_HIGH(" %s buffer mode\n",
(metabuffer->bStoreMetaData == true)? "Enabled dynamic" : "Disabled dynamic");
+ dynamic_buf_mode = metabuffer->bStoreMetaData;
} else {
DEBUG_PRINT_ERROR("Failed to %s buffer mode\n",
(metabuffer->bStoreMetaData == true)? "enable dynamic" : "disable dynamic");
@@ -3392,6 +3437,7 @@
}
break;
}
+#endif
default: {
DEBUG_PRINT_ERROR("Setparameter: unknown param %d\n", paramIndex);
eRet = OMX_ErrorUnsupportedIndex;
@@ -3744,9 +3790,11 @@
*indexType = (OMX_INDEXTYPE)OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage;
}
#endif
+#ifdef META_DATA_MODE_SUPPORTED
else if (!strncmp(paramName, "OMX.google.android.index.storeMetaDataInBuffers", sizeof("OMX.google.android.index.storeMetaDataInBuffers") - 1)) {
*indexType = (OMX_INDEXTYPE)OMX_QcomIndexParamVideoMetaBufferMode;
}
+#endif
else {
DEBUG_PRINT_ERROR("Extension: %s not implemented\n", paramName);
return OMX_ErrorNotImplemented;
@@ -3897,6 +3945,29 @@
eRet = OMX_ErrorInsufficientResources;
}
+#ifdef META_DATA_MODE_SUPPORTED
+ if (dynamic_buf_mode) {
+ *bufferHdr = (m_out_mem_ptr + i );
+ (*bufferHdr)->pBuffer = NULL;
+ if (i == (drv_ctx.op_buf.actualcount -1) && !streaming[CAPTURE_PORT]) {
+ enum v4l2_buf_type buf_type;
+ int rr = 0;
+ buf_type=V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ if (rr = ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMON,&buf_type)) {
+ DEBUG_PRINT_ERROR("STREAMON FAILED : %d", rr);
+ return OMX_ErrorInsufficientResources;
+ } else {
+ streaming[CAPTURE_PORT] = true;
+ DEBUG_PRINT_LOW("STREAMON Successful");
+ }
+ }
+ BITMASK_SET(&m_out_bm_count,i);
+ (*bufferHdr)->pAppPrivate = appData;
+ (*bufferHdr)->pBuffer = buffer;
+ (*bufferHdr)->nAllocLen = sizeof(struct VideoDecoderOutputMetaData);
+ return eRet;
+ }
+#endif
if (eRet == OMX_ErrorNone) {
#if defined(_ANDROID_HONEYCOMB_) || defined(_ANDROID_ICS_)
if (m_enable_android_native_buffers) {
@@ -5497,6 +5568,42 @@
OMX_ERRORTYPE omx_vdec::fill_this_buffer(OMX_IN OMX_HANDLETYPE hComp,
OMX_IN OMX_BUFFERHEADERTYPE* buffer)
{
+#ifdef META_DATA_MODE_SUPPORTED
+ if (dynamic_buf_mode) {
+ private_handle_t *handle = NULL;
+ struct VideoDecoderOutputMetaData *meta;
+ OMX_U8 *buff = NULL;
+ unsigned int nPortIndex = 0;
+
+ if (!buffer || !buffer->pBuffer) {
+ DEBUG_PRINT_ERROR("%s: invalid params: %p %p", __FUNCTION__, buffer, buffer->pBuffer);
+ return OMX_ErrorBadParameter;
+ }
+
+ //get the buffer type and fd info
+ meta = (struct VideoDecoderOutputMetaData *)buffer->pBuffer;
+ handle = (private_handle_t *)meta->pHandle;
+ DEBUG_PRINT_LOW("FTB: buftype: %d bufhndl: %p", meta->eType, meta->pHandle);
+
+ //map the buffer handle based on the size set on output port definition.
+ if (!secure_mode) {
+ buff = (OMX_U8*)mmap(0, drv_ctx.op_buf.buffer_size,
+ PROT_READ|PROT_WRITE, MAP_SHARED, handle->fd, 0);
+ } else {
+ buff = (OMX_U8*) buffer;
+ }
+
+ //Fill outputbuffer with buffer details, this will be sent to f/w during VIDIOC_QBUF
+ nPortIndex = buffer-((OMX_BUFFERHEADERTYPE *)client_buffers.get_il_buf_hdr());
+ drv_ctx.ptr_outputbuffer[nPortIndex].pmem_fd = handle->fd;
+ drv_ctx.ptr_outputbuffer[nPortIndex].offset = 0;
+ drv_ctx.ptr_outputbuffer[nPortIndex].bufferaddr = buff;
+ drv_ctx.ptr_outputbuffer[nPortIndex].buffer_len = drv_ctx.op_buf.buffer_size;
+ drv_ctx.ptr_outputbuffer[nPortIndex].mmaped_size = drv_ctx.op_buf.buffer_size;
+ buf_ref_add(drv_ctx.ptr_outputbuffer[nPortIndex].pmem_fd,
+ drv_ctx.ptr_outputbuffer[nPortIndex].offset);
+ }
+#endif
if (m_state == OMX_StateInvalid) {
DEBUG_PRINT_ERROR("FTB in Invalid State\n");
@@ -5611,6 +5718,9 @@
}
buf.m.planes = plane;
buf.length = drv_ctx.num_planes;
+ DEBUG_PRINT_LOW("SENDING FTB TO F/W - fd[0] = %d fd[1] = %d offset[1] = %d\n",
+ plane[0].reserved[0],plane[extra_idx].reserved[0], plane[extra_idx].reserved[1]);
+
rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_QBUF, &buf);
if (rc) {
/*TODO: How to handle this case */
@@ -6172,6 +6282,15 @@
buffer, buffer->pBuffer);
pending_output_buffers --;
+#ifdef META_DATA_MODE_SUPPORTED
+ if (dynamic_buf_mode && !secure_mode) {
+ unsigned int nPortIndex = 0;
+ nPortIndex = buffer-((OMX_BUFFERHEADERTYPE *)client_buffers.get_il_buf_hdr());
+ munmap(drv_ctx.ptr_outputbuffer[nPortIndex].bufferaddr,
+ drv_ctx.ptr_outputbuffer[nPortIndex].mmaped_size);
+ }
+#endif
+
if (buffer->nFlags & OMX_BUFFERFLAG_EOS) {
DEBUG_PRINT_HIGH("\n Output EOS has been reached");
if (!output_flush_progress)
@@ -6446,6 +6565,11 @@
((omxhdr - omx->m_out_mem_ptr) < omx->drv_ctx.op_buf.actualcount) &&
(((struct vdec_output_frameinfo *)omxhdr->pOutputPortPrivate
- omx->drv_ctx.ptr_respbuffer) < omx->drv_ctx.op_buf.actualcount)) {
+#ifdef META_DATA_MODE_SUPPORTED
+ if (omx->dynamic_buf_mode && vdec_msg->msgdata.output_frame.len) {
+ vdec_msg->msgdata.output_frame.len = omxhdr->nAllocLen;
+ }
+#endif
if ( vdec_msg->msgdata.output_frame.len <= omxhdr->nAllocLen) {
omxhdr->nFilledLen = vdec_msg->msgdata.output_frame.len;
omxhdr->nOffset = vdec_msg->msgdata.output_frame.offset;
@@ -6470,6 +6594,17 @@
if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_DECODEONLY) {
omxhdr->nFlags |= OMX_BUFFERFLAG_DECODEONLY;
}
+#ifdef META_DATA_MODE_SUPPORTED
+ if (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_READONLY) {
+ DEBUG_PRINT_LOW("F_B_D: READONLY BUFFER - REFERENCE WITH F/W fd = %d",
+ omx->drv_ctx.ptr_outputbuffer[v4l2_buf_ptr->index].pmem_fd);
+ }
+
+ if (omx->dynamic_buf_mode && !(v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_READONLY)) {
+ omx->buf_ref_remove(omx->drv_ctx.ptr_outputbuffer[v4l2_buf_ptr->index].pmem_fd,
+ omxhdr->nOffset);
+ }
+#endif
if (omxhdr && (v4l2_buf_ptr->flags & V4L2_QCOM_BUF_DROP_FRAME) &&
!(v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_DECODEONLY) &&
!(v4l2_buf_ptr->flags & V4L2_QCOM_BUF_FLAG_EOS)) {
@@ -7232,6 +7367,12 @@
drv_ctx.op_buf_ion_info = NULL;
}
#endif
+#ifdef META_DATA_MODE_SUPPORTED
+ if (out_dynamic_list) {
+ free(out_dynamic_list);
+ out_dynamic_list = NULL;
+ }
+#endif
}
void omx_vdec::free_input_buffer_header()
@@ -7612,7 +7753,12 @@
drv_ctx.op_buf_ion_info = (struct vdec_ion * ) \
calloc (sizeof(struct vdec_ion),drv_ctx.op_buf.actualcount);
#endif
-
+#ifdef META_DATA_MODE_SUPPORTED
+ if (dynamic_buf_mode) {
+ out_dynamic_list = (struct dynamic_buf_list *) \
+ calloc (sizeof(struct dynamic_buf_list), drv_ctx.op_buf.actualcount);
+ }
+#endif
if (m_out_mem_ptr && pPtr && drv_ctx.ptr_outputbuffer
&& drv_ctx.ptr_respbuffer) {
bufHdr = m_out_mem_ptr;
@@ -8752,3 +8898,66 @@
}
return status;
}
+
+#ifdef META_DATA_MODE_SUPPORTED
+void omx_vdec::buf_ref_add(OMX_U32 fd, OMX_U32 offset)
+{
+ int i = 0;
+ bool buf_present = false;
+ pthread_mutex_lock(&m_lock);
+ for (i = 0; i < drv_ctx.op_buf.actualcount; i++) {
+ //check the buffer fd, offset, uv addr with list contents
+ //If present increment reference.
+ if ((out_dynamic_list[i].fd == fd) &&
+ (out_dynamic_list[i].offset == offset)) {
+ out_dynamic_list[i].ref_count++;
+ DEBUG_PRINT_LOW("buf_ref_add: [ALREADY PRESENT] fd = %d ref_count = %d\n",
+ out_dynamic_list[i].fd, out_dynamic_list[i].ref_count);
+ buf_present = true;
+ break;
+ }
+ }
+ if (!buf_present) {
+ for (i = 0; i < drv_ctx.op_buf.actualcount; i++) {
+ //search for a entry to insert details of the new buffer
+ if (out_dynamic_list[i].dup_fd == 0) {
+ out_dynamic_list[i].fd = fd;
+ out_dynamic_list[i].offset = offset;
+ out_dynamic_list[i].dup_fd = dup(fd);
+ out_dynamic_list[i].ref_count++;
+ DEBUG_PRINT_LOW("buf_ref_add: [ADDED] fd = %d ref_count = %d\n",
+ out_dynamic_list[i].fd, out_dynamic_list[i].ref_count);
+ break;
+ }
+ }
+ }
+ pthread_mutex_unlock(&m_lock);
+}
+
+void omx_vdec::buf_ref_remove(OMX_U32 fd, OMX_U32 offset)
+{
+ int i = 0;
+ pthread_mutex_lock(&m_lock);
+ for (i = 0; i < drv_ctx.op_buf.actualcount; i++) {
+ //check the buffer fd, offset, uv addr with list contents
+ //If present decrement reference.
+ if ((out_dynamic_list[i].fd == fd) &&
+ (out_dynamic_list[i].offset == offset)) {
+ out_dynamic_list[i].ref_count--;
+ if (out_dynamic_list[i].ref_count == 0) {
+ close(out_dynamic_list[i].dup_fd);
+ DEBUG_PRINT_LOW("buf_ref_remove: [REMOVED] fd = %d ref_count = %d\n",
+ out_dynamic_list[i].fd, out_dynamic_list[i].ref_count);
+ out_dynamic_list[i].dup_fd = 0;
+ out_dynamic_list[i].fd = 0;
+ out_dynamic_list[i].offset = 0;
+ }
+ break;
+ }
+ }
+ if (i >= drv_ctx.op_buf.actualcount) {
+ DEBUG_PRINT_ERROR("Error - could not remove ref, no match with any entry in list\n");
+ }
+ pthread_mutex_unlock(&m_lock);
+}
+#endif