A desktop application for viewing cameras from multiple Hikvision NVRs in a single window, with a full-screen kiosk mode.
- 🎥 View multiple cameras from different NVRs in one window
- 🔒 Secure storage of credentials (encryption)
- 🎨 Flexible camera grid layouts (auto or manual)
- 🖥️ Kiosk mode (full screen)
- 🔄 Automatic reconnect on connection loss
- 📊 Friendly graphical interface
- ⚡ Command-line launching (CLI)
- 📝 Detailed logging
- Python 3.7+
- Windows / Linux / macOS
- Network access to the Hikvision NVRs
Install everything with:
pip install -r requirements.txtOr manually:
pip install opencv-python numpy requests cryptography screeninfo PillowHikVision-KioskMode-Viewer/
├── main.py # Main application entry point
├── config/
│ ├── __init__.py
│ ├── settings.py # Global settings
│ └── nvr_config.py # NVR configuration (encrypted data)
├── core/
│ ├── __init__.py
│ ├── security.py # Encryption and authorization
│ ├── nvr_manager.py # NVR manager and API communication
│ └── video_stream.py # RTSP stream handling
├── gui/
│ ├── __init__.py
│ ├── main_window.py # Main GUI window
│ ├── viewer_window.py # Camera viewer window
│ └── dialogs.py # Dialogs (splash, loading, password)
├── utils/
│ ├── __init__.py
│ ├── cli_parser.py # CLI argument parser
│ └── credential_generator.py # Encrypted credentials generator
├── assets/
│ └── app_icon.ico # Application icon
├── test/ # Local test tooling (fake NVR / RTSP)
├── HikvisionViewer-onefile.spec # PyInstaller spec (single .exe)
├── HikvisionViewer-onedir.spec # PyInstaller spec (folder build)
├── build_exe.bat # Build script (onefile + onedir)
├── build_env.bat # Virtual environment setup script
├── requirements.txt
├── LICENSE
└── README.md
pip install -r requirements.txtpython main.py --generate-credsFollow the prompts and add the generated entry to config/nvr_config.py.
python main.pypython main.py -c NVR1:1 NVR1:2 NVR2:5python main.py -c NVR1:1 NVR1:2 -k- Select an NVR – choose an NVR from the list
- Test the connection – click "🔗 Test" to check access
- Select a camera – choose a camera from the list
- Add the camera – click "➕ Add camera"
- Manage the list – remove cameras or change their order
- Options – choose kiosk mode and layout (optional)
- Start – click "▶ Start viewer"
- Q or ESC – exit the application
- M – return to the menu
python main.py [OPTIONS]
Options:
-c, --cameras NVR:CHANNEL [NVR:CHANNEL ...]
List of cameras (e.g. NVR1:1 NVR2:3)
-s, --substream {main,sub,third,1,2,3}
Substream: main/1 (highest quality), sub/2 (default 640x360), third/3
-k, --kiosk Kiosk mode (full screen)
-l, --layout ROWSxCOLS
Forced layout (e.g. 2x2, 3x3)
-p, --password PASSWORD
Application password (not recommended!)
--generate-creds Encrypted credentials generator
-v, --verbose Verbose logging
--version Application version# Show 4 cameras in a 2x2 layout
python main.py -c NVR1:1 NVR1:2 NVR1:3 NVR1:4 -l 2x2
# Kiosk mode with auto layout
python main.py -c NVR1:1 NVR2:2 NVR3:1 -k
# Generate credentials
python main.py --generate-credsDefault password: admin123
The password hash lives in config/settings.py:
APP_PASSWORD_HASH = "240be518fabd2724ddb6f04eeb1da5967448d7e831c08c8fa822809f74c720a9"To change the password:
- Run
python main.py --generate-creds - Copy the generated hash
- Paste it into
config/settings.py
Security note: Change both
APP_PASSWORD_HASHandENCRYPTION_SALTinconfig/settings.pybefore deploying.
Default (auto) layouts:
| Cameras | Layout |
|---|---|
| 1 | 1×1 |
| 2 | 1×2 |
| 3–4 | 2×2 |
| 5–6 | 2×3 |
| 7–9 | 3×3 |
| 10–12 | 3×4 |
| 13–16 | 4×4 |
You can force a custom layout in the GUI or with -l.
In config/settings.py:
VIDEO_SETTINGS = {
'retry_delay': 2, # Reconnect delay (s)
'frame_timeout': 3, # Frame timeout (s)
'buffer_size': 1, # Buffer size
'initial_load_timeout': 5 # Initial load timeout (s)
}- Generate the encrypted data:
python main.py --generate-creds
- Add it to
config/nvr_config.py:ENCRYPTED_NVR_DATA = { "NVR1": "encrypted_string_1", "NVR2": "encrypted_string_2", }
Logs and run history are written under %APPDATA%\HCV\ (Windows):
- Logs:
%APPDATA%\HCV\logs\app_YYYY-MM-DD.log - Rotation: one file per day
- Level: INFO (use
-vfor DEBUG)
- Credentials are encrypted with AES (Fernet)
- NVR passwords are never stored in plaintext
- Authorization is required at startup
- The application password is hashed with SHA256
- Check network access (ping)
- Use the "🔗 Test" button in the GUI
- Check the credentials in
config/nvr_config.py - Review the logs in
%APPDATA%\HCV\logs
- The camera may be disabled on the NVR
- Check the 640×360 substream on the NVR
- Increase
initial_load_timeoutin the settings
- Make sure you are using the correct password
- The password hash must match the one in
config/settings.py - Use
--generate-credsto generate a new hash
Install PyInstaller first:
pip install pyinstallerbuild_exe.bat # builds both onefile and onedir
build_exe.bat onefile # single .exe only
build_exe.bat onedir # folder build onlyOnefile – a single self-contained .exe:
pyinstaller HikvisionViewer-onefile.specOutput: dist/HikvisionViewer.exe
Onedir – a folder build that keeps all files next to the .exe
(uses contents-directory=".", so there is no _internal subfolder):
pyinstaller HikvisionViewer-onedir.specOutput: dist/HikvisionViewer/HikvisionViewer.exe
Onefile:
pyinstaller --onefile --windowed --name HikvisionViewer ^
--add-data "config;config" --add-data "assets;assets" ^
--hidden-import PIL._tkinter_finder ^
--icon assets/app_icon.ico main.pyOnedir with contents-directory=".":
pyinstaller --onedir --contents-directory "." --windowed --name HikvisionViewer ^
--add-data "config;config" --add-data "assets;assets" ^
--hidden-import PIL._tkinter_finder ^
--icon assets/app_icon.ico main.pyOn Linux/macOS, replace
;with:in the--add-dataarguments and^line continuations with\.
Released under the MIT License – free to use, modify, and distribute.
Marak123
Built with the help of Claude Code (Opus 4.8).
Pull requests are welcome! For larger changes, please open an issue first to discuss what you would like to change.