{"id":896,"date":"2022-11-25T14:48:14","date_gmt":"2022-11-25T06:48:14","guid":{"rendered":"https:\/\/swordofmorning.com\/?p=896"},"modified":"2025-10-09T13:55:34","modified_gmt":"2025-10-09T05:55:34","slug":"linux-media-01","status":"publish","type":"post","link":"https:\/\/swordofmorning.com\/index.php\/2022\/11\/25\/linux-media-01\/","title":{"rendered":"Linux Media 01 Get UVC Camera Data via V4L2"},"content":{"rendered":"<p><div class=\"has-toc have-toc\"><\/div><\/p>\n<p>&emsp;&emsp;In this page, I'll introduce how to get UVC camera data via v4l2. Here is my environment:<\/p>\n<ol>\n<li>Dev Board: QiHua-RV1126<\/li>\n<li>Camera: Rmoncam A2 1080P<\/li>\n<li>System: Linux 4.19.193 #12 SMP PREEMPT Tue Nov 15 11:21:50 CST 2022 armv7l GNU\/Linux<\/li>\n<\/ol>\n<h2>\u00a71 Check Camera Information<\/h2>\n<p>&emsp;&emsp;We'll use <code>v4l2-ctl<\/code> command to check camera information, here is some commands we need:<\/p>\n<ol>\n<li><code>v4l2-ctl --list-device<\/code>, list all video device.<\/li>\n<li><code>v4l2-ctl --all -d \/dev\/video45<\/code>, list all information of video45.<\/li>\n<li><code>v4l2-ctl --list-formats -d \/dev\/video45<\/code>, list output formats of video45.<\/li>\n<li><code>v4l2-ctl --list-formats-ext -d \/dev\/video45<\/code>, list detailed information which include image size and fps.<\/li>\n<\/ol>\n<p>Here is my uvc camera's info:<\/p>\n<pre><code class=\"language-shell\">[root@DCIR:\/]# v4l2-ctl --all -d \/dev\/video45\nDriver Info:\n    Driver name      : uvcvideo\n    Card type        : Rmoncam A2 1080P: RMONCAM A2 10\n    Bus info         : usb-ffe00000.usb-1.3\n    Driver version   : 4.19.193\n    Capabilities     : 0x84a00001\n        Video Capture\n        Metadata Capture\n        Streaming\n        Extended Pix Format\n        Device Capabilities\n    Device Caps      : 0x04200001\n        Video Capture\n        Streaming\n        Extended Pix Format\nMedia Driver Info:\n    Driver name      : uvcvideo\n    Model            : Rmoncam A2 1080P: RMONCAM A2 10\n    Serial           : 200901010001\n    Bus info         : usb-ffe00000.usb-1.3\n    Media version    : 4.19.193\n    Hardware revision: 0x00000101 (257)\n    Driver version   : 4.19.193\nInterface Info:\n    ID               : 0x03000002\n    Type             : V4L Video\nEntity Info:\n    ID               : 0x00000001 (1)\n    Name             : Rmoncam A2 1080P: RMONCAM A2 10\n    Function         : V4L2 I\/O\n    Flags         : default\n    Pad 0x01000004   : 0: Sink\n      Link 0x0200000d: from remote pad 0x1000007 of entity &#039;Extension 4&#039;: Data, Enabled, Immutable\nPriority: 2\nVideo input : 0 (Camera 1: ok)\nFormat Video Capture:\n    Width\/Height      : 1920\/1080\n    Pixel Format      : &#039;MJPG&#039; (Motion-JPEG)\n    Field             : None\n    Bytes per Line    : 0\n    Size Image        : 4147200\n    Colorspace        : sRGB\n    Transfer Function : Default (maps to sRGB)\n    YCbCr\/HSV Encoding: Default (maps to ITU-R 601)\n    Quantization      : Default (maps to Full Range)\n    Flags             : \nCrop Capability Video Capture:\n    Bounds      : Left 0, Top 0, Width 1920, Height 1080\n    Default     : Left 0, Top 0, Width 1920, Height 1080\n    Pixel Aspect: 1\/1\nSelection: crop_default, Left 0, Top 0, Width 1920, Height 1080, Flags: \nSelection: crop_bounds, Left 0, Top 0, Width 1920, Height 1080, Flags: \nStreaming Parameters Video Capture:\n    Capabilities     : timeperframe\n    Frames per second: 30.000 (30\/1)\n    Read buffers     : 0\n                     brightness 0x00980900 (int)    : min=-64 max=64 step=1 default=0 value=0\n                       contrast 0x00980901 (int)    : min=0 max=100 step=1 default=32 value=32\n                     saturation 0x00980902 (int)    : min=0 max=100 step=1 default=64 value=64\n                            hue 0x00980903 (int)    : min=-180 max=180 step=1 default=0 value=0\n white_balance_temperature_auto 0x0098090c (bool)   : default=1 value=1\n                          gamma 0x00980910 (int)    : min=100 max=500 step=1 default=300 value=300\n                           gain 0x00980913 (int)    : min=1 max=128 step=1 default=64 value=64\n           power_line_frequency 0x00980918 (menu)   : min=0 max=2 default=1 value=1\n      white_balance_temperature 0x0098091a (int)    : min=2800 max=6500 step=10 default=4600 value=4600 flags=inactive\n                      sharpness 0x0098091b (int)    : min=0 max=100 step=1 default=50 value=50\n         backlight_compensation 0x0098091c (int)    : min=0 max=2 step=1 default=0 value=0\n                  exposure_auto 0x009a0901 (menu)   : min=0 max=3 default=3 value=3\n              exposure_absolute 0x009a0902 (int)    : min=50 max=10000 step=1 default=166 value=166 flags=inactive\n         exposure_auto_priority 0x009a0903 (bool)   : default=0 value=1<\/code><\/pre>\n<p>and let's check it's formats:<\/p>\n<pre><code class=\"language-shell\">[root@DCIR:\/]# v4l2-ctl --list-formats -d \/dev\/video45\nioctl: VIDIOC_ENUM_FMT\n    Type: Video Capture\n\n    [0]: &#039;MJPG&#039; (Motion-JPEG, compressed)\n    [1]: &#039;YUYV&#039; (YUYV 4:2:2)\n[root@DCIR:\/]# v4l2-ctl --list-formats-ext -d \/dev\/video45\nioctl: VIDIOC_ENUM_FMT\n    Type: Video Capture\n\n    [0]: &#039;MJPG&#039; (Motion-JPEG, compressed)\n        Size: Discrete 1920x1080\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 160x120\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 320x240\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 320x180\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 640x480\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 800x600\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 848x480\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 960x540\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 1280x720\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 1280x1024\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 640x360\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 176x144\n            Interval: Discrete 0.033s (30.000 fps)\n    [1]: &#039;YUYV&#039; (YUYV 4:2:2)\n        Size: Discrete 1920x1080\n            Interval: Discrete 0.200s (5.000 fps)\n        Size: Discrete 160x120\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 320x240\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 320x180\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 640x480\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 800x600\n            Interval: Discrete 0.050s (20.000 fps)\n        Size: Discrete 848x480\n            Interval: Discrete 0.050s (20.000 fps)\n        Size: Discrete 960x540\n            Interval: Discrete 0.050s (20.000 fps)\n        Size: Discrete 1280x720\n            Interval: Discrete 0.100s (10.000 fps)\n        Size: Discrete 1280x1024\n            Interval: Discrete 0.100s (10.000 fps)\n        Size: Discrete 640x360\n            Interval: Discrete 0.033s (30.000 fps)\n        Size: Discrete 176x144\n            Interval: Discrete 0.033s (30.000 fps)<\/code><\/pre>\n<h2>\u00a72 Example Code<\/h2>\n<h3>2.1 extern define<\/h3>\n<p>&emsp;&emsp;I'd like to get yuv data, so I choose <code>V4L2_PIX_FMT_YUYV<\/code> as my pix format. Usually, UVC camera is single-planar capture, so our buffer type is <code>V4L2_BUF_TYPE_VIDEO_CAPTURE<\/code>, but some MIPI-CSI, DVP and CIF camera maybe multi-planar device, and it's parsing method is different from single-planar device. The method of getting multi-planar camera data will be introduce in subsequent chapters. At the same time, we specify the query buffer number equals 5.<\/p>\n<pre><code class=\"language-c\">\/* =================== *\/\n\/* ===== .h file ===== *\/\n\/* =================== *\/\n\n#define _Video_Device_SP_ &quot;\/dev\/video45&quot;\n#define _V4L2_SP_PIX_FMT_ V4L2_PIX_FMT_YUYV\n#define _V4L2_SP_BUF_TYPE_ V4L2_BUF_TYPE_VIDEO_CAPTURE\n#define _V4L2_SP_BUF_REQ_COUNT_ 5\n\nextern const int v4l2_sp_capture_width;\nextern const int v4l2_sp_capture_height;\n\n\/\/ device number for v4l2 single-planar\nextern int v4l2_sp_fd;\n\n\/\/ global memory for mmap v4l2 query buffer, 5 block\nextern uint8_t* v4l2_sp_globalBuffer[_V4L2_SP_BUF_REQ_COUNT_];\n\n\/\/ global memory buffer length\nextern int v4l2_sp_globalBufferLength;\n\n\/\/ to specify which memory is currently available\nextern int v4l2_sp_globalBufferIndex;\n\n\/\/ to specify globalBuffer length\nextern int v4l2_sp_globalBufferLength;\n\n\/\/ stop capture or not\nextern bool v4l2_sp_captureLoopFlag;\n\n\/* =================== *\/\n\/* ===== .c file ===== *\/\n\/* =================== *\/\n\nconst int v4l2_sp_capture_width = 640;\nconst int v4l2_sp_capture_height = 480;\n\nint v4l2_sp_fd;\nuint8_t* v4l2_sp_globalBuffer[_V4L2_SP_BUF_REQ_COUNT_];\nint v4l2_sp_globalBufferLength;\nint v4l2_sp_globalBufferIndex;\n\nbool v4l2_sp_captureLoopFlag = true;<\/code><\/pre>\n<h3>2.1 implement<\/h3>\n<pre><code class=\"language-c\">int V4L2_SP_Streaming()\n{\n    \/* Step 0 : Pre-Define *\/\n    int retval = 0;     \/\/ V4L2_SP_Streaming return value\n    int ret = 0;        \/\/ ioctl check\n\n#if Print_Debug_Info\n    printf(&quot;V4L2_SP_Streaming(): Step 1 Open Device\\n&quot;);\n#endif\n    \/* Step 1 : Open Device *\/\n    v4l2_sp_fd = open(_Video_Device_SP_, O_RDWR);\n    if (v4l2_sp_fd == -1)\n    {\n        perror(&quot;V4L2_SP_Streaming() open device&quot;);\n        retval = 1;\n        goto out_return;\n    }\n\n#if Print_Debug_Info\n    printf(&quot;V4L2_SP_Streaming(): Step 2 Setting Capture Format\\n&quot;);\n#endif\n    \/* Step 2: Setting Capture Format *\/\n    struct v4l2_format format;\n    format.type = _V4L2_SP_BUF_TYPE_;\n    format.fmt.pix.width = v4l2_sp_capture_width;\n    format.fmt.pix.height = v4l2_sp_capture_height;\n    format.fmt.pix.pixelformat = _V4L2_SP_PIX_FMT_;\n\n    ret = ioctl(v4l2_sp_fd, VIDIOC_S_FMT, &amp;format);             \/\/ set FMT\n    if (ret == -1)\n    {\n        perror(&quot;V4L2_SP_Streaming() setting format&quot;);\n        retval = 2;\n        goto error_close;\n    }\n\n#if Print_Debug_Info\n    printf(&quot;V4L2_SP_Streaming(): Step 3 Checking FMT Setting\\n&quot;);\n#endif\n    \/* Step 3: Checking FMT Setting *\/\n    ret = ioctl(v4l2_sp_fd, VIDIOC_G_FMT, &amp;format);             \/\/ get FMT\n    if (ret == -1)\n    {\n        perror(&quot;V4L2_SP_Streaming() checking format&quot;);\n        retval = 3;\n        goto error_close;\n    }\n\n    if (format.fmt.pix.pixelformat == _V4L2_SP_PIX_FMT_)        \/\/ set FMT == get FMT ?\n    {\n        printf(&quot;ioctl VIDIOC_S_FMT sucessful\\n&quot;);\n    }\n    else\n    {\n        printf(&quot;ioctl VIDIOC_S_FMT failed\\n&quot;);\n        retval = 4;\n        goto error_close;\n    }\n\n#if Print_Debug_Info\n    printf(&quot;V4L2_SP_Streaming(): Step 4 Request Buffer\\n&quot;);\n#endif\n    \/* Step 4: Request Buffer *\/\n    struct v4l2_requestbuffers reqbuf;\n    reqbuf.count = _V4L2_SP_BUF_REQ_COUNT_;\n    reqbuf.type = _V4L2_SP_BUF_TYPE_;\n    reqbuf.memory = V4L2_MEMORY_MMAP;\n    ret = ioctl(v4l2_sp_fd, VIDIOC_REQBUFS, &amp;reqbuf);\n    if (-1 == ret)\n    {\n        perror(&quot;V4L2_SP_Streaming() reqeuset buff&quot;);\n        retval = 1;\n        goto error_close;\n    }\n\n#if Print_Debug_Info\n    printf(&quot;V4L2_SP_Streaming(): Step 5 mmap Buffer\\n&quot;);\n#endif\n    \/* Step 5: mmap Buffer *\/\n    struct v4l2_buffer buff;\n    buff.type = _V4L2_SP_BUF_TYPE_;\n    buff.memory = V4L2_MEMORY_MMAP;\n    for (int i = 0; i &lt; _V4L2_SP_BUF_REQ_COUNT_; ++i)\n    {\n        \/\/ query buf\n        buff.index = i;\n        ret = ioctl(v4l2_sp_fd, VIDIOC_QUERYBUF, &amp;buff);\n        if (ret == -1)\n        {\n            perror(&quot;V4L2_SP_Streaming() query&quot;);\n            retval = 2;\n            goto error_close;\n        }\n\n        printf(&quot;buf[%d]: len = %d offset: %d\\n&quot;, i, buff.length, buff.m.offset);\n\n        \/\/ mmap\n        v4l2_sp_globalBuffer[i] = mmap(NULL, buff.length, PROT_READ, MAP_SHARED, v4l2_sp_fd, buff.m.offset);\n        v4l2_sp_globalBufferLength = buff.length;\n        if (MAP_FAILED == v4l2_sp_globalBuffer[i])\n        {\n            perror(&quot;V4L2_SP_Streaming() mmap&quot;);\n            retval = 3;\n            goto error_munmap;\n        }\n\n        \/\/ queue\n        ret = ioctl(v4l2_sp_fd, VIDIOC_QBUF, &amp;buff);\n        if (-1 == ret)\n        {\n            perror(&quot;V4L2_SP_Streaming() queue&quot;);\n            retval = 4;\n            goto error_munmap;\n        }\n    }\n\n#if Print_Debug_Info\n    printf(&quot;V4L2_SP_Streaming(): Step 6 Start Streaming\\n&quot;);\n#endif\n    \/* Step 6: Start Streaming *\/\n    int on = _V4L2_SP_BUF_TYPE_;\n    ret = ioctl(v4l2_sp_fd, VIDIOC_STREAMON, &amp;on);\n    if (-1 == ret)\n    {\n        perror(&quot;V4L2_SP_Streaming() VIDIOC_STREAMON&quot;);\n        retval = 5;\n        goto error_munmap;\n    }\n\n#if Print_Debug_Info\n    printf(&quot;V4L2_SP_Streaming(): Step 7 Capture\\n&quot;);\n#endif\n    \/* Step 7: Capture *\/\n    while (v4l2_sp_captureLoopFlag)\n    {\n        \/\/ deque\n        ret = ioctl(v4l2_sp_fd, VIDIOC_DQBUF, &amp;buff);\n        if (ret != -1)\n        {\n            \/\/ updata global var\n            v4l2_sp_globalBufferIndex = buff.index;\n            v4l2_sp_globalBufferLength = buff.bytesused;\n\n            \/\/ queue\n            ret = ioctl(v4l2_sp_fd, VIDIOC_QBUF, &amp;buff);\n        }\n    }\n\n#if Print_Debug_Info\n    printf(&quot;V4L2_SP_Streaming(): Exit\\n&quot;);\n#endif\nerror_munmap:\n    for (int i = 0; i &lt; _V4L2_SP_BUF_REQ_COUNT_; ++i)\n    {\n        if (v4l2_sp_globalBuffer[i] != NULL)\n            munmap(v4l2_sp_globalBuffer[i], v4l2_sp_globalBufferLength);\n    }\n\nerror_close:\n    close(v4l2_sp_fd);\n\nout_return:\n    return retval;\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>&emsp;&emsp;In this page, I&#8217;ll introduce how to get UVC camera da &#823","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[54],"tags":[],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/swordofmorning.com\/index.php\/wp-json\/wp\/v2\/posts\/896"}],"collection":[{"href":"https:\/\/swordofmorning.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/swordofmorning.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/swordofmorning.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/swordofmorning.com\/index.php\/wp-json\/wp\/v2\/comments?post=896"}],"version-history":[{"count":6,"href":"https:\/\/swordofmorning.com\/index.php\/wp-json\/wp\/v2\/posts\/896\/revisions"}],"predecessor-version":[{"id":904,"href":"https:\/\/swordofmorning.com\/index.php\/wp-json\/wp\/v2\/posts\/896\/revisions\/904"}],"wp:attachment":[{"href":"https:\/\/swordofmorning.com\/index.php\/wp-json\/wp\/v2\/media?parent=896"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/swordofmorning.com\/index.php\/wp-json\/wp\/v2\/categories?post=896"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/swordofmorning.com\/index.php\/wp-json\/wp\/v2\/tags?post=896"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}