|
10 | 10 | from mediaforce.core.db_tables import run_manifests as run_manifests_table |
11 | 11 | from mediaforce.execution import describe_item_plan, encode_manifest_items, promote_manifest_items, \ |
12 | 12 | validate_manifest_items |
| 13 | +from mediaforce.encoding.bakeoff import DEFAULT_BAKEOFF_ENGINES, build_bakeoff_plan, write_bakeoff_plan |
13 | 14 | from mediaforce.library.folder_profiles import inspect_prefix |
14 | 15 | from mediaforce.library.planner import recommend_item |
15 | 16 | from mediaforce.library.run_manifests import build_run_manifest as build_db_run_manifest, \ |
@@ -98,6 +99,32 @@ def build_parser() -> argparse.ArgumentParser: |
98 | 99 | _add_manifest_selection_args(compare_parser, require_manifest=False) |
99 | 100 | _add_compare_clip_args(compare_parser) |
100 | 101 |
|
| 102 | + bakeoff_parser = subparsers.add_parser("bakeoff", help="Write a scene-aware engine bakeoff plan") |
| 103 | + _add_manifest_selection_args(bakeoff_parser, require_manifest=False) |
| 104 | + bakeoff_parser.add_argument( |
| 105 | + "--engine", |
| 106 | + action="append", |
| 107 | + choices=DEFAULT_BAKEOFF_ENGINES, |
| 108 | + default=[], |
| 109 | + help="Candidate engine to include; defaults to all candidates", |
| 110 | + ) |
| 111 | + bakeoff_parser.add_argument( |
| 112 | + "--output", |
| 113 | + type=Path, |
| 114 | + help="Write the bakeoff plan JSON to an explicit path", |
| 115 | + ) |
| 116 | + bakeoff_parser.add_argument( |
| 117 | + "--artifact-dir", |
| 118 | + type=Path, |
| 119 | + help="Directory where bakeoff artifacts should be written by the candidate commands", |
| 120 | + ) |
| 121 | + bakeoff_parser.add_argument( |
| 122 | + "--clip-duration", |
| 123 | + type=float, |
| 124 | + default=20.0, |
| 125 | + help="Review clip duration expected from each candidate engine", |
| 126 | + ) |
| 127 | + |
101 | 128 | return parser |
102 | 129 |
|
103 | 130 |
|
@@ -293,6 +320,29 @@ def main(argv: Sequence[str] | None = None) -> int: |
293 | 320 | ) |
294 | 321 | return 0 |
295 | 322 |
|
| 323 | + if args.command == "bakeoff": |
| 324 | + manifest_path = _resolve_manifest_path(connection, args.manifest) |
| 325 | + manifest = _load_manifest(manifest_path) |
| 326 | + indexes = _resolve_indexes(manifest, args) |
| 327 | + artifact_dir = args.artifact_dir or config.paths.review_dir / "engine-bakeoff" |
| 328 | + plan = build_bakeoff_plan( |
| 329 | + config, |
| 330 | + manifest, |
| 331 | + indexes=indexes, |
| 332 | + engines=args.engine or None, |
| 333 | + output_dir=artifact_dir, |
| 334 | + clip_duration_seconds=args.clip_duration, |
| 335 | + ) |
| 336 | + output_path = args.output or config.paths.run_manifest_dir / f"bakeoff-{manifest.get('run_id', 'latest')}.json" |
| 337 | + write_bakeoff_plan(plan, output_path) |
| 338 | + print(f"bakeoff plan {output_path}") |
| 339 | + for item in plan["items"]: |
| 340 | + print( |
| 341 | + f" item {item['index']}: target={_format_optional_size(item['target_size_bytes'])} " |
| 342 | + f"runtime={item['duration_seconds']:.0f}s engines={len(item['engines'])}" |
| 343 | + ) |
| 344 | + return 0 |
| 345 | + |
296 | 346 | return 1 |
297 | 347 |
|
298 | 348 |
|
@@ -586,6 +636,12 @@ def _format_size(size_bytes: int) -> str: |
586 | 636 | return f"{size_bytes}B" |
587 | 637 |
|
588 | 638 |
|
| 639 | +def _format_optional_size(size_bytes: int | None) -> str: |
| 640 | + if size_bytes is None: |
| 641 | + return "unset" |
| 642 | + return _format_size(size_bytes) |
| 643 | + |
| 644 | + |
589 | 645 | def _format_signed_bytes(size_bytes: int) -> str: |
590 | 646 | prefix = "+" if size_bytes >= 0 else "-" |
591 | 647 | return f"{prefix}{_format_size(abs(size_bytes))}" |
|
0 commit comments