https://github.com/tiagocoutinho/v4l2py
V4L2 python library
https://github.com/tiagocoutinho/v4l2py
python v4l2 video4linux
Last synced: 12 months ago
JSON representation
V4L2 python library
- Host: GitHub
- URL: https://github.com/tiagocoutinho/v4l2py
- Owner: tiagocoutinho
- License: gpl-3.0
- Created: 2021-04-24T16:37:45.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2024-03-11T20:54:20.000Z (over 2 years ago)
- Last Synced: 2025-04-09T19:19:19.657Z (about 1 year ago)
- Topics: python, v4l2, video4linux
- Language: Python
- Homepage:
- Size: 335 KB
- Stars: 71
- Watchers: 2
- Forks: 20
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# v4l2py
**Since version 3.0 this project is now a shim for `linuxpy.video`**
**Please consider using [linuxpy](https://github.com/tiagocoutinho/linuxpy) directly.**
[![V4L2py][pypi-version]](https://pypi.python.org/pypi/v4l2py)
[![Python Versions][pypi-python-versions]](https://pypi.python.org/pypi/v4l2py)
![License][license]
[![CI][CI]](https://github.com/tiagocoutinho/v4l2py/actions/workflows/ci.yml)
Video for Linux 2 (V4L2) python library
A two purpose API:
* high level Device API for humans to play with :-)
* raw python binding for the v4l2 (video4linux2) userspace API, using ctypes (don't even
bother wasting your time here. You probably won't use it)
Only works on python >= 3.9.
## Why?
So, why another library dedicated to video control? Couldn't I just use `cv2.VideoCapture`?
Here is a list of features that this library provides which I couldn't find in other libraries:
* List available V4L2 devices
* Obtain detailed information about a device (name, driver, capabilities, available formats)
* Fine control over the camera parameters (ex: resolution, format, brightness, contrast, etc)
* Fine control resource management to take profit of memory map, DMA or user pointers (buffers)
* Detailed information about a frame (timestamp, frame number, etc)
* Write to VideoOutput
* Integration with non blocking coroutine based applications (`gevent` and `asyncio`)
without the usual tricks like using `asyncio.to_thread`
## Installation
From within your favorite python environment:
```bash
$ pip install v4l2py
```
## Usage
Without further ado:
```python
>>> from v4l2py import Device
>>> with Device.from_id(0) as cam:
>>> for i, frame in enumerate(cam):
... print(f"frame #{i}: {len(frame)} bytes")
... if i > 9:
... break
...
frame #0: 54630 bytes
frame #1: 50184 bytes
frame #2: 44054 bytes
frame #3: 42822 bytes
frame #4: 42116 bytes
frame #5: 41868 bytes
frame #6: 41322 bytes
frame #7: 40896 bytes
frame #8: 40844 bytes
frame #9: 40714 bytes
frame #10: 40662 bytes
```
Getting information about the device:
```python
>>> from v4l2py.device import Device, BufferType
>>> cam = Device.from_id(0)
>>> cam.open()
>>> cam.info.card
'Integrated_Webcam_HD: Integrate'
>>> cam.info.capabilities
>>> cam.info.formats
[ImageFormat(type=, description=b'Motion-JPEG',
flags=, pixelformat=),
ImageFormat(type=, description=b'YUYV 4:2:2',
flags=, pixelformat=)]
>>> cam.get_format(BufferType.VIDEO_CAPTURE)
Format(width=640, height=480, pixelformat=}
>>> for ctrl in cam.controls.values(): print(ctrl)
>>> cam.controls["saturation"]
>>> cam.controls["saturation"].id
9963778
>>> cam.controls[9963778]
>>> cam.controls.brightness
>>> cam.controls.brightness.value = 64
>>> cam.controls.brightness
```
(see also [v4l2py-ctl](examples/v4l2py-ctl.py) example)
### asyncio
v4l2py is asyncio friendly:
```bash
$ python -m asyncio
>>> from v4l2py import Device
>>> with Device.from_id(0) as camera:
... async for frame in camera:
... print(f"frame {len(frame)}")
frame 10224
frame 10304
frame 10224
frame 10136
...
```
(check [basic async](examples/basic_async.py) and [web async](examples/web/async.py) examples)
### gevent
v4l2py is also gevent friendly:
```
$ python
>>> from v4l2py import Device, GeventIO
>>> with Device.from_id(0, io=GeventIO) as camera:
... for frame in camera:
... print(f"frame {len(frame)}")
frame 10224
frame 10304
frame 10224
frame 10136
...
```
(check [basic gevent](examples/basic_gevent.py) and [web gevent](examples/web/sync.py) examples)
## Bonus track
You've been patient enough to read until here so, just for you,
a 20 line gem: a flask web server displaying your device on the web:
```bash
$ pip install flask
```
```python
# web.py
import flask
from v4l2py import Device
app = flask.Flask('basic-web-cam')
def gen_frames():
with Device.from_id(0) as cam:
for frame in cam:
yield b"--frame\r\nContent-Type: image/jpeg\r\n\r\n" + frame.data + b"\r\n"
@app.route("/")
def index():
return '
'
@app.route("/stream")
def stream():
return flask.Response(
gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
```
run with:
```bash
$ FLASK_APP=web flask run -h 0.0.0.0
```
Point your browser to [127.0.0.1:5000](http://127.0.0.1:5000) and you should see
your camera rolling!
## Migrating from 1.x to 2
A frame changed from a simple bytes object to a Frame which contains
the data plus all frame metadata.
As a consequence, when migrating from 1.x to 2, you will need to cast
frame object with `bytes` or access the `frame.data` item:
Before:
```python
with Device.from_id(0) as cam:
for frame in cam:
buff = io.BytesIO(frame)
```
Now:
```python
with Device.from_id(0) as cam:
for frame in cam:
frame = bytes(frame) # or frame = frame.data
buff = io.BytesIO(frame)
```
## Improved device controls
Device controls have been improved to provide a more pythonic interface. The
new interface is the default now; however, the legacy interface can be
requested: `Device.from_id(x, legacy_controls=True)`.
Before:
```python
>>> from v4l2py import Device
>>> cam = Device.from_id(0)
>>> cam.open()
>>> for ctrl in cam.controls.values():
... print(ctrl)
... for item in ctrl.menu.values():
... print(f" - {item.index}: {item.name}")
- 0: Disabled
- 1: 50 Hz
- 2: 60 Hz
- 1: Manual Mode
- 3: Aperture Priority Mode
>>> type(cam.controls.exposure_dynamic_framerate.value)
```
Now:
```python
>>> from v4l2py.device import Device, MenuControl
>>> cam = Device.from_id(0)
>>> cam.open()
>>> for ctrl in cam.controls.values():
... print(ctrl)
... if isinstance(ctrl, MenuControl):
... for (index, name) in ctrl.items():
... print(f" - {index}: {name}")
- 0: Disabled
- 1: 50 Hz
- 2: 60 Hz
- 1: Manual Mode
- 3: Aperture Priority Mode
>>> type(cam.controls.white_balance_automatic.value)
>>> cam.controls.white_balance_automatic.value
>>> cam.controls.white_balance_automatic.value = False
>>> wba = cam.controls.white_balance_automatic
>>> wba.value = "enable" # or "on", "1", "true", "yes"
>>> wba
>>> wba.value = "off" # or "disable", "0", "false", "no"
>>> wba
```
The initial upgrade path for existing code is to request the legacy interface
by passing `legacy_controls=True` when instantiating the `Device` object, use
`LegacyControl` instead of `Control` for instantiations, and `BaseControl`
for isinstance() checks. And in the unlikely case your code does isinstance()
checks for `MenuItem`, these should be changed to `LegacyMenuItem`.
## References
See the ``linux/videodev2.h`` header file for details.
* `Video for Linux Two Specification `
[pypi-python-versions]: https://img.shields.io/pypi/pyversions/v4l2py.svg
[pypi-version]: https://img.shields.io/pypi/v/v4l2py.svg
[pypi-status]: https://img.shields.io/pypi/status/v4l2py.svg
[license]: https://img.shields.io/pypi/l/v4l2py.svg
[CI]: https://github.com/tiagocoutinho/v4l2py/actions/workflows/ci.yml/badge.svg