// Mitus — Python transport pipeline (default mode, --python or no flag) // Sender bash script wraps ffmpeg CLI; receiver runs ffmpeg in-process via Python. digraph python_pipeline { graph [fontname="monospace" bgcolor="#1e1e2e" rankdir=TB pad="0.6" splines=polyline] node [fontname="monospace" fontcolor="#cdd6f4" style=filled shape=box fillcolor="#313244" color="#585b70" margin="0.25,0.12"] edge [color="#585b70" fontname="monospace" fontcolor="#a6adc8"] // Hardware / OS drm [label="/dev/dri/card0\n(KMS scanout)" shape=cylinder fillcolor="#1e3a2f" color="#a6e3a1"] pulse [label="PulseAudio\n─────────────\nmonitor: default sink\nmic: webcam (C922)" shape=cylinder fillcolor="#1e3a2f" color="#a6e3a1"] net [label="TCP :4444\nmpegts" shape=parallelogram fillcolor="#1e2a3e" color="#89b4fa"] subgraph cluster_sender { label="Sender — sender/stream_av.sh" fontcolor="#a6adc8" color="#45475a" fontname="monospace" watchdog [label="watchdog loop\n─────────────\nffmpeg restart on stall\n(total_size or frame stuck > 10s)\nimmediate restart on\nDRM plane format change" fillcolor="#2d2038" color="#cba6f7"] ffmpeg_send [label="ffmpeg CLI\n─────────────\nkmsgrab → hwmap=vaapi\nscale_vaapi 1920x1080 nv12\nh264_vaapi (qp=20, gop=30, no B-frames)\namix(monitor, mic) → aac 128k\nmpegts → TCP" fillcolor="#1e2d3e" color="#89b4fa"] } subgraph cluster_recorder { label="StreamRecorder — cht/stream/recorder.py" fontcolor="#a6adc8" color="#45475a" fontname="monospace" ffmpeg_recv [label="ffmpeg listener\n─────────────\nlisten=1 on TCP :4444\n→ 2 outputs:\n fragmented MP4 (recording_*.mp4)\n UDP :4445 (mpegts → mpv)\n stdout pipe (showinfo)" fillcolor="#1e2d3e" color="#89b4fa"] scene_pipe [label="scene-detect parser\n─────────────\nreads stdout pipe\nshowinfo → scene timestamps\nemits raw_frame(jpeg, ts)" fillcolor="#2d2038" color="#cba6f7"] } subgraph cluster_processor { label="SessionProcessor — cht/stream/processor.py" fontcolor="#a6adc8" color="#45475a" fontname="monospace" frame_writer [label="frame writer\n─────────────\nwrites JPEG to frames/\nappends to index.json\nfires on_new_frames(ts, path)" fillcolor="#2d2038" color="#cba6f7"] audio_extract [label="audio extractor\n─────────────\npolls fMP4 for new audio\nffmpeg → 16 kHz mono WAV\nchunks for transcription" fillcolor="#2d2038" color="#cba6f7"] tracker [label="RecordingTracker\n─────────────\nffprobe duration\nsums segments\nfeeds timeline UI" fillcolor="#2d2038" color="#cba6f7"] } transcriber [label="TranscriberEngine\n─────────────\ncht/transcriber/engine.py\nfaster-whisper (CUDA)\ngrouped segments → transcript.json" fillcolor="#2d2038" color="#cba6f7"] gui [label="Mitus GUI (GTK4)\n─────────────\nMonitor (mpv UDP)\nScrub bar · Frames · Transcript\nAgent input/output" fillcolor="#2d2038" color="#cba6f7"] // Outputs fmp4 [label="stream/\nrecording_*.mp4" shape=folder fillcolor="#2a2a3e" color="#585b70"] udp [label="UDP :4445\n→ mpv" shape=parallelogram fillcolor="#2a2a3e" color="#585b70"] frames [label="frames/\nindex.json + *.jpg" shape=folder fillcolor="#2a2a3e" color="#585b70"] audio [label="audio/\nchunk_*.wav" shape=folder fillcolor="#2a2a3e" color="#585b70"] txt [label="transcript.json" shape=folder fillcolor="#2a2a3e" color="#585b70"] // Flow — sender drm -> ffmpeg_send [label="kmsgrab"] pulse -> ffmpeg_send [label="-f pulse"] watchdog -> ffmpeg_send [style=dashed label="restart"] ffmpeg_send -> net // Flow — recorder net -> ffmpeg_recv [label="mpegts"] ffmpeg_recv -> fmp4 ffmpeg_recv -> udp ffmpeg_recv -> scene_pipe [label="stdout"] udp -> gui [label="live\nmonitor"] // Flow — processor scene_pipe -> frame_writer [label="raw_frame"] frame_writer -> frames fmp4 -> audio_extract [label="poll" style=dashed] audio_extract -> audio audio -> transcriber [label="WAV"] transcriber -> txt fmp4 -> tracker [label="ffprobe" style=dashed] tracker -> gui [label="duration"] // Flow — GUI frames -> gui txt -> gui }