Privacy-preserving video publishing for creators.
PublishSafe detects and tracks people, keeps the selected creator visible, and blurs everyone else along their body masks. Video stays on the machine running PublishSafe.
Left: original public sample. Right: one person preserved while other people are protected.
Requirements: Docker Desktop
git clone https://github.com/96528025/publishsafe.git
cd publishsafe
./scripts/start.shOpen http://localhost:5173.
The first start builds the containers and downloads the YOLO segmentation weights, so it takes longer than later starts.
# Follow startup and processing logs
docker compose logs -f
# Stop PublishSafe
./scripts/stop.shThe repository also contains a native accelerated profile for the maintainer's preconfigured Apple M2 Mac:
./scripts/start_owner.shThis profile uses Apple GPU inference through PyTorch MPS and H.264 hardware encoding through VideoToolbox. It requires a local machine fingerprint file that is excluded from Git, so cloning the repository does not enable owner mode on another computer.
Everyone else should continue to use ./scripts/start.sh. Both modes share the
same frontend, detection, tracking, blur, and export code. Only the execution
device and final encoder differ.
Stop the native owner services with Ctrl+C in their terminal or:
./scripts/stop_owner.sh- Upload an MP4, MOV, AVI, MKV, or WebM video.
- YOLOv8n-seg detects person masks and ByteTrack assigns stable IDs.
- Select yourself from an annotated preview.
- Adjust the default anonymizing blur on a 10-100 strength slider, or choose the experimental avatar mode. The selected creator and blur strength are shown immediately on one frame.
- Preview the first 10 seconds at a faster 15 FPS / 720p proxy quality.
- Process and download the protected MP4 at the source resolution and frame rate.
The default privacy rule is protect everyone except the selected creator.
Uploads and outputs stay in local uploads/ and outputs/ directories.
PublishSafe uses lower-cost previews so users can test the selected person and blur strength without waiting for a complete render:
| Mode | Purpose | Quality |
|---|---|---|
| Single-frame preview | Check the selected creator and blur strength | One JPEG frame |
| 10-second preview | Quickly review tracking and blur in motion | Up to 1280px wide, approximately 15 FPS |
| Full Process | Create the final shareable video | Source resolution, source FPS, every frame processed |
The reduced preview quality does not affect the Full Process export. For example, a 4K 30 FPS source remains 4K 30 FPS in the final render; only the 10-second preview uses the faster proxy settings.
publishsafe/
├── assets/avatars/ # Generated transparent mascot PNGs
├── backend/
│ ├── app/
│ │ ├── main.py # FastAPI routes and upload analysis
│ │ ├── processor.py # Background video processing jobs
│ │ ├── tracker.py # Small fallback tracking utilities
│ │ └── vision.py # YOLO segmentation and privacy rendering
│ └── requirements.txt
├── frontend/ # Vite + React UI
├── outputs/
└── uploads/
Requirements:
- Python 3.10+
- Node.js 18+
- Optional:
ffmpegto preserve source audio in the exported MP4
From the project root:
python3 -m venv .venv
source .venv/bin/activate
pip install -r backend/requirements.txt
cd frontend && npm install && cd ..The first backend start downloads the open-source YOLOv8 nano segmentation
weights (yolov8n-seg.pt). No model is trained by this project.
Terminal 1:
source .venv/bin/activate
uvicorn backend.app.main:app --reload --port 8000Terminal 2:
cd frontend
npm run devOpen http://localhost:5173. API documentation is available at
http://localhost:8000/docs.
Generate a small public sample video based on the Ultralytics bus image:
./scripts/download_sample.shUpload samples/publishsafe-sample.mp4 through the UI.
The download is optional and requires curl and ffmpeg.
Use a short, low-resolution clip while tuning blur or tracking:
./scripts/make_test_clip.sh /path/to/video.mp4To test a specific section, pass the start time and duration in seconds:
./scripts/make_test_clip.sh /path/to/video.mp4 10 5The script creates a 960x540, 15 FPS clip in test-clips/. Upload that clip
through the normal UI. Five seconds is about 75 frames and processes much
faster than a full 4K video.
docker compose ps
docker compose logs -fWait until the backend health check passes. The first model download may take several minutes.
Stop another local Vite/PublishSafe process, or change the frontend mapping in
docker-compose.yml:
ports:
- "8080:80"Then open http://localhost:8080.
Frame processing has finished and FFmpeg is encoding H.264 and restoring audio. Large 4K videos can spend noticeable time in this final stage.
Increase Docker Desktop's memory allocation. PyTorch and Ultralytics are large dependencies. Testing with a 720p or 1080p clip also reduces memory pressure.
PublishSafe uses ByteTrack plus clothing appearance recovery, but long occlusions and similar outfits can still cause errors. Try a clearer preview frame or open an issue with a reproducible, non-sensitive sample.
The Docker setup currently uses CPU inference for portability. Running from source through the maintainer owner profile uses MPS on its preconfigured M2 Mac. Other users should treat the Docker CPU workflow as the supported default.
The current full-video pipeline is the quality-first baseline:
- It processes every source frame with YOLO and ByteTrack.
- It preserves the source resolution and frame rate in the rendered video.
- It uses the full tracking history instead of intentionally skipping frames.
- It encodes a browser-compatible H.264 MP4 and restores the source audio.
This makes the current version slow on 4K or high-FPS footage, but it avoids deliberately reducing temporal coverage or output resolution. It is the highest-quality mode currently implemented in PublishSafe, not a guarantee of perfect results. Detection can still fail for small people, motion blur, long occlusions, or people with similar clothing.
Approximate work scales with:
video duration x source FPS x per-frame detection/rendering cost
For example, 10 seconds at 30 FPS contains about 300 frames, while one minute at 60 FPS contains about 3,600 frames.
-
Generate a proxy video after upload
Convert 4K footage to a 720p or 1080p working copy for detection, tracking, and previews. This should provide one of the largest speed improvements. Bounding boxes can later be scaled back to the original video. Tradeoff: very small or distant people may be harder to detect.
-
Use Apple GPU acceleration
Run PyTorch/YOLO on the Apple Silicon
MPSdevice when available instead of CPU-only inference. This may substantially improve model speed. It requires compatibility and memory testing on the target Mac. -
Detect every second or third frame
Run YOLO less frequently and use ByteTrack, interpolation, or optical flow for frames between detections. This can remove 50-67% of detector calls. Tradeoff: fast movement, brief appearances, and crossings may be less accurate.
-
Reduce YOLO input size
Lower
imgszfrom 640 to 512 or 416 for preview/fast modes. Tradeoff: reduced accuracy for small or distant people. -
Add output quality presets
Offer modes such as:
Fast: 720p / 15 FPS Balanced: 1080p / 30 FPS Original: source resolution / source FPSThis lets users choose processing speed versus output fidelity.
-
Use Apple VideoToolbox encoding
Replace CPU
libx264encoding withh264_videotoolboxwhen available. This primarily reduces the final 99% encoding/audio-merging wait. Tradeoff: hardware encoding can produce different quality or file sizes at equivalent settings. -
Cache detection and tracking results
Persist per-frame boxes and track IDs. A full render can then reuse the first 10 seconds already analyzed for the effect preview, and users can change avatar/blur styles without rerunning YOLO. This improves repeated renders without sacrificing detection quality, at the cost of additional cache storage and implementation complexity.
-
Evaluate newer lightweight detectors
Benchmark YOLO11n or another small person detector against YOLOv8n using the same videos. A newer model is not automatically faster or more accurate, so it should only replace the baseline after measured comparison.
The most practical next performance iteration is:
1080p proxy detection
-> MPS acceleration
-> cached tracking results
-> VideoToolbox encoding
-> optional frame skipping in Fast mode
Keep the current every-frame, original-resolution workflow as an Original
quality option so speed improvements do not remove the quality-first baseline.
Contributions are welcome. See CONTRIBUTING.md. Do not attach private or identifying videos to issues or pull requests.
PublishSafe is licensed under the GNU Affero General Public License v3.0, consistent with its Ultralytics dependency.
POST /api/upload: validate, store, analyze, and create a previewPOST /api/frame-preview: render a fast single-frame blur previewPOST /api/process: start a protected-video jobGET /api/jobs/{job_id}: poll status and frame progressGET /api/health: detector/tracker health summary
- Blur mode uses instance-segmentation masks, with mask dilation and feathered edges so the background remains clear. It falls back to a bounding box if a mask is unavailable on a frame.
- Tracking uses ByteTrack with a longer occlusion buffer. A clothing-appearance fallback recovers the selected creator when IDs switch during crossings.
- Processing is serialized around the YOLO model for demo reliability.
- OpenCV writes video frames. When
ffmpegis installed, source audio is automatically merged into the final file. - Tracking can still struggle after a long full-body occlusion. A polished version should use learned ReID embeddings and persist analyzed tracks before rendering.
PublishSafe performs person detection, not face identification. It does not attempt to infer names or identities. This MVP stores media locally and does not upload it to an external service.

