From f916075a2dc72e32fdd2c5131953a181bd87045b Mon Sep 17 00:00:00 2001 From: Jose Tiago Macara Coutinho Date: Sat, 16 Dec 2023 08:41:03 +0100 Subject: [PATCH] Deployed d835a4d with MkDocs version: 1.5.3 --- search/search_index.json | 2 +- sitemap.xml | 20 +-- sitemap.xml.gz | Bin 273 -> 273 bytes user_guide/video.svg | 307 ++++++++++++++++++++++++++++++++++++ user_guide/video/index.html | 21 ++- user_guide/video_demo.svg | 67 ++++++++ 6 files changed, 403 insertions(+), 14 deletions(-) create mode 100644 user_guide/video.svg create mode 100644 user_guide/video_demo.svg diff --git a/search/search_index.json b/search/search_index.json index 01b147b..f2335f8 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Welcome to linuxpy","text":"

Human friendly interface to linux subsystems using python.

Provides python access to several linux subsystems like V4L2, input and MIDI.

There is experimental, undocumented, incomplete and unstable access to USB.

Need fine control over Webcams, MIDI devices, input devices (joysticks, gamepads, keyboards, mice or even the keyboard light on your laptop)? Linuxpy has your back.

Requirements:

And yes, it is true: there are no python dependencies! Also there are no C libraries dependencies! Everything is done here through direct ioctl, read and write calls. Ain't linux wonderful?

"},{"location":"#goals","title":"Goals","text":""},{"location":"#installation","title":"Installation","text":"

From within your favorite python environment:

pip install linuxpy pip install linuxpy

To run the examples you'll need:

$ pip install linuxpy[examples]\n

To develop, run tests, build package, lint, etc you'll need:

$ pip install linuxpy[dev]\n

To run docs you'll need:

$ pip install linuxpy[docs]\n
"},{"location":"#faq","title":"FAQ","text":"

Most python libraries try as hard as possible to be platform independent. Why create a library that is explicitly designed to work only on linux?

Well, first of all, one of the goals is to be able to access low level linux device capabilities like video controls. Second, I don't have access to proprietary OS like Windows or MacOS.

If this answer is not enough than think of this library as a low level dependency on linux systems of other libraries that will be concerned with providing a common API on different platforms.

"},{"location":"develop/","title":"Developers corner","text":""},{"location":"develop/#requirements","title":"Requirements","text":"

A linux OS and python >= 3.9.

From within your favorite python environment:

$ pip install linuxpy[dev]\n

Additionally, to run the code generation tool you'll need castxml installed on your system.

On a debian based run:

$ apt install castxml\n
"},{"location":"develop/#code-generation","title":"Code generation","text":"

This project uses an internal simple code generator that reads linux kernel header files and produces several raw.py ctypes based python files for each sub-system.

To re-generate these files for a newer linux kernel (or fix a bug) you'll need linux header files installed on your system + black.

To launch the tool call:

$ python -m linuxpy.codegen.cli\n
"},{"location":"develop/#running-tests","title":"Running tests","text":"

Some video tests will only run with a properly configured v4l2loopback.

$ sudo modprobe v4l2loopback video_nr=199 card_label=\"Loopback 199\"\n

Additionally the user which runs the tests will need read/write access to /dev/video199. On most systems this can be achieved by adding the user to the video group:

$ sudo addgroup $USER video\n

Some input tests require the user which runs the tests to have read/write access to /dev/uinput. On most systems this can be achieved by adding the user to the input group:

$ sudo addgroup $USER input\n
"},{"location":"api/","title":"LinuxPy reference API","text":"

Here's the reference or code API, the classes, functions, parameters, attributes, and all the LinuxPy parts you can use in your applications.

If you want to learn LinuxPy you are much better off reading the LinuxPy User Guide.

"},{"location":"api/input/","title":"Input API","text":""},{"location":"api/input/#linuxpy.input.device","title":"linuxpy.input.device","text":"

Human friendly interface to linux Input subsystem.

The heart of linuxpy MIDI library is the Device class. The recommended way is to use one of the find methods to create a Device object and use it within a context manager like:

from linuxpy.input.device import find_gamepad\n\nwith find_gamepad() as gamepad:\n    print(f\"Gamepad name: {gamepad.name}\")\n
"},{"location":"api/input/#linuxpy.input.device.InputError","title":"InputError","text":"

Bases: Exception

Input error

"},{"location":"api/input/#linuxpy.input.device.Device","title":"Device(*args, **kwargs)","text":"

Bases: BaseDevice

Central linux input subsystem class.

You can create an instance directly if you know the device name:

from linuxpy.input.device import Device\n\nwith Device(\"/dev/input11\") as i11:\n    print(i11.name)\n

... but it is generally easier to use the find helper to get a device with a certain condition. Example:

from linuxpy.input.device import find\n\ntrack_point = find(name=\"TPPS/2 Elan TrackPoint\")\n
"},{"location":"api/input/#linuxpy.input.device.Device.name","title":"name: str cached property","text":"

The device name

"},{"location":"api/input/#linuxpy.input.device.Device.version","title":"version: Version cached property","text":"

The version

"},{"location":"api/input/#linuxpy.input.device.Device.physical_location","title":"physical_location: str cached property","text":"

The physical location

"},{"location":"api/input/#linuxpy.input.device.Device.device_id","title":"device_id: input_id cached property","text":"

The device input ID

"},{"location":"api/input/#linuxpy.input.device.Device.capabilities","title":"capabilities cached property","text":"

The device capabilities

"},{"location":"api/input/#linuxpy.input.device.Device.active_keys","title":"active_keys property","text":"

All active keys at the moment of calling this

"},{"location":"api/input/#linuxpy.input.device.Device.x","title":"x property","text":"

Current absolute X value

"},{"location":"api/input/#linuxpy.input.device.Device.y","title":"y property","text":"

Current absolute Y value

"},{"location":"api/input/#linuxpy.input.device.Device.z","title":"z property","text":"

Current absolute Z value

"},{"location":"api/input/#linuxpy.input.device.Device.rx","title":"rx property","text":"

Current relative X value

"},{"location":"api/input/#linuxpy.input.device.Device.ry","title":"ry property","text":"

Current relative Y value

"},{"location":"api/input/#linuxpy.input.device.Device.rz","title":"rz property","text":"

Current relative Z value

"},{"location":"api/input/#linuxpy.input.device.Device.__iter__","title":"__iter__() -> Iterable[InputEvent]","text":"

Build an infinite iterator that streams input events You'll need an open Device before using it:

from linuxpy.input.device import find_mouse\n\nwith find_mouse() as mouse:\n    for event in mouse:\n        print(event)\n
"},{"location":"api/input/#linuxpy.input.device.Device.__aiter__","title":"__aiter__() -> AsyncIterable[InputEvent] async","text":"

Build an infinite async iterator that streams input events You'll need an open Device before using it:

import asyncio\nfrom linuxpy.input.device import find_mouse\n\nasync def main():\n    with find_mouse() as mouse:\n        async for event in mouse:\n            print(event)\n\nasyncio.run(main())\n
"},{"location":"api/input/#linuxpy.input.device.Device.get_abs_info","title":"get_abs_info(abs_code)","text":"

Absolute information for the given abs code

"},{"location":"api/input/#linuxpy.input.device.Device.read_event","title":"read_event()","text":"

Read event. Event must be available to read or otherwise will raise an error

"},{"location":"api/input/#linuxpy.input.device.EventReader","title":"EventReader(device: Device, max_queue_size=1)","text":""},{"location":"api/input/#linuxpy.input.device.EventReader.aread","title":"aread() async","text":"

Wait for next event or return last event

"},{"location":"api/input/#linuxpy.input.device.BaseUDevice","title":"BaseUDevice(filename=PATH, bus=Bus.USB, vendor_id=1, product_id=1, name='linuxpy emulated device')","text":"

Bases: BaseDevice

A uinput device with no capabilities registered

"},{"location":"api/input/#linuxpy.input.device.iter_input_files","title":"iter_input_files(path: PathLike = '/dev/input', pattern: str = 'event*')","text":"

List readable character devices in the given path.

"},{"location":"api/input/#linuxpy.input.device.event_batch_stream","title":"event_batch_stream(fd) -> Iterable[Sequence[InputEvent]]","text":"

Yields packets of events occurring at the same moment in time.

"},{"location":"api/input/#linuxpy.input.device.async_event_batch_stream","title":"async_event_batch_stream(fd, maxsize: int = 1000) -> AsyncIterable[Sequence[InputEvent]] async","text":"

Yields packets of events occurring at the same moment in time.

"},{"location":"api/input/#linuxpy.input.device.find","title":"find(find_all: bool = False, custom_match: Optional[Callable] = None, **kwargs) -> Union[Device, Iterable[Device], None]","text":"

If find_all is False:

Find a device follwing the criteria matched by custom_match and kwargs. If no device is found matching the criteria it returns None. Default is to return a random first device.

If find_all is True:

The result is an iterator. Find all devices that match the criteria custom_match and kwargs. If no device is found matching the criteria it returns an empty iterator. Default is to return an iterator over all input devices found on the system.

"},{"location":"api/input/#linuxpy.input.device.find_gamepad","title":"find_gamepad(find_all: bool = False, custom_match: Optional[Callable] = None, **kwargs) -> Union[Device, Iterable[Device], None]","text":"

If find_all is False:

Find a gamepad device follwing the criteria matched by custom_match and kwargs. If no device is found matching the criteria it returns None. Default is to return a random first gamepad.

If find_all is True:

The result is an iterator. Find all gamepad devices that match the criteria custom_match and kwargs. If no gamepad is found matching the criteria it returns an empty iterator. Default is to return an iterator over all gamepad devices found on the system.

"},{"location":"api/input/#linuxpy.input.device.find_keyboard","title":"find_keyboard(find_all: bool = False, custom_match: Optional[Callable] = None, **kwargs) -> Union[Device, Iterable[Device], None]","text":"

If find_all is False:

Find a keyboard device follwing the criteria matched by custom_match and kwargs. If no device is found matching the criteria it returns None. Default is to return a random first keyboard.

If find_all is True:

The result is an iterator. Find all keyboard devices that match the criteria custom_match and kwargs. If no keyboard is found matching the criteria it returns an empty iterator. Default is to return an iterator over all keyboard devices found on the system.

"},{"location":"api/input/#linuxpy.input.device.find_mouse","title":"find_mouse(find_all: bool = False, custom_match: Optional[Callable] = None, **kwargs) -> Union[Device, Iterable[Device], None]","text":"

If find_all is False:

Find a mouse device follwing the criteria matched by custom_match and kwargs. If no device is found matching the criteria it returns None. Default is to return a random first mouse.

If find_all is True:

The result is an iterator. Find all mouse devices that match the criteria custom_match and kwargs. If no mouse is found matching the criteria it returns an empty iterator. Default is to return an iterator over all mouse devices found on the system.

"},{"location":"api/midi/","title":"MIDI API","text":""},{"location":"api/midi/#linuxpy.midi.device","title":"linuxpy.midi.device","text":"

Human friendly interface to linux MIDI subsystem.

The heart of linuxpy MIDI library is the Sequencer class. Usually you need only one instance of Sequencer for your application. The recommended way is to use it within a context manager like:

with Sequencer(\"My MIDI App\") as midi:\n    print(f\"MIDI version: {midi.version}\")\n

which is roughly equivalent to:

midi = Sequencer(\"My MIDI App\")\nmidi.open()\ntry:\n    print(f\"MIDI version: {midi.version}\")\nfinally:\n    midi.close()\n

Here's a real world example:

from linuxpy.midi.device import Sequencer\n\nwith Sequencer(\"My MIDI App\") as midi:\n    print(f\"I'm client {midi.client_id}\")\n    print(f\"MIDI version: {midi.version}\")\n    port = midi.create_port()\n    port.connect_from((0, 1))\n    for event in midi:\n        print(event)\n
"},{"location":"api/midi/#linuxpy.midi.device.MidiError","title":"MidiError","text":"

Bases: Exception

MIDI error

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer","title":"Sequencer(name: str = 'linuxpy client', **kwargs)","text":"

Bases: BaseDevice

Central MIDI class.

from linuxpy.midi.device import Sequencer\n\nwith Sequencer(\"My MIDI App\") as midi:\n    print(f\"I'm client {midi.client_id}\")\n    print(f\"MIDI version: {midi.version}\")\n    port = midi.create_port()\n    port.connect_from((0, 1))\n    for event in midi:\n        print(event)\n
"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.client_info","title":"client_info: snd_seq_client_info property","text":"

Current Client information

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.client","title":"client: Client property","text":"

Current Client information

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.running_mode","title":"running_mode: snd_seq_running_info property","text":"

Current running mode

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.system_info","title":"system_info: snd_seq_system_info property","text":"

Current system information

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.iter_clients","title":"iter_clients: Iterable[Client] property","text":"

An iterator over all open clients on the system. It returns new Client each time

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.clients","title":"clients: Sequence[Client] property","text":"

Returns a new list of all clients on the system

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.iter_ports","title":"iter_ports: Iterable[Port] property","text":"

An iterator over all open ports on the system. It returns new Port objects each time

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.ports","title":"ports: Sequence[Port] property","text":"

Returns a new list of all open ports on the system. It returns new Port objects each time

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.__iter__","title":"__iter__() -> Iterable[Event]","text":"

Build an infinite iterator that streams MIDI events from the subscribed ports. You'll need an open sequencer before using it:

from linuxpy.midi.device import Sequencer\n\nwith Sequencer() as midi:\n    port = midi.create_port()\n    port.connect_from((0, 1))\n    for event in midi:\n        print(event)\n
"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.__aiter__","title":"__aiter__() -> AsyncIterable[Event] async","text":"

Build an infinite async iterator that streams MIDI events from the subscribed ports. You'll need an open sequencer before using it:

import asyncio\nfrom linuxpy.midi.device import Sequencer\n\nasync def main():\n    with Sequencer() as midi:\n        port = midi.create_port()\n        port.connect_from((0, 1))\n        async for event in midi:\n            print(event)\n\nasyncio.run(main())\n
"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.get_client","title":"get_client(client_id: int) -> Client","text":"

Returns a Client for the given ID or raises an error if the client doesn't exist. It returns new Client object each time

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.get_port","title":"get_port(address: FullPortAddress) -> Port","text":"

Returns a Port for the given address or raises an error if the port doesn't exist. It returns new Port object each time

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.create_port","title":"create_port(name: str = 'linuxpy port', capabilities: PortCapability = INPUT_OUTPUT, port_type: PortType = PortType.MIDI_GENERIC | PortType.APPLICATION) -> Port","text":"

Create a new local port. By default it will create a MIDI generic application Input/Output port.

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.delete_port","title":"delete_port(port: Union[int, Port])","text":"

Delete a previously created local port. If the port has any subscriptions they will be closed before the port is deleted

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.subscribe","title":"subscribe(src: FullPortAddress, dest: FullPortAddress)","text":"

Subscribe a source port to a destination port

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.unsubscribe","title":"unsubscribe(src: FullPortAddress, dest: FullPortAddress)","text":"

Unsubscribe a previously subscribed source port to a destination port

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.iter_raw_read","title":"iter_raw_read(max_nb_packets: int = 64) -> Iterable[Event]","text":"

Read list of pending events. If the sequencer is opened in blocking mode and there are no events it blocks until at least one event occurs otherwise as OSError is raised.

Use the read() call instead because it handles blocking vs non-blocking variants transperently.

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.raw_read","title":"raw_read(max_nb_packets=64) -> Sequence[Event]","text":"

Read list of pending events. If there are no events it blocks until at least one event occurs and returns it.

Use the read() call instead because it handles blocking vs non-blocking variants transperently.

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.wait_read","title":"wait_read() -> Sequence[Event]","text":"

Read list of pending events. If there are no events it blocks until at least one event occurs and returns it. This method assumes the internal file descriptior was opened in non-blocking mode.

Use the read() call instead because it handles blocking vs non-blocking variants transperently

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.read","title":"read() -> Sequence[Event]","text":"

Read list of pending events. If there are no events it blocks until at least one event occurs and returns it

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.write","title":"write(event: Event)","text":"

Send an event message

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.send","title":"send(port: PortAddress, event_type: Union[str, int, EventType], queue: int = QUEUE_DIRECT, to: Union[FullPortAddress, FullPortAddresses] = SUBSCRIBERS, **kwargs)","text":"

Send a message of the given type from a specific port to the destination address(es). Use kwargs to pass specific event arguments like velocity in a \"note on\" event.

event_type can be an instance of EventType or the equivalent number or a case insensitive string matching the event type (ex: \"noteon\", \"NOTEON\", \"note-on\" or \"note on\").

The following example sends \"note on\" with velocity 45 on port 0 of client 14:

midi.send((14, 0), \"note on\", velocity=45)\n
"},{"location":"api/midi/#linuxpy.midi.device.Client","title":"Client(sequencer: Sequencer, client: snd_seq_client_info)","text":"

MIDI sequencer client. Don't instantiate this object directly Use instead Sequencer.get_client()

"},{"location":"api/midi/#linuxpy.midi.device.Client.name","title":"name: str property","text":"

Client name

"},{"location":"api/midi/#linuxpy.midi.device.Client.is_local","title":"is_local: bool property","text":"

True if the client was created by the MIDI sequencer that it references or False otherwise\"

"},{"location":"api/midi/#linuxpy.midi.device.Client.iter_ports","title":"iter_ports: Iterable[Port] property","text":"

An iterator over all open ports for this client. It returns new Port each time

"},{"location":"api/midi/#linuxpy.midi.device.Client.ports","title":"ports: Sequence[Port] property","text":"

Returns a new list of all open ports for this client

"},{"location":"api/midi/#linuxpy.midi.device.Client.__int__","title":"__int__()","text":"

The client ID

"},{"location":"api/midi/#linuxpy.midi.device.Port","title":"Port(sequencer: Sequencer, port: snd_seq_port_info)","text":"

MIDI sequencer port. Don't instantiate this object directly Use instead Sequencer.get_port()

"},{"location":"api/midi/#linuxpy.midi.device.Port.name","title":"name: str property","text":"

Port name

"},{"location":"api/midi/#linuxpy.midi.device.Port.is_local","title":"is_local: bool property","text":"

True if the port was created by the MIDI sequencer that it references or False otherwise\"

"},{"location":"api/midi/#linuxpy.midi.device.Port.client_id","title":"client_id: int property","text":"

The client ID

"},{"location":"api/midi/#linuxpy.midi.device.Port.port_id","title":"port_id: int property","text":"

The port ID

"},{"location":"api/midi/#linuxpy.midi.device.Port.type","title":"type: PortType property","text":"

The port type

"},{"location":"api/midi/#linuxpy.midi.device.Port.capability","title":"capability: PortCapability property","text":"

The port capabilities

"},{"location":"api/midi/#linuxpy.midi.device.Port.address","title":"address: snd_seq_addr property","text":"

The port address

"},{"location":"api/midi/#linuxpy.midi.device.Port.__int__","title":"__int__()","text":"

The port ID

"},{"location":"api/midi/#linuxpy.midi.device.Port.connect_from","title":"connect_from(src: FullPortAddress)","text":"

Connect this port to a remote port. After connecting, this port will receive events originating from the source port.

Example:

from linuxpy.midi.device import Sequencer\n\nwith Sequencer() as midi:\n    port = midi.create_port()\n    port.connect_from((0, 1))\n    for event in midi:\n        print(event)\n
"},{"location":"api/midi/#linuxpy.midi.device.Port.disconnect_from","title":"disconnect_from(src: FullPortAddress)","text":"

Disconnect this port from a previously connected source port.

"},{"location":"api/midi/#linuxpy.midi.device.Port.connect_to","title":"connect_to(dest: FullPortAddress)","text":"

Connect this port to a remote port. After connecting, events originating from this port will be sent to the destination port.

Example:

from linuxpy.midi.device import Sequencer\n\nwith Sequencer() as midi:\n    port = midi.create_port()\n    # Assume 14:0 is Midi Through\n    port.connect_to((14, 0))\n    port.send(\"note on\", note=11, velocity=10)\n
"},{"location":"api/midi/#linuxpy.midi.device.Port.disconnect_to","title":"disconnect_to(dest: FullPortAddress)","text":"

Disconnect this port from a previously connected destination port.

"},{"location":"api/midi/#linuxpy.midi.device.Port.delete","title":"delete()","text":"

Delete this port. Raises MidiError if port is not local. Any subscriptions are canceled before the port is deleted.

"},{"location":"api/midi/#linuxpy.midi.device.Port.send","title":"send(event_type: Union[str, int, EventType], **kwargs)","text":"

Send a message of the given type from to the destination address(es). Use kwargs to pass specific event arguments like velocity in a \"note on\" event.

event_type can be an instance of EventType or the equivalent number or a case insensitive string matching the event type (ex: \"noteon\", \"NOTEON\", \"note-on\" or \"note on\").

The following example sends \"note on\" on note 42, with velocity 45:

port.send(\"note on\", note=42, velocity=45)\n
"},{"location":"api/midi/#linuxpy.midi.device.Event","title":"Event(event: snd_seq_event)","text":"

Event message object result of listening on a sequencer

"},{"location":"api/midi/#linuxpy.midi.device.Event.__bytes__","title":"__bytes__()","text":"

Serialize the Event in a bytes ready to be sent

"},{"location":"api/midi/#linuxpy.midi.device.Event.new","title":"new(etype: EventT, **kwargs) classmethod","text":"

Create new Event of the given type

"},{"location":"api/midi/#linuxpy.midi.device.to_address","title":"to_address(addr: FullPortAddress) -> snd_seq_addr","text":"

Convert to low level snd_seq_addr

"},{"location":"api/midi/#linuxpy.midi.device.event_stream","title":"event_stream(sequencer: Sequencer) -> Iterable[Event]","text":"

Infinite stream of events coming from the given sequencer

"},{"location":"api/midi/#linuxpy.midi.device.async_event_stream","title":"async_event_stream(sequencer: Sequencer, maxsize: int = 10) -> AsyncIterable[Event] async","text":"

Infinite async stream of events coming from the given sequencer

"},{"location":"api/video/","title":"Video API","text":""},{"location":"api/video/#linuxpy.video.device","title":"linuxpy.video.device","text":"

Human friendly interface to V4L2 (Video 4 Linux 2) subsystem.

"},{"location":"api/video/#linuxpy.video.device.V4L2Error","title":"V4L2Error","text":"

Bases: Exception

Video for linux 2 error

"},{"location":"api/video/#linuxpy.video.device.Frame","title":"Frame(data: bytes, buff: raw.v4l2_buffer, format: Format)","text":"

The resulting object from an acquisition.

"},{"location":"api/video/#linuxpy.video.device.EventReader","title":"EventReader(device: Device, max_queue_size=100)","text":""},{"location":"api/video/#linuxpy.video.device.EventReader.aread","title":"aread() async","text":"

Wait for next event or return last event in queue

"},{"location":"api/video/#linuxpy.video.device.FrameReader","title":"FrameReader(device: Device, raw_read: Callable[[], Buffer], max_queue_size: int = 1)","text":""},{"location":"api/video/#linuxpy.video.device.FrameReader.aread","title":"aread() -> Frame async","text":"

Wait for next frame or return last frame

"},{"location":"api/video/#linuxpy.video.device.create_buffer","title":"create_buffer(fd, buffer_type: BufferType, memory: Memory) -> raw.v4l2_buffer","text":"

request + query buffers

"},{"location":"api/video/#linuxpy.video.device.create_buffers","title":"create_buffers(fd, buffer_type: BufferType, memory: Memory, count: int) -> list[raw.v4l2_buffer]","text":"

request + query buffers

"},{"location":"api/video/#linuxpy.video.device.create_mmap_buffers","title":"create_mmap_buffers(fd, buffer_type: BufferType, memory: Memory, count: int) -> list[mmap.mmap]","text":"

create buffers + mmap_from_buffer

"},{"location":"api/video/#linuxpy.video.device.iter_video_output_files","title":"iter_video_output_files(path: PathLike = '/dev') -> Iterable[Path]","text":"

Some drivers (ex: v4l2loopback) don't report being output capable so that apps like zoom recognize them as valid capture devices so some results might be missing

"},{"location":"user_guide/","title":"User guide","text":"

This tutorial shows you how to use LinuxPy with most of its features.

"},{"location":"user_guide/input/","title":"Input","text":"

Human friendly interface to the Linux Input subsystem.

API not documented yet. Just this example:

import time\nfrom linuxpy.input.device import find_gamepads\n\npad = next(find_gamepads())\nabs = pad.absolute\n\nwith pad:\n    while True:\n        print(f\"X:{abs.x:>3} | Y:{abs.y:>3} | RX:{abs.rx:>3} | RY:{abs.ry:>3}\", end=\"\\r\", flush=True)\n        time.sleep(0.1)\n
"},{"location":"user_guide/input/#asyncio","title":"asyncio","text":"python -m asyncio from linuxpy.input.device import find_gamepad with find_gamepad() as pad: async for event in pad: print(event) InputEvent(time=1697520475.348099, type=<EventType.SYN: 0>, code=<Synchronization.REPORT: 0>, value=0) InputEvent(time=1697520475.361564, type=<EventType.REL: 2>, code=<Relative.X: 0>, value=-1) InputEvent(time=1697520475.361564, type=<EventType.REL: 2>, code=<Relative.Y: 1>, value=1) InputEvent(time=1697520475.361564, type=<EventType.SYN: 0>, code=<Synchronization.REPORT: 0>, value=0) InputEvent(time=1697520475.371128, type=<EventType.REL: 2>, code=<Relative.X: 0>, value=-1) InputEvent(time=1697520475.371128, type=<EventType.SYN: 0>, code=<Synchronization.REPORT: 0>, value=0) ..."},{"location":"user_guide/input/#references","title":"References","text":""},{"location":"user_guide/midi/","title":"MIDI Sequencer","text":"

Without further ado:

python from linuxpy.midi.device import Sequencer with Sequencer() as seq: port = seq.create_port() port.connect_from(14, 0) for event in seq: print(event) 14:0 Note on channel=0, note=100, velocity=3, off_velocity=0, duration=0 14:0 Clock queue=0, pad=b'' 14:0 System exclusive F0 61 62 63 F7 14:0 Note off channel=0, note=55, velocity=3, off_velocity=0, duration=0"},{"location":"user_guide/midi/#system-information","title":"System information","text":"
$ python\n>>> from linuxpy.midi.device import Sequencer\n>>> seq = Sequencer(\"a midi client\")\n>>> seq.open()\n\n>>> seq.version\n1.0.2\n\n>>> seq.client_info\nsnd_seq_client_info(client=128, type=1, name=b'a midi client', filter=0, multicast_filter=b'', event_filter=b'', num_ports=0, event_lost=0, card=-1, pid=1288570)\n\n>>> seq.running_mode\nsnd_seq_running_info(client=0, big_endian=0, cpu_mode=0, pad=0)\n\n>>> seq.system_info\nsnd_seq_system_info(queues=32, clients=192, ports=254, channels=256, cur_clients=3, cur_queues=0)\n
"},{"location":"user_guide/midi/#asyncio","title":"asyncio","text":"

asyncio is a first class citizen to linuxpy.midi:

$ python -m asyncio\n\n>>> from linuxpy.midi.device import Sequencer\n>>> with Sequencer() as seq:\n...     port = seq.create_port()\n...     port.connect_from(14, 0)\n...     async for event in seq:\n...         print(event)\n 14:0   Note on              channel=0, note=100, velocity=3, off_velocity=0, duration=0\n 14:0   Clock                queue=0, pad=b''\n 14:0   System exclusive     F0 61 62 63 F7\n 14:0   Note off             channel=0, note=55, velocity=3, off_velocity=0, duration=0\n
"},{"location":"user_guide/midi/#cli","title":"CLI","text":"

A basic CLI is provided that allows listing MIDI clients & ports and dumping MIDI sequencer events:

List all ports:

python -m linuxpy.midi.cli ls Port Client Port Type Capabilities 0:0 System Timer 0 SR, W, R 0:1 System Announce 0 SR, R 14:0 Midi Through Midi Through Port-0 PORT, SOFTWARE, MIDI_GENERIC SW, SR, W, R

Listen to events on selected port(s):

python -m linuxpy.midi.cli listen 0:1 14:0 0:1 Port subscribed sender=(client=0, port=1), dest=(client=128, port=0) 0:1 Port start client=128, port=1 0:1 Port subscribed sender=(client=14, port=0), dest=(client=128, port=1) 0:1 Client start client=130, port=0 0:1 Port start client=130, port=0 0:1 Port subscribed sender=(client=130, port=0), dest=(client=14, port=0) 14:0 Note on channel=0, note=100, velocity=3, off_velocity=0, duration=0 0:1 Port unsubscribed sender=(client=130, port=0), dest=(client=14, port=0) 0:1 Port exit client=130, port=0 0:1 Client exit client=130, port=0 0:1 Port exit client=129, port=0 0:1 Client exit client=129, port=0 0:1 Client start client=129, port=0 0:1 Port start client=129, port=0 14:0 Note on channel=0, note=100, velocity=3, off_velocity=0, duration=0 14:0 Note on channel=0, note=0, velocity=255, off_velocity=0, duration=0 14:0 Note on channel=0, note=0, velocity=255, off_velocity=0, duration=0"},{"location":"user_guide/video/","title":"Video","text":"

Human friendly interface to the Video for Linux 2 (V4L2) subsystem.

Without further ado:

python from linuxpy.video.device import Device with Device.from_id(0) as cam: for i, frame in enumerate(cam): print(f\"frame #{i}: {len(frame)} bytes\") 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 ..."},{"location":"user_guide/video/#device-creation","title":"Device creation","text":"

Create a device object from an ID:

from linuxpy.video.device import Device\ncamera = Device.from_id(10)\n

from a filename:

from linuxpy.video.device import Device\ncamera = Device(\"/dev/video10\")\n

or from an existing file object:

from linuxpy.video.device import Device\nwith open(\"/dev/video10\", \"rb+\", buffering=0) as fd:\n    camera = Device(fd)\n

Before using video Device object you need to open it. You can either use the device object as a context manager (prefered):

with Device.from_id(10) as camera:\n    ...\n

... or manage call Device.open()/Device.close() manually:

camera = Device.from_id(10)\ncamera.open()\ntry:\n    ...\nfinally:\n    camera.close()\n
"},{"location":"user_guide/video/#capture","title":"Capture","text":"

Simple capture without any configuration is possible using the Device object as an infinite iterator:

from linuxpy.video.device import Device, VideoCapture\n\nwith Device.from_id(0) as camera:\n    for frame in camera:\n        ...\n

The resulting Frame objects can safely and efficiently be converted to bytes.

To be able to configure the acquisition, you will need to use the VideoCapture helper. Here is an example with image size and format configuration:

from linuxpy.video.device import Device, VideoCapture\n\nwith Device.from_id(0) as camera:\n    capture = VideoCapture(camera)\n    capture.set_format(640, 480, \"MJPG\")\n    with capture:\n        for frame in capture:\n            ...\n

Note that VideoCapture configuration must be done before the capture is started (ie, the the with capture: statement.)

By default, VideoCapture will use memory map if the device has STREAMING capability and falls back to standard read if not. It is also possible to force a specific reader:

from linuxpy.video.device import Capability, Device, VideoCapture\n\nwith Device.from_id(0) as cam:\n    with VideoCapture(cam, source=Capability.READWRITE):\n        for frame in capture:\n            ...\n
"},{"location":"user_guide/video/#information","title":"Information","text":"

Getting information about the device:

>>> from linuxpy.video.device import Device, BufferType\n\n>>> cam = Device.from_id(0)\n>>> cam.open()\n>>> cam.info.card\n'Integrated_Webcam_HD: Integrate'\n\n>>> cam.info.capabilities\n<Capability.STREAMING|EXT_PIX_FORMAT|VIDEO_CAPTURE: 69206017>\n\n>>> cam.info.formats\n[ImageFormat(type=<BufferType.VIDEO_CAPTURE: 1>, description=b'Motion-JPEG',\n             flags=<ImageFormatFlag.COMPRESSED: 1>, pixelformat=<PixelFormat.MJPEG: 1196444237>),\n ImageFormat(type=<BufferType.VIDEO_CAPTURE: 1>, description=b'YUYV 4:2:2',\n             flags=<ImageFormatFlag.0: 0>, pixelformat=<PixelFormat.YUYV: 1448695129>)]\n\n>>> cam.get_format(BufferType.VIDEO_CAPTURE)\nFormat(width=640, height=480, pixelformat=<PixelFormat.MJPEG: 1196444237>}\n\n>>> for ctrl in cam.controls.values(): print(ctrl)\n<IntegerControl brightness min=0 max=255 step=1 default=128 value=128>\n<IntegerControl contrast min=0 max=255 step=1 default=32 value=32>\n<IntegerControl saturation min=0 max=100 step=1 default=64 value=64>\n<IntegerControl hue min=-180 max=180 step=1 default=0 value=0>\n<BooleanControl white_balance_automatic default=True value=True>\n<IntegerControl gamma min=90 max=150 step=1 default=120 value=120>\n<MenuControl power_line_frequency default=1 value=1>\n<IntegerControl white_balance_temperature min=2800 max=6500 step=1 default=4000 value=4000 flags=inactive>\n<IntegerControl sharpness min=0 max=7 step=1 default=2 value=2>\n<IntegerControl backlight_compensation min=0 max=2 step=1 default=1 value=1>\n<MenuControl auto_exposure default=3 value=3>\n<IntegerControl exposure_time_absolute min=4 max=1250 step=1 default=156 value=156 flags=inactive>\n<BooleanControl exposure_dynamic_framerate default=False value=False>\n\n>>> cam.controls[\"saturation\"]\n<IntegerControl saturation min=0 max=100 step=1 default=64 value=64>\n\n>>> cam.controls[\"saturation\"].id\n9963778\n>>> cam.controls[9963778]\n<IntegerControl saturation min=0 max=100 step=1 default=64 value=64>\n\n>>> cam.controls.brightness\n<IntegerControl brightness min=0 max=255 step=1 default=128 value=128>\n>>> cam.controls.brightness.value = 64\n>>> cam.controls.brightness\n<IntegerControl brightness min=0 max=255 step=1 default=128 value=64>\n

(see also v4l2py-ctl example)

"},{"location":"user_guide/video/#asyncio","title":"asyncio","text":"

linuxpy.video is asyncio friendly:

python -m asyncio from linuxpy.video.device import Device with Device.from_id(0) as cam: async for frame in cam: print(f\"frame {len(frame)}\") frame 10224 frame 10304 frame 10136 ...

(check basic async and web async examples)

"},{"location":"user_guide/video/#gevent","title":"gevent","text":"

linuxpy.video is also gevent friendly:

>>> from linuxpy.io import GeventIO\n>>> from linuxpy.video.device import Device\n>>> with Device.from_id(0, io=GeventIO) as camera:\n...     for frame in camera:\n...         print(f\"frame {len(frame)}\")\nframe 10224\nframe 10304\nframe 10224\nframe 10136\n...\n

(check basic gevent and web gevent examples)

"},{"location":"user_guide/video/#video-output","title":"Video output","text":"

It is possible to write to a video output capable device (ex: v4l2loopback). The following example shows how to grab frames from device 0 and write them to device 10:

>>> from linuxpy.video.device import Device, VideoOutput, BufferType\n>>> dev_source = Device.from_id(0)\n>>> dev_sink = Device.from_id(10)\n>>> with dev_source, dev_target:\n>>>     source = VideoCapture(dev_source)\n>>>     sink = VideoOutput(dev_sink)\n>>>     source.set_format(640, 480, \"MJPG\")\n>>>     sink.set_format(640, 480, \"MJPG\")\n>>>     with source, sink:\n>>>         for frame in source:\n>>>             sink.write(frame.data)\n

By default, VideoOutput will use memory map if the device has STREAMING capability and falls back to standard write if not. It is also possible to force a specific writer with VideoOutput(cam, sink=Capability.READWRITE):

"},{"location":"user_guide/video/#v4l2loopback","title":"v4l2loopback","text":"

This is just an example on how to setup v4l2loopback.

Start from scratch:

# Remove kernel module and all devices (no client can be connected at this point)\nsudo modprobe -r v4l2loopback\n\n# Install some devices\nsudo modprobe v4l2loopback video_nr=20,21 card_label=\"Loopback 0\",\"Loopback 1\"\n
"},{"location":"user_guide/video/#references","title":"References","text":"

See the linux/videodev2.h header file for details.

"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Welcome to linuxpy","text":"

Human friendly interface to linux subsystems using python.

Provides python access to several linux subsystems like V4L2, input and MIDI.

There is experimental, undocumented, incomplete and unstable access to USB.

Need fine control over Webcams, MIDI devices, input devices (joysticks, gamepads, keyboards, mice or even the keyboard light on your laptop)? Linuxpy has your back.

Requirements:

And yes, it is true: there are no python dependencies! Also there are no C libraries dependencies! Everything is done here through direct ioctl, read and write calls. Ain't linux wonderful?

"},{"location":"#goals","title":"Goals","text":""},{"location":"#installation","title":"Installation","text":"

From within your favorite python environment:

pip install linuxpy pip install linuxpy

To run the examples you'll need:

$ pip install linuxpy[examples]\n

To develop, run tests, build package, lint, etc you'll need:

$ pip install linuxpy[dev]\n

To run docs you'll need:

$ pip install linuxpy[docs]\n
"},{"location":"#faq","title":"FAQ","text":"

Most python libraries try as hard as possible to be platform independent. Why create a library that is explicitly designed to work only on linux?

Well, first of all, one of the goals is to be able to access low level linux device capabilities like video controls. Second, I don't have access to proprietary OS like Windows or MacOS.

If this answer is not enough than think of this library as a low level dependency on linux systems of other libraries that will be concerned with providing a common API on different platforms.

"},{"location":"develop/","title":"Developers corner","text":""},{"location":"develop/#requirements","title":"Requirements","text":"

A linux OS and python >= 3.9.

From within your favorite python environment:

$ pip install linuxpy[dev]\n

Additionally, to run the code generation tool you'll need castxml installed on your system.

On a debian based run:

$ apt install castxml\n
"},{"location":"develop/#code-generation","title":"Code generation","text":"

This project uses an internal simple code generator that reads linux kernel header files and produces several raw.py ctypes based python files for each sub-system.

To re-generate these files for a newer linux kernel (or fix a bug) you'll need linux header files installed on your system + black.

To launch the tool call:

$ python -m linuxpy.codegen.cli\n
"},{"location":"develop/#running-tests","title":"Running tests","text":"

Some video tests will only run with a properly configured v4l2loopback.

$ sudo modprobe v4l2loopback video_nr=199 card_label=\"Loopback 199\"\n

Additionally the user which runs the tests will need read/write access to /dev/video199. On most systems this can be achieved by adding the user to the video group:

$ sudo addgroup $USER video\n

Some input tests require the user which runs the tests to have read/write access to /dev/uinput. On most systems this can be achieved by adding the user to the input group:

$ sudo addgroup $USER input\n
"},{"location":"api/","title":"LinuxPy reference API","text":"

Here's the reference or code API, the classes, functions, parameters, attributes, and all the LinuxPy parts you can use in your applications.

If you want to learn LinuxPy you are much better off reading the LinuxPy User Guide.

"},{"location":"api/input/","title":"Input API","text":""},{"location":"api/input/#linuxpy.input.device","title":"linuxpy.input.device","text":"

Human friendly interface to linux Input subsystem.

The heart of linuxpy MIDI library is the Device class. The recommended way is to use one of the find methods to create a Device object and use it within a context manager like:

from linuxpy.input.device import find_gamepad\n\nwith find_gamepad() as gamepad:\n    print(f\"Gamepad name: {gamepad.name}\")\n
"},{"location":"api/input/#linuxpy.input.device.InputError","title":"InputError","text":"

Bases: Exception

Input error

"},{"location":"api/input/#linuxpy.input.device.Device","title":"Device(*args, **kwargs)","text":"

Bases: BaseDevice

Central linux input subsystem class.

You can create an instance directly if you know the device name:

from linuxpy.input.device import Device\n\nwith Device(\"/dev/input11\") as i11:\n    print(i11.name)\n

... but it is generally easier to use the find helper to get a device with a certain condition. Example:

from linuxpy.input.device import find\n\ntrack_point = find(name=\"TPPS/2 Elan TrackPoint\")\n
"},{"location":"api/input/#linuxpy.input.device.Device.name","title":"name: str cached property","text":"

The device name

"},{"location":"api/input/#linuxpy.input.device.Device.version","title":"version: Version cached property","text":"

The version

"},{"location":"api/input/#linuxpy.input.device.Device.physical_location","title":"physical_location: str cached property","text":"

The physical location

"},{"location":"api/input/#linuxpy.input.device.Device.device_id","title":"device_id: input_id cached property","text":"

The device input ID

"},{"location":"api/input/#linuxpy.input.device.Device.capabilities","title":"capabilities cached property","text":"

The device capabilities

"},{"location":"api/input/#linuxpy.input.device.Device.active_keys","title":"active_keys property","text":"

All active keys at the moment of calling this

"},{"location":"api/input/#linuxpy.input.device.Device.x","title":"x property","text":"

Current absolute X value

"},{"location":"api/input/#linuxpy.input.device.Device.y","title":"y property","text":"

Current absolute Y value

"},{"location":"api/input/#linuxpy.input.device.Device.z","title":"z property","text":"

Current absolute Z value

"},{"location":"api/input/#linuxpy.input.device.Device.rx","title":"rx property","text":"

Current relative X value

"},{"location":"api/input/#linuxpy.input.device.Device.ry","title":"ry property","text":"

Current relative Y value

"},{"location":"api/input/#linuxpy.input.device.Device.rz","title":"rz property","text":"

Current relative Z value

"},{"location":"api/input/#linuxpy.input.device.Device.__iter__","title":"__iter__() -> Iterable[InputEvent]","text":"

Build an infinite iterator that streams input events You'll need an open Device before using it:

from linuxpy.input.device import find_mouse\n\nwith find_mouse() as mouse:\n    for event in mouse:\n        print(event)\n
"},{"location":"api/input/#linuxpy.input.device.Device.__aiter__","title":"__aiter__() -> AsyncIterable[InputEvent] async","text":"

Build an infinite async iterator that streams input events You'll need an open Device before using it:

import asyncio\nfrom linuxpy.input.device import find_mouse\n\nasync def main():\n    with find_mouse() as mouse:\n        async for event in mouse:\n            print(event)\n\nasyncio.run(main())\n
"},{"location":"api/input/#linuxpy.input.device.Device.get_abs_info","title":"get_abs_info(abs_code)","text":"

Absolute information for the given abs code

"},{"location":"api/input/#linuxpy.input.device.Device.read_event","title":"read_event()","text":"

Read event. Event must be available to read or otherwise will raise an error

"},{"location":"api/input/#linuxpy.input.device.EventReader","title":"EventReader(device: Device, max_queue_size=1)","text":""},{"location":"api/input/#linuxpy.input.device.EventReader.aread","title":"aread() async","text":"

Wait for next event or return last event

"},{"location":"api/input/#linuxpy.input.device.BaseUDevice","title":"BaseUDevice(filename=PATH, bus=Bus.USB, vendor_id=1, product_id=1, name='linuxpy emulated device')","text":"

Bases: BaseDevice

A uinput device with no capabilities registered

"},{"location":"api/input/#linuxpy.input.device.iter_input_files","title":"iter_input_files(path: PathLike = '/dev/input', pattern: str = 'event*')","text":"

List readable character devices in the given path.

"},{"location":"api/input/#linuxpy.input.device.event_batch_stream","title":"event_batch_stream(fd) -> Iterable[Sequence[InputEvent]]","text":"

Yields packets of events occurring at the same moment in time.

"},{"location":"api/input/#linuxpy.input.device.async_event_batch_stream","title":"async_event_batch_stream(fd, maxsize: int = 1000) -> AsyncIterable[Sequence[InputEvent]] async","text":"

Yields packets of events occurring at the same moment in time.

"},{"location":"api/input/#linuxpy.input.device.find","title":"find(find_all: bool = False, custom_match: Optional[Callable] = None, **kwargs) -> Union[Device, Iterable[Device], None]","text":"

If find_all is False:

Find a device follwing the criteria matched by custom_match and kwargs. If no device is found matching the criteria it returns None. Default is to return a random first device.

If find_all is True:

The result is an iterator. Find all devices that match the criteria custom_match and kwargs. If no device is found matching the criteria it returns an empty iterator. Default is to return an iterator over all input devices found on the system.

"},{"location":"api/input/#linuxpy.input.device.find_gamepad","title":"find_gamepad(find_all: bool = False, custom_match: Optional[Callable] = None, **kwargs) -> Union[Device, Iterable[Device], None]","text":"

If find_all is False:

Find a gamepad device follwing the criteria matched by custom_match and kwargs. If no device is found matching the criteria it returns None. Default is to return a random first gamepad.

If find_all is True:

The result is an iterator. Find all gamepad devices that match the criteria custom_match and kwargs. If no gamepad is found matching the criteria it returns an empty iterator. Default is to return an iterator over all gamepad devices found on the system.

"},{"location":"api/input/#linuxpy.input.device.find_keyboard","title":"find_keyboard(find_all: bool = False, custom_match: Optional[Callable] = None, **kwargs) -> Union[Device, Iterable[Device], None]","text":"

If find_all is False:

Find a keyboard device follwing the criteria matched by custom_match and kwargs. If no device is found matching the criteria it returns None. Default is to return a random first keyboard.

If find_all is True:

The result is an iterator. Find all keyboard devices that match the criteria custom_match and kwargs. If no keyboard is found matching the criteria it returns an empty iterator. Default is to return an iterator over all keyboard devices found on the system.

"},{"location":"api/input/#linuxpy.input.device.find_mouse","title":"find_mouse(find_all: bool = False, custom_match: Optional[Callable] = None, **kwargs) -> Union[Device, Iterable[Device], None]","text":"

If find_all is False:

Find a mouse device follwing the criteria matched by custom_match and kwargs. If no device is found matching the criteria it returns None. Default is to return a random first mouse.

If find_all is True:

The result is an iterator. Find all mouse devices that match the criteria custom_match and kwargs. If no mouse is found matching the criteria it returns an empty iterator. Default is to return an iterator over all mouse devices found on the system.

"},{"location":"api/midi/","title":"MIDI API","text":""},{"location":"api/midi/#linuxpy.midi.device","title":"linuxpy.midi.device","text":"

Human friendly interface to linux MIDI subsystem.

The heart of linuxpy MIDI library is the Sequencer class. Usually you need only one instance of Sequencer for your application. The recommended way is to use it within a context manager like:

with Sequencer(\"My MIDI App\") as midi:\n    print(f\"MIDI version: {midi.version}\")\n

which is roughly equivalent to:

midi = Sequencer(\"My MIDI App\")\nmidi.open()\ntry:\n    print(f\"MIDI version: {midi.version}\")\nfinally:\n    midi.close()\n

Here's a real world example:

from linuxpy.midi.device import Sequencer\n\nwith Sequencer(\"My MIDI App\") as midi:\n    print(f\"I'm client {midi.client_id}\")\n    print(f\"MIDI version: {midi.version}\")\n    port = midi.create_port()\n    port.connect_from((0, 1))\n    for event in midi:\n        print(event)\n
"},{"location":"api/midi/#linuxpy.midi.device.MidiError","title":"MidiError","text":"

Bases: Exception

MIDI error

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer","title":"Sequencer(name: str = 'linuxpy client', **kwargs)","text":"

Bases: BaseDevice

Central MIDI class.

from linuxpy.midi.device import Sequencer\n\nwith Sequencer(\"My MIDI App\") as midi:\n    print(f\"I'm client {midi.client_id}\")\n    print(f\"MIDI version: {midi.version}\")\n    port = midi.create_port()\n    port.connect_from((0, 1))\n    for event in midi:\n        print(event)\n
"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.client_info","title":"client_info: snd_seq_client_info property","text":"

Current Client information

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.client","title":"client: Client property","text":"

Current Client information

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.running_mode","title":"running_mode: snd_seq_running_info property","text":"

Current running mode

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.system_info","title":"system_info: snd_seq_system_info property","text":"

Current system information

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.iter_clients","title":"iter_clients: Iterable[Client] property","text":"

An iterator over all open clients on the system. It returns new Client each time

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.clients","title":"clients: Sequence[Client] property","text":"

Returns a new list of all clients on the system

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.iter_ports","title":"iter_ports: Iterable[Port] property","text":"

An iterator over all open ports on the system. It returns new Port objects each time

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.ports","title":"ports: Sequence[Port] property","text":"

Returns a new list of all open ports on the system. It returns new Port objects each time

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.__iter__","title":"__iter__() -> Iterable[Event]","text":"

Build an infinite iterator that streams MIDI events from the subscribed ports. You'll need an open sequencer before using it:

from linuxpy.midi.device import Sequencer\n\nwith Sequencer() as midi:\n    port = midi.create_port()\n    port.connect_from((0, 1))\n    for event in midi:\n        print(event)\n
"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.__aiter__","title":"__aiter__() -> AsyncIterable[Event] async","text":"

Build an infinite async iterator that streams MIDI events from the subscribed ports. You'll need an open sequencer before using it:

import asyncio\nfrom linuxpy.midi.device import Sequencer\n\nasync def main():\n    with Sequencer() as midi:\n        port = midi.create_port()\n        port.connect_from((0, 1))\n        async for event in midi:\n            print(event)\n\nasyncio.run(main())\n
"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.get_client","title":"get_client(client_id: int) -> Client","text":"

Returns a Client for the given ID or raises an error if the client doesn't exist. It returns new Client object each time

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.get_port","title":"get_port(address: FullPortAddress) -> Port","text":"

Returns a Port for the given address or raises an error if the port doesn't exist. It returns new Port object each time

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.create_port","title":"create_port(name: str = 'linuxpy port', capabilities: PortCapability = INPUT_OUTPUT, port_type: PortType = PortType.MIDI_GENERIC | PortType.APPLICATION) -> Port","text":"

Create a new local port. By default it will create a MIDI generic application Input/Output port.

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.delete_port","title":"delete_port(port: Union[int, Port])","text":"

Delete a previously created local port. If the port has any subscriptions they will be closed before the port is deleted

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.subscribe","title":"subscribe(src: FullPortAddress, dest: FullPortAddress)","text":"

Subscribe a source port to a destination port

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.unsubscribe","title":"unsubscribe(src: FullPortAddress, dest: FullPortAddress)","text":"

Unsubscribe a previously subscribed source port to a destination port

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.iter_raw_read","title":"iter_raw_read(max_nb_packets: int = 64) -> Iterable[Event]","text":"

Read list of pending events. If the sequencer is opened in blocking mode and there are no events it blocks until at least one event occurs otherwise as OSError is raised.

Use the read() call instead because it handles blocking vs non-blocking variants transperently.

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.raw_read","title":"raw_read(max_nb_packets=64) -> Sequence[Event]","text":"

Read list of pending events. If there are no events it blocks until at least one event occurs and returns it.

Use the read() call instead because it handles blocking vs non-blocking variants transperently.

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.wait_read","title":"wait_read() -> Sequence[Event]","text":"

Read list of pending events. If there are no events it blocks until at least one event occurs and returns it. This method assumes the internal file descriptior was opened in non-blocking mode.

Use the read() call instead because it handles blocking vs non-blocking variants transperently

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.read","title":"read() -> Sequence[Event]","text":"

Read list of pending events. If there are no events it blocks until at least one event occurs and returns it

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.write","title":"write(event: Event)","text":"

Send an event message

"},{"location":"api/midi/#linuxpy.midi.device.Sequencer.send","title":"send(port: PortAddress, event_type: Union[str, int, EventType], queue: int = QUEUE_DIRECT, to: Union[FullPortAddress, FullPortAddresses] = SUBSCRIBERS, **kwargs)","text":"

Send a message of the given type from a specific port to the destination address(es). Use kwargs to pass specific event arguments like velocity in a \"note on\" event.

event_type can be an instance of EventType or the equivalent number or a case insensitive string matching the event type (ex: \"noteon\", \"NOTEON\", \"note-on\" or \"note on\").

The following example sends \"note on\" with velocity 45 on port 0 of client 14:

midi.send((14, 0), \"note on\", velocity=45)\n
"},{"location":"api/midi/#linuxpy.midi.device.Client","title":"Client(sequencer: Sequencer, client: snd_seq_client_info)","text":"

MIDI sequencer client. Don't instantiate this object directly Use instead Sequencer.get_client()

"},{"location":"api/midi/#linuxpy.midi.device.Client.name","title":"name: str property","text":"

Client name

"},{"location":"api/midi/#linuxpy.midi.device.Client.is_local","title":"is_local: bool property","text":"

True if the client was created by the MIDI sequencer that it references or False otherwise\"

"},{"location":"api/midi/#linuxpy.midi.device.Client.iter_ports","title":"iter_ports: Iterable[Port] property","text":"

An iterator over all open ports for this client. It returns new Port each time

"},{"location":"api/midi/#linuxpy.midi.device.Client.ports","title":"ports: Sequence[Port] property","text":"

Returns a new list of all open ports for this client

"},{"location":"api/midi/#linuxpy.midi.device.Client.__int__","title":"__int__()","text":"

The client ID

"},{"location":"api/midi/#linuxpy.midi.device.Port","title":"Port(sequencer: Sequencer, port: snd_seq_port_info)","text":"

MIDI sequencer port. Don't instantiate this object directly Use instead Sequencer.get_port()

"},{"location":"api/midi/#linuxpy.midi.device.Port.name","title":"name: str property","text":"

Port name

"},{"location":"api/midi/#linuxpy.midi.device.Port.is_local","title":"is_local: bool property","text":"

True if the port was created by the MIDI sequencer that it references or False otherwise\"

"},{"location":"api/midi/#linuxpy.midi.device.Port.client_id","title":"client_id: int property","text":"

The client ID

"},{"location":"api/midi/#linuxpy.midi.device.Port.port_id","title":"port_id: int property","text":"

The port ID

"},{"location":"api/midi/#linuxpy.midi.device.Port.type","title":"type: PortType property","text":"

The port type

"},{"location":"api/midi/#linuxpy.midi.device.Port.capability","title":"capability: PortCapability property","text":"

The port capabilities

"},{"location":"api/midi/#linuxpy.midi.device.Port.address","title":"address: snd_seq_addr property","text":"

The port address

"},{"location":"api/midi/#linuxpy.midi.device.Port.__int__","title":"__int__()","text":"

The port ID

"},{"location":"api/midi/#linuxpy.midi.device.Port.connect_from","title":"connect_from(src: FullPortAddress)","text":"

Connect this port to a remote port. After connecting, this port will receive events originating from the source port.

Example:

from linuxpy.midi.device import Sequencer\n\nwith Sequencer() as midi:\n    port = midi.create_port()\n    port.connect_from((0, 1))\n    for event in midi:\n        print(event)\n
"},{"location":"api/midi/#linuxpy.midi.device.Port.disconnect_from","title":"disconnect_from(src: FullPortAddress)","text":"

Disconnect this port from a previously connected source port.

"},{"location":"api/midi/#linuxpy.midi.device.Port.connect_to","title":"connect_to(dest: FullPortAddress)","text":"

Connect this port to a remote port. After connecting, events originating from this port will be sent to the destination port.

Example:

from linuxpy.midi.device import Sequencer\n\nwith Sequencer() as midi:\n    port = midi.create_port()\n    # Assume 14:0 is Midi Through\n    port.connect_to((14, 0))\n    port.send(\"note on\", note=11, velocity=10)\n
"},{"location":"api/midi/#linuxpy.midi.device.Port.disconnect_to","title":"disconnect_to(dest: FullPortAddress)","text":"

Disconnect this port from a previously connected destination port.

"},{"location":"api/midi/#linuxpy.midi.device.Port.delete","title":"delete()","text":"

Delete this port. Raises MidiError if port is not local. Any subscriptions are canceled before the port is deleted.

"},{"location":"api/midi/#linuxpy.midi.device.Port.send","title":"send(event_type: Union[str, int, EventType], **kwargs)","text":"

Send a message of the given type from to the destination address(es). Use kwargs to pass specific event arguments like velocity in a \"note on\" event.

event_type can be an instance of EventType or the equivalent number or a case insensitive string matching the event type (ex: \"noteon\", \"NOTEON\", \"note-on\" or \"note on\").

The following example sends \"note on\" on note 42, with velocity 45:

port.send(\"note on\", note=42, velocity=45)\n
"},{"location":"api/midi/#linuxpy.midi.device.Event","title":"Event(event: snd_seq_event)","text":"

Event message object result of listening on a sequencer

"},{"location":"api/midi/#linuxpy.midi.device.Event.__bytes__","title":"__bytes__()","text":"

Serialize the Event in a bytes ready to be sent

"},{"location":"api/midi/#linuxpy.midi.device.Event.new","title":"new(etype: EventT, **kwargs) classmethod","text":"

Create new Event of the given type

"},{"location":"api/midi/#linuxpy.midi.device.to_address","title":"to_address(addr: FullPortAddress) -> snd_seq_addr","text":"

Convert to low level snd_seq_addr

"},{"location":"api/midi/#linuxpy.midi.device.event_stream","title":"event_stream(sequencer: Sequencer) -> Iterable[Event]","text":"

Infinite stream of events coming from the given sequencer

"},{"location":"api/midi/#linuxpy.midi.device.async_event_stream","title":"async_event_stream(sequencer: Sequencer, maxsize: int = 10) -> AsyncIterable[Event] async","text":"

Infinite async stream of events coming from the given sequencer

"},{"location":"api/video/","title":"Video API","text":""},{"location":"api/video/#linuxpy.video.device","title":"linuxpy.video.device","text":"

Human friendly interface to V4L2 (Video 4 Linux 2) subsystem.

"},{"location":"api/video/#linuxpy.video.device.V4L2Error","title":"V4L2Error","text":"

Bases: Exception

Video for linux 2 error

"},{"location":"api/video/#linuxpy.video.device.Frame","title":"Frame(data: bytes, buff: raw.v4l2_buffer, format: Format)","text":"

The resulting object from an acquisition.

"},{"location":"api/video/#linuxpy.video.device.EventReader","title":"EventReader(device: Device, max_queue_size=100)","text":""},{"location":"api/video/#linuxpy.video.device.EventReader.aread","title":"aread() async","text":"

Wait for next event or return last event in queue

"},{"location":"api/video/#linuxpy.video.device.FrameReader","title":"FrameReader(device: Device, raw_read: Callable[[], Buffer], max_queue_size: int = 1)","text":""},{"location":"api/video/#linuxpy.video.device.FrameReader.aread","title":"aread() -> Frame async","text":"

Wait for next frame or return last frame

"},{"location":"api/video/#linuxpy.video.device.create_buffer","title":"create_buffer(fd, buffer_type: BufferType, memory: Memory) -> raw.v4l2_buffer","text":"

request + query buffers

"},{"location":"api/video/#linuxpy.video.device.create_buffers","title":"create_buffers(fd, buffer_type: BufferType, memory: Memory, count: int) -> list[raw.v4l2_buffer]","text":"

request + query buffers

"},{"location":"api/video/#linuxpy.video.device.create_mmap_buffers","title":"create_mmap_buffers(fd, buffer_type: BufferType, memory: Memory, count: int) -> list[mmap.mmap]","text":"

create buffers + mmap_from_buffer

"},{"location":"api/video/#linuxpy.video.device.iter_video_output_files","title":"iter_video_output_files(path: PathLike = '/dev') -> Iterable[Path]","text":"

Some drivers (ex: v4l2loopback) don't report being output capable so that apps like zoom recognize them as valid capture devices so some results might be missing

"},{"location":"user_guide/","title":"User guide","text":"

This tutorial shows you how to use LinuxPy with most of its features.

"},{"location":"user_guide/input/","title":"Input","text":"

Human friendly interface to the Linux Input subsystem.

API not documented yet. Just this example:

import time\nfrom linuxpy.input.device import find_gamepads\n\npad = next(find_gamepads())\nabs = pad.absolute\n\nwith pad:\n    while True:\n        print(f\"X:{abs.x:>3} | Y:{abs.y:>3} | RX:{abs.rx:>3} | RY:{abs.ry:>3}\", end=\"\\r\", flush=True)\n        time.sleep(0.1)\n
"},{"location":"user_guide/input/#asyncio","title":"asyncio","text":"python -m asyncio from linuxpy.input.device import find_gamepad with find_gamepad() as pad: async for event in pad: print(event) InputEvent(time=1697520475.348099, type=<EventType.SYN: 0>, code=<Synchronization.REPORT: 0>, value=0) InputEvent(time=1697520475.361564, type=<EventType.REL: 2>, code=<Relative.X: 0>, value=-1) InputEvent(time=1697520475.361564, type=<EventType.REL: 2>, code=<Relative.Y: 1>, value=1) InputEvent(time=1697520475.361564, type=<EventType.SYN: 0>, code=<Synchronization.REPORT: 0>, value=0) InputEvent(time=1697520475.371128, type=<EventType.REL: 2>, code=<Relative.X: 0>, value=-1) InputEvent(time=1697520475.371128, type=<EventType.SYN: 0>, code=<Synchronization.REPORT: 0>, value=0) ..."},{"location":"user_guide/input/#references","title":"References","text":""},{"location":"user_guide/midi/","title":"MIDI Sequencer","text":"

Without further ado:

python from linuxpy.midi.device import Sequencer with Sequencer() as seq: port = seq.create_port() port.connect_from(14, 0) for event in seq: print(event) 14:0 Note on channel=0, note=100, velocity=3, off_velocity=0, duration=0 14:0 Clock queue=0, pad=b'' 14:0 System exclusive F0 61 62 63 F7 14:0 Note off channel=0, note=55, velocity=3, off_velocity=0, duration=0"},{"location":"user_guide/midi/#system-information","title":"System information","text":"
$ python\n>>> from linuxpy.midi.device import Sequencer\n>>> seq = Sequencer(\"a midi client\")\n>>> seq.open()\n\n>>> seq.version\n1.0.2\n\n>>> seq.client_info\nsnd_seq_client_info(client=128, type=1, name=b'a midi client', filter=0, multicast_filter=b'', event_filter=b'', num_ports=0, event_lost=0, card=-1, pid=1288570)\n\n>>> seq.running_mode\nsnd_seq_running_info(client=0, big_endian=0, cpu_mode=0, pad=0)\n\n>>> seq.system_info\nsnd_seq_system_info(queues=32, clients=192, ports=254, channels=256, cur_clients=3, cur_queues=0)\n
"},{"location":"user_guide/midi/#asyncio","title":"asyncio","text":"

asyncio is a first class citizen to linuxpy.midi:

$ python -m asyncio\n\n>>> from linuxpy.midi.device import Sequencer\n>>> with Sequencer() as seq:\n...     port = seq.create_port()\n...     port.connect_from(14, 0)\n...     async for event in seq:\n...         print(event)\n 14:0   Note on              channel=0, note=100, velocity=3, off_velocity=0, duration=0\n 14:0   Clock                queue=0, pad=b''\n 14:0   System exclusive     F0 61 62 63 F7\n 14:0   Note off             channel=0, note=55, velocity=3, off_velocity=0, duration=0\n
"},{"location":"user_guide/midi/#cli","title":"CLI","text":"

A basic CLI is provided that allows listing MIDI clients & ports and dumping MIDI sequencer events:

List all ports:

python -m linuxpy.midi.cli ls Port Client Port Type Capabilities 0:0 System Timer 0 SR, W, R 0:1 System Announce 0 SR, R 14:0 Midi Through Midi Through Port-0 PORT, SOFTWARE, MIDI_GENERIC SW, SR, W, R

Listen to events on selected port(s):

python -m linuxpy.midi.cli listen 0:1 14:0 0:1 Port subscribed sender=(client=0, port=1), dest=(client=128, port=0) 0:1 Port start client=128, port=1 0:1 Port subscribed sender=(client=14, port=0), dest=(client=128, port=1) 0:1 Client start client=130, port=0 0:1 Port start client=130, port=0 0:1 Port subscribed sender=(client=130, port=0), dest=(client=14, port=0) 14:0 Note on channel=0, note=100, velocity=3, off_velocity=0, duration=0 0:1 Port unsubscribed sender=(client=130, port=0), dest=(client=14, port=0) 0:1 Port exit client=130, port=0 0:1 Client exit client=130, port=0 0:1 Port exit client=129, port=0 0:1 Client exit client=129, port=0 0:1 Client start client=129, port=0 0:1 Port start client=129, port=0 14:0 Note on channel=0, note=100, velocity=3, off_velocity=0, duration=0 14:0 Note on channel=0, note=0, velocity=255, off_velocity=0, duration=0 14:0 Note on channel=0, note=0, velocity=255, off_velocity=0, duration=0"},{"location":"user_guide/video/","title":"Video","text":"

Human friendly interface to the Video for Linux 2 (V4L2) subsystem.

Without further ado:

python from linuxpy.video.device import Device with Device.from_id(0) as cam: for i, frame in enumerate(cam): print(f\"frame #{i}: {len(frame)} bytes\") 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 ..."},{"location":"user_guide/video/#device-creation","title":"Device creation","text":"

Create a device object from an ID:

from linuxpy.video.device import Device\ncamera = Device.from_id(10)\n

from a filename:

from linuxpy.video.device import Device\ncamera = Device(\"/dev/video10\")\n

or from an existing file object:

from linuxpy.video.device import Device\nwith open(\"/dev/video10\", \"rb+\", buffering=0) as fd:\n    camera = Device(fd)\n

Before using video Device object you need to open it (except in the example directly above when creating a device from a file object). You can either use the device object as a context manager (prefered):

with Device.from_id(10) as camera:\n    ...\n

The Device object is a reusable, reentrant but not thread safe context manager. This means that Device object can not only be used in multiple with statements, but may also be used inside a with statement that is already using the same context manager.

So the following examples will work just fine:

with Device.from_id(10) as camera:\n    ...\n    with camera:\n        ...\n\nwith camera:\n    ...\n

Alternatively, you can manage calls Device.open()/Device.close() manually:

camera = Device.from_id(10)\ncamera.open()\ntry:\n    ...\nfinally:\n    camera.close()\n
"},{"location":"user_guide/video/#capture","title":"Capture","text":"

Simple capture without any configuration is possible using the Device object as an infinite iterator:

from linuxpy.video.device import Device, VideoCapture\n\nwith Device.from_id(0) as camera:\n    for frame in camera:\n        ...\n

The resulting Frame objects can safely and efficiently be converted to bytes.

To be able to configure the acquisition, you will need to use the VideoCapture helper. Here is an example with image size and format configuration:

from linuxpy.video.device import Device, VideoCapture\n\nwith Device.from_id(0) as camera:\n    capture = VideoCapture(camera)\n    capture.set_format(640, 480, \"MJPG\")\n    with capture:\n        for frame in capture:\n            ...\n

Note that VideoCapture configuration must be done before the capture is started (ie, the with capture: statement.)

By default, VideoCapture will use memory map if the device has STREAMING capability and falls back to standard read if not. It is also possible to force a specific reader:

from linuxpy.video.device import Capability, Device, VideoCapture\n\nwith Device.from_id(0) as cam:\n    with VideoCapture(cam, source=Capability.READWRITE):\n        for frame in capture:\n            ...\n
"},{"location":"user_guide/video/#information","title":"Information","text":"

Getting information about the device:

>>> from linuxpy.video.device import Device, BufferType\n\n>>> cam = Device.from_id(0)\n>>> cam.open()\n>>> cam.info.card\n'Integrated_Webcam_HD: Integrate'\n\n>>> cam.info.capabilities\n<Capability.STREAMING|EXT_PIX_FORMAT|VIDEO_CAPTURE: 69206017>\n\n>>> cam.info.formats\n[ImageFormat(type=<BufferType.VIDEO_CAPTURE: 1>, description=b'Motion-JPEG',\n             flags=<ImageFormatFlag.COMPRESSED: 1>, pixelformat=<PixelFormat.MJPEG: 1196444237>),\n ImageFormat(type=<BufferType.VIDEO_CAPTURE: 1>, description=b'YUYV 4:2:2',\n             flags=<ImageFormatFlag.0: 0>, pixelformat=<PixelFormat.YUYV: 1448695129>)]\n\n>>> cam.get_format(BufferType.VIDEO_CAPTURE)\nFormat(width=640, height=480, pixelformat=<PixelFormat.MJPEG: 1196444237>}\n\n>>> for ctrl in cam.controls.values(): print(ctrl)\n<IntegerControl brightness min=0 max=255 step=1 default=128 value=128>\n<IntegerControl contrast min=0 max=255 step=1 default=32 value=32>\n<IntegerControl saturation min=0 max=100 step=1 default=64 value=64>\n<IntegerControl hue min=-180 max=180 step=1 default=0 value=0>\n<BooleanControl white_balance_automatic default=True value=True>\n<IntegerControl gamma min=90 max=150 step=1 default=120 value=120>\n<MenuControl power_line_frequency default=1 value=1>\n<IntegerControl white_balance_temperature min=2800 max=6500 step=1 default=4000 value=4000 flags=inactive>\n<IntegerControl sharpness min=0 max=7 step=1 default=2 value=2>\n<IntegerControl backlight_compensation min=0 max=2 step=1 default=1 value=1>\n<MenuControl auto_exposure default=3 value=3>\n<IntegerControl exposure_time_absolute min=4 max=1250 step=1 default=156 value=156 flags=inactive>\n<BooleanControl exposure_dynamic_framerate default=False value=False>\n\n>>> cam.controls[\"saturation\"]\n<IntegerControl saturation min=0 max=100 step=1 default=64 value=64>\n\n>>> cam.controls[\"saturation\"].id\n9963778\n>>> cam.controls[9963778]\n<IntegerControl saturation min=0 max=100 step=1 default=64 value=64>\n\n>>> cam.controls.brightness\n<IntegerControl brightness min=0 max=255 step=1 default=128 value=128>\n>>> cam.controls.brightness.value = 64\n>>> cam.controls.brightness\n<IntegerControl brightness min=0 max=255 step=1 default=128 value=64>\n

(see also v4l2py-ctl example)

"},{"location":"user_guide/video/#asyncio","title":"asyncio","text":"

linuxpy.video is asyncio friendly:

python -m asyncio from linuxpy.video.device import Device with Device.from_id(0) as cam: async for frame in cam: print(f\"frame {len(frame)}\") frame 10224 frame 10304 frame 10136 ...

(check basic async and web async examples)

"},{"location":"user_guide/video/#gevent","title":"gevent","text":"

linuxpy.video is also gevent friendly:

>>> from linuxpy.io import GeventIO\n>>> from linuxpy.video.device import Device\n>>> with Device.from_id(0, io=GeventIO) as camera:\n...     for frame in camera:\n...         print(f\"frame {len(frame)}\")\nframe 10224\nframe 10304\nframe 10224\nframe 10136\n...\n

(check basic gevent and web gevent examples)

"},{"location":"user_guide/video/#video-output","title":"Video output","text":"

It is possible to write to a video output capable device (ex: v4l2loopback). The following example shows how to grab frames from device 0 and write them to device 10:

>>> from linuxpy.video.device import Device, VideoOutput, BufferType\n>>> dev_source = Device.from_id(0)\n>>> dev_sink = Device.from_id(10)\n>>> with dev_source, dev_target:\n>>>     source = VideoCapture(dev_source)\n>>>     sink = VideoOutput(dev_sink)\n>>>     source.set_format(640, 480, \"MJPG\")\n>>>     sink.set_format(640, 480, \"MJPG\")\n>>>     with source, sink:\n>>>         for frame in source:\n>>>             sink.write(frame.data)\n

By default, VideoOutput will use memory map if the device has STREAMING capability and falls back to standard write if not. It is also possible to force a specific writer with VideoOutput(cam, sink=Capability.READWRITE):

"},{"location":"user_guide/video/#v4l2loopback","title":"v4l2loopback","text":"

This is just an example on how to setup v4l2loopback.

Start from scratch:

# Remove kernel module and all devices (no client can be connected at this point)\nsudo modprobe -r v4l2loopback\n\n# Install some devices\nsudo modprobe v4l2loopback video_nr=20,21 card_label=\"Loopback 0\",\"Loopback 1\"\n
"},{"location":"user_guide/video/#references","title":"References","text":"

See the linux/videodev2.h header file for details.

"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index 49c6159..89dba85 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -2,52 +2,52 @@ https://tiagocoutinho.github.io/linuxpy/ - 2023-12-15 + 2023-12-16 daily https://tiagocoutinho.github.io/linuxpy/develop/ - 2023-12-15 + 2023-12-16 daily https://tiagocoutinho.github.io/linuxpy/api/ - 2023-12-15 + 2023-12-16 daily https://tiagocoutinho.github.io/linuxpy/api/input/ - 2023-12-15 + 2023-12-16 daily https://tiagocoutinho.github.io/linuxpy/api/midi/ - 2023-12-15 + 2023-12-16 daily https://tiagocoutinho.github.io/linuxpy/api/video/ - 2023-12-15 + 2023-12-16 daily https://tiagocoutinho.github.io/linuxpy/user_guide/ - 2023-12-15 + 2023-12-16 daily https://tiagocoutinho.github.io/linuxpy/user_guide/input/ - 2023-12-15 + 2023-12-16 daily https://tiagocoutinho.github.io/linuxpy/user_guide/midi/ - 2023-12-15 + 2023-12-16 daily https://tiagocoutinho.github.io/linuxpy/user_guide/video/ - 2023-12-15 + 2023-12-16 daily \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz index aa2df8679972d1287d24e9a285f739be122d6924..8b63e2865caf88463f07ad7d11e677cacd70e3e0 100644 GIT binary patch delta 29 lcmbQpG?9s2zMF%iKcsddyBy=fiE58Imb#Tqk!5FK004f(2wMOE delta 29 kcmbQpG?9s2zMF%CueoL-yBwqDM775pw)w7eWZ4-Q0B+<5C;$Ke diff --git a/user_guide/video.svg b/user_guide/video.svg new file mode 100644 index 0000000..a38c2e9 --- /dev/null +++ b/user_guide/video.svg @@ -0,0 +1,307 @@ + + + + + + + + + + + $ # Trying video output & capture for HD at 800 Hz $ python examples/video/video_output.py --frame-rate=800 --no-gui --frame-size=1280x720 10 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────$ python examples/video/video_capture.py 10 [0] 0:bash* "bash /home/coutinho/w" 08:37 16-Dec-23$ python examples/video/video_output.py --frame-rate=800 --no-gui --frame-size=1280x720 10 MainThread 2023-12-16 08:37:08,796 INFO linuxpy.device.video10: opening /dev/video10 MainThread 2023-12-16 08:37:08,797 INFO linuxpy.device.video10: opened /dev/video10 MainThread 2023-12-16 08:37:08,797 INFO linuxpy.device.video10: Preparing for video output... MainThread 2023-12-16 08:37:08,797 INFO linuxpy.device.video10: Video output using memory map MainThread 2023-12-16 08:37:08,797 INFO linuxpy.device.video10: Reserving buffers... MainThread 2023-12-16 08:37:08,798 INFO linuxpy.device.video10: Buffers reserved MainThread 2023-12-16 08:37:08,798 INFO [0] 0:python* "bash /home/coutinho/w" 08:37 16-Dec-23MainThread 2023-12-16 08:37:08,798 INFO linuxpy.device.video10: Starting 'VIDEO_OUTPUT' stream... MainThread 2023-12-16 08:37:08,798 INFO linuxpy.device.video10: 'VIDEO_OUTPUT' stream ON MainThread 2023-12-16 08:37:08,798 INFO linuxpy.device.video10: Video output started! Frame: 0 | Elapsed: 0.0 s | Rate: 0.0 fps | Skipped: 0 Frame: 80 | Elapsed: 0.1 s | Rate: 799.8 fps | Skipped: 0 Frame: 160 | Elapsed: 0.2 s | Rate: 799.3 fps | Skipped: 0 Frame: 241 | Elapsed: 0.3 s | Rate: 800.8 fps | Skipped: 0 Frame: 321 | Elapsed: 0.4 s | Rate: 797.1 fps | Skipped: 0 Frame: 402 | Elapsed: 0.5 s | Rate: 800.3 fps | Skipped: 0 Frame: 483 | Elapsed: 0.6 s | Rate: 802.2 fps | Skipped: 0 Frame: 563 | Elapsed: 0.7 s | Rate: 798.1 fps | Skipped: 0 Frame: 644 | Elapsed: 0.8 s | Rate: 801.0 fps | Skipped: 0 Frame: 725 | Elapsed: 0.9 s | Rate: 802.1 fps | Skipped: 0 Frame: 805 | Elapsed: 1.0 s | Rate: 798.4 fps | Skipped: 0 Frame: 886 | Elapsed: 1.1 s | Rate: 800.2 fps | Skipped: 0 Frame: 966 | Elapsed: 1.2 s | Rate: 799.3 fps | Skipped: 0 Frame: 1047 | Elapsed: 1.3 s | Rate: 800.8 fps | Skipped: 0 Frame: 1128 | Elapsed: 1.4 s | Rate: 800.0 fps | Skipped: 0 Frame: 1208 | Elapsed: 1.5 s | Rate: 799.9 fps | Skipped: 0 Frame: 1288 | Elapsed: 1.6 s | Rate: 800.0 fps | Skipped: 0 Frame: 1368 | Elapsed: 1.7 s | Rate: 799.8 fps | Skipped: 0 Frame: 1449 | Elapsed: 1.8 s | Rate: 801.6 fps | Skipped: 0 Frame: 1530 | Elapsed: 1.9 s | Rate: 799.7 fps | Skipped: 0 Frame: 1610 | Elapsed: 2.0 s | Rate: 798.7 fps | Skipped: 0 Frame: 1691 | Elapsed: 2.1 s | Rate: 801.7 fps | Skipped: 0 Frame: 1771 | Elapsed: 2.2 s | Rate: 800.0 fps | Skipped: 0 Frame: 1851 | Elapsed: 2.3 s | Rate: 799.9 fps | Skipped: 0 Frame: 1851 | Elapsed: 2.3 s | Rate: 799.9 fps | Skipped: 0 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────$ python examples/video/video_capture.py 10 Frame: 1931 | Elapsed: 2.4 s | Rate: 799.8 fps | Skipped: 0 Frame: 2012 | Elapsed: 2.5 s | Rate: 798.7 fps | Skipped: 0 Frame: 2093 | Elapsed: 2.6 s | Rate: 801.4 fps | Skipped: 0 Frame: 2173 | Elapsed: 2.7 s | Rate: 798.5 fps | Skipped: 0 Frame: 2254 | Elapsed: 2.8 s | Rate: 800.9 fps | Skipped: 0 Frame: 2335 | Elapsed: 2.9 s | Rate: 800.6 fps | Skipped: 0 Frame: 2415 | Elapsed: 3.0 s | Rate: 797.5 fps | Skipped: 0 Frame: 2496 | Elapsed: 3.1 s | Rate: 801.3 fps | Skipped: 0 Frame: 2576 | Elapsed: 3.2 s | Rate: 799.1 fps | Skipped: 0 Frame: 2657 | Elapsed: 3.3 s | Rate: 801.3 fps | Skipped: 0 Frame: 2738 | Elapsed: 3.4 s | Rate: 799.2 fps | Skipped: 0 Frame: 2819 | Elapsed: 3.5 s | Rate: 800.4 fps | Skipped: 0 Frame: 2900 | Elapsed: 3.6 s | Rate: 801.7 fps | Skipped: 0 MainThread 2023-12-16 08:37:12,451 INFO linuxpy.device.video10: opening /dev/video10 MainThread 2023-12-16 08:37:12,452 INFO linuxpy.device.video10: opened /dev/video10 MainThread 2023-12-16 08:37:12,453 INFO linuxpy.device.video10: Preparing for video capture... MainThread 2023-12-16 08:37:12,453 INFO linuxpy.device.video10: Video capture using memory map MainThread 2023-12-16 08:37:12,453 INFO linuxpy.device.video10: Reserving buffers... MainThread 2023-12-16 08:37:12,453 INFO linuxpy.device.video10: Buffers reserved MainThread 2023-12-16 08:37:12,453 INFO linuxpy.device.video10: Starting 'VIDEO_CAPTURE' stream... MainThread 2023-12-16 08:37:12,453 INFO linuxpy.device.video10: 'VIDEO_CAPTURE' stream ON MainThread 2023-12-16 08:37:12,453 INFO linuxpy.device.video10: Video capture started! MainThread 2023-12-16 08:37:12,453 INFO linuxpy.device.video10: Starting capture 1280x720 at 10 fps in RGB24 Frame: 0 Size: 2764.8 Kb | Elapsed: 0.0 s | Rate 577.6 fps Frame: 2980 | Elapsed: 3.7 s | Rate: 798.5 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 0.1 s | Rate 822.2 fps Frame: 3061 | Elapsed: 3.8 s | Rate: 799.4 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 0.2 s | Rate 821.9 fps Frame: 3142 | Elapsed: 3.9 s | Rate: 801.2 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 0.3 s | Rate 860.1 fps Frame: 3222 | Elapsed: 4.0 s | Rate: 799.4 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 0.4 s | Rate 857.7 fps Frame: 3302 | Elapsed: 4.1 s | Rate: 799.8 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 0.5 s | Rate 781.7 fps Frame: 3382 | Elapsed: 4.2 s | Rate: 799.3 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 0.6 s | Rate 754.7 fps Frame: 3463 | Elapsed: 4.3 s | Rate: 800.4 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 0.7 s | Rate 766.3 fps Frame: 3543 | Elapsed: 4.4 s | Rate: 800.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 0.8 s | Rate 696.6 fps Frame: 3623 | Elapsed: 4.5 s | Rate: 799.8 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 0.9 s | Rate 694.7 fps Frame: 3704 | Elapsed: 4.6 s | Rate: 801.3 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 1.0 s | Rate 693.4 fps Frame: 3784 | Elapsed: 4.7 s | Rate: 798.6 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 1.1 s | Rate 615.1 fps Frame: 3865 | Elapsed: 4.8 s | Rate: 800.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 1.2 s | Rate 713.2 fps Frame: 3946 | Elapsed: 4.9 s | Rate: 800.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 1.3 s | Rate 817.3 fps Frame: 4027 | Elapsed: 5.0 s | Rate: 801.5 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 1.4 s | Rate 785.0 fps Frame: 4108 | Elapsed: 5.1 s | Rate: 798.7 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 1.5 s | Rate 801.4 fps Frame: 4188 | Elapsed: 5.2 s | Rate: 799.1 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 1.6 s | Rate 786.2 fps Frame: 4269 | Elapsed: 5.3 s | Rate: 801.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 1.7 s | Rate 910.7 fps Frame: 4349 | Elapsed: 5.4 s | Rate: 799.4 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 1.8 s | Rate 798.1 fps Frame: 4430 | Elapsed: 5.5 s | Rate: 801.2 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 1.9 s | Rate 818.1 fps Frame: 4511 | Elapsed: 5.6 s | Rate: 800.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 2.0 s | Rate 811.3 fps Frame: 4591 | Elapsed: 5.7 s | Rate: 798.1 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 2.1 s | Rate 771.4 fps Frame: 4671 | Elapsed: 5.8 s | Rate: 799.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 2.2 s | Rate 823.7 fps Frame: 4752 | Elapsed: 5.9 s | Rate: 800.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 2.3 s | Rate 809.3 fps Frame: 4832 | Elapsed: 6.0 s | Rate: 799.8 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 2.4 s | Rate 811.9 fps Frame: 4912 | Elapsed: 6.1 s | Rate: 800.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 2.5 s | Rate 774.9 fps Frame: 4993 | Elapsed: 6.2 s | Rate: 800.8 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 2.6 s | Rate 767.7 fps Frame: 5074 | Elapsed: 6.3 s | Rate: 800.4 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 2.7 s | Rate 818.0 fps Frame: 5154 | Elapsed: 6.4 s | Rate: 798.8 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 2.8 s | Rate 784.8 fps Frame: 5234 | Elapsed: 6.5 s | Rate: 800.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 2.9 s | Rate 796.3 fps Frame: 5315 | Elapsed: 6.6 s | Rate: 801.1 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 3.0 s | Rate 878.1 fps Frame: 5395 | Elapsed: 6.7 s | Rate: 799.5 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 3.1 s | Rate 865.4 fps Frame: 5475 | Elapsed: 6.8 s | Rate: 799.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 3.2 s | Rate 807.6 fps Frame: 5556 | Elapsed: 6.9 s | Rate: 799.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 3.3 s | Rate 773.4 fps Frame: 5636 | Elapsed: 7.0 s | Rate: 800.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 3.4 s | Rate 785.4 fps Frame: 5716 | Elapsed: 7.1 s | Rate: 799.8 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 3.5 s | Rate 756.2 fps Frame: 5797 | Elapsed: 7.2 s | Rate: 800.1 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 3.6 s | Rate 794.3 fps Frame: 5878 | Elapsed: 7.3 s | Rate: 801.3 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 3.7 s | Rate 805.6 fps Frame: 5958 | Elapsed: 7.4 s | Rate: 798.5 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 3.8 s | Rate 790.1 fps Frame: 6039 | Elapsed: 7.5 s | Rate: 799.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 3.9 s | Rate 817.2 fps Frame: 6120 | Elapsed: 7.7 s | Rate: 800.1 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 4.0 s | Rate 788.3 fps Frame: 6201 | Elapsed: 7.8 s | Rate: 801.4 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 4.1 s | Rate 785.5 fps Frame: 6281 | Elapsed: 7.9 s | Rate: 799.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 4.2 s | Rate 794.0 fps Frame: 6361 | Elapsed: 8.0 s | Rate: 798.8 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 4.3 s | Rate 799.0 fps Frame: 6442 | Elapsed: 8.1 s | Rate: 802.2 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 4.4 s | Rate 829.5 fps Frame: 6522 | Elapsed: 8.2 s | Rate: 797.8 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 4.5 s | Rate 810.3 fps Frame: 6603 | Elapsed: 8.3 s | Rate: 801.7 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 4.6 s | Rate 774.8 fps Frame: 6683 | Elapsed: 8.4 s | Rate: 799.4 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 4.7 s | Rate 816.3 fps Frame: 6764 | Elapsed: 8.5 s | Rate: 799.2 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 4.8 s | Rate 785.6 fps Frame: 6844 | Elapsed: 8.6 s | Rate: 799.8 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 4.9 s | Rate 817.6 fps Frame: 6925 | Elapsed: 8.7 s | Rate: 800.2 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 5.0 s | Rate 801.0 fps Frame: 7006 | Elapsed: 8.8 s | Rate: 801.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 5.1 s | Rate 787.0 fps Frame: 7086 | Elapsed: 8.9 s | Rate: 799.7 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 5.2 s | Rate 816.9 fps Frame: 7166 | Elapsed: 9.0 s | Rate: 798.2 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 5.3 s | Rate 829.5 fps Frame: 7247 | Elapsed: 9.1 s | Rate: 801.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 5.4 s | Rate 808.3 fps Frame: 7327 | Elapsed: 9.2 s | Rate: 799.5 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 5.5 s | Rate 696.9 fps Frame: 7407 | Elapsed: 9.3 s | Rate: 798.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 5.6 s | Rate 723.7 fps Frame: 7487 | Elapsed: 9.4 s | Rate: 798.4 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 5.7 s | Rate 770.1 fps Frame: 7568 | Elapsed: 9.5 s | Rate: 801.6 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 5.8 s | Rate 932.9 fps Frame: 7648 | Elapsed: 9.6 s | Rate: 799.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 5.9 s | Rate 940.4 fps Frame: 7729 | Elapsed: 9.7 s | Rate: 799.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 6.0 s | Rate 672.0 fps Frame: 7810 | Elapsed: 9.8 s | Rate: 801.7 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 6.1 s | Rate 632.4 fps Frame: 7890 | Elapsed: 9.9 s | Rate: 797.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 6.2 s | Rate 722.4 fps Frame: 7970 | Elapsed: 10.0 s | Rate: 799.7 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 6.3 s | Rate 695.4 fps Frame: 8050 | Elapsed: 10.1 s | Rate: 800.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 6.4 s | Rate 838.2 fps Frame: 8131 | Elapsed: 10.2 s | Rate: 801.1 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 6.5 s | Rate 753.2 fps Frame: 8212 | Elapsed: 10.3 s | Rate: 798.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 6.6 s | Rate 661.5 fps Frame: 8293 | Elapsed: 10.4 s | Rate: 800.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 6.7 s | Rate 817.1 fps Frame: 8374 | Elapsed: 10.5 s | Rate: 800.8 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 6.8 s | Rate 805.8 fps Frame: 8454 | Elapsed: 10.6 s | Rate: 799.7 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 6.9 s | Rate 802.4 fps Frame: 8534 | Elapsed: 10.7 s | Rate: 799.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 7.0 s | Rate 773.8 fps Frame: 8615 | Elapsed: 10.8 s | Rate: 802.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 7.1 s | Rate 773.4 fps Frame: 8695 | Elapsed: 10.9 s | Rate: 798.3 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 7.2 s | Rate 816.2 fps Frame: 8775 | Elapsed: 11.0 s | Rate: 799.8 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 7.3 s | Rate 676.7 fps Frame: 8856 | Elapsed: 11.1 s | Rate: 800.5 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 7.4 s | Rate 837.1 fps Frame: 8936 | Elapsed: 11.2 s | Rate: 799.7 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 7.5 s | Rate 815.5 fps Frame: 9017 | Elapsed: 11.3 s | Rate: 800.1 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 7.7 s | Rate 788.6 fps Frame: 9097 | Elapsed: 11.4 s | Rate: 799.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 7.8 s | Rate 739.8 fps Frame: 9178 | Elapsed: 11.5 s | Rate: 800.7 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 7.9 s | Rate 707.4 fps Frame: 9259 | Elapsed: 11.6 s | Rate: 800.8 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 8.0 s | Rate 695.6 fps Frame: 9339 | Elapsed: 11.7 s | Rate: 800.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 8.1 s | Rate 776.1 fps Frame: 9420 | Elapsed: 11.8 s | Rate: 800.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 8.2 s | Rate 808.0 fps Frame: 9500 | Elapsed: 11.9 s | Rate: 798.2 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 8.3 s | Rate 689.2 fps Frame: 9581 | Elapsed: 12.0 s | Rate: 801.6 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 8.4 s | Rate 778.8 fps Frame: 9661 | Elapsed: 12.1 s | Rate: 798.7 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 8.5 s | Rate 830.7 fps Frame: 9741 | Elapsed: 12.2 s | Rate: 799.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 8.6 s | Rate 926.5 fps Frame: 9822 | Elapsed: 12.3 s | Rate: 801.3 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 8.7 s | Rate 699.5 fps Frame: 9903 | Elapsed: 12.4 s | Rate: 799.2 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 8.8 s | Rate 753.8 fps Frame: 9984 | Elapsed: 12.5 s | Rate: 800.6 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 8.9 s | Rate 878.8 fps Frame: 10064 | Elapsed: 12.6 s | Rate: 798.8 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 9.0 s | Rate 734.1 fps Frame: 10144 | Elapsed: 12.7 s | Rate: 800.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 9.1 s | Rate 774.2 fps Frame: 10224 | Elapsed: 12.8 s | Rate: 799.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 9.2 s | Rate 800.2 fps Frame: 10305 | Elapsed: 12.9 s | Rate: 799.9 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 9.3 s | Rate 802.8 fps Frame: 10386 | Elapsed: 13.0 s | Rate: 800.4 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 9.4 s | Rate 777.5 fps Frame: 10466 | Elapsed: 13.1 s | Rate: 798.7 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 9.5 s | Rate 801.7 fps Frame: 10547 | Elapsed: 13.2 s | Rate: 801.8 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 9.6 s | Rate 764.3 fps Frame: 10627 | Elapsed: 13.3 s | Rate: 799.4 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 9.7 s | Rate 776.2 fps Frame: 10707 | Elapsed: 13.4 s | Rate: 799.0 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 9.8 s | Rate 854.5 fps Frame: 10788 | Elapsed: 13.5 s | Rate: 802.5 fps | Skipped: 0 Frame: 0 Size: 2764.8 Kb | Elapsed: 9.9 s | Rate 826.1 fps Frame: 10868 | Elapsed: 13.6 s | Rate: 798.4 fps | Skipped: 0 [detached (from session 0)] + diff --git a/user_guide/video/index.html b/user_guide/video/index.html index 3ada257..ff5f35e 100644 --- a/user_guide/video/index.html +++ b/user_guide/video/index.html @@ -802,6 +802,7 @@

Video

Human friendly interface to the Video for Linux 2 (V4L2) subsystem.

+

V4L2 demo

Without further ado:

python @@ -837,12 +838,26 @@

Device creationwith open("/dev/video10", "rb+", buffering=0) as fd: camera = Device(fd)

-

Before using video Device object you need to open it. +

Before using video Device object you need to open it (except in the +example directly above when creating a device from a file object). You can either use the device object as a context manager (prefered):

with Device.from_id(10) as camera:
     ...
 
-

... or manage call Device.open()/Device.close() manually:

+

The Device object is a reusable, reentrant but not thread safe context +manager. This means that Device object can not only be used in multiple with +statements, but may also be used inside a with statement that is already +using the same context manager.

+

So the following examples will work just fine:

+
with Device.from_id(10) as camera:
+    ...
+    with camera:
+        ...
+
+with camera:
+    ...
+
+

Alternatively, you can manage calls Device.open()/Device.close() manually:

camera = Device.from_id(10)
 camera.open()
 try:
@@ -872,7 +887,7 @@ 

Capture...

Note that VideoCapture configuration must be done before the capture is started -(ie, the the with capture: statement.)

+(ie, the with capture: statement.)

By default, VideoCapture will use memory map if the device has STREAMING capability and falls back to standard read if not. It is also possible to force a specific reader:

diff --git a/user_guide/video_demo.svg b/user_guide/video_demo.svg new file mode 100644 index 0000000..79754d2 --- /dev/null +++ b/user_guide/video_demo.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + coutinho@tiago-crunch:~/workspace/coutinho/python-linux$ coutinho@tiago-crunch:~/workspace/coutinho/python-linux$ e coutinho@tiago-crunch:~/workspace/coutinho/python-linux$ ex coutinho@tiago-crunch:~/workspace/coutinho/python-linux$ exi coutinho@tiago-crunch:~/workspace/coutinho/python-linux$ exit coutinho@tiago-crunch:~/workspace/coutinho/python-linux$ exit exit + \ No newline at end of file