// Oak Video Editor - Non-Linear Video Editor
// Copyright (C) 2026 Oak Team
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//! describe 的产物:效果描述符与 clip 描述符。
//!
//! 参照:HS: ofxhImageEffect.cpp `Descriptor`(describe action 期间
//! 插件可读写的属性容器)。
//!
//! 句柄约定([`crate::suites::tag`]):`props` 在偏移 0 且
//! `#[repr(C)]`;`params`/`clips` 元素装箱(Vec 重分配不移动对象)。
use std::ffi::CString;
use crate::param::ParamDef;
use crate::property::{PropertySet, Value};
fn cs(s: &str) -> CString {
CString::new(s).unwrap()
}
// ---- clip 描述符属性(ofxImageEffect.h / ofxCore.h)----
/// kOfxImageClipPropOptional。
pub(crate) const CLIP_OPTIONAL: &str = "OfxImageClipPropOptional";
/// kOfxImageClipPropIsMask。
pub(crate) const CLIP_IS_MASK: &str = "OfxImageClipPropIsMask";
/// kOfxImageClipPropFieldExtraction。
pub(crate) const CLIP_FIELD_EXTRACTION: &str = "OfxImageClipPropFieldExtraction";
/// kOfxImageEffectPropSupportedComponents。
pub(crate) const CLIP_SUPPORTED_COMPONENTS: &str = "OfxImageEffectPropSupportedComponents";
/// kOfxImageEffectPropTemporalClipAccess。
pub(crate) const CLIP_TEMPORAL_ACCESS: &str = "OfxImageEffectPropTemporalClipAccess";
/// kOfxImageEffectPropSupportsTiles。
pub(crate) const CLIP_SUPPORTS_TILES: &str = "OfxImageEffectPropSupportsTiles";
/// kOfxImageFieldDoubled(FieldExtraction 默认值)。
pub(crate) const CLIP_FIELD_DOUBLED: &str = "OfxImageFieldDoubled";
/// kOfxTypeClip。
pub(crate) const CLIP_TYPE: &str = "OfxTypeClip";
/// clip 描述符(describe 期间由插件定义)。
/// `#[repr(C)]` + props 在偏移 0(句柄约定;describe 期 clip handle
/// 即 &props,与实例期 [`crate::clip::ClipInstance`] 共用 CLIP 标签)。
#[repr(C)]
pub struct ClipDescriptor {
/// 描述属性:label、可选性(kOfxImageClipPropOptional)、支持分量
/// (kOfxImageEffectPropSupportedComponents)、field 支持等。
pub props: PropertySet,
/// clip 名(如 "Source"/"Output")。
pub name: String,
}
impl ClipDescriptor {
/// 按名构建(镜像 HS ofxhClip.cpp `ClipDescriptor::ClipDescriptor`
/// + clipDescriptorStuffs 属性表,ofxhClip.cpp:22-38)。公开:
/// 测试构造 clip 实例(GL suite 往返)。
pub fn new(name: &str) -> Self {
let props = PropertySet::new();
props.set_one(crate::param::PROP_TYPE, Value::String(cs(CLIP_TYPE)));
props.set_one(crate::param::PROP_NAME, Value::String(cs(name)));
props.set_one(crate::param::PROP_LABEL, Value::String(cs(name)));
props.set_one(crate::param::PROP_SHORT_LABEL, Value::String(cs("")));
props.set_one(crate::param::PROP_LONG_LABEL, Value::String(cs("")));
props.define(CLIP_SUPPORTED_COMPONENTS, vec![]);
props.set_one(CLIP_TEMPORAL_ACCESS, Value::Int(0));
props.set_one(CLIP_OPTIONAL, Value::Int(0));
props.set_one(CLIP_IS_MASK, Value::Int(0));
props.set_one(CLIP_FIELD_EXTRACTION, Value::String(cs(CLIP_FIELD_DOUBLED)));
// kOfxImageClipPropFieldOrder(ofxhClip.cpp 的 clip 描述符必备
// 属性;ofxs `Clip::getFieldOrder()` 无默认值强读——Mirror 这类
// 场感知插件缺它直接 MissingHostFeature)。取值是
// kOfxImageField* 族(ofxImageEffect.h:1288),默认无场。
props.set_one(
"OfxImageClipPropFieldOrder",
Value::String(cs("OfxFieldNone")),
);
props.set_one(CLIP_SUPPORTS_TILES, Value::Int(1));
// ofxColour(M11 §4):clip 色彩空间属性族。Colourspace 由宿主
// 在实例化时写入(输入 clip = 工作空间 ACEScg);Preferred 由
// 插件在 GetClipPreferences 写(宿主侧预置空数组)。
props.set_one(crate::host::PROP_CLIP_COLOURSPACE, Value::String(cs("")));
props.define(crate::host::PROP_CLIP_PREFERRED_COLOURSPACES, vec![]);
Self {
props,
name: name.to_string(),
}
}
}
/// 效果描述符。
/// `#[repr(C)]` + props 在偏移 0(句柄约定:describe 期 effect/
/// param-set handle 即 &props)。
#[repr(C)]
pub struct EffectDescriptor {
/// 效果级属性:label、描述、分组、单帧/时间域标记等。
pub props: PropertySet,
/// 参数定义集(describe 期间插件经 Param suite 填充;
/// 值类型见 [`crate::param::ParamDef`];Box 保证句柄地址稳定)。
pub params: Vec>,
/// clip 定义集(含 "Output";Box 保证句柄地址稳定)。
pub clips: Vec>,
}
impl EffectDescriptor {
/// 空描述符(describe action 前由 host 创建并预置根属性)。
pub fn new() -> Self {
Self {
props: PropertySet::new(),
params: Vec::new(),
clips: Vec::new(),
}
}
/// 按名找 clip。
pub fn clip(&self, name: &str) -> Option<&ClipDescriptor> {
self.clips
.iter()
.find(|c| c.name == name)
.map(|b| b.as_ref())
}
/// 按名找参数定义。
pub fn param(&self, name: &str) -> Option<&ParamDef> {
self.params
.iter()
.find(|p| p.name == name)
.map(|b| b.as_ref())
}
}