sysprog
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Help
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # Linux 核心專題: 虛擬攝影裝置驅動程式 > 執行人: liangchingyun > [解說影片](https://www.youtube.com/watch?v=Ye0y3MaOC48) ### Reviewed by `dingsen-Greenhorn` 「Print this informations.」→ 「Print this information.」 (information 是不可數名詞,不用加 s) > 了解,之後會提交 PR 修改這部分。 ### Reviewed by `charliechiou` 目前的實驗測試在 framebuffer 寫入圖片,想詢問是有辦法換成影片輸入的嗎 ? 單純依照帧數輸入圖片至 buffer 中或是否需要做對應的調整 ? > 可以,ffmpeg 會把影片轉成一張張圖片,讀進 framebuffer。 ### Reviewed by `wurrrrrrrrrr` kmodleak 報告顯示有 13 個未釋放的記憶體分配,那這些記憶體可能是由哪個函式所分配的呢? > 可能是 `register_framebuffer()` 分配的記憶體在卸載時未正確釋放。 ### Reviewed by `horseface1110` kmodleak 報告顯示有 13 個未釋放的記憶體分配,但是為什麼需要強調有一個記憶體空間大小是32768 byte呢?這個數字有甚麼涵義嗎? > 代表最大的未釋放記憶體大小是 32768 bytes。 > ### Reviewed by `MuChengChen` 在 DMABUF 的測試結果中有提到「驅動為了確保正常運作,自動分配了比請求更多的 buffer」,那請求分配的 buffer 和驅動多分配的 buffer 數量間呈現怎麼樣的關係 ? 是請求分配的 buffer 越多驅動多分配的 buffer 就越多嗎 ? > 待測試 ### Reviewed by `leonnig` > 將 RGB565 格式的 ui.bin 轉換成 RGB888 格式的 ui.rgb 想請問在文中有提到 RGB565 效率較高,然後有附上由 RGB565 轉換為 RGB888 的程式,那在這個專案中有提到是使用哪一種方式嗎,有的考量為何 ? > 此專案是使用 RGB24,原因可能為 V4L2 的預設 pixel format 是 RGB24 , 且因使用較多的位元數較多,圖片品質會比 RGB565 好。 ## TODO: 重現去年實驗並確保在 Linux v6.11+ 運作 > [2024 年報告-1](https://hackmd.io/@sysprog/HJBxRsRr0), [2024 年報告-2](https://hackmd.io/@sysprog/S1l3ZlcLA) ### 在 Linux v6.11+ 執行原專案 #### 編譯 `./fb.c` 中使用 `remap_vmalloc_range()` 等函式需要加上: ```c #include <linux/vmalloc.h> ``` 加上後即可成功編譯。[#38](https://github.com/sysprog21/vcam/pull/40) #### 執行專案 ``` ./vcam-util [選項] ``` ``` -h --help Print this informations. -c --create Create a new device. -m --modify idx Modify a device. -r --remove idx Remove a device. -l --list List devices. -s --size WIDTHxHEIGHTxCROPRATIO Specify virtual resolution or crop ratio. Crop ratio will only be applied in cropping mode. For instance: WxH: 640x480 Specify the virtual resolution. CR: 5/6 Apply crop ratio to the current resolution. WxHxCR: 640x480x5/6 Specify the virtual resolution and apply with crop ratio. -p --pixfmt pix_fmt Specify pixel format (rgb24,yuyv). -d --device /dev/* Control device node. ``` ##### 建立虛擬攝影機裝置 :::danger 注意用語: device 是「裝置」 ::: 1. 預設 ``` $ sudo ./vcam-util -c ``` 2. 自訂解析度和像素格式(預設:解析度`640x480`,像素格式`rgb24`) ``` $ sudo ./vcam-util -c -s 1280x720 -p yuyv ``` 3. 加入裁切比例(預設:`1/1`) ``` $ sudo ./vcam-util -c -s 1280x720x5/6 -p rgb24 ``` 4. 指定控制裝置節點(預設:`/dev/vcamctl`) ``` $ sudo ./vcam-util -c -d /dev/custom_vcamctl ``` ##### 修改索引為 idx 的裝置 ``` $ sudo ./vcam-util -m idx -s 1920x1080 -p yuyv ``` > idx 從 1 開始 ##### 刪除索引為 idx 的裝置 ``` $ sudo ./vcam-util -r idx ``` > idx 從 1 開始 ##### 列出所有虛擬攝影機裝置 ``` $ sudo ./vcam-util -l ``` ##### 測試 查看圖片格式 ``` $ ffprobe image.jpg ... Stream #0:0: Video: mjpeg (Progressive), yuvj444p(pc, bt470bg/unknown/unknown), 612x544 [SAR 300:300 DAR 9:8], 25 fps, 25 tbr, 25 tbn ``` 調整 vcam 輸出格式 ``` $ sudo ./vcam-util -m idx -s 612x544 -p yuyv ``` 將圖片寫入虛擬攝影機的 framebuffer 裝置。 ``` $ sudo ffmpeg -i image.jpg -vf scale=612:544 -f rawvideo -pix_fmt yuyv422 -y /dev/fbX ``` > Pixel Format : `'YUYV'` 對應到 `yuyv422` 使用 VLC 查看輸出 ``` $ vlc v4l2:///dev/video0 VLC media player 3.0.20 Vetinari (revision 3.0.20-0-g6f0d0ab126b) ``` 無法開啟 VLC,可能因為我是用遠端連線,待測試。改存成圖片來確認虛擬攝影機內容: ``` # 從虛擬攝影機擷取一幀 $ sudo v4l2-ctl -d /dev/video0 --stream-mmap --stream-count=1 --stream-to=capture.raw # 檢查檔案大小 $ ls -lh capture.raw # 轉換成 JPG $ ffmpeg -f rawvideo -pix_fmt yuyv422 -s 612x544 -i capture.raw output.jpg ``` 得到以下畫面,代表 framebuffer 中沒有資料。 ![image](https://hackmd.io/_uploads/rkTiaqZ7el.png) 改成寫入 framebuffer 時馬上擷取: ``` $ sudo ffmpeg -i image.jpg -vf scale=612:544 -f rawvideo -pix_fmt rgb24 -y /dev/fbX -f rawvideo -pix_fmt yuyv422 -frames:v 1 capture.raw ``` 得到正確的圖: ![image](https://hackmd.io/_uploads/BJEKgbfXeg.png) --- `./Makefile` 理解: ```makefile target = vcam # 定義模組的名稱 vcam-objs = module.o control.o device.o videobuf.o fb.o # 指定 vcam.o 是由這幾個 .o 檔組成 obj-m = $(target).o CFLAGS_utils = -O2 -Wall -Wextra -pedantic -std=c99 # 同時編譯 kernel module 與 user tool .PHONY: all all: kmod vcam-util # 用 GCC 編譯一個 user-space 的 C 程式 vcam-util.c vcam-util: vcam-util.c vcam.h $(CC) $(CFLAGS_utils) -o $@ $< # 使用 kernel build system 進行模組建構 kmod: $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules .PHONY: clean clean: $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean $(RM) vcam-util ``` ### 通過 V4L2 測試 使用 `vcam-util` 來確認 video 裝置的名稱: ``` $ sudo ./vcam-util -l 1. fb1(640,480,1/1,rgb24) -> /dev/video0 ``` 對 vcam 做測試,顯示所有程式皆通過: ``` $ sudo v4l2-compliance -d /dev/video0 -f Total for vcam device /dev/video0: 48, Succeeded: 48, Failed: 0, Warnings: 0 ``` ### 檢查記憶體洩漏 使用 [kmodleak](https://github.com/tzussman/kmodleak) 來追蹤記憶體洩漏。 編譯後,執行: ``` $ sudo ./kmodleak vcam ``` 在另一個終端機掛載及卸載 vcam 模組: ``` $ sudo insmod vcam.ko $ sudo rmmod vcam ``` 卸載後 kmodleak 會自動停止,並產生報告: ``` using page size: 4096 Tracing module memory allocs... Unload module (or hit Ctrl-C) to end module 'vcam' loaded module 'vcam' unloaded 13 stacks with outstanding allocations: 32768 bytes in 1 allocations from stack addr = 0x230248 size = 32768 0 [<ffffffff84a80e92>] __alloc_pages_noprof+0x232 1 [<ffffffff84a80e92>] __alloc_pages_noprof+0x232 2 [<ffffffff84a90ce7>] allocate_slab+0xa7 3 [<ffffffff84a90ff8>] new_slab+0x38 4 [<ffffffff84a9162c>] ___slab_alloc+0x5fc 5 [<ffffffff84a93761>] __kmalloc_cache_noprof+0x2c1 6 [<ffffffff85007cc7>] do_register_framebuffer+0x297 7 [<ffffffff85007d71>] register_framebuffer+0x21 8 [<ffffffffc18e9470>] vcamfb_init+0x2a0 9 [<ffffffffc18e8161>] create_vcam_device+0x2c1 10 [<ffffffffc18e6307>] request_vcam_device+0xa7 11 [<ffffffffc18f3045>] __param_devices_max+0x2215 12 [<ffffffff84602c5b>] do_one_initcall+0x5b 13 [<ffffffff848060b7>] do_init_module+0x97 14 [<ffffffff84807715>] load_module+0x6b5 15 [<ffffffff84807b46>] init_module_from_file+0x96 16 [<ffffffff84807cdc>] idempotent_init_module+0x11c 17 [<ffffffff84808024>] __x64_sys_finit_module+0x64 18 [<ffffffff8460c360>] x64_sys_call+0x2580 19 [<ffffffff8589124e>] do_syscall_64+0x7e 20 [<ffffffff85a0012b>] entry_SYSCALL_64_after_hwframe+0x76 ... ``` 結果顯示有 13 個沒有被釋放掉的記憶體配置,其中一個為 32768 bytes。 ## TODO: vcam 所需的背景知識回顧 > 適度整理之前的報告內容,針對 Linux v6.8+,探討 V4L2 和 Linux framebuffer ### 影像處理 #### RGBA color model > [維基百科](https://en.wikipedia.org/wiki/RGBA_color_model) RGBA: red, green, blue, alpha。其中 alpha 代表透明度。 ##### RGBA8888 用 32 位元的無號整數來表達 * ARGB32: alpha 在最高 8 位元。 ![PixelSamples32bppRGBA](https://hackmd.io/_uploads/Hk_5BpINxe.png) * RGBA32: alpha 在最低 8 位元。 ![HexRGBAbits](https://hackmd.io/_uploads/HJXor684lg.png) ##### RGB888 用 24 位元的無號整數來表達(Red: 8 bits / Green: 8 bits / Blue: 8 bits) ##### RGB565 用 16 位元的無號整數來表達(Red: 5 bits / Green: 6 bits / Blue: 5 bits) 效率很高,每個像素只需要 2 bytes,因此很常被使用。 ##### 轉換程式 將 RGB565 格式的 `ui.bin` 轉換成 RGB888 格式的 `ui.rgb` ```java //convert RGB565 to RGB888 byte src[] = loadBytes("ui.bin"); byte dst[] = new byte[src.length/2*3]; // 從 2 bytes 變成 3 bytes for (int i=0, j=0; i<src.length; i+=2) { int c = src[i] + (src[i+1]<<8); // 將 2 bytes 合併成一個 16-bit 整數 byte r = byte(((c & 0xF800) >> 11) << 3); byte g = byte(((c & 0x7E0) >> 5) << 2); byte b = byte(((c & 0x1F)) << 3); dst[j++]=r; dst[j++]=g; dst[j++]=b; } saveBytes("ui.rgb", dst); size(754,754); println(dst.length); loadPixels(); for (int i=0; i<dst.length-3; ) { char r = char(dst[i++] & 255); char g = char(dst[i++] & 255); char b = char(dst[i++] & 255); pixels[i/3] = color(r, g, b); } updatePixels(); ``` > 假設某像素為 `1111100000011111`,`r` 的變換: > 1. `& 0xF800` --> `1111100000000000` > 2. `>> 11` --> `11111` > 3. `<< 3` --> `11111000`,補足 8 位元 #### YUV color model > [2.10 YUV Formats](https://www.kernel.org/doc/html/v4.12/media/uapi/v4l/yuv-formats.html): 以使用的位元個數區分 電視使用的標準。Y 代表亮度,U、V 代表彩度。原因是人眼對亮度較敏感,需給予較大的頻寬。其與 RGB 之間的關係為: ![image](https://hackmd.io/_uploads/rkEbL6IVle.png) #### Motion JPEG > [維基百科](https://zh.wikipedia.org/zh-tw/Motion_JPEG) 一種影像壓縮格式,其中每一訊框圖像都分別使用JPEG編碼。 只單獨的對某一訊框進行壓縮,而不考慮影像畫面中不同訊框之間的變化。因此壓縮率不高,但處理成本較低。 ### 虛擬攝影機裝置 > 參考 [2024 年報告-1](https://hackmd.io/@sysprog/HJBxRsRr0) :::danger 使用 Graphviz 重新製圖並嵌入到 HackMD 筆記頁面 ::: ```graphviz digraph _graph_name_ { rankdir=BT; graph [fontname="DFKai-SB", label="何謂虛擬攝影機裝置驅動程式", fontsize=30]; node [fontname="DFKai-SB"]; edge [fontname="DFKai-SB"]; subgraph cluster_real { label = ""; style = dashed; A[label="視訊輸入\n(VideoX)", shape=box, width=2.5, fontsize=20]; B[label="裝置驅動程式", shape=box, width=2.5, fontsize=20]; C[label="攝影機裝置", shape=box, width=2.5, fontsize=20]; a[label="Userspace", shape=plaintext, fontsize=20]; b[label="Kernel", shape=plaintext, fontsize=20]; c[label="Hardware", shape=plaintext, fontsize=20]; { rank=same; a; A; } { rank=same; b; B; } { rank=same; c; C; } C -> B -> A; } subgraph cluster_virtual { label = ""; style = dashed; D[label="視訊輸入\n(VideoX)", shape=box, width=2.5, fontsize=20]; E[label="裝置驅動程式", shape=box, width=2.5, fontsize=20]; F[label="虛擬攝影機裝置", shape=box, width=2.5, fontsize=20]; d[label="Userspace", shape=plaintext, fontsize=20]; e[label="Kernel", shape=plaintext, fontsize=20]; f[label="Hardware", shape=plaintext, fontsize=20]; { rank=max; d, D; F} { rank=same; e; E; } F -> E -> D; f -> e -> d [style=invis]; } B -> e [label=" 使用虛擬攝影機 \n 取代真實攝影機 ", style=dashed, constraint=false, fontsize=20]; } ``` 使用 V4l2 框架以及 Linux Frambuffer API 運作流程:將資料寫入虛擬 Frambuffer 中,影片播放程式可以透過 /dev/videoX 來播放影片 ```graphviz digraph _graph_name_ { rankdir=BT; graph [fontname="DFKai-SB"]; node [fontname="DFKai-SB"]; edge [fontname="DFKai-SB"]; subgraph cluster_a { label = ""; style = invis; A[label="視訊輸入\n(/dev/VideoX)", shape=box, width=1.5]; B[label="vcam", shape=box, width=1.5]; a[label="Userspace", shape=plaintext]; x[label="", shape=plaintext]; b[label="Kernel", shape=plaintext]; {rank=max; a; A} {rank=same; b; B} #{rank=same; x; C} B -> A; b -> x -> a [style=invis]; } subgraph cluster_b { label = ""; style = invis; C[label="Framebuffer API", shape=box, width=2]; D[label="虛擬 Framebuffer\n(/dev/fbX)", shape=box, width=2]; c[label="", shape=plaintext]; y[label="", shape=plaintext]; d[label="", shape=plaintext]; {rank=max; c; D} {rank=same; y; C} D -> C; d -> y -> c [style=invis]; } C -> B [constraint=false] } ``` #### V4L2 (Video for Linux 2) > [Linux V4L2 學習](https://work-blog.readthedocs.io/en/latest/index.html) Linux 下關於視訊裝置的驅動框架,支援的裝置有: 1. Video capture device (ex. 攝影機) 2. Video output device (ex. 螢幕) 3. Radio device (沒有影像,只有聲音) 兩種角度來看 V4L2 框架 1. userspace 角度 常見的 ioctl 參數 * VIDIOC_QUERYCAP: 詢問 V4L2 裝置的 capability * VIDIOC_S_INPUT / VIDIOC_G_INPUT: 設置、取得目前的輸入來源 * VIDIOC_S_FMT / VIDIOC_G_FMT: 設置、取得 V4L2 裝置的 format (ex. resolution) 2. 驅動程式開發者角度 * 關係綁定 * 將 V4L2 的結構體嵌入到自己所定義的結構體中,例如: ```c struct vcam_device *create_vcam_device(size_t idx, struct vcam_device_spec *dev_spec) { struct video_device *vdev; ... } ``` * 透過 V4L2 的函式將自定義的結構體跟 V4L2 框架作綁定,例如: ```c ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); ``` * 函數綁定 * 實作特定函式並且將函式跟 V4L2 框架綁定 * 當某件事情發生時,驅動框架就會呼叫綁定的程式 #### Linux framebuffer 類似畫布 Frambuffer: RAM 中的一段連續記憶體,CPU 或 GPU 會把要顯示的影像放到 Framebuffer 中,讓 Display 裝置顯示。 ```graphviz digraph _graph_name_ { rankdir=BT; graph [fontname="DFKai-SB"]; node [fontname="DFKai-SB"]; edge [fontname="DFKai-SB"]; subgraph cluster_a { label = "RAM"; Framebuffer[label="Framebuffer", shape=box, width=1.5]; } Display[label="Display", shape=box, width=1.5, height=0.7]; Framebuffer -> Display [constraint=false, minlen=3] } ``` :::danger 使用 Graphviz 重新製圖並嵌入到 HackMD 筆記頁面 ::: Linux 有提供 Framebuffer 的 API 框架,使用者可以透過 API 對 Framebuffer 進行操作,也可以使用該框架做一個須你的 Framebuffer。 ### vcam 專案 framebuffer 為輸入! MP4 → framebuffer → vcam 的 /dev/video1 (可被擷取) → VLC / MPlayer #### 針對 Linux v6.8+ 的調整 Problem: 在其版本上無法成功編譯 Solution: 1. 修正呼叫函式時所用的參數數量: `class_create(owner, name)` --> `class_create(name)` 2. 修正 `struct vb2_queue` 的 member 名稱: `min_buffers_needed` --> `min_queued_buffers` 3. 修改初始化 `struct fb_info` 的方式: `info->flags = FBINFO_FLAG_DEFAULT;` --> `fb_data->info = framebuffer_alloc(0, &dev->vdev.dev);` 注意:不可以直接改成定值,以防 Linux 核心哪天將初始值改掉。 :::danger 確認後,提交 pull request,注意要讓舊的 Linux 核心也能編譯 vcam 核心模組。 ::: ## TODO: 支援 DMABUF > 提交 pull request ### 原理理解 DMA-BUF (Direct Memory Access Buffer) : 允許在不同裝置間共享的 buffer。 ```graphviz digraph { A [label="行程 A"] B [label="行程 B\n來自 socket"] DA [label="裝置 A" shape="rectangle"] DB [label="裝置 B" shape="rectangle"] BUF [label="buffer" shape="rectangle"] subgraph cluster_0 { {rank=same A B} A->B label="userspace" } subgraph cluster_1 { DA->BUF DB->BUF label="kernel space" } DA->A [label=" 導出 fd"] B->DB [label=" 導入 fd"] } ``` 簡單來說,buffer 為共享的目標,應用程式將 buffer 導出為 fd,在 userspace 傳遞,再將 fd 導入另一個裝置。 ### 程式實作 查詢關鍵字: ``` grep -rn 'vb2_queue' ``` 在 `vb2_queue.io_modes` 中啟用 `VB2_DMABUF` ```diff - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF; ``` 新增操作函式 ```diff static const struct vb2_ops vcam_vb2_ops = { .queue_setup = vcam_out_queue_setup, .buf_prepare = vcam_out_buffer_prepare, .buf_queue = vcam_out_buffer_queue, .start_streaming = vcam_start_streaming, .stop_streaming = vcam_stop_streaming, .wait_prepare = vcam_outbuf_unlock, .wait_finish = vcam_outbuf_lock, + .buf_init = vcam_buf_init, + .buf_cleanup = vcam_buf_cleanup, }; ``` ```c static int vcam_buf_init(struct vb2_buffer *vb) { struct vcam_out_buffer *buf = container_of(vb, struct vcam_out_buffer, vb.vb2_buf); buf->filled = 0; INIT_LIST_HEAD(&buf->list); pr_debug("vcam_buf_init: buffer initialized\n"); return 0; } static void vcam_buf_cleanup(struct vb2_buffer *vb) { pr_debug("vcam_buf_cleanup called\n"); } ``` 修改 buffer 的 memory type: `vb2_queue.mem_ops` 原指定為 `vb2_vmalloc_memops`,但 vmalloc 的記憶體不能拿去 DMA, 無法支援 DMABUF。 > 原因: `vmalloc()` 分配的是虛擬連續、實體不連續的記憶體。大多數硬體 DMA 控制器只接受 實體連續記憶體。[reference](https://www.cnblogs.com/arnoldlu/p/18063912) 改為 `vb2_dma_contig_memops` ```diff - q->mem_ops = &vb2_vmalloc_memops; + q->mem_ops = &vb2_dma_contig_memops; ``` 載入模組 ``` $ sudo modprobe videobuf2-dma-contig ``` ### 測試程式 #### 確認支援 DMABUF ```c int main() { const char *dev_name = "/dev/video0"; int fd = open(dev_name, O_RDWR); if (fd < 0) { perror("Failed to open video device"); return 1; } struct v4l2_requestbuffers req; memset(&req, 0, sizeof(req)); req.count = 2; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_DMABUF; if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) { perror("VIDIOC_REQBUFS (DMABUF) not supported"); close(fd); return 1; } printf("DMABUF is supported! Requested %u buffers, got %u.\n", 2, req.count); close(fd); return 0; } ``` ``` $ gcc -o test_dmabuf test_dmabuf.c $ ./test_dmabuf DMABUF is supported! Requested 2 buffers, got 3. ``` 驅動為了確保正常運作,自動分配了比請求更多的 buffer,確認 vcam 支援 DMABUF。 #### 確認 zero-copy 的效益 ``` $ gcc -o test_dmabuf_performance test_dmabuf_performance.c $ ./test_dmabuf_performance ``` ## 專案貢獻 [Pull Requests](https://github.com/sysprog21/vcam/pulls?q=is%3Amerged+is%3Apr+author%3Aliangchingyun+)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully