Skip to content

dsvsergey/ptzcam_kivy

Repository files navigation

BZB Cam — PTZ Camera Controller

A desktop application built with Kivy/KivyMD for controlling networked PTZ cameras over the VISCA over IP protocol while displaying the live RTSP video stream. Supports gesture-based camera control (pan/tilt/zoom) and saving position presets with frame thumbnails.


Features

  • Camera list with add, edit and delete operations
  • Live RTSP video preview rendered in real time (60 FPS render loop)
  • Gesture-driven PTZ control:
    • Single-finger drag — pan/tilt the camera in the gesture direction
    • Multi-touch — optical zoom in/out depending on direction
  • Position presets:
    • Save the current camera position together with a frame snapshot
    • Quick recall (camera returns to the saved position)
    • Long-press to delete a preset
  • Local persistence of camera configurations and presets in SQLite

Tech Stack

Component Purpose
Kivy / KivyMD UI framework, Material Design widgets
OpenCV RTSP capture, frame conversion
SQLAlchemy + SQLite ORM and local store for cameras and presets
NumPy Frame manipulation as pixel arrays
socket (UDP) Transport for VISCA commands to the camera

Requirements

  • Python 3.8+
  • A PTZ camera with VISCA over IP and RTSP streaming support
  • Network connectivity to the camera

Platform note. requirements.txt pins Windows-only dependencies (pypiwin32, pywin32, kivy-deps.glew/gstreamer/sdl2). On macOS/Linux these packages are not needed — Kivy installs directly from PyPI.


Installation

Windows

git clone <repo-url>
cd ptzcam_kivy
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt

macOS / Linux

git clone <repo-url>
cd ptzcam_kivy
python3 -m venv .venv
source .venv/bin/activate
pip install kivy kivymd opencv-python numpy SQLAlchemy SQLAlchemy-Utils python-dotenv Pillow

Run

python app.py

The SQLite database ~/Documents/bzbcam.db is created automatically on the first run.


Usage

1. Add a camera

On the main screen tap the «+» button and fill in the connection parameters:

Field Description Example
Title Human-readable camera name Conference Room
IP Address Camera's IP address on the network 192.168.20.183
VISCA Port UDP port for VISCA commands 1259
RTSP Port TCP port of the RTSP stream 554
User Name Login for RTSP access admin
Password Password for RTSP access ••••••

The RTSP URL is built using the template: rtsp://<user>:<pass>@<ip>:<port>/live/av1

2. Camera control

Pick a camera from the list — the player opens with the live video.

  • Pan/Tilt: touch the video area and drag in the desired direction. The camera moves while the finger is held; releasing stops it.
  • Zoom: use a multi-touch gesture (upward — zoom in, downward — zoom out).
  • Camera settings: ⚙ icon in the top-right corner.

3. Working with presets

  • Save preset: tap «🔖+» at the bottom of the player screen, enter a name and save.
  • Recall preset: short tap on the preset tile.
  • Delete preset: long-press the tile and confirm in the dialog.

Architecture

┌────────────────────────────────────────────────────────────┐
│                       app.py (entry)                        │
└───────────────────────────┬─────────────────────────────────┘
                            │
                ┌───────────▼────────────┐
                │   Bzbcam (MDApp)       │
                │   bzbcam.py + .kv      │
                │   ─ ScreenManager       │
                │   ─ Touch dispatcher    │
                │   ─ 60Hz render loop    │
                └───┬─────────┬─────────┬─┘
                    │         │         │
        ┌───────────▼──┐ ┌────▼─────┐ ┌─▼─────────────┐
        │  ViscaClient │ │VideoStream│ │  SQLAlchemy   │
        │  (UDP / VISCA│ │(cv2 thread│ │  models.py    │
        │   protocols) │ │ + Lock)   │ │  SQLite       │
        └──────┬───────┘ └─────┬─────┘ └───────────────┘
               │               │
               ▼               ▼
        ┌─────────────────────────┐
        │      PTZ Camera         │
        │   VISCA :1259 / RTSP    │
        └─────────────────────────┘

Key modules

File Responsibility
app.py Entry point — instantiates and runs Bzbcam
bzbcam.py Main application class, screen navigation, gesture handling
bzbcam.kv KivyMD UI layout (screens, toolbars, lists)
models.py SQLAlchemy models: Camera, Preset, AppSettings
video_straem.py Threaded wrapper around cv2.VideoCapture for RTSP
visca/visca.py ViscaClient — UDP client for VISCA commands
visca/protocols.py Hex templates of VISCA commands (zoom, pan, memory recall, …)
consts.py Screen indices in the ScreenManager
camera_editor.py Screen class for adding/editing a camera
camera_player.py Screen class of the video player
preset_viewer.py Preset tile with long-press-to-delete behavior
utls.py Helper functions (currently just rtsp_builder)

PTZ control flow

While the finger moves across the video area, Bzbcam.on_touch_move computes the gesture angle through __calc_degrees (atan2-style quadrant logic) and dispatches the matching VISCA command:

  • 45°–135° → pan_up
  • 135°–225° → pan_left
  • 225°–315° → pan_down
  • otherwise → pan_right

Multi-touch gestures are interpreted as zoom: upper half-plane → zoom_tele, lower → zoom_wide. Both motion types are continuous: the corresponding *_stop commands are sent in on_touch_up.

Data storage

  • Database: ~/Documents/bzbcam.db (SQLite, path hardcoded in models.py)
  • Preset thumbnails: PNG files {preset_id}.png in the current working directory
  • Thumbnail backup: pickled numpy.ndarray in the Preset.img BLOB column — used to regenerate the PNG when the file is missing

Project structure

ptzcam_kivy/
├── app.py                  # Entry point
├── bzbcam.py               # MDApp + controller
├── bzbcam.kv               # UI layout
├── camera_editor.py        # Screen class
├── camera_player.py        # Screen class
├── preset_viewer.py        # Preset tile
├── consts.py               # Screen indices
├── models.py               # SQLAlchemy ORM
├── utls.py                 # Utilities
├── video_straem.py         # RTSP threading wrapper
├── tab.py                  # (currently unused)
├── visca/
│   ├── __init__.py
│   ├── visca.py            # VISCA client
│   └── protocols.py        # Hex command templates
├── requirements.txt
└── README.md

Known limitations

  • The RTSP path is hardcoded as /live/av1 — for cameras with a different path segment, edit utls.rtsp_builder.
  • The database location ~/Documents/bzbcam.db is not configurable.
  • Preset thumbnails live in the CWD — running the app from different directories causes PNG regeneration.
  • No connection-state indicator for the camera / RTSP stream.
  • No automated tests.

VISCA protocol

The application sends VISCA commands as UDP datagrams wrapped in a payload header (payload_type 01 00, length, sequence number, body). Command templates are stored in visca/protocols.py as hex strings with letter placeholders (p, q, …) substituted via .replace() at call time.

Supported operations:

  • camera_on / camera_off
  • Pan/Tilt: pan_up, pan_down, pan_left, pan_right, diagonals, pan_stop, pan_home
  • Zoom: zoom_tele, zoom_wide, zoom_stop
  • Focus: focus_near, focus_far
  • Memory: memory_set, memory_recall (used for presets)
  • Preset speed: set_preset_speed, get_preset_speed

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors