{"id":1708,"date":"2019-03-21T18:09:15","date_gmt":"2019-03-21T09:09:15","guid":{"rendered":"http:\/\/rageworx.info\/?p=1708"},"modified":"2022-06-16T00:26:51","modified_gmt":"2022-06-15T15:26:51","slug":"v4l2-v4l-utils-capture-for-multi-planar-2","status":"publish","type":"post","link":"https:\/\/rageworx.info\/?p=1708","title":{"rendered":"V4L2 + V4l-utils, Capture for multi-planar #2"},"content":{"rendered":"<blockquote><p>This post was continued from &#8220;<a href=\"http:\/\/rageworx.info\/index.php\/v4l2-v4l-utils-capture-for-multi-planar-1\/\" target=\"_blank\" rel=\"noopener noreferrer\">V4L2 + V4l-utils, Capture for multi-planar #1<\/a>&#8220;<\/p><\/blockquote>\n<h2>Querying external controls<\/h2>\n<p>Getting external control should be an optional job, but it maybe needed to control brightness and gain for good to get excellent balanced image. Little bit difficult to understand in first time but can be understood soon.<\/p>\n<p>Query all user controls should be used as like this,<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"dracula\">struct v4l2_query_ext_ctrl* pExtCtl = new struct v4l2_query_ext_ctrl;\r\nmemset( pExtCtl, 0, sizeof( struct v4l2_query_ext_ctrl ) );\r\npExtCtl-&gt;id = V4L2_CID_USER_BASE;\r\n\r\nret = v4l_query_ext_ctrl( &amp;camera_fd, pExtCtl, false, false );\r\nwhile( ret &gt;= 0 )\r\n{\r\n    printf( \":::found external control : %X - %s\\n\",\r\n            pExtCtl-&gt;id,\r\n            pExtCtl-&gt;name );\r\n\r\n    unsigned tmpid = pExtCtl-&gt;id;\r\n    memset( pExtCtl, 0, sizeof( struct v4l2_query_ext_ctrl ) )\r\n    pExtCtl-&gt;id = tmpid;\r\n\r\n    \/\/ search for next control.\r\n    ret = v4l_query_ext_ctrl( &amp;camera_fd, pExtCtl, true, false );\r\n\r\n    if ( pExtCtl-&gt;id == tmpid )\r\n        break;\r\n}\r\n\r\ndelete pExtCtl;\r\n<\/pre>\n<p>It shows all user controls as below result.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-theme=\"dracula\">:::found external control : 980900 -\r\n:::found external control : 980911 - Exposure\r\n:::found external control : 980913 - Gain\r\n:::found external control : 980914 - Horizontal Flip\r\n:::found external control : 980915 - Vertical Flip\r\n:::found external control : 9F0001 - Image Processing Controls\r\n:::found external control : 9F0901 - Link Frequency\r\n:::found external control : 9F0902 - Pixel Rate\r\n:::found external control : 9F0903 - Test Pattern\r\n:::found external control : 809F0903 -<\/pre>\n<p>Some user controls no name or symbol, so it should filtered out for only named control by checking string length with strlen().<\/p>\n<h3>Some tweaks for exposure and gain<\/h3>\n<p>In search of looping by v4l_query_ext_ctrl(), it should be export some external control for future, and here some code for getting exposure and gain control.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"dracula\">struct v4l2_query_ext_ctrl* pExtCtlExposure = NULL;\r\nstruct v4l2_query_ext_ctrl* pExtCtlGain = NULL;\r\n\r\nstruct v4l2_query_ext_ctrl* pExtCtl = new struct v4l2_query_ext_ctrl;\r\nmemset( pExtCtl, 0, sizeof( struct v4l2_query_ext_ctrl ) );\r\npExtCtl-&gt;id = V4L2_CID_USER_BASE;\r\n\r\nret = v4l_query_ext_ctrl( &amp;camera_fd, pExtCtl, false, false );\r\nwhile( ret &gt;= 0 )\r\n{\r\n    unsigned tmpid = pExtCtl-&gt;id;\r\n    \r\n    switch( pExtCtl-&gt;id )\r\n    {\r\n        case V4L2_CID_EXPOSURE:\r\n            pExtCtlExposure = pExtCtl;\r\n            break;\r\n            \r\n        case V4L2_CID_GAIN:\r\n            pExtCtlGain = pExtCtl;\r\n            break;\r\n            \r\n        default:\r\n            delete pExtCtl;\r\n    }\r\n        \r\n    pExtCtl = new struct v4l2_query_ext_ctrl;\r\n    memset( pExtCtl, 0, sizeof( struct v4l2_query_ext_ctrl ) );    \r\n    pExtCtl-&gt;id = tmpid;\r\n\r\n    \/\/ search for next control.\r\n    ret = v4l_query_ext_ctrl( &amp;camera_fd, pExtCtl, true, false );\r\n\r\n    if ( pExtCtl-&gt;id == tmpid )\r\n        break;\r\n}\r\n<\/pre>\n<p>Then, exposure should be adjusted as below:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"dracula\">bool adjustExposure( int val )\r\n{\r\n    struct v4l2_control c = {0};\r\n\r\n    int  maxv = pExtCtlExposure-&gt;maximum;\r\n    int  minv = pExtCtlExposure-&gt;minimum;\r\n    int  step = pExtCtlExposure-&gt;step;\r\n\r\n    if ( val &gt; maxv )\r\n        val = maxv;\r\n    else\r\n    if ( val &lt; minv )\r\n        val = minv;\r\n    \r\n    c.id    = V4L2_CID_EXPOSURE;\r\n    c.value = step * ( val \/ step );\r\n    int ret = v4l_ioctl( cfd, VIDIOC_S_CTRL, &amp;c );\r\n\r\n    if ( ret &lt; 0 )\r\n    {\r\n        perror( \"EXPOSURE CONTROL\" );\r\n        return false;\r\n    }\r\n\r\n    return true;\r\n}<\/pre>\n<h2>Now, it&#8217;s turn to capture<\/h2>\n<p>To getting secured image from MIPI CSI-2 camera types with Multiplanar, it should be recommended using memory type for NMAP for quickly approaching to driver side memroy access. And need to following sequence to prepare buffers to be get image data from memory in directly.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"dracula\">unsigned memtype = V4L2_MEMORY_MMAP;\r\n\r\nv4l_buffer vbuffer;\r\nv4l_buffer_init( &amp;vbuffer, captype, memtype, 0 );\r\nv4l_queue  vqueue;\r\n\r\nret = v4l_buffer_prepare_buf( &amp;cam1, &amp;vbuffer );\r\nif ( ret &lt; 0 ) perror( \"v4l_buffer_prepare_buf()\" );\r\n\r\nv4l_queue_init( &amp;vqueue, captype, memtype );\r\n\r\nret = v4l_queue_querybufs( &amp;cam1, &amp;vqueue, 0 );\r\nif ( ret &lt; 0 ) perror( \"v4l_queue_querybufs()\" );\r\n\r\nret = v4l_queue_reqbufs( &amp;cam1, &amp;vqueue, REQ_BUFF_SZ );\r\nif ( ret &lt; 0 ) perror( \"v4l_queue_reqbufs()\" );\r\n\r\nret = v4l_queue_mmap_bufs( &amp;cam1, &amp;vqueue, 0 );\r\nif ( ret &lt; 0 ) perror( \"v4l_queue_mmap_bufs()\" );<\/pre>\n<p>REQ_BUFF_SZ is a pre-definition set for 4. And v4l_queu_reqbufs() count at least or bigger than 4. Now you can make stream on for grab continuously buffers.<\/p>\n<h2>Make it streamed on<\/h2>\n<p>Before it captures any image from camera, it must be started streaming to \u201con\u201d as below:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"dracula\">int ret = v4l_ioctl( &amp;cam1, VIDIOC_STREAMON, &amp;vqueue.type );\r\nif ( ret &lt; 0 ) perror( \"v4l_ioctrl(VIDIOC_STREAMON)\" );<\/pre>\n<p>If it fails or, doesn&#8217;t do this, it will impossibly get real captured image \u2013 just blacked (NULL) image may receive.<\/p>\n<h2>Wait for a sync.<\/h2>\n<p>Every camera, monitors has V-Sync signal for complete draw and capture. V4L just simply can make it sens with select() as below code:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"dracula\">fd_set fds;\r\n\r\nFD_ZERO( &amp;fds );\r\nFD_SET( realfd, &amp;fds );\r\n\r\nstruct timeval tv;\r\ntv.tv_sec = 1;\r\ntv.tv_usec = 0;\r\n\r\nret = select( realfd + 1, &amp;fds, NULL, NULL, &amp;tv );\r\nif ( ret &lt;= 0 ) perror( \"wait sync failure.\\n\" );<\/pre>\n<p>If it returns to failure, just skip for capturing image.<\/p>\n<h2>Getting an image now<\/h2>\n<p>When it succeeds to wait a V-Sync, now time to get image as below:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"dracula\">int ret = v4l_buffer_dqbuf( &amp;camera_fd, &amp;vbuffer );\r\nif ( ret &lt; 0 ) perror( \"v4l_buffer_dqbuf()\" );\r\n\r\nunsigned bufflen = v4l_queue_g_length( &amp;vqueue, 0 );\r\nif ( bufflen &gt; 0 )\r\n{\r\n    size_t bidx = 0;\r\n    void* ptrData = v4l_queue_g_mmapping( &amp;vqueue, bidx, 0 );\r\n    if ( ptrData != NULL )\r\n    {\r\n        \/\/ ptrData is RAW pixel array from camera or ISP.\r\n    }\r\n}\r\n\r\nret = v4l_buffer_qbuf( &amp;camera_fd, &amp;vbuffer );\r\nif ( ret &lt; 0 ) perror( \"v4l_buffer_qbuf()\" );<\/pre>\n<p>It&#8217;s done to get an image from camera with v4l_queue_g_mmapping().<\/p>\n<h2>Conclusion<\/h2>\n<p>Controlling V4L2 with only native API is very hard to understand, controlling and handling all. But v4l-utils helps to make it easier than before but still hard to understand all because there are not many good examples not existed. So I will continue to writing some articles for understanding multiplanar typed camera accessing methods.<\/p>\n<p>Any question should be let written on guest book.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post was continued from &#8220;V4L2 + V4l-utils, Capture for multi-planar #1&#8220; Querying external controls Getting external control should be an optional job, but it maybe needed to control brightness and gain for good to get excellent balanced image. Little bit difficult to understand in first time but can be&#8230; <a href=\"https:\/\/rageworx.info\/?p=1708\">Read more &raquo;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,573,3],"tags":[10,193,11,616,609,152,102,153,608,615,614,606],"class_list":["post-1708","post","type-post","status-publish","format-standard","hentry","category-development","category-embedded","category-raphs","tag-c","tag-camera","tag-code","tag-cpp","tag-csi2","tag-embedded","tag-example","tag-linux","tag-mipi","tag-v4l","tag-v4l-utils","tag-v4l2"],"_links":{"self":[{"href":"https:\/\/rageworx.info\/index.php?rest_route=\/wp\/v2\/posts\/1708","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rageworx.info\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rageworx.info\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rageworx.info\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rageworx.info\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1708"}],"version-history":[{"count":0,"href":"https:\/\/rageworx.info\/index.php?rest_route=\/wp\/v2\/posts\/1708\/revisions"}],"wp:attachment":[{"href":"https:\/\/rageworx.info\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1708"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rageworx.info\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1708"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rageworx.info\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1708"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}