---
tags: Linux kernel, vcam, v4l2
---
# vcam 測試記錄
此篇為測試 jserv 老師的 github 專案 [vcam](https://github.com/jserv/vcam) 的過程記錄。
測試環境
- Lubuntu 18.04
- Linux kernel 4.15.0-74
## 準備相關套件
編譯 linux kernel module 會用到 linux header。安裝命令如下:
```shell
$ sudo apt install linux-headers-$(uname -r)
```
為了方便後續驗證 vcam 的 v4l2 interface,先安裝工具 vlc 和 v4l-utils:
```shell
$ sudo apt install v4l-utils
$ sudo apt install vlc
```
編譯前最後一個步驟,下載 source code:
```shell
$ git clone https://github.com/jserv/vcam.git
```
## 編譯
在 vcam 目錄下執行 `make` 即可,過程訊息如下
> make -C /lib/modules/4.15.0-74-generic/build M=/home/ben/study/vcam modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-74-generic'
CC [M] /home/ben/study/vcam/module.o
CC [M] /home/ben/study/vcam/control.o
CC [M] /home/ben/study/vcam/device.o
CC [M] /home/ben/study/vcam/videobuf.o
CC [M] /home/ben/study/vcam/fb.o
LD [M] /home/ben/study/vcam/vcam.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/ben/study/vcam/vcam.mod.o
LD [M] /home/ben/study/vcam/vcam.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-74-generic'
cc -O2 -Wall -Wextra -pedantic -std=c99 -o vcam-util vcam-util.c
編譯完成可以看到目錄下產生了 kernel module 和執行檔,分別是 `vcam.ko` 和 `vcam-util`。
## 載入 vcam
測試的第一個步驟是載入編譯出的 module。首先確認相依的 module videobuf2_vmalloc 和 videobuf2_v4l2 是否已載入
```shell
$ lsmod | grep videobuf2*
```
因為我使用的電腦是內建 camera 的筆電,從下方輸出訊息可以看到相依 module 已經載入
> videobuf2_vmalloc 16384 1 uvcvideo
videobuf2_memops 16384 1 videobuf2_vmalloc
videobuf2_v4l2 24576 1 uvcvideo
videobuf2_core 40960 2 videobuf2_v4l2,uvcvideo
videodev 184320 3 videobuf2_core,videobuf2_v4l2,uvcvideo
若相依的 module 還未載入,執行下面指令載入
```shell
$ sudo modprobe videobuf2_vmalloc videobuf2_v4l2
```
執行下面指令載入 vcam module
```shell
$ sudo insmod vcam.ko
```
執行 `lsmod | grep vcam` 確認載入是否成功
> vcam 36864 0
videobuf2_vmalloc 16384 2 vcam,uvcvideo
videobuf2_v4l2 24576 2 vcam,uvcvideo
videobuf2_core 40960 3 vcam,videobuf2_v4l2,uvcvideo
videodev 184320 4 videobuf2_core,vcam,videobuf2_v4l2,uvcvideo
## 檢視 vcam 相關資訊
kernel module 載入後,可用下方指令列出目前有哪些 vcam device 產生
```shell
$ sudo ./vcam-util -l
```
輸出如下
> Available virtual V4L2 compatible devices:
> 1. vcamfb1(640,480,rgb24) -> /dev/video1
得知有一個 vcam device 是 /dev/video1,其對應輸入裝置為 vcamfb1,可接受的格式為 24-bit RGB,解析度 640x480。
實際使用指令 `ls -l /dev/video1` 確認 device file 存在
> crw-rw----+ 1 root video 81, 1 Feb 18 21:46 /dev/video1
此外 module 載入後還會產生一個 device file vcamctl,後續可用工具程式 vcam-util 對其做 ioctl,修改或增減 vcam device
> crw------- 1 root root 238, 0 Feb 18 21:46 /dev/vcamctl
使用下方指令測試此 vcam device 的能力(v4l2相關操作的相容性)
```shell
$ v4l2-compliance -d /dev/video1 -f
```
輸出結果如下
>v4l2-compliance SHA : not available
>
>Driver Info:
> Driver name : vcam
> Card type : vcam
> Bus info : platform: virtual
> Driver version: 4.15.18
> Capabilities : 0x85200001
> Video Capture
> Read/Write
> Streaming
> Extended Pix Format
> Device Capabilities
> Device Caps : 0x05200001
> Video Capture
> Read/Write
> Streaming
> Extended Pix Format
>
>Compliance test for device /dev/video1 (not using libv4l2):
>
>Required ioctls:
> test VIDIOC_QUERYCAP: OK
>
>Allow for multiple opens:
> test second video open: OK
> test VIDIOC_QUERYCAP: OK
> test VIDIOC_G/S_PRIORITY: OK
> test for unlimited opens: OK
>
>Debug ioctls:
> test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
> test VIDIOC_LOG_STATUS: OK (Not Supported)
>
>Input ioctls:
> test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
> test VIDIOC_ENUMAUDIO: OK (Not Supported)
> test VIDIOC_G/S/ENUMINPUT: OK
> test VIDIOC_G/S_AUDIO: OK (Not Supported)
> Inputs: 1 Audio Inputs: 0 Tuners: 0
>
>Output ioctls:
> test VIDIOC_G/S_MODULATOR: OK (Not Supported)
> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> test VIDIOC_ENUMAUDOUT: OK (Not Supported)
> test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
> test VIDIOC_G/S_AUDOUT: OK (Not Supported)
> Outputs: 0 Audio Outputs: 0 Modulators: 0
>
>Input/Output configuration ioctls:
> test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
> test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
> test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
> test VIDIOC_G/S_EDID: OK (Not Supported)
>
>Test input 0:
>
> Control ioctls:
> test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
> test VIDIOC_QUERYCTRL: OK (Not Supported)
> test VIDIOC_G/S_CTRL: OK (Not Supported)
> test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
> test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
> test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
> Standard Controls: 0 Private Controls: 0
>
> Format ioctls:
> test >VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
> fail: v4l2-test-formats.cpp(1140): node->has_frmintervals && !cap->capability
> test VIDIOC_G/S_PARM: FAIL
> test VIDIOC_G_FBUF: OK (Not Supported)
> test VIDIOC_G_FMT: OK
> test VIDIOC_TRY_FMT: OK
> test VIDIOC_S_FMT: OK
> test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
> test Cropping: OK (Not Supported)
> test Composing: OK (Not Supported)
> test Scaling: OK (Not Supported)
>
> Codec ioctls:
> test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
> test VIDIOC_G_ENC_INDEX: OK (Not Supported)
> test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
>
> Buffer ioctls:
> test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
> test VIDIOC_EXPBUF: OK
>
>Test input 0:
>
>Stream using all formats:
> test MMAP for Format RGB3, Frame Size 640x480@59.94 Hz:
> Stride 1920, Field None: OK
> test MMAP for Format RGB3, Frame Size 640x480@0.00 Hz:
> Stride 1920, Field None: OK
>
>Total: 45, Succeeded: 44, Failed: 1, Warnings: 0
下方指令也可以印出 vcam device 的相關資訊
```shell
$ sudo v4l2-ctl -d /dev/video1 --all
```
>Driver Info (not using libv4l2):
> Driver name : vcam
> Card type : vcam
> Bus info : platform: virtual
> Driver version: 4.15.18
> Capabilities : 0x85200001
> Video Capture
> Read/Write
> Streaming
> Extended Pix Format
> Device Capabilities
> Device Caps : 0x05200001
> Video Capture
> Read/Write
> Streaming
> Extended Pix Format
>Priority: 2
>Video input : 0 (vcam_in 0: ok)
>Format Video Capture:
> Width/Height : 640/480
> Pixel Format : 'RGB3'
> Field : None
> Bytes per Line : 1920
> Size Image : 921600
> Colorspace : sRGB
> Transfer Function : Default (maps to sRGB)
> YCbCr/HSV Encoding: Default (maps to ITU-R 601)
> Quantization : Default (maps to Full Range)
> Flags :
>Streaming Parameters Video Capture:
> Frames per second: 29.970 (30000/1001)
> Read buffers : 1
## 測試 vcam
使用 vlc 播放 vcam 影像
```shell
$ vlc v4l2:///dev/video1
```
看到的影像是固定不變的漸層畫面

試著對 /proc/vcamfb1 持續寫入 random 資料
```shell
$ cat /dev/urandom > /proc/vcamfb1
```
看到的影像是不停跳動的雜訊

寫支小程式產生持續變化的單色畫面,程式碼如下:
```C=
#include <stdio.h>
int main()
{
int i, j;
unsigned char rgb[3] = {10, 60, 128};
while (1) {
for (i = 0; i < 480; i++) {
for (j = 0; j < 640; j++) {
fwrite(rgb, sizeof(rgb), 1, stdout);
}
}
for (i = 0; i < 3; i++) {
rgb[i]++;
}
}
return 0;
}
```
編譯並程式,將輸出導向 /proc/vcamfb1
```shell
$ gcc rgb.c -o rgb
$ ./rgb > /proc/vcamfb1
```
從 vlc 看到影像的確是單色,且會漸漸改變顏色。因為懶得做 gif 動畫,下面只截一張圖示意

## 後續
- 用 vcam-util 增減和修改 device
- v4l2 device driver 架構
- framebuffer 的運作機制