Merges full history from art-dag/mono.git into the monorepo under the artdag/ directory. Contains: core (DAG engine), l1 (Celery rendering server), l2 (ActivityPub registry), common (shared templates/middleware), client (CLI), test (e2e). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> git-subtree-dir: artdag git-subtree-mainline:1a179de547git-subtree-split:4c2e716558
126 lines
4.0 KiB
Python
126 lines
4.0 KiB
Python
#!/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()
|