mm-video: vidc: Adds support for smooth streaming

Adds support for smooth streaming by enabling
continue data transfer mode.

Change-Id: I5b872aa5081a1d13c35eed0d462292cbaaefb1e4
diff --git a/mm-video/vidc/vdec/src/omx_vdec_msm8974.cpp b/mm-video/vidc/vdec/src/omx_vdec_msm8974.cpp
index d46b308..1350cb8 100755
--- a/mm-video/vidc/vdec/src/omx_vdec_msm8974.cpp
+++ b/mm-video/vidc/vdec/src/omx_vdec_msm8974.cpp
@@ -128,7 +128,6 @@
 void* async_message_thread (void *input)
 {
   struct vdec_ioctl_msg ioctl_msg;
-  struct vdec_msginfo vdec_msg;
   OMX_BUFFERHEADERTYPE *buffer;
   struct v4l2_plane plane;
   struct pollfd pfd;
@@ -150,7 +149,40 @@
 			DEBUG_PRINT_ERROR("Error while polling: %d\n", rc);
 			break;
 		}
+		if (pfd.revents & POLLERR){
+			printf("\n async_message_thread Exited \n");
+			break;
+		}
+		if (pfd.revents & POLLPRI){
+			rc = ioctl(pfd.fd, VIDIOC_DQEVENT, &dqevent);
+			if(dqevent.type == V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT) {
+				DEBUG_PRINT_HIGH("\n VIDC Sufficinet resources recieved \n");
+				continue;
+			} else if(dqevent.type == V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT) {
+				struct vdec_msginfo vdec_msg;
+				vdec_msg.msgcode=VDEC_MSG_EVT_CONFIG_CHANGED;
+				vdec_msg.status_code=VDEC_S_SUCCESS;
+				printf("\n VIDC Port Reconfig recieved \n");
+				if (omx->async_message_process(input,&vdec_msg) < 0) {
+					DEBUG_PRINT_HIGH("\n async_message_thread Exited  \n");
+					break;
+				}
+			} else if (dqevent.type == V4L2_EVENT_MSM_VIDC_FLUSH_DONE) {
+				struct vdec_msginfo vdec_msg;
+				vdec_msg.msgcode=VDEC_MSG_RESP_FLUSH_OUTPUT_DONE;
+				vdec_msg.status_code=VDEC_S_SUCCESS;
+				DEBUG_PRINT_HIGH("\n VIDC Flush Done Recieved \n");
+				if (omx->async_message_process(input,&vdec_msg) < 0) {
+					DEBUG_PRINT_HIGH("\n async_message_thread Exited  \n");
+					break;
+				}
+			} else {
+				DEBUG_PRINT_HIGH("\n VIDC Some Event recieved \n");
+				continue;
+			}
+		}
 		if ((pfd.revents & POLLIN) || (pfd.revents & POLLRDNORM)) {
+			struct vdec_msginfo vdec_msg;
 			v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
 			v4l2_buf.memory = V4L2_MEMORY_USERPTR;
 			v4l2_buf.length = 1;
@@ -166,8 +198,13 @@
 			vdec_msg.msgdata.output_frame.client_data=(void*)&v4l2_buf;
 			vdec_msg.msgdata.output_frame.len=plane.bytesused;
 			vdec_msg.msgdata.output_frame.bufferaddr=(void*)plane.m.userptr;
+			if (omx->async_message_process(input,&vdec_msg) < 0) {
+				DEBUG_PRINT_HIGH("\n async_message_thread Exited  \n");
+				break;
+			}
 		}
-		else if((pfd.revents & POLLOUT) || (pfd.revents & POLLWRNORM)) {
+		if((pfd.revents & POLLOUT) || (pfd.revents & POLLWRNORM)) {
+			struct vdec_msginfo vdec_msg;
 			v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
 			v4l2_buf.memory = V4L2_MEMORY_USERPTR;
 			v4l2_buf.m.planes = &plane;
@@ -177,34 +214,13 @@
 				DEBUG_PRINT_ERROR("Failed to dequeue buf: %d from output capability\n", rc);
 				break;
 			}
-            vdec_msg.msgcode=VDEC_MSG_RESP_INPUT_BUFFER_DONE;
+			vdec_msg.msgcode=VDEC_MSG_RESP_INPUT_BUFFER_DONE;
 			vdec_msg.status_code=VDEC_S_SUCCESS;
 			vdec_msg.msgdata.input_frame_clientdata=(void*)&v4l2_buf;
-		} else if (pfd.revents & POLLPRI){
-			rc = ioctl(pfd.fd, VIDIOC_DQEVENT, &dqevent);
-			if(dqevent.u.data[0] == MSM_VIDC_DECODER_EVENT_CHANGE){
-				vdec_msg.msgcode=VDEC_MSG_EVT_CONFIG_CHANGED;
-				vdec_msg.status_code=VDEC_S_SUCCESS;
-				printf("\n VIDC Port Reconfig recieved \n");
-			} else if (dqevent.u.data[0] == MSM_VIDC_DECODER_FLUSH_DONE){
-				vdec_msg.msgcode=VDEC_MSG_RESP_FLUSH_OUTPUT_DONE;
-				vdec_msg.status_code=VDEC_S_SUCCESS;
-				DEBUG_PRINT_HIGH("\n VIDC Flush Done Recieved \n");
-			} else {
-				DEBUG_PRINT_HIGH("\n VIDC Some Event recieved \n");
-				continue;
-			}
-		} else if (pfd.revents & POLLERR){
-			DEBUG_PRINT_HIGH("\n async_message_thread Exited \n");
-			break;
-		} else{
-			/*TODO: How to handle this case */		
-			continue;
-		}
-
-		if (omx->async_message_process(input,&vdec_msg) < 0) {
-			DEBUG_PRINT_HIGH("\n async_message_thread Exited  \n");
+			if (omx->async_message_process(input,&vdec_msg) < 0) {
+				DEBUG_PRINT_HIGH("\n async_message_thread Exited  \n");
 				break;
+			}
 		}
   }
     DEBUG_PRINT_HIGH("omx_vdec: Async thread stop\n");
@@ -569,6 +585,68 @@
 
 }
 
+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,
+};
+
+static OMX_ERRORTYPE subscribe_to_events(int fd)
+{
+	OMX_ERRORTYPE eRet = OMX_ErrorNone;
+	struct v4l2_event_subscription sub;
+	int array_sz = sizeof(event_type)/sizeof(int);
+	int i,rc;
+	if (fd < 0) {
+		printf("Invalid input: %d\n", fd);
+		return OMX_ErrorBadParameter;
+	}
+
+	for (i = 0; i < array_sz; ++i) {
+		memset(&sub, 0, sizeof(sub));
+		sub.type = event_type[i];
+		rc = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
+		if (rc) {
+			printf("Failed to subscribe event: 0x%x\n", sub.type);
+			break;
+		}
+	}
+	if (i < array_sz) {
+		for (--i; i >=0 ; i--) {
+			memset(&sub, 0, sizeof(sub));
+			sub.type = event_type[i];
+			rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub);
+			if (rc)
+				printf("Failed to unsubscribe event: 0x%x\n", sub.type);
+		}
+		eRet = OMX_ErrorNotImplemented;
+	}
+	return eRet;
+}
+
+
+static OMX_ERRORTYPE unsubscribe_to_events(int fd)
+{
+	OMX_ERRORTYPE eRet = OMX_ErrorNone;
+	struct v4l2_event_subscription sub;
+	int array_sz = sizeof(event_type)/sizeof(int);
+	int i,rc;
+	if (fd < 0) {
+		printf("Invalid input: %d\n", fd);
+		return OMX_ErrorBadParameter;
+	}
+
+	for (i = 0; i < array_sz; ++i) {
+		memset(&sub, 0, sizeof(sub));
+		sub.type = event_type[i];
+		rc = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub);
+		if (rc) {
+			printf("Failed to unsubscribe event: 0x%x\n", sub.type);
+			break;
+		}
+	}
+	return eRet;
+}
 
 /* ======================================================================
 FUNCTION
@@ -595,6 +673,7 @@
   pthread_join(msg_thread_id,NULL);
   DEBUG_PRINT_HIGH("Waiting on OMX Async Thread exit");
   pthread_join(async_thread_id,NULL);
+  unsubscribe_to_events(drv_ctx.video_driver_fd);
   close(drv_ctx.video_driver_fd);
   pthread_mutex_destroy(&m_lock);
   sem_destroy(&m_cmd_lock);
@@ -1170,8 +1249,6 @@
 
 }
 
-
-
 /* ======================================================================
 FUNCTION
   omx_vdec::ComponentInit
@@ -1365,10 +1442,7 @@
 
 		drv_ctx.output_format = VDEC_YUV_FORMAT_TILE_4x2;
 		capture_capability= V4L2_PIX_FMT_NV12;
-
-		struct v4l2_event_subscription sub;
-		sub.type=V4L2_EVENT_ALL;
-		ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
+		ret = subscribe_to_events(drv_ctx.video_driver_fd);
 		if (ret) {
 			DEBUG_PRINT_ERROR("\n Subscribe Event Failed \n");
 			return OMX_ErrorInsufficientResources;
@@ -1813,46 +1887,39 @@
        DEBUG_PRINT_LOW("\n Command Recieved in OMX_StateExecuting");
        /* Requesting transition from Executing to Idle */
        if(eState == OMX_StateIdle)
-       {
-         /* Since error is None , we will post an event
-         at the end of this function definition
-         */
-         DEBUG_PRINT_LOW("\n send_command_proxy(): Executing --> Idle \n");
-         //BITMASK_SET(&m_flags,OMX_COMPONENT_IDLE_PENDING);
-         if(!sem_posted)
-         {
-           sem_posted = 1;
-           sem_post (&m_cmd_lock);
-           execute_omx_flush(OMX_ALL);
-         }
-         bFlag = 1;
-	 int rc=0;
-	 enum v4l2_buf_type btype;
-	 btype = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-	 rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMOFF, &btype);
-	 if (rc) {
-		 /*TODO: How to handle this case */
-		 DEBUG_PRINT_ERROR("\n Failed to call streamoff on OUTPUT Port \n");
-	 } else {
-		 streaming[OUTPUT_PORT] = false;
-	 }
-	 btype = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-	 rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMOFF, &btype);
-	 if (rc) {
-		 /*TODO: How to handle this case */
-		 DEBUG_PRINT_ERROR("\n Failed to call streamoff on CAPTURE Port \n");
-	 } else {
-		 streaming[CAPTURE_PORT] = false;
-	 }
-		struct v4l2_event_subscription sub;
-		sub.type=V4L2_EVENT_ALL;
-		ret = ioctl(drv_ctx.video_driver_fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub);
-		if (ret) {
-		DEBUG_PRINT_ERROR("\n Subscribe Event Failed \n");
-		eRet = OMX_ErrorHardware;
-		}
-	 m_state == OMX_StateIdle;
-       }
+	   {
+		   /* Since error is None , we will post an event
+			  at the end of this function definition
+			*/
+		   DEBUG_PRINT_LOW("\n send_command_proxy(): Executing --> Idle \n");
+		   //BITMASK_SET(&m_flags,OMX_COMPONENT_IDLE_PENDING);
+		   if(!sem_posted)
+		   {
+			   sem_posted = 1;
+			   sem_post (&m_cmd_lock);
+			   execute_omx_flush(OMX_ALL);
+		   }
+		   bFlag = 1;
+		   int rc=0;
+		   enum v4l2_buf_type btype;
+		   btype = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+		   rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMOFF, &btype);
+		   if (rc) {
+			   /*TODO: How to handle this case */
+			   DEBUG_PRINT_ERROR("\n Failed to call streamoff on OUTPUT Port \n");
+		   } else {
+			   streaming[OUTPUT_PORT] = false;
+		   }
+		   btype = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+		   rc = ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMOFF, &btype);
+		   if (rc) {
+			   /*TODO: How to handle this case */
+			   DEBUG_PRINT_ERROR("\n Failed to call streamoff on CAPTURE Port \n");
+		   } else {
+			   streaming[CAPTURE_PORT] = false;
+		   }
+		   m_state = OMX_StateIdle;
+	   }
        /* Requesting transition from Executing to Paused */
        else if(eState == OMX_StatePause)
        {
@@ -5428,6 +5495,13 @@
   {
 	enum v4l2_buf_type buf_type;
 	int ret,r;
+
+	struct v4l2_control control;
+	control.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
+	control.value = 1;
+	ret=ioctl(drv_ctx.video_driver_fd, VIDIOC_S_CTRL,&control);
+	if(ret)
+		printf("\n Continue data Xfer failed \n");
 	buf_type=V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
         DEBUG_PRINT_LOW("send_command_proxy(): Idle-->Executing\n");
 	ret=ioctl(drv_ctx.video_driver_fd, VIDIOC_STREAMON,&buf_type);