#!/usr/bin/env python3 """ Demo script for streaming compositor. Usage: # Preview two videos blended python -m streaming.demo preview video1.mp4 video2.mp4 # Record output to file python -m streaming.demo record video1.mp4 video2.mp4 -o output.mp4 # Benchmark (no output) python -m streaming.demo benchmark video1.mp4 --duration 10 """ import argparse import sys from pathlib import Path # Add parent to path for imports sys.path.insert(0, str(Path(__file__).parent.parent)) from streaming import StreamingCompositor, VideoSource from streaming.output import NullOutput def demo_preview(sources: list, duration: float, effects: bool = False): """Preview sources with optional simple effects.""" effects_config = None if effects: effects_config = [ [{"effect": "rotate", "angle": 15}], [{"effect": "zoom", "amount": 1.2}], ][:len(sources)] compositor = StreamingCompositor( sources=sources, effects_per_source=effects_config, recipe_dir=Path(__file__).parent.parent, ) compositor.run(output="preview", duration=duration) def demo_record(sources: list, output_path: str, duration: float): """Record blended output to file.""" compositor = StreamingCompositor( sources=sources, recipe_dir=Path(__file__).parent.parent, ) compositor.run(output=output_path, duration=duration) def demo_benchmark(sources: list, duration: float): """Benchmark processing speed (no output).""" compositor = StreamingCompositor( sources=sources, recipe_dir=Path(__file__).parent.parent, ) compositor.run(output="null", duration=duration) def demo_audio_reactive(sources: list, duration: float): """Preview with live audio reactivity.""" from streaming.audio import AudioAnalyzer # Create compositor with energy-reactive effects effects_config = [ [{ "effect": "zoom", "amount": {"_binding": True, "source": "live_energy", "feature": "values", "range": [1.0, 1.5]}, }] for _ in sources ] compositor = StreamingCompositor( sources=sources, effects_per_source=effects_config, recipe_dir=Path(__file__).parent.parent, ) # Start audio analyzer try: with AudioAnalyzer() as audio: print("Audio analyzer started. Make some noise!", file=sys.stderr) compositor.run(output="preview", duration=duration, audio_analyzer=audio) except Exception as e: print(f"Audio not available: {e}", file=sys.stderr) print("Running without audio...", file=sys.stderr) compositor.run(output="preview", duration=duration) def main(): parser = argparse.ArgumentParser(description="Streaming compositor demo") parser.add_argument("mode", choices=["preview", "record", "benchmark", "audio"], help="Demo mode") parser.add_argument("sources", nargs="+", help="Video source files") parser.add_argument("-o", "--output", help="Output file (for record mode)") parser.add_argument("-d", "--duration", type=float, default=30, help="Duration in seconds") parser.add_argument("--effects", action="store_true", help="Apply simple effects (for preview)") args = parser.parse_args() # Verify sources exist for src in args.sources: if not Path(src).exists(): print(f"Error: Source not found: {src}", file=sys.stderr) sys.exit(1) if args.mode == "preview": demo_preview(args.sources, args.duration, args.effects) elif args.mode == "record": if not args.output: print("Error: --output required for record mode", file=sys.stderr) sys.exit(1) demo_record(args.sources, args.output, args.duration) elif args.mode == "benchmark": demo_benchmark(args.sources, args.duration) elif args.mode == "audio": demo_audio_reactive(args.sources, args.duration) if __name__ == "__main__": main()