#!/usr/bin/env python3 """Dump messages from a ZoneMinder monitor stream socket (protocol v1). Usage: zm_stream_socket_dump.py /run/zm/stream_1.sock [message_count] """ import socket import struct import sys TYPES = {1: 'HELLO', 2: 'MEDIA', 3: 'KEYFRAME', 4: 'STATS', 5: 'BYE', 6: 'EVENT'} TLV_NAMES = {1: 'codec_id', 2: 'extradata', 3: 'width', 4: 'height', 5: 'fps_num', 6: 'fps_den', 7: 'sample_rate', 8: 'channels', 9: 'profile', 10: 'level'} EVENT_CODES = {0x0001: 'snapshot', 0x0101: 'connection_failed', 0x0102: 'connection_restored', 0x0103: 'prime_capture_failed', 0x0104: 'prime_capture_restored', 0x0105: 'capture_failed', 0x0106: 'capture_resumed', 0x0201: 'state_changed'} EVENT_TLV_NAMES = {1: 'wall_clock_us', 2: 'message', 3: 'state_id', 4: 'prev_state_id', 5: 'detail', 6: 'state_name', 7: 'health_code'} def read_exact(sock, n): buf = b'' while len(buf) < n: chunk = sock.recv(n - len(buf)) if not chunk: raise EOFError('socket closed') buf += chunk return buf def parse_hello(payload): parts = [] pos = 0 while pos + 3 <= len(payload): tag = payload[pos] length = struct.unpack(' 2 else 30 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.settimeout(20) sock.connect(path) media_seen = {} # (stream, generation) -> last MEDIA sequence for _ in range(count): header = read_exact(sock, 24) # pts is signed (two's-complement) and may be AV_NOPTS_VALUE length, version, mtype, stream, flags, seq, gen, pts = \ struct.unpack('