Commit Graph

145 Commits

Author SHA1 Message Date
benjcooley fd3bea9156 refactor: replace typed vendor domains with a named integrations dispatch
Eleven vendor-shaped Protocols are replaced by one IntegrationsDomain with
`call(integration, operation, **params)` and `describe()`. The published API
was growing by one class per third-party service while the enforcement point
— `integrations.<name>`, checked at the broker — never varied. The hand-kept
public stub had already fallen behind that growth: Luma, ImgBB and SenseNova
existed in the implementation but had never been published.

Three defects surfaced and are fixed here:

- LlamaCppModelRef.generate reached the vendor by attribute, so every pack
  using the returned handle broke at the wire, not at the call site.
- The in-process path exposed vendors as public attributes and had no
  `call`, so a node could work unsandboxed and fail once sandboxed. The
  vendors are now private and reached only by name, giving both paths the
  same surface.
- `describe` was declared sync in the Protocol but implemented async in the
  guest, which must round-trip to the host.

Also removes a test for load_onnx_image_classifier, deleted from core in
2076700f without its tests; the surviving _validate_onnx_weight_file test
is kept.
2026-09-03 16:40:13 -07:00
benjcooley 677acea1d4 Remove SegFormer from the core node API 2026-09-03 14:10:34 -07:00
benjcooley 2076700f5e refactor: remove pack-owned classifiers from core API 2026-09-03 14:04:04 -07:00
benjcooley e88c901199 refactor: remove transparent VAE decoder from core API 2026-09-03 13:56:17 -07:00
benjcooley a559a53955 refactor: move pack-specific operations out of the dispatcher
The twenty handlers for IP-Adapter, SAM, CLIPSeg, image classification,
advanced ControlNet, transparent VAE, segmentation, inpainting, image
preprocessing and interpolation state used no instance state: they were
module functions parked on a class. They now live in _vendor_ops and
register through the same table, which leaves InProcessOps holding the
engine primitives and collects every pack-specific operation in one file
that can move out to the packs that own them.

They reach the SDK through the module rather than by importing names, so
substitution still resolves at call time.
2026-09-02 13:21:08 -07:00
benjcooley 118e34eb99 fix: keep comfy_api importable without the engine
comfy_api is the API layer; importing it must not require comfy core.
Load comfy.utils at the one call site that needs the progress bar.
2026-09-02 12:19:17 -07:00
benjcooley 0dee840a53 fix: satisfy ruff across the V2 SDK surface 2026-09-02 11:24:55 -07:00
benjcooley 21f3a1cad1 merge: origin/master into v2-nodes-api 2026-09-02 11:22:46 -07:00
benjcooley eef9033de8 fix: keep the SDK seam inert unless a node or provider engages it
A stock install — no overlay, no SDK markers on the node — now takes the
original invocation path: no ExecutionPlan, no ref table, no runtime
binding, and the pre-existing async task semantics. The seam engages per
node when it declares SDK_REFS/SDK_PERMISSIONS/SDK_REQUIRED_WEIGHTS, or
globally once any default provider is replaced, so a registered backend
still sees every node and provenance-based sandboxing cannot be bypassed
by a node simply declaring nothing.
2026-09-02 11:20:45 -07:00
benjcooley ce2f08182e refactor: move the IP-Adapter typed facade to the packs
The pipeline patches a live model, so its operations stay in core. What
leaves is the typed facade over them: IpAdapterRef and IpAdapterEmbedsRef
were published contract, so every one of their methods was a permanent
commitment. The same ergonomics now ship with the packs that want them,
built on the generic dispatch, and core keeps the operations without
keeping the surface.

ipadapter.apply, apply_tiled, encode and ipadapter_embeds.combine all
remain available by name. Handles cross as generic Refs carrying the
IPADAPTER_PIPE and IPADAPTER_EMBEDS kinds, which is what the validation and
the marshaller now check.

Ref gains _wrap so a handle with no dedicated class can still be re-typed
by the marshaller; the base keeps the resolver's kind while a subclass that
declares KIND asserts its own.
2026-09-02 10:14:04 -07:00
Terry Jia ace9172e95 Annotate temp paths in Preview3DAdvanced / PreviewGaussianSplat / PreviewPointCloud outputs (#16038) 2026-09-02 07:35:27 -04:00
benjcooley e7f7524ec7 feat: let any handle reach the operation vocabulary
op() was defined only on ImageRef, so a pack holding any other handle had
no way to call a named operation on it and had to wait for core to grow a
typed method. The dispatch itself was always generic: the broker's wire
parameter is named image but passes straight through to
ops.apply(op, subject, params), and core's own vendor wrappers already send
non-image handles along it.

Moving op() to the base Ref is what lets a pack build its own typed
accessor over a capability core knows nothing about, so the operation
vocabulary can keep growing while the API does not. ImageRef keeps its
override to narrow the return type.
2026-09-01 18:29:32 -07:00
benjcooley dbae8051e7 refactor: keep the ONNX detector inside the packs that use it
Removes OnnxDetectorRef, ctx.models.load_onnx_detector, the
onnx_detector.detect operation, its entry type, loader and cache, and the
secure_kind inference branch that mapped to the removed type.

The detector is one model family, and running an untrusted ONNX graph
belongs in the sandbox rather than in the trusted host process, so the packs
now load and execute it themselves through the generic asset broker.
2026-09-01 16:59:58 -07:00
benjcooley b05c60f5c5 refactor: drop ViTMatte from the public stub
Completes the removal: the hand-maintained public surface still declared
MattingModelRef and load_vitmatte after the implementation moved to the
LayerStyle pack.
2026-09-01 16:30:12 -07:00
benjcooley c5d4c384cf refactor: keep ViTMatte inside the LayerStyle pack
ViTMatte is one pack's model family, so the architecture, the loader and the
refinement move to the pack that uses it. Removes MattingModelRef,
ctx.models.load_vitmatte, the matting.refine operation, the ViTMatte entry
type, its loader and its cache from core.

The pack asks only for generic primitives: resolve a declared weight and read
its state dict. It selects and offloads its own device, because the model is
its own and runs in its own process.
2026-09-01 16:28:30 -07:00
benjcooley 7a941e6e8b feat: add a versioned, self-describing capability registry
Ports de91e80c from api-v2-runtime so both cores expose the same mechanism
for describing and negotiating the operation vocabulary.
2026-09-01 16:01:57 -07:00
benjcooley f23c8a57c2 refactor: extract bounded weight cache and fix LRU eviction
Ports 31d76988 from api-v2-runtime so both cores carry the same cache
behaviour. Seven of the thirteen copy-pasted caches evicted with
dict.popitem(), dropping the most recently inserted entry rather than the
least recently used, which pinned whichever model loaded first.
2026-09-01 16:01:57 -07:00
benjcooley 42678d3b6b refactor: keep BLIP out of the secure core V2 SDK
Ports the core half of the LayerStyle BLIP move to this branch, which had
only received the pack half. Removes VqaModelRef, ctx.models.load_vqa, the
VQA cache and the 30,522-token BERT vocabulary from core; LayerStyle now
carries that implementation and its own vocabulary and asks for weights
through the generic asset broker.

Brings this core back into step with api-v2-runtime, where this landed as
f1510546.
2026-09-01 15:57:13 -07:00
benjcooley 61d06654cb checkpoint: cloud media surface on the secure core
Preserves in-progress work so it is not lost: a new _cloud_media module
plus the SDK, public-surface, and model-transform changes that reference
it. All four files compile; committed as a recovery point rather than a
validated release.
2026-09-01 15:34:38 -07:00
benjcooley 13a341d673 Add cloud node runtime SDK support 2026-08-31 15:37:58 -07:00
benjcooley ec955d53ba Expand secure V2 SDK surface 2026-08-31 10:42:20 -07:00
Terry Jia f938505952 feat: add VideoTrim and VideoCrop nodes with VIDEO_EDIT widget inputs (#15637) 2026-08-30 15:54:48 -07:00
benjcooley 52fab0fec6 Make comfy_api importable without ComfyUI core 2026-08-27 09:33:02 -07:00
benjcooley b4b7b14b25 feat(sdk): transport unchanged V2 node values 2026-08-27 02:05:23 -07:00
benjcooley 4416b35be2 feat(io): publish MAX_RESOLUTION on the io surface
Pack schemas use it for input bounds, and the module that has always
defined it (nodes.py) is a host module a sandboxed pack cannot import.
Same value by definition: 16384 is frozen into every workflow that
ever serialized a bound.
2026-08-27 00:03:54 -07:00
benjcooley d6f16f7263 feat(sdk): model transforms, preview/profiling surfaces, structured-vs-live ref boundary
The V2 additions the KJNodes completion needed on the core side:

- _model_transforms: the closed, core-owned transform vocabulary
  behind ModelRef.patch — 29 named transforms, declaratively
  parameterized, validated host-side, immutable and stacking. No
  function ever crosses the boundary; a pack cannot register one.
- structured-vs-live split: value()/from_value() only on structured
  data refs (LATENT, AUDIO, TRACKS...). MODEL/CLIP/VAE/asset refs are
  handles in every execution mode — in-process identity resolution no
  longer hands a live model to node code.
- preview overrides (tiny-VAE, LTX factors), triton VAE seam, memory
  attention, and profiling surfaces backing the corresponding closed
  brokers in the overlay.
- torch_compile/model_patcher/model_management: compiled-view
  aliasing recognized by the model manager (no double-counted
  weights); shared state-dict loading path so the native loader and
  the V2 broker cannot drift.
2026-08-26 23:48:44 -07:00
Alexander Piskun d8e7bbc9d5 fix(video): remux HEVC to mp4/mov as hvc1 via hevc_mp4toannexb (#15809) 2026-08-26 20:28:50 -04:00
benjcooley 478d368f93 feat(sdk): handle ops for live engine objects; host-authoritative refs
VaeRef.decode/encode, ClipRef.tokenize/encode_from_tokens_scheduled/encode,
CondRef.combine/concat, with in-process implementations behind the existing
named-op registry so an overlay extends the vocabulary without touching the
contract.

These keep the old API's shape on purpose — you still write vae.decode(latent)
— and change only what the call means: the node holds a handle, awaits, and the
decode runs on the trusted plane against weights it never sees. That is what
lets a node DECLARE a VAE input and still be sandboxable. Compatible in shape so
conversion is mechanical across a corpus nobody here maintains; different in
substance so a converted node is sandboxable by construction.

Two mirroring defects fixed before shipping: encode() sliced its input to three
channels (core's VAEEncode does not, so it silently dropped alpha), and ClipRef
offered only a combined encode(text) (CLIPTextEncodeSDXL builds one token dict
from two prompts, and the ACE nodes pass a dozen tokenizer kwargs, so the
collapse made both inexpressible).

InProcessRefResolver now records a ref's kind at creation and checks it at
resolve. Ref tokens cross as {kind, id, cls} and the host rebuilt from what
arrived, so the holder chose its own ref's type: an ImageRef id could be
presented as a VaeRef. Unguessable ids already stopped a guest reaching a handle
it was never given; possessing a handle is not the same as labelling it.

Release is explicit, not collected. InProcessRefResolver.clear() drops the
table's strong references at a known point, called from execution.py in a
finally so it also covers the path where the node raised or its guest died —
which is exactly when nothing else will run. A ref table can hold multi-gigabyte
tensors, and refcount timing neither crosses a process boundary nor is bounded
under reference cycles.

OpsProvider.apply is annotated (op, subject: Ref, params) -> Any; it claimed
ImageRef in and out while handle ops take a VaeRef and may return a LatentRef,
a CondRef, or a plain token dict.
2026-08-26 12:13:21 -07:00
comfyanonymous 9db05e0e1f Add colorspace option and change bit_depth to a combo on CreateVideo. (#15810) 2026-08-22 21:07:29 -04:00
benjcooley d994e9ef6f feat(sdk): live engine objects cross the seam as refs; nodes declare permissions
Two generic gaps that blocked an out-of-process node from being a sampler.

1. wrap_inputs only wrapped tensors and latents. A MODEL or CONDITIONING is a
   live engine object, so it passed straight through — and an out-of-process
   backend cannot serialize a ModelPatcher, so any node taking one simply could
   not run in a guest. The rule is now by capability rather than an enumerated
   type list: a value that can cross as data does, and anything else becomes a
   handle. That is the correct boundary rule anyway — objects do not cross,
   handles do — and it is what lets a node take a MODEL and still run isolated.

2. ExecutionPlan.permissions was never populated, so the seam could not tell a
   backend what a node needs. A node now declares SDK_PERMISSIONS and the seam
   copies it onto the plan. Declaring is not granting: the backend decides, and
   an out-of-process one still gates every call at the wire. Nodes that declare
   nothing — the overwhelming majority — get nothing.

Behaviour-preserving in-process: 54 core seam tests and 26 overlay tests pass.
2026-08-22 01:01:04 -07:00
benjcooley 3deeb22ed2 fix(sdk): unwrap_outputs must preserve ui/expand/block_execution
`unwrap_outputs` rebuilds a node's NodeOutput in order to swap output refs back
for real objects. It rebuilt it from the results alone — `NodeOutput(*resolved)`
— silently discarding `ui`, `expand` and `block_execution`.

The practical effect: no SDK_REFS node could be an output node. ComfyUI only
emits the `executed` websocket event, the one that delivers a node's results to
the frontend, for nodes that return ui data (`if len(output_ui) > 0`). So a
converted PreviewImage-style node executed perfectly and then displayed
nothing, with no error anywhere to explain it. `expand` (subgraph expansion)
and `block_execution` were lost the same way.

Resolving refs is a transport concern and has no business changing what the
node said. Generic fix, not specific to any backend: it applies equally to the
in-process path.
2026-08-22 00:27:56 -07:00
benjcooley 48ecebe889 feat(sdk): generic image.op(name, **params) transport — op vocabulary is data, not API surface
Replaces enumerated invert/scale methods on OpsProvider with generic dispatch:
apply(op, image, params) + supports(op) + a built-in registry {invert, scale}
+ register_op. ImageRef.op(name, **params) is the untyped transport seam;
invert()/scale() remain as built-in convenience. Adds OpNotSupported (carries
the capability name) so a node can fall back to the raw tier. An overlay now
extends the op vocabulary without touching OSS core.

Statically-typed op methods live on the secure-lib side (per guidance), not
here — core stays a generic seam.
2026-08-21 21:08:48 -07:00
benjcooley e7160bf7ab feat(sdk): execution seam carries the work unit — plan.inputs/node_module, dispatch(plan, local_call, runtime)
Generic out-of-process enablement: the ExecutionPlan now ships the node's
module spec and ref-wrapped inputs, and dispatch receives the per-node host
runtime (refs/ctx/ops) so an external backend can execute the node elsewhere
and broker guest calls against the same ref table. In-process default ignores
all of it; legacy nodes unaffected (seam tests green).
2026-08-21 20:41:28 -07:00
benjcooley f1681ee669 feat(sdk): ops-first asset interface — OpsProvider seam, SDK_REFS marshaling, raw() escape hatch
Nodes operate on assets (image.invert()) and never receive buffers; compute
runs on the trusted plane via the OpsProvider seam. Raw buffer access becomes
a permissioned, discouraged escape hatch (raw(); forces dedicated tier under
the overlay). The execution seam wraps heavy inputs as refs for SDK_REFS
nodes and resolves output refs for downstream legacy nodes. The .pyi contract
no longer imports torch.

POC stand-ins (interface debt, ledgered in the overlay repo DEBT.md):
invert/scale enumerated on OpsProvider; duck-typed wrap_inputs; SDK_REFS
class-attr opt-in.
2026-08-21 20:36:37 -07:00
benjcooley e92fa15805 feat(sdk): wire execution seam + .pyi contract + POC node & test
- execution.py: route V3 node dispatch through providers.execution_backend
  with a behavior-preserving local_call closure (exact sync/async-task
  semantics retained); bind per-node ctx+refs inside the invocation scope so
  the concurrent-async path is correct. V1 nodes untouched. Default backend =
  in-process => byte-identical to today.
- comfy_api/latest/_sdk_public.pyi: authoritative type contract for the secure
  SDK (backend analog of the frontend comfy-api.d.ts): refs, ctx + domains,
  ctx() accessor; host/overlay seam separated.
- custom_nodes/comfy_sdk_poc: SandboxInvert POC node authored to the SDK.
- tests-unit: seam regression (sync+async SDK nodes through the real engine;
  provider-swap intercept). Verified PASS.
2026-08-21 20:07:27 -07:00
benjcooley 17ca834fd5 feat(sdk): custom-node SDK seam — refs, ctx, provider registry, overlay loader
Establishes the open-source 'key Python API' for secure custom nodes:
- comfy_api/latest/_sdk.py: opaque typed refs (ImageRef/ModelRef/AssetRef...),
  a brokered ctx surface (assets/progress/scratch/events/storage + stubs),
  and a Providers registry (ExecutionBackend/CtxProvider/RefResolver) with
  in-process DEFAULTS so OSS behaves exactly as today (a ref wraps the real
  object; ctx is a passthrough; zero-copy, zero-overhead).
- load_overlay(): env-var (COMFY_OVERLAY_MODULE) path loader that lets a
  separable, proprietary cloud overlay register isolated implementations at
  the seam. Unset => pure OSS. Wired guarded into main.startup.
- comfy_api/v0_0_3: new API version exposing sdk; registered in version_list.

Nothing isolation-specific lives in OSS: this is the seam, not the engine.
2026-08-21 19:52:49 -07:00
Jukka Seppänen 0e65cb9071 feat: Support Pixal3d and TRELLIS2 (CORE-278) (CORE-199) (CORE-236) (CORE-312) (#14718) 2026-08-21 20:32:25 -04:00
comfyanonymous dcbcf8c2e1 Support HDR video saving, AV1 codec, mkv and webm. (#15741) 2026-08-20 19:29:20 -04:00
Terry Jia 8fadc7b5be [Partner Nodes] feat: ImageCompositor node with layer-state compositing, layer from bbox and Seedream Layer Separation node (#15317) 2026-08-07 13:25:37 -07:00
comfyanonymous 9a9fdb10ed Harden some nodes against potential issues related to combos. (#15277) 2026-08-03 23:55:13 -04:00
comfyanonymous 2881e61610 Store mp4 metadata at the beginning of the file when possible. (#15195) 2026-08-01 03:21:28 -04:00
comfyanonymous 235b466a0c Add crf option to save video node. (#15191) 2026-08-01 00:27:48 -04:00
Alexander Piskun cc6b352511 fix(Video): stream the video transcode instead of buffering every frame in RAM (CORE-353) (CORE-351) (#14813) 2026-07-15 15:23:43 +08:00
Simon Pinfold 55a15f87ce feat(assets): add namespaced model_type tags and align tag semantics (#14511)
* feat(assets): add namespaced model type tags

* fix(assets): mark path-derived upload tags automatic

* fix(assets): merge duplicate scan specs

* test(assets): make duplicate path normalization portable

* feat(assets): add loader_path as the authoritative loader locator (#14796)

* fix(assets): filter model_type tags by bucket extension sets

Buckets sharing a base directory (e.g. diffusion_models and a custom
unet_gguf) tagged every file in the directory regardless of whether the
bucket could load it, so .safetensors files were tagged
model_type:unet_gguf and vice versa. Carry each bucket's registered
extension set through get_comfy_models_folders and only emit a
model_type tag when the file extension matches, keeping the empty-set
match-all convention from folder_paths.filter_files_extensions.

Files under a model base matching no bucket now keep only the models
tag instead of every directory-matching model_type tag.

* feat(assets): replace response file_path with persisted loader_path

The old file_path response field was a namespaced storage locator
(models/checkpoints/foo.safetensors): not an absolute path, not unique
identity, and not the value a loader consumes. Nothing needs that shape
on the wire (hash/ID-based locating is the long-term direction), so it
is dropped rather than renamed; the storage-root matching stays internal,
powering display_name.

What loaders DO need is the in-root loader path (category dropped:
models/checkpoints/foo/bar.safetensors -> foo/bar.safetensors). Serve it
as a first-class loader_path field, persisted on asset_references
(migration 0006) and written by every ingest pipeline at insert, so
responses read the column verbatim.

Like the model_type tags, loader_path is a seed-time derivative of the
model folder registry, maintained by the same scan lifecycle (new files seed
fresh values, pruning retires rows whose bucket disappeared). Rows
predating the column serve a null loader_path; databases from before
this stack already need recreating for the base branch's tag changes.

loader_path resolves every registered base including extra_model_paths
entries; display_name only the canonical storage roots. A file can
therefore be loadable with no display name (extra-path models) or the
reverse (unregistered files under the models root), and loader_path is
null exactly when no loader can resolve the file.

* test(assets): lock loader_path matrix (asymmetry, null, persist/read)

Cover the behaviour that has no production change but is easy to regress:
the extra-path asymmetry (loadable but no storage namespace), null
loader_path persistence for orphan files, and the response reading the
stored column with a compute fallback for un-backfilled rows.

* fix(assets): persist subfolder-qualified loader_path for ingested outputs

ingest_existing_file built its seed spec with the file's basename, so
outputs saved into a subfolder persisted loader_path (and the
user_metadata filename that preview URLs split for their subfolder
param) as just the basename: the served locator pointed at a file that
does not exist at that path. Scanner and seeder specs already derive
fname via compute_loader_path; use the same derivation here.

* fix(assets): only extension-matching buckets contribute a loader_path

The model-base match in get_asset_category_and_relative_path ignored
each bucket's extension set, so a file inside a registered base whose
extension the bucket cannot load (e.g. a .txt uploaded into
model_type:checkpoints) advertised a loader_path that no loader list
would ever resolve, while the tag side of the same stack already
excluded it. Apply the extension check used for backend tags (empty set
accepts any extension), keeping loader_path null exactly when no loader
can resolve the file.

* fix(assets): refresh loader_path when re-ingesting an existing reference

upsert_reference only wrote loader_path on the INSERT branch, so
re-ingesting an existing reference (an output overwritten in place, or a
file re-registered after its loader_path derivation changed) kept the
stale or NULL value forever. Write it on the UPDATE branch too, with a
null-safe change guard so a loader_path difference alone is enough to
trigger the update, and identical values stay a no-op.

* fix(assets): repair semantic merge breakage from #14796 and master

Two textually-clean but semantically-broken merges:

- routes.py lost its folder_paths import when #14796's import block
  superseded the base's, while the content-type hardening added via the
  base's master merge still calls folder_paths.is_dangerous_content_type.
- master's SVG download-hardening test uploads with the pre-namespacing
  bare checkpoints tag, which this branch's destination validation
  rejects; use model_type:checkpoints.

---------

Co-authored-by: guill <jacob.e.segal@gmail.com>
2026-07-08 22:00:08 -07:00
Alexander Piskun a3020f107e fix(Video): don't crash on videos with undecodable audio streams (#14746)
* fix(Video): don't crash on videos with undecodable audio streams

Signed-off-by: bigcat88 <bigcat88@icloud.com>

* Update comfy_api_nodes/util/upload_helpers.py

---------

Signed-off-by: bigcat88 <bigcat88@icloud.com>
Co-authored-by: Alexis Rolland <alexisrolland@hotmail.com>
2026-07-07 15:59:49 +03:00
Terry Jia dac4ea3a80 feat: Bounding boxes canvas and Ideogram JSON prompt (#14537) 2026-06-25 22:34:09 +08:00
Jedrzej Kosinski f2270f070a feat: add enable_telemetry CLI feature flag (#14530) 2026-06-17 19:35:05 -07:00
John Pollock 5db51b76b4 Fix odd-height crash and edge bleed in unaligned-width image/video decode (#14491)
a1d95f3f padded the decode width to the next multiple of 32 with the pad filter to fix libswscale's float YUV->GBR edge corruption, but kept the pad target height equal to the source height. The pad filter requires the target height to be a multiple of the input's vertical chroma subsampling factor, so a chroma-subsampled input such as yuv420p (the format the gbrpf32le float branch decodes) with an odd height makes the filter round the target below the input height and fail to configure: 'Padded dimensions cannot be smaller than input dimensions' (Errno 22). This is reachable from LoadImage, which routes static images through VideoFromFile, on a lossy WebP whose width is not a multiple of 32 and whose height is odd.

The pad filter also fills the added border with black, and chroma upsampling bleeds that black into the cropped edge of every unaligned-width subsampled decode.

Pad both axes to the next multiple of 32 (32 is a multiple of every vertical subsampling factor, including yuv410p's 4 that a plain even rounding misses) and run fillborders mode=smear to replicate the real edge into the padding so it never bleeds into the cropped output, then crop both axes back to the source size. Aligned-width and uint8 paths run the identical to_ndarray call as before and are byte-identical to master; only unaligned-width subsampled inputs change, from a crash or edge artifact to a clean, deterministic decode.
2026-06-15 20:23:09 -07:00
John Pollock a1d95f3f82 Fix nondeterministic video decode at unaligned widths (CORE-299) (#14438) 2026-06-14 08:58:48 +08:00
Alexander Piskun fe54b5e955 Add 10-bit video support (#14452)
Create Video gets a bit_depth option (8-bit/10-bit); the selected depth is carried by the video and applied when it gets encoded. Save Video and Video Slice now keep the source bit depth instead of always quantizing to 8-bit, so 10-bit videos stay 10-bit. 10-bit uses h264 with the yuv420p10le pixel format,so there's no new codec or container.

Signed-off-by: bigcat88 <bigcat88@icloud.com>
2026-06-13 16:05:25 +03:00