export media: editable resolution / frame rate / bit rate spin boxes
CI / Build & test (Linux) (push) Canceled after 0s
CI / Build & test (Windows) (push) Canceled after 0s

The three values are SpinBoxes (typed input + stepping): width & height
(0 = use the sequence size), frame rate in fps (0 = sequence rate),
bit rate in bit/s (0 = the codec default). The engine already accepted
arbitrary values, so the dialog now exposes them instead of the closed
preset lists. i18n across the 8 packs.
This commit is contained in:
2026-09-02 09:35:54 +08:00
parent 92813707bc
commit 2c64317a58
9 changed files with 104 additions and 6 deletions
+3
View File
@@ -379,6 +379,9 @@
"export.audio_codec": "Audio-Codec"
"export.color": "Farbraum"
"export.color.sdr": "SDR — Rec.709 8-bit"
"export.resolution": "Auflösung (0 = Sequenz)"
"export.framerate": "Bildrate (0 = Sequenz)"
"export.bitrate": "Bitrate (0 = Codec-Standard)"
"export.color.hdr": "HDR — BT.2020 10-bit"
"export.range": "Exportbereich"
"export.range.all": "Ganze Timeline"
+3
View File
@@ -377,6 +377,9 @@
"export.audio_codec": "Audio Codec"
"export.color": "Color Space"
"export.color.sdr": "SDR — Rec.709 8-bit"
"export.resolution": "Resolution (0 = sequence)"
"export.framerate": "Frame Rate (0 = sequence)"
"export.bitrate": "Bit Rate (0 = codec default)"
"export.color.hdr": "HDR — BT.2020 10-bit"
"export.range": "Export Range"
"export.range.all": "Whole Timeline"
+3
View File
@@ -379,6 +379,9 @@
"export.audio_codec": "Códec de audio"
"export.color": "Espacio de color"
"export.color.sdr": "SDR — Rec.709 8-bit"
"export.resolution": "Resolución (0 = secuencia)"
"export.framerate": "Frecuencia de imagen (0 = secuencia)"
"export.bitrate": "Tasa de bits (0 = valor por defecto)"
"export.color.hdr": "HDR — BT.2020 10-bit"
"export.range": "Rango de exportación"
"export.range.all": "Toda la línea de tiempo"
+3
View File
@@ -379,6 +379,9 @@
"export.audio_codec": "Codec audio"
"export.color": "Espace colorimétrique"
"export.color.sdr": "SDR — Rec.709 8 bits"
"export.resolution": "Résolution (0 = séquence)"
"export.framerate": "Cadence (0 = séquence)"
"export.bitrate": "Débit (0 = défaut codec)"
"export.color.hdr": "HDR — BT.2020 10 bits"
"export.range": "Plage dexport"
"export.range.all": "Toute la timeline"
+3
View File
@@ -379,6 +379,9 @@
"export.audio_codec": "オーディオコーデック"
"export.color": "色域"
"export.color.sdr": "SDR — Rec.709 8bit"
"export.resolution": "解像度(0 = シーケンスに従う)"
"export.framerate": "フレームレート(0 = シーケンスに従う)"
"export.bitrate": "ビットレート(0 = コーデック既定)"
"export.color.hdr": "HDR — BT.2020 10bit"
"export.range": "書き出し範囲"
"export.range.all": "タイムライン全体"
+3
View File
@@ -379,6 +379,9 @@
"export.audio_codec": "Codec de áudio"
"export.color": "Espaço de cor"
"export.color.sdr": "SDR — Rec.709 8-bit"
"export.resolution": "Resolução (0 = sequência)"
"export.framerate": "Taxa de quadros (0 = sequência)"
"export.bitrate": "Taxa de bits (0 = padrão do codec)"
"export.color.hdr": "HDR — BT.2020 10-bit"
"export.range": "Faixa de exportação"
"export.range.all": "Linha do tempo inteira"
+3
View File
@@ -379,6 +379,9 @@
"export.audio_codec": "Аудиокодек"
"export.color": "Цветовое пространство"
"export.color.sdr": "SDR — Rec.709 8 бит"
"export.resolution": "Разрешение (0 = как в последовательности)"
"export.framerate": "Частота кадров (0 = как в последовательности)"
"export.bitrate": "Битрейт (0 = по умолчанию кодекa)"
"export.color.hdr": "HDR — BT.2020 10 бит"
"export.range": "Диапазон экспорта"
"export.range.all": "Вся таймлиния"
+3
View File
@@ -377,6 +377,9 @@
"export.audio_codec": "音频编码"
"export.color": "色域/色深"
"export.color.sdr": "SDR — Rec.709 8 位"
"export.resolution": "分辨率(0 = 跟随序列)"
"export.framerate": "帧率(0 = 跟随序列)"
"export.bitrate": "码率(0 = 编码器默认)"
"export.color.hdr": "HDR — BT.2020 10 位"
"export.range": "导出范围"
"export.range.all": "整条时间轴"
+80 -6
View File
@@ -997,6 +997,10 @@ pub struct ExportDialogContent {
audio_codec: Entity<ComboBox>,
color: Entity<ComboBox>,
range: Entity<ComboBox>,
resolution_w: Entity<SpinBox>,
resolution_h: Entity<SpinBox>,
frame_rate: Entity<SpinBox>,
bitrate: Entity<SpinBox>,
path: Entity<PathField>,
/// (format id, display name, extension) in dropdown order.
formats: Vec<(i32, String, String)>,
@@ -1101,6 +1105,43 @@ impl ExportDialogContent {
});
range.update(cx, |combo, cx| combo.set_selected(Some(0), cx));
// Resolution / frame rate / bitrate SPIN boxes: 0 = keep the
// sequence's / the codec's default (the engine treats 0 that way),
// any typed value is honored (the backend accepts arbitrary
// width/height/rate/bitrate).
let resolution_w = cx.new(|cx| {
SpinBox::new(
9,
SliderModel::new(ValueKind::Integer, 0.0, 16384.0, 4.0, 0.0),
window,
cx,
)
});
let resolution_h = cx.new(|cx| {
SpinBox::new(
12,
SliderModel::new(ValueKind::Integer, 0.0, 16384.0, 4.0, 0.0),
window,
cx,
)
});
let frame_rate = cx.new(|cx| {
SpinBox::new(
10,
SliderModel::new(ValueKind::Float, 0.0, 240.0, 0.1, 0.0),
window,
cx,
)
});
let bitrate = cx.new(|cx| {
SpinBox::new(
11,
SliderModel::new(ValueKind::Integer, 0.0, 500_000_000.0, 1_000_000.0, 0.0),
window,
cx,
)
});
let path = cx.new(|cx| {
let editor = cx.new(|cx| EditableTextState::new(StringStorage::default(), cx));
PathField {
@@ -1115,6 +1156,10 @@ impl ExportDialogContent {
audio_codec,
color,
range,
resolution_w,
resolution_h,
frame_rate,
bitrate,
path,
formats,
active_format,
@@ -1197,9 +1242,10 @@ impl ExportDialogContent {
cx.notify();
}
/// The full export settings (codec/color/bit-depth/range) the engine
/// consumes. The codec combos expose only the container's compatible
/// codes, so the picked ids are always valid for `format`.
/// The full export settings (codec/color/bit-depth/range/size/fps/
/// bitrate) the engine consumes. The codec combos expose only the
/// container's compatible codes, so the picked ids are always valid
/// for `format`.
pub fn settings(&self, cx: &App) -> crate::oakui::engine::ExportSettings {
let video_codec = compatible_video_codecs(self.active_format)
.get(self.video_codec.read(cx).selected().unwrap_or(0))
@@ -1211,13 +1257,18 @@ impl ExportDialogContent {
.unwrap_or(12);
let hdr = self.color.read(cx).selected() == Some(1);
let in_out = self.range.read(cx).selected() == Some(1);
let w = self.resolution_w.read(cx).value().to_f64().round() as i32;
let h = self.resolution_h.read(cx).value().to_f64().round() as i32;
let size = if w > 0 && h > 0 { (w, h) } else { (0, 0) };
let frame_rate = self.frame_rate.read(cx).value().to_f64();
let video_bitrate = self.bitrate.read(cx).value().to_f64().round() as i64;
crate::oakui::engine::ExportSettings {
format: self.active_format,
video_codec,
audio_codec,
size: (0, 0),
frame_rate: 0.0,
video_bitrate: 0,
size,
frame_rate,
video_bitrate,
audio_bitrate: 0,
bit_depth: if hdr { 10 } else { 8 },
color_primaries: if hdr { 9 } else { 1 },
@@ -1284,6 +1335,29 @@ impl Render for ExportDialogContent {
i18n::tr("export.range").into(),
self.range.clone(),
))
.child(form_row(
&colors,
i18n::tr("export.resolution").into(),
div()
.flex()
.gap_2()
.child(self.resolution_w.clone())
.child(div()
.text_color(colors.disabled)
.text_xs()
.child("×"))
.child(self.resolution_h.clone()),
))
.child(form_row(
&colors,
i18n::tr("export.framerate").into(),
self.frame_rate.clone(),
))
.child(form_row(
&colors,
i18n::tr("export.bitrate").into(),
self.bitrate.clone(),
))
.child(form_row(
&colors,
i18n::tr("export.path").into(),