Fix V4L2 mmap capture and service configuration
- capture.py: use mmap.mmap instead of non-existent os.mmap - capture.py: fix v4l2_fourcc() to pass 4 char arguments - camera-webui.service: add Group=video and PATH env var
This commit is contained in:
@@ -6,8 +6,9 @@ Wants=network-online.target
|
|||||||
[Service]
|
[Service]
|
||||||
Type=exec
|
Type=exec
|
||||||
User=mikkeli
|
User=mikkeli
|
||||||
|
Group=video
|
||||||
WorkingDirectory=/home/mikkeli/dev/usb-camera-webui
|
WorkingDirectory=/home/mikkeli/dev/usb-camera-webui
|
||||||
ExecStartPre=/usr/bin/python3 -c "import v4l2"
|
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||||
ExecStart=/usr/bin/python3 -m camera.app --host 0.0.0.0 --port 8080
|
ExecStart=/usr/bin/python3 -m camera.app --host 0.0.0.0 --port 8080
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
|
|||||||
+10
-6
@@ -1,16 +1,20 @@
|
|||||||
"""V4L2 MJPEG capture via the v4l2 Python library (mmap).
|
"""V4L2 MJPEG capture via mmap buffers.
|
||||||
|
|
||||||
Uses memory-mapped buffers for efficient frame capture without subprocess
|
Opens /dev/video0 and uses memory-mapped V4L2 buffers for efficient frame
|
||||||
overhead. Each frame is a complete JPEG image ready for MJPEG streaming.
|
capture. Each frame is a complete JPEG image ready for MJPEG streaming.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import fcntl
|
import fcntl
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
|
import mmap
|
||||||
|
|
||||||
import v4l2
|
import v4l2
|
||||||
|
|
||||||
|
# Fourcc for Motion JPEG
|
||||||
|
MJPG = v4l2.v4l2_fourcc("M", "J", "P", "G")
|
||||||
|
|
||||||
# Global camera singleton
|
# Global camera singleton
|
||||||
_camera: "Capture | None" = None
|
_camera: "Capture | None" = None
|
||||||
_camera_lock = threading.Lock()
|
_camera_lock = threading.Lock()
|
||||||
@@ -79,10 +83,10 @@ class Capture:
|
|||||||
fmt.type = v4l2.V4L2_BUF_TYPE_VIDEO_CAPTURE
|
fmt.type = v4l2.V4L2_BUF_TYPE_VIDEO_CAPTURE
|
||||||
fmt.fmt.pix.width = self._width
|
fmt.fmt.pix.width = self._width
|
||||||
fmt.fmt.pix.height = self._height
|
fmt.fmt.pix.height = self._height
|
||||||
fmt.fmt.pix.pixelformat = v4l2.v4l2_fourcc("MJPG")
|
fmt.fmt.pix.pixelformat = MJPG
|
||||||
fmt.fmt.pix.field = v4l2.V4L2_FIELD_ANY
|
fmt.fmt.pix.field = v4l2.V4L2_FIELD_ANY
|
||||||
_ioctl(self._fd, v4l2.VIDIOC_S_FMT, fmt)
|
_ioctl(self._fd, v4l2.VIDIOC_S_FMT, fmt)
|
||||||
print(f"Format set: {fmt.fmt.pix.width}x{fmt.fmt.pix.height} {v4l2.v4l2_fourcc2str(fmt.fmt.pix.pixelformat)}")
|
print(f"Format: {fmt.fmt.pix.width}x{fmt.fmt.pix.height} {v4l2.v4l2_fourcc2str(fmt.fmt.pix.pixelformat)}")
|
||||||
|
|
||||||
def _allocate_buffers(self) -> None:
|
def _allocate_buffers(self) -> None:
|
||||||
req = v4l2.v4l2_requestbuffers()
|
req = v4l2.v4l2_requestbuffers()
|
||||||
@@ -101,7 +105,7 @@ class Capture:
|
|||||||
|
|
||||||
length = buf.length
|
length = buf.length
|
||||||
offset = buf.m.offset
|
offset = buf.m.offset
|
||||||
data = os.mmap(0, length, os.PROT_READ, os.MAP_SHARED, self._fd, offset)
|
data = mmap.mmap(self._fd, length, mmap.MAP_SHARED, mmap.PROT_READ, 0, offset)
|
||||||
self._buffers.append({
|
self._buffers.append({
|
||||||
"index": i,
|
"index": i,
|
||||||
"length": length,
|
"length": length,
|
||||||
|
|||||||
Reference in New Issue
Block a user