Skip to content

Instantly share code, notes, and snippets.

@parkerlreed
Created April 6, 2025 19:41
Show Gist options
  • Save parkerlreed/bb65bf71b4868516236cc93c7f1161dd to your computer and use it in GitHub Desktop.
Save parkerlreed/bb65bf71b4868516236cc93c7f1161dd to your computer and use it in GitHub Desktop.
V380 camera viewer and PTZ control
import time
import pygame
import cv2
import numpy as np
from onvif import ONVIFCamera
from threading import Thread, Lock
# ---- Config ----
IP = '192.168.86.21'
RTSP_URL = f'rtsp://{IP}/live/ch00_1'
PORT = 8899
USER = 'admin'
PASSWORD = '123456'
SPEED = 0.5
MOVE_DURATION = 0.4 # seconds
# -----------------
def move(ptz, profile, x, y, zoom=0.0):
req = ptz.create_type('ContinuousMove')
req.ProfileToken = profile.token
req.Velocity = {
'PanTilt': {'x': x, 'y': y},
'Zoom': {'x': zoom}
}
ptz.ContinuousMove(req)
time.sleep(MOVE_DURATION)
ptz.Stop({'ProfileToken': profile.token})
def video_thread(rtsp_url, surface, lock):
cap = cv2.VideoCapture(rtsp_url)
if not cap.isOpened():
print("⚠️ Failed to open RTSP stream")
return
while cap.isOpened():
ret, frame = cap.read()
if not ret:
continue
# Resize and convert frame for Pygame
frame = cv2.resize(frame, (640, 360))
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = np.rot90(frame) # Optional: if orientation is off
frame = pygame.surfarray.make_surface(frame)
with lock:
surface.blit(frame, (0, 0))
cap.release()
def main():
pygame.init()
screen = pygame.display.set_mode((640, 400))
pygame.display.set_caption("V380 PTZ + Video Feed")
font = pygame.font.SysFont(None, 24)
clock = pygame.time.Clock()
cam = ONVIFCamera(IP, PORT, USER, PASSWORD)
media = cam.create_media_service()
ptz = cam.create_ptz_service()
profile = media.GetProfiles()[0]
rtsp_surface = pygame.Surface((640, 360))
lock = Lock()
# Start RTSP feed in background
Thread(target=video_thread, args=(RTSP_URL, rtsp_surface, lock), daemon=True).start()
running = True
while running:
screen.fill((0, 0, 0))
with lock:
screen.blit(rtsp_surface, (0, 0))
help_text = font.render("Arrow keys to move PTZ, ESC to quit", True, (255, 255, 255))
screen.blit(help_text, (10, 365))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
elif event.key == pygame.K_UP:
move(ptz, profile, 0.0, SPEED)
elif event.key == pygame.K_DOWN:
move(ptz, profile, 0.0, -SPEED)
elif event.key == pygame.K_LEFT: # SWAPPED
move(ptz, profile, -SPEED, 0.0)
elif event.key == pygame.K_RIGHT: # SWAPPED
move(ptz, profile, SPEED, 0.0)
clock.tick(30)
pygame.quit()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment