blazar-video 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. blazar_video-0.1.0/Cargo.toml +50 -0
  2. blazar_video-0.1.0/PKG-INFO +113 -0
  3. blazar_video-0.1.0/README.md +89 -0
  4. blazar_video-0.1.0/bindings/python/Cargo.lock +1164 -0
  5. blazar_video-0.1.0/bindings/python/Cargo.toml +45 -0
  6. blazar_video-0.1.0/bindings/python/README.md +89 -0
  7. blazar_video-0.1.0/bindings/python/build.rs +18 -0
  8. blazar_video-0.1.0/bindings/python/sglang_patch/README.md +29 -0
  9. blazar_video-0.1.0/bindings/python/sglang_patch/sitecustomize.py +121 -0
  10. blazar_video-0.1.0/bindings/python/src/lib.rs +1865 -0
  11. blazar_video-0.1.0/bindings/python/tests/test_acceptance.py +344 -0
  12. blazar_video-0.1.0/bindings/python/tests/test_audio.py +140 -0
  13. blazar_video-0.1.0/bindings/python/tests/test_backend_selection.py +109 -0
  14. blazar_video-0.1.0/bindings/python/tests/test_encoder.py +385 -0
  15. blazar_video-0.1.0/bindings/python/tests/test_hardware.py +110 -0
  16. blazar_video-0.1.0/bindings/python/tests/test_memory_sink.py +58 -0
  17. blazar_video-0.1.0/bindings/python/tests/test_preprocess.py +128 -0
  18. blazar_video-0.1.0/bindings/python/tests/test_sglang_interop.py +109 -0
  19. blazar_video-0.1.0/bindings/python/tests/test_submit_dispatch.py +135 -0
  20. blazar_video-0.1.0/crates/blazar-calibration/Cargo.toml +13 -0
  21. blazar_video-0.1.0/crates/blazar-calibration/src/index.rs +325 -0
  22. blazar_video-0.1.0/crates/blazar-calibration/src/lib.rs +18 -0
  23. blazar_video-0.1.0/crates/blazar-calibration/src/loader.rs +190 -0
  24. blazar_video-0.1.0/crates/blazar-calibration/src/schema.rs +232 -0
  25. blazar_video-0.1.0/crates/blazar-calibration/tests/default_files.rs +107 -0
  26. blazar_video-0.1.0/crates/blazar-calibration/tests/load_dir.rs +159 -0
  27. blazar_video-0.1.0/crates/blazar-core/Cargo.toml +10 -0
  28. blazar_video-0.1.0/crates/blazar-core/src/error.rs +26 -0
  29. blazar_video-0.1.0/crates/blazar-core/src/frame.rs +236 -0
  30. blazar_video-0.1.0/crates/blazar-core/src/identity.rs +54 -0
  31. blazar_video-0.1.0/crates/blazar-core/src/lib.rs +33 -0
  32. blazar_video-0.1.0/crates/blazar-core/src/stream_params.rs +144 -0
  33. blazar_video-0.1.0/crates/blazar-core/src/target.rs +67 -0
  34. blazar_video-0.1.0/crates/blazar-core/src/timebase.rs +132 -0
  35. blazar_video-0.1.0/crates/blazar-core/src/unit.rs +82 -0
  36. blazar_video-0.1.0/crates/blazar-encoder/Cargo.toml +65 -0
  37. blazar_video-0.1.0/crates/blazar-encoder/src/av1.rs +445 -0
  38. blazar_video-0.1.0/crates/blazar-encoder/src/config.rs +108 -0
  39. blazar_video-0.1.0/crates/blazar-encoder/src/cpu_preprocess.rs +70 -0
  40. blazar_video-0.1.0/crates/blazar-encoder/src/gpu_preprocess.rs +358 -0
  41. blazar_video-0.1.0/crates/blazar-encoder/src/lib.rs +293 -0
  42. blazar_video-0.1.0/crates/blazar-encoder/src/nal.rs +547 -0
  43. blazar_video-0.1.0/crates/blazar-encoder/src/nvenc/config.rs +332 -0
  44. blazar_video-0.1.0/crates/blazar-encoder/src/nvenc/cuda.rs +320 -0
  45. blazar_video-0.1.0/crates/blazar-encoder/src/nvenc/keyframe.rs +97 -0
  46. blazar_video-0.1.0/crates/blazar-encoder/src/nvenc/mod.rs +24 -0
  47. blazar_video-0.1.0/crates/blazar-encoder/src/nvenc/nv12.rs +178 -0
  48. blazar_video-0.1.0/crates/blazar-encoder/src/nvenc/pool.rs +168 -0
  49. blazar_video-0.1.0/crates/blazar-encoder/src/nvenc/worker.rs +1532 -0
  50. blazar_video-0.1.0/crates/blazar-encoder/src/opus.rs +252 -0
  51. blazar_video-0.1.0/crates/blazar-encoder/src/svtav1.rs +246 -0
  52. blazar_video-0.1.0/crates/blazar-encoder/src/videotoolbox/apple.rs +225 -0
  53. blazar_video-0.1.0/crates/blazar-encoder/src/videotoolbox/mod.rs +610 -0
  54. blazar_video-0.1.0/crates/blazar-encoder/src/vp9.rs +279 -0
  55. blazar_video-0.1.0/crates/blazar-encoder/src/x264.rs +406 -0
  56. blazar_video-0.1.0/crates/blazar-encoder/src/x265.rs +392 -0
  57. blazar_video-0.1.0/crates/blazar-encoder/tests/av1_config.rs +91 -0
  58. blazar_video-0.1.0/crates/blazar-encoder/tests/fixtures/README.md +13 -0
  59. blazar_video-0.1.0/crates/blazar-encoder/tests/fixtures/h264.annexb +0 -0
  60. blazar_video-0.1.0/crates/blazar-encoder/tests/fixtures/hevc.annexb +0 -0
  61. blazar_video-0.1.0/crates/blazar-encoder/tests/fixtures/nvenc_av1_keyframe_head.bin +0 -0
  62. blazar_video-0.1.0/crates/blazar-encoder/tests/gpu_preprocess.rs +174 -0
  63. blazar_video-0.1.0/crates/blazar-encoder/tests/nvenc_cuda.rs +324 -0
  64. blazar_video-0.1.0/crates/blazar-encoder/tests/nvenc_hardware.rs +295 -0
  65. blazar_video-0.1.0/crates/blazar-encoder/tests/nvenc_host_convert.rs +259 -0
  66. blazar_video-0.1.0/crates/blazar-encoder/tests/svt_config_probe.rs +157 -0
  67. blazar_video-0.1.0/crates/blazar-encoder/tests/svtav1_backend.rs +78 -0
  68. blazar_video-0.1.0/crates/blazar-encoder/tests/videotoolbox.rs +245 -0
  69. blazar_video-0.1.0/crates/blazar-encoder/tests/vp9_backend.rs +66 -0
  70. blazar_video-0.1.0/crates/blazar-encoder/tests/x264_backend.rs +137 -0
  71. blazar_video-0.1.0/crates/blazar-encoder/tests/x265_backend.rs +117 -0
  72. blazar_video-0.1.0/crates/blazar-preprocess/Cargo.toml +11 -0
  73. blazar_video-0.1.0/crates/blazar-preprocess/src/lib.rs +1438 -0
  74. blazar_video-0.1.0/crates/blazar-preprocess/src/simd/avx2.rs +656 -0
  75. blazar_video-0.1.0/crates/blazar-preprocess/src/simd/neon.rs +573 -0
  76. blazar_video-0.1.0/crates/blazar-preprocess/src/simd.rs +160 -0
  77. blazar_video-0.1.0/crates/blazar-runtime/Cargo.toml +34 -0
  78. blazar_video-0.1.0/crates/blazar-runtime/examples/videotoolbox_encode.rs +129 -0
  79. blazar_video-0.1.0/crates/blazar-runtime/src/backend_selection.rs +464 -0
  80. blazar_video-0.1.0/crates/blazar-runtime/src/lib.rs +1081 -0
  81. blazar_video-0.1.0/crates/blazar-runtime/src/preprocess_placement.rs +326 -0
  82. blazar_video-0.1.0/crates/blazar-runtime/tests/nvenc_e2e.rs +199 -0
  83. blazar_video-0.1.0/crates/blazar-runtime/tests/pipeline.rs +351 -0
  84. blazar_video-0.1.0/crates/blazar-runtime/tests/videotoolbox_e2e.rs +184 -0
  85. blazar_video-0.1.0/crates/blazar-runtime/tests/x264_close.rs +126 -0
  86. blazar_video-0.1.0/crates/blazar-sink/Cargo.toml +13 -0
  87. blazar_video-0.1.0/crates/blazar-sink/src/fmp4.rs +501 -0
  88. blazar_video-0.1.0/crates/blazar-sink/src/lib.rs +309 -0
  89. blazar_video-0.1.0/crates/blazar-sink/tests/fmp4_sink.rs +240 -0
  90. blazar_video-0.1.0/crates/blazar-svtav1-sys/Cargo.toml +11 -0
  91. blazar_video-0.1.0/crates/blazar-svtav1-sys/build.rs +48 -0
  92. blazar_video-0.1.0/crates/blazar-svtav1-sys/src/lib.rs +87 -0
  93. blazar_video-0.1.0/crates/blazar-vpx-sys/Cargo.toml +17 -0
  94. blazar_video-0.1.0/crates/blazar-vpx-sys/build.rs +61 -0
  95. blazar_video-0.1.0/crates/blazar-vpx-sys/src/lib.rs +29 -0
  96. blazar_video-0.1.0/crates/blazar-vpx-sys/src/pregenerated.rs +4133 -0
  97. blazar_video-0.1.0/crates/blazar-x265-sys/Cargo.toml +16 -0
  98. blazar_video-0.1.0/crates/blazar-x265-sys/build.rs +78 -0
  99. blazar_video-0.1.0/crates/blazar-x265-sys/src/lib.rs +36 -0
  100. blazar_video-0.1.0/crates/blazar-x265-sys/src/pregenerated.rs +1213 -0
  101. blazar_video-0.1.0/pyproject.toml +50 -0
  102. blazar_video-0.1.0/python/blazar/__init__.py +23 -0
  103. blazar_video-0.1.0/python/blazar/__init__.pyi +89 -0
  104. blazar_video-0.1.0/python/blazar/py.typed +0 -0
  105. blazar_video-0.1.0/python/blazar/sglang_interop.py +195 -0
@@ -0,0 +1,50 @@
1
+ [workspace]
2
+ # The Python binding is its own workspace: maturin builds it with
3
+ # `extension-module`, which breaks `cargo test` linking, so it must not be part of
4
+ # the portable test surface.
5
+ exclude = ["bindings/python"]
6
+ resolver = "2"
7
+ members = [
8
+ "crates/blazar-svtav1-sys",
9
+ "crates/blazar-vpx-sys",
10
+ "crates/blazar-x265-sys",
11
+ "crates/blazar-core",
12
+ "crates/blazar-calibration",
13
+ "crates/blazar-encoder",
14
+ "crates/blazar-sink",
15
+ "crates/blazar-preprocess",
16
+ "crates/blazar-runtime",
17
+ ]
18
+ [workspace.package]
19
+ version = "0.1.0"
20
+ edition = "2021"
21
+ license = "Apache-2.0"
22
+ rust-version = "1.95"
23
+
24
+ # Shared dependency versions. Pinned (see project rules: exact/pinned versions).
25
+ [workspace.dependencies]
26
+ thiserror = "=2.0.21"
27
+ serde = { version = "=1.0.229", features = ["derive"] }
28
+ toml = "=1.1.8"
29
+ tracing = "=0.1.44"
30
+ # CPU preprocess is data-parallel over chroma rows; exact pin per project rules.
31
+ rayon = "=1.12.0"
32
+ oxideav-core = "=0.1.40"
33
+ oxideav-mp4 = { git = "https://github.com/jgh-/oxideav-mp4", rev = "9b6f7bb6a0dee7de72b8e593cb1feba5f14034e6" }
34
+ # NVENC (Phase 2). Fork pinned by rev: adds EncodePictureParams::encode_pic_flags
35
+ # (forced IDR) and Buffer::pitch() to the upstream 0.4.0 wrapper.
36
+ nvidia-video-codec-sdk = { git = "https://github.com/jgh-/nvidia-video-codec-sdk", rev = "84ac15e" }
37
+ # The SDK's published 0.4.0 pins cudarc 0.16.6, which rejects CUDA 13. The git
38
+ # revision depends on cudarc 0.19; pin it with the explicit toolkit feature.
39
+ cudarc = { version = "=0.19.10", default-features = false, features = ["cuda-13010", "driver", "dynamic-loading", "nvrtc"] }
40
+
41
+ # Internal crates
42
+ blazar-core = { path = "crates/blazar-core" }
43
+ blazar-calibration = { path = "crates/blazar-calibration" }
44
+ blazar-encoder = { path = "crates/blazar-encoder" }
45
+ blazar-sink = { path = "crates/blazar-sink" }
46
+ blazar-preprocess = { path = "crates/blazar-preprocess" }
47
+
48
+ [profile.release]
49
+ lto = "thin"
50
+ codegen-units = 1
@@ -0,0 +1,113 @@
1
+ Metadata-Version: 2.4
2
+ Name: blazar-video
3
+ Version: 0.1.0
4
+ Classifier: Development Status :: 3 - Alpha
5
+ Classifier: License :: OSI Approved :: Apache Software License
6
+ Classifier: Programming Language :: Rust
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.9
9
+ Classifier: Programming Language :: Python :: 3.13
10
+ Classifier: Topic :: Multimedia :: Video :: Conversion
11
+ Classifier: Topic :: Multimedia :: Video :: Non-Linear Editor
12
+ Classifier: Operating System :: POSIX :: Linux
13
+ Classifier: Operating System :: MacOS
14
+ Summary: Model-aware video encoding for generated video: zero-copy GPU ingest, per-model calibrations, and one submit for host or device frames
15
+ Keywords: video,encoding,nvenc,av1,h264,hevc,diffusion,torch
16
+ License: Apache-2.0
17
+ Requires-Python: >=3.9
18
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
19
+ Project-URL: Changelog, https://github.com/blazar-video/blazar/blob/main/CHANGELOG.md
20
+ Project-URL: Documentation, https://github.com/blazar-video/blazar/blob/main/docs/python-api.md
21
+ Project-URL: Homepage, https://github.com/blazar-video/blazar
22
+ Project-URL: Issues, https://github.com/blazar-video/blazar/issues
23
+
24
+ # Python bindings
25
+
26
+ PyO3 bindings over `blazar-runtime`, built with maturin.
27
+
28
+ ## Build
29
+
30
+ ```sh
31
+ python3 -m venv .venv && . .venv/bin/activate
32
+ pip install maturin numpy pytest
33
+
34
+ # mock encoder (no CUDA): enough to exercise the binding and the muxer
35
+ maturin develop
36
+
37
+ # hardware AV1 on a CUDA host
38
+ maturin develop --features nvenc
39
+ ```
40
+
41
+ `bindings/python` is its own cargo workspace on purpose: `extension-module` does
42
+ not link libpython, which breaks `cargo test` linking, so the portable
43
+ `cargo test --workspace` must not see it.
44
+
45
+ ## Test
46
+
47
+ ```sh
48
+ pytest bindings/python/tests -v
49
+ ```
50
+
51
+ The suite uses the mock encoder and asserts container structure, not decodability:
52
+ the mock has no real codec, so it is given a plausible `video_extradata` and
53
+ writes synthetic payload bytes. Decode validation stays on hardware (see the
54
+ repo README, "Hardware validation").
55
+
56
+ ## Use
57
+
58
+ ```python
59
+ import numpy as np
60
+ import blazar
61
+
62
+ Calibrations = blazar.Calibrations.load("calibrations/default")
63
+
64
+ with blazar.Encoder(
65
+ calibrations=calibrations,
66
+ identity={"family": "wan", "version": "2.1", "quant": "bf16", "size": "1.3b"},
67
+ target="balanced",
68
+ backend="svtav1", # or "nvenc", or "auto" with backend_pool=
69
+ output="out.mp4",
70
+ queue_depth=4, # frames the encoder may be behind
71
+ ) as stream:
72
+ for i, frame in enumerate(frames): # frame: (H, W, 3) float32 in [0, 1]
73
+ stream.submit(
74
+ frame, width=W, height=H, fps=24.0,
75
+ layout="thwc", range="unit01",
76
+ scene_cut=(i == 0),
77
+ )
78
+ for event in stream.poll(): # optional: non-blocking
79
+ if event["kind"] == "encoded" and event["keyframe"]:
80
+ pass # a fragment boundary was just closed
81
+ ```
82
+
83
+ `submit` copies the frame and enqueues it; a Rust worker thread does the
84
+ preprocess, encode and muxing. It blocks only when `queue_depth` frames are
85
+ already queued, and it releases the GIL while blocking, so other Python threads
86
+ keep running. Use `flush()` as a barrier (everything submitted before it is
87
+ durable) and `stats` for counters.
88
+
89
+ `poll()` returns dicts:
90
+
91
+ ```
92
+ {"kind": "encoded", "seq", "pts", "keyframe", "units", "bytes",
93
+ "encode_us", "queue_depth"}
94
+ {"kind": "failed", "seq", "message"}
95
+ {"kind": "closed"}
96
+ ```
97
+
98
+ `keyframe: True` means the fMP4 sink closed a fragment at that frame, which is
99
+ the segment boundary a transport sink will publish.
100
+
101
+ Worker failures surface as a `failed` event, are re-raised by `submit`, and are
102
+ re-raised by `close()`. Nothing is swallowed.
103
+
104
+ Defaults synthesise PTS as `frame_index * 90000 / fps`; pass `pts_ticks=` to
105
+ place frames explicitly (vLLM-Omni chunks carry a cumulative frame index).
106
+
107
+ ## Boundaries
108
+
109
+ - Video only. `submit_audio` does not exist on the Python object.
110
+ - The sink is a file. There is no WebSocket/streaming destination yet, so this
111
+ measures the encode path rather than delivering a live stream.
112
+ - Device tensors are Phase 2: the frame is copied to host and then into Rust.
113
+
@@ -0,0 +1,89 @@
1
+ # Python bindings
2
+
3
+ PyO3 bindings over `blazar-runtime`, built with maturin.
4
+
5
+ ## Build
6
+
7
+ ```sh
8
+ python3 -m venv .venv && . .venv/bin/activate
9
+ pip install maturin numpy pytest
10
+
11
+ # mock encoder (no CUDA): enough to exercise the binding and the muxer
12
+ maturin develop
13
+
14
+ # hardware AV1 on a CUDA host
15
+ maturin develop --features nvenc
16
+ ```
17
+
18
+ `bindings/python` is its own cargo workspace on purpose: `extension-module` does
19
+ not link libpython, which breaks `cargo test` linking, so the portable
20
+ `cargo test --workspace` must not see it.
21
+
22
+ ## Test
23
+
24
+ ```sh
25
+ pytest bindings/python/tests -v
26
+ ```
27
+
28
+ The suite uses the mock encoder and asserts container structure, not decodability:
29
+ the mock has no real codec, so it is given a plausible `video_extradata` and
30
+ writes synthetic payload bytes. Decode validation stays on hardware (see the
31
+ repo README, "Hardware validation").
32
+
33
+ ## Use
34
+
35
+ ```python
36
+ import numpy as np
37
+ import blazar
38
+
39
+ Calibrations = blazar.Calibrations.load("calibrations/default")
40
+
41
+ with blazar.Encoder(
42
+ calibrations=calibrations,
43
+ identity={"family": "wan", "version": "2.1", "quant": "bf16", "size": "1.3b"},
44
+ target="balanced",
45
+ backend="svtav1", # or "nvenc", or "auto" with backend_pool=
46
+ output="out.mp4",
47
+ queue_depth=4, # frames the encoder may be behind
48
+ ) as stream:
49
+ for i, frame in enumerate(frames): # frame: (H, W, 3) float32 in [0, 1]
50
+ stream.submit(
51
+ frame, width=W, height=H, fps=24.0,
52
+ layout="thwc", range="unit01",
53
+ scene_cut=(i == 0),
54
+ )
55
+ for event in stream.poll(): # optional: non-blocking
56
+ if event["kind"] == "encoded" and event["keyframe"]:
57
+ pass # a fragment boundary was just closed
58
+ ```
59
+
60
+ `submit` copies the frame and enqueues it; a Rust worker thread does the
61
+ preprocess, encode and muxing. It blocks only when `queue_depth` frames are
62
+ already queued, and it releases the GIL while blocking, so other Python threads
63
+ keep running. Use `flush()` as a barrier (everything submitted before it is
64
+ durable) and `stats` for counters.
65
+
66
+ `poll()` returns dicts:
67
+
68
+ ```
69
+ {"kind": "encoded", "seq", "pts", "keyframe", "units", "bytes",
70
+ "encode_us", "queue_depth"}
71
+ {"kind": "failed", "seq", "message"}
72
+ {"kind": "closed"}
73
+ ```
74
+
75
+ `keyframe: True` means the fMP4 sink closed a fragment at that frame, which is
76
+ the segment boundary a transport sink will publish.
77
+
78
+ Worker failures surface as a `failed` event, are re-raised by `submit`, and are
79
+ re-raised by `close()`. Nothing is swallowed.
80
+
81
+ Defaults synthesise PTS as `frame_index * 90000 / fps`; pass `pts_ticks=` to
82
+ place frames explicitly (vLLM-Omni chunks carry a cumulative frame index).
83
+
84
+ ## Boundaries
85
+
86
+ - Video only. `submit_audio` does not exist on the Python object.
87
+ - The sink is a file. There is no WebSocket/streaming destination yet, so this
88
+ measures the encode path rather than delivering a live stream.
89
+ - Device tensors are Phase 2: the frame is copied to host and then into Rust.