Merge pull request #682 from vangel76/fix-342-prores-4444-export
#342: ProRes 4444 and 4444 XQ export, with alpha
This commit is contained in:
commit
73723151ce
|
|
@ -1264,7 +1264,7 @@ fn build() -> Vec<CommandSpec> {
|
|||
"Media…",
|
||||
["File", "Export"],
|
||||
None,
|
||||
r#"{"path":str,"preset":str?,"settings":ExportSettings?,"format":"h264|hevc|prores|dnxhr|apv|mjpeg|mxf-op1a|mxf-opatom|png|tiff|bmp|gif|wav|aiff"?,"width":u32?,"height":u32?,"fps":f64?,"bitrateKbps":u32?,"bitrateMode":"cbr|vbr1Pass|vbr2Pass|crf"?,"crf":0..51=23,"hardwareEncoding":"off|auto"?,"scale":f32=1,"audio":bool=true,"quality":0..100,"burnCaptions":bool=false,"alpha":bool=false,"captionSidecar":"srt|vtt"?,"loudnessLufs":f64?,"proresProfile":"proxy|lt|standard|hq"?,"dnxProfile":"lb|sq|hq|hqx"?,"apvProfile":"422-10|422-12|444-10|444-12"?,"mxfVideoCodec":"dnxhr|proRes|h264"?,"sequence":id?,"range":"entire|inOut|workArea|custom"?,"startSeconds":f64?,"endSeconds":f64?,"wait":bool=false}"#,
|
||||
r#"{"path":str,"preset":str?,"settings":ExportSettings?,"format":"h264|hevc|prores|dnxhr|apv|mjpeg|mxf-op1a|mxf-opatom|png|tiff|bmp|gif|wav|aiff"?,"width":u32?,"height":u32?,"fps":f64?,"bitrateKbps":u32?,"bitrateMode":"cbr|vbr1Pass|vbr2Pass|crf"?,"crf":0..51=23,"hardwareEncoding":"off|auto"?,"scale":f32=1,"audio":bool=true,"quality":0..100,"burnCaptions":bool=false,"alpha":bool=false,"captionSidecar":"srt|vtt"?,"loudnessLufs":f64?,"proresProfile":"proxy|lt|standard|hq|4444|4444xq"?,"dnxProfile":"lb|sq|hq|hqx"?,"apvProfile":"422-10|422-12|444-10|444-12"?,"mxfVideoCodec":"dnxhr|proRes|h264"?,"sequence":id?,"range":"entire|inOut|workArea|custom"?,"startSeconds":f64?,"endSeconds":f64?,"wait":bool=false}"#,
|
||||
has_seq,
|
||||
crate::export_tools::export_media
|
||||
),
|
||||
|
|
|
|||
|
|
@ -217,9 +217,16 @@ fn every_builtin_preset_exports_and_ffprobe_confirms() {
|
|||
"proxy" => ("Proxy", 45.0),
|
||||
"lt" => ("LT", 102.0),
|
||||
"standard" => ("Standard", 147.0),
|
||||
"4444" => ("4444", 330.0),
|
||||
"4444xq" => ("XQ", 500.0),
|
||||
_ => ("HQ", 220.0),
|
||||
};
|
||||
assert_eq!(v["profile"], profile, "{name}");
|
||||
if matches!(profile, "4444" | "XQ") {
|
||||
let pix = v["pix_fmt"].as_str().unwrap_or_default();
|
||||
let alpha = settings["alpha"].as_bool().unwrap_or(false);
|
||||
assert!(pix.contains("444") && pix.starts_with("yuva") == alpha, "{name}: {pix}");
|
||||
}
|
||||
assert!(vbr <= mbps * px * 1.5, "{name}: {vbr:.1} Mb/s vs nominal {:.1}", mbps * px);
|
||||
assert_eq!(a["codec_name"], "pcm_s24le", "{name}");
|
||||
}
|
||||
|
|
@ -318,7 +325,7 @@ fn user_presets_persist_with_favourites_import_and_export() {
|
|||
let favs = s.execute("export.presets.list", json!({"favorites": true})).unwrap()["presets"].as_array().unwrap().len();
|
||||
assert_eq!(favs, 2);
|
||||
let hits = s.execute("export.presets.list", json!({"query": "prores"})).unwrap()["presets"].as_array().unwrap().len();
|
||||
assert_eq!(hits, 5, "four QuickTime ProRes presets and MXF OP1a ProRes 422 HQ");
|
||||
assert_eq!(hits, 8, "seven QuickTime ProRes presets and MXF OP1a ProRes 422 HQ");
|
||||
// persisted: a fresh session with the same data directory sees both
|
||||
let mut s2 = demo();
|
||||
s2.export_presets.set_dir(&dir.0);
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ pub struct ExportSettings {
|
|||
/// `progress.total`, `finished` and the final status; this call only adds to `done`.
|
||||
#[serde(default)]
|
||||
pub part_of_batch: bool,
|
||||
/// ProRes flavour: `proxy`, `lt`, `standard` or `hq` (empty = HQ).
|
||||
/// ProRes flavour: `proxy`, `lt`, `standard`, `hq`, `4444` or `4444xq` (empty = HQ).
|
||||
#[serde(default)]
|
||||
pub prores_profile: String,
|
||||
/// DNxHR profile: `lb`, `sq`, `hq` or `hqx` (empty = HQ).
|
||||
|
|
@ -256,8 +256,9 @@ pub struct ExportSettings {
|
|||
/// sequence's HDR space and signal it (VUI / `colr` / `mdcv` / `clli` / SEI).
|
||||
#[serde(default)]
|
||||
pub sdr: bool,
|
||||
/// Keep the alpha channel in PNG and TIFF sequences (straight alpha, Premiere's "Include
|
||||
/// Alpha Channel"). Off, every frame is flattened over black (#160). Other formats ignore it.
|
||||
/// Keep the alpha channel in PNG and TIFF sequences and ProRes 4444 / 4444 XQ QuickTime movies
|
||||
/// (straight alpha, Premiere's "Include Alpha Channel"). Off, every frame is flattened over
|
||||
/// black (#160). Other formats ignore it.
|
||||
#[serde(default)]
|
||||
pub alpha: bool,
|
||||
/// Output frame size (None = Match Source: the sequence size times `scale`).
|
||||
|
|
@ -1006,6 +1007,8 @@ fn aac_factory(_format: Format, sample_rate: u32, channels: u32, s: &ExportSetti
|
|||
struct ProResEncoder {
|
||||
enc: filmcraft_prores::Encoder,
|
||||
profile: filmcraft_prores::Profile,
|
||||
/// Code the frames' alpha channel (4444 profiles with Include Alpha Channel).
|
||||
alpha: bool,
|
||||
w: u32,
|
||||
h: u32,
|
||||
rate: FrameRate,
|
||||
|
|
@ -1022,13 +1025,19 @@ impl VideoEncoder for ProResEncoder {
|
|||
self.rate.num as u32
|
||||
}
|
||||
fn encode(&mut self, f: &EncoderFrame) -> Result<Vec<EncodedPacket>> {
|
||||
let mut fr = filmcraft_prores::Frame::new(f.width, f.height, filmcraft_prores::ChromaFormat::Yuv422, 10, false);
|
||||
timed(Stage::Convert, || match f.hdr {
|
||||
Some(rgb) => {
|
||||
let (kr, kb) = self.signal.kr_kb();
|
||||
rgbf_to_yuv422_10(rgb, f.width as usize, f.height as usize, kr, kb, &mut fr.y, &mut fr.cb, &mut fr.cr)
|
||||
let chroma = self.profile.chroma();
|
||||
let mut fr = filmcraft_prores::Frame::new(f.width, f.height, chroma, 10, self.alpha);
|
||||
let (w, h) = (f.width as usize, f.height as usize);
|
||||
timed(Stage::Convert, || match (chroma, f.hdr) {
|
||||
(filmcraft_prores::ChromaFormat::Yuv444, hdr) => {
|
||||
let (kr, kb) = if hdr.is_some() { self.signal.kr_kb() } else { (0.2126, 0.0722) };
|
||||
to_yuv444_10(f.rgba, hdr, w, h, kr, kb, &mut fr.y, &mut fr.cb, &mut fr.cr, fr.alpha.as_deref_mut())
|
||||
}
|
||||
None => rgba_to_yuv422_10(f.rgba, f.width as usize, f.height as usize, &mut fr.y, &mut fr.cb, &mut fr.cr),
|
||||
(_, Some(rgb)) => {
|
||||
let (kr, kb) = self.signal.kr_kb();
|
||||
rgbf_to_yuv422_10(rgb, w, h, kr, kb, &mut fr.y, &mut fr.cb, &mut fr.cr)
|
||||
}
|
||||
(_, None) => rgba_to_yuv422_10(f.rgba, w, h, &mut fr.y, &mut fr.cb, &mut fr.cr),
|
||||
});
|
||||
let data = self.enc.encode(&fr).map_err(|e| ExportError::Encode(e.to_string()))?;
|
||||
Ok(vec![EncodedPacket { data, key: true, duration: self.rate.den as u32, composition_offset: 0 }])
|
||||
|
|
@ -1038,6 +1047,47 @@ impl VideoEncoder for ProResEncoder {
|
|||
}
|
||||
}
|
||||
|
||||
/// Limited-range 10-bit 4:4:4 with matrix (Kr, Kb) from straight RGBA8, or from encoded R'G'B'
|
||||
/// floats (3 per pixel) when `hdr` is given. `alpha` (full range, 0 = transparent) takes the
|
||||
/// RGBA8 alpha; it stays opaque for float input, which carries none.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn to_yuv444_10(
|
||||
rgba: &[u8],
|
||||
hdr: Option<&[f32]>,
|
||||
w: usize,
|
||||
h: usize,
|
||||
kr: f32,
|
||||
kb: f32,
|
||||
y: &mut [u16],
|
||||
cb: &mut [u16],
|
||||
cr: &mut [u16],
|
||||
alpha: Option<&mut [u16]>,
|
||||
) {
|
||||
let (w, n) = (w.max(1), w.saturating_mul(h));
|
||||
let kg = 1.0 - kr - kb;
|
||||
let (sb, sr) = (2.0 * (1.0 - kb), 2.0 * (1.0 - kr));
|
||||
let rgb_at = |i: usize| -> [f32; 3] {
|
||||
match hdr {
|
||||
Some(f) => f.get(i * 3..i * 3 + 3).map_or([0.0; 3], |p| [p[0], p[1], p[2]]),
|
||||
None => rgba.get(i * 4..i * 4 + 3).map_or([0.0; 3], |p| [p[0] as f32 / 255.0, p[1] as f32 / 255.0, p[2] as f32 / 255.0]),
|
||||
}
|
||||
};
|
||||
y.par_chunks_mut(w).zip(cb.par_chunks_mut(w).zip(cr.par_chunks_mut(w))).enumerate().for_each(|(row, (yr, (cbr, crr)))| {
|
||||
for (x, (yv, (cbv, crv))) in yr.iter_mut().zip(cbr.iter_mut().zip(crr.iter_mut())).enumerate() {
|
||||
let [r, g, b] = rgb_at(row * w + x);
|
||||
let yy = kr * r + kg * g + kb * b;
|
||||
*yv = (64.0 + 876.0 * yy).round().clamp(4.0, 1019.0) as u16;
|
||||
*cbv = (512.0 + 896.0 * (b - yy) / sb).round().clamp(4.0, 1019.0) as u16;
|
||||
*crv = (512.0 + 896.0 * (r - yy) / sr).round().clamp(4.0, 1019.0) as u16;
|
||||
}
|
||||
});
|
||||
if let (Some(a), None) = (alpha, hdr) {
|
||||
for (i, dst) in a.iter_mut().enumerate().take(n) {
|
||||
*dst = rgba.get(i * 4 + 3).map_or(1023, |&v| ((v as u32 * 1023 + 127) / 255) as u16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// BT.709 limited-range 10-bit 4:2:2 from straight RGBA8 (chroma averaged horizontally).
|
||||
pub fn rgba_to_yuv422_10(rgba: &[u8], w: usize, h: usize, y: &mut [u16], cb: &mut [u16], cr: &mut [u16]) {
|
||||
let cw = w.div_ceil(2);
|
||||
|
|
@ -1071,6 +1121,8 @@ pub fn prores_profile(name: &str) -> filmcraft_prores::Profile {
|
|||
"proxy" => Profile::Proxy,
|
||||
"lt" => Profile::Lt,
|
||||
"standard" | "422" => Profile::Standard,
|
||||
"4444" => Profile::P4444,
|
||||
"4444xq" | "4444 xq" | "4444-xq" | "xq" => Profile::P4444Xq,
|
||||
_ => Profile::Hq,
|
||||
}
|
||||
}
|
||||
|
|
@ -1109,7 +1161,10 @@ fn prores_factory(format: Format, w: u32, h: u32, rate: FrameRate, s: &ExportSet
|
|||
if s.signal.is_hdr() {
|
||||
cfg.color = filmcraft_prores::ColorInfo { primaries: s.signal.primaries, transfer: s.signal.transfer, matrix: s.signal.matrix };
|
||||
}
|
||||
Ok(Box::new(ProResEncoder { enc: filmcraft_prores::Encoder::with_config(cfg), profile, w, h, rate, signal: s.signal }) as Box<dyn VideoEncoder>)
|
||||
let alpha = s.keeps_alpha();
|
||||
cfg.encode_alpha = alpha;
|
||||
let enc = filmcraft_prores::Encoder::with_config(cfg);
|
||||
Ok(Box::new(ProResEncoder { enc, profile, alpha, w, h, rate, signal: s.signal }) as Box<dyn VideoEncoder>)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ fn picture(settings: &ExportSettings, w: u32, h: u32) -> PictureDesc {
|
|||
Profile::Proxy => 1,
|
||||
Profile::Lt => 2,
|
||||
Profile::Standard => 3,
|
||||
_ => 4,
|
||||
Profile::Hq => 4,
|
||||
Profile::P4444 => 5,
|
||||
Profile::P4444Xq => 6,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -53,9 +55,6 @@ fn picture(settings: &ExportSettings, w: u32, h: u32) -> PictureDesc {
|
|||
_ => PictureCoding::Vc3 { cid: crate::dnx_profile(&settings.dnx_profile).cid() },
|
||||
};
|
||||
let mut d = PictureDesc::new(coding, w, h);
|
||||
if matches!(coding, PictureCoding::ProRes { .. }) {
|
||||
d.depth = 10;
|
||||
}
|
||||
d.color = match settings.signal {
|
||||
s if s == ColorSignal::PQ => ColorSpace::Rec2020Pq,
|
||||
s if s == ColorSignal::HLG => ColorSpace::Rec2020Hlg,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use filmcraft_time::FrameRate;
|
|||
use rayon::prelude::*;
|
||||
|
||||
use crate::settings::{ExportEffects, Placement, Scaling, TextOverlay};
|
||||
use crate::{ExportError, ExportSettings, Format, FrameRenderer, GpuRendering, Result, build_frame_renderer, note_gpu_fallback, note_gpu_frame};
|
||||
use crate::{ExportError, ExportSettings, FrameRenderer, GpuRendering, Result, build_frame_renderer, note_gpu_fallback, note_gpu_frame};
|
||||
|
||||
/// Where the rendered picture lands in the output frame.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
|
|
@ -201,7 +201,7 @@ impl Pipeline {
|
|||
geom,
|
||||
opts,
|
||||
hdr_out,
|
||||
alpha: settings.alpha && matches!(settings.format, Format::PngSequence | Format::TiffSequence),
|
||||
alpha: settings.keeps_alpha(),
|
||||
out_tf,
|
||||
effects,
|
||||
overlay,
|
||||
|
|
|
|||
|
|
@ -122,6 +122,14 @@ pub fn builtin_presets() -> Vec<ExportPreset> {
|
|||
p("Apple ProRes 422", bc, "QuickTime, ProRes 422, 24-bit 48 kHz PCM", mov(Format::ProRes, "standard")),
|
||||
p("Apple ProRes 422 LT", bc, "QuickTime, ProRes 422 LT, 24-bit 48 kHz PCM", mov(Format::ProRes, "lt")),
|
||||
p("Apple ProRes 422 Proxy", bc, "QuickTime, ProRes 422 Proxy, 24-bit 48 kHz PCM", mov(Format::ProRes, "proxy")),
|
||||
p("Apple ProRes 4444", bc, "QuickTime, ProRes 4444 (4:4:4), 24-bit 48 kHz PCM", mov(Format::ProRes, "4444")),
|
||||
p(
|
||||
"Apple ProRes 4444 with Alpha",
|
||||
bc,
|
||||
"QuickTime, ProRes 4444 (4:4:4) with alpha channel, 24-bit 48 kHz PCM",
|
||||
ExportSettings { alpha: true, ..mov(Format::ProRes, "4444") },
|
||||
),
|
||||
p("Apple ProRes 4444 XQ", bc, "QuickTime, ProRes 4444 XQ (4:4:4), 24-bit 48 kHz PCM", mov(Format::ProRes, "4444xq")),
|
||||
p("Avid DNxHR HQ", bc, "QuickTime, DNxHR HQ (8-bit 4:2:2), 24-bit 48 kHz PCM", mov(Format::DnxHr, "hq")),
|
||||
p("Avid DNxHR SQ", bc, "QuickTime, DNxHR SQ (8-bit 4:2:2), 24-bit 48 kHz PCM", mov(Format::DnxHr, "sq")),
|
||||
p("Avid DNxHR LB", bc, "QuickTime, DNxHR LB (8-bit 4:2:2), 24-bit 48 kHz PCM", mov(Format::DnxHr, "lb")),
|
||||
|
|
|
|||
|
|
@ -378,6 +378,21 @@ impl ExportSettings {
|
|||
if self.format.is_mxf() { self.mxf_video_codec.encoder_format() } else { self.format }
|
||||
}
|
||||
|
||||
/// Whether the output can carry an alpha channel ([`ExportSettings::alpha`]): PNG and TIFF
|
||||
/// sequences and ProRes 4444 / 4444 XQ QuickTime movies.
|
||||
pub fn supports_alpha(&self) -> bool {
|
||||
match self.format {
|
||||
Format::PngSequence | Format::TiffSequence => true,
|
||||
Format::ProRes => crate::prores_profile(&self.prores_profile).chroma() == filmcraft_prores::ChromaFormat::Yuv444,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the exported frames keep their alpha channel instead of being flattened over black.
|
||||
pub fn keeps_alpha(&self) -> bool {
|
||||
self.alpha && self.supports_alpha()
|
||||
}
|
||||
|
||||
/// Whether the output is a numbered image sequence.
|
||||
pub fn is_image_sequence(&self) -> bool {
|
||||
matches!(self.format, Format::PngSequence | Format::TiffSequence | Format::BmpSequence)
|
||||
|
|
@ -536,7 +551,9 @@ impl ExportSettings {
|
|||
Profile::Proxy => ", ProRes 422 Proxy",
|
||||
Profile::Lt => ", ProRes 422 LT",
|
||||
Profile::Standard => ", ProRes 422",
|
||||
_ => ", ProRes 422 HQ",
|
||||
Profile::Hq => ", ProRes 422 HQ",
|
||||
Profile::P4444 => ", ProRes 4444",
|
||||
Profile::P4444Xq => ", ProRes 4444 XQ",
|
||||
}
|
||||
}
|
||||
Format::DnxHr => v += &format!(", DNxHR {}", if self.dnx_profile.is_empty() { "HQ".into() } else { self.dnx_profile.to_ascii_uppercase() }),
|
||||
|
|
|
|||
|
|
@ -101,6 +101,51 @@ fn prores_export_roundtrip() {
|
|||
assert!(f[0] > 240 && f[1] < 15 && f[2] < 15, "{:?}", &f[..4]);
|
||||
}
|
||||
|
||||
/// ProRes 4444 / 4444 XQ export (#342): 4:4:4 frames under the `ap4h` / `ap4x` codes, and with
|
||||
/// Include Alpha Channel the picture's alpha survives instead of being flattened over black.
|
||||
#[test]
|
||||
fn prores_4444_export_roundtrip() {
|
||||
let (p, seq, m) = project();
|
||||
for (profile, label) in [("4444", "ProRes 4444"), ("4444xq", "ProRes 4444 XQ")] {
|
||||
let path = tmp(&format!("pr_{profile}.mov"));
|
||||
let s = ExportSettings { format: Format::ProRes, path: path.clone(), prores_profile: profile.into(), ..Default::default() };
|
||||
export(&p, seq, &s, &m, &Progress::default()).unwrap();
|
||||
let bytes: Arc<[u8]> = std::fs::read(&path).unwrap().into();
|
||||
let src = filmcraft_codecs::open_bytes("pr.mov", bytes).unwrap();
|
||||
let codec = src.info().video.as_ref().unwrap().codec.clone();
|
||||
assert!(codec.contains(label), "{profile}: {codec}");
|
||||
let f = src.video_frame(FrameRequest::full(Tick(TICKS_PER_SECOND / 3))).unwrap();
|
||||
assert!(f.format_label().contains("4:4:4"), "{profile}: {}", f.format_label());
|
||||
let px = f.to_rgba8();
|
||||
assert!(px[0] > 240 && px[1] < 15 && px[2] < 15 && px[3] == 255, "{profile}: {:?}", &px[..4]);
|
||||
}
|
||||
|
||||
// a half-transparent matte keeps its alpha with Include Alpha Channel, and only then
|
||||
let mut p = (*p).clone();
|
||||
let half = GeneratorSource::new(Generator::ColorMatte { color: [1.0, 0.0, 0.0, 0.5] }, 320, 180, FrameRate::FPS_24, Tick(2 * TICKS_PER_SECOND));
|
||||
let item = p.sequence(seq).unwrap().video_tracks[0].items[0].item;
|
||||
if let ItemKind::Media(mc) = &mut p.item_mut(item).unwrap().kind {
|
||||
mc.media = MediaRef::Generator(half.generator.clone());
|
||||
}
|
||||
let mut m = m;
|
||||
m.0.insert(item, Arc::new(half));
|
||||
let p = Arc::new(p);
|
||||
for alpha in [true, false] {
|
||||
let path = tmp(&format!("pr_4444_alpha_{alpha}.mov"));
|
||||
let s = ExportSettings { format: Format::ProRes, path: path.clone(), prores_profile: "4444".into(), alpha, ..Default::default() };
|
||||
assert!(s.keeps_alpha() == alpha);
|
||||
export(&p, seq, &s, &m, &Progress::default()).unwrap();
|
||||
let bytes: Arc<[u8]> = std::fs::read(&path).unwrap().into();
|
||||
let src = filmcraft_codecs::open_bytes("pr.mov", bytes).unwrap();
|
||||
let px = src.video_frame(FrameRequest::full(Tick(TICKS_PER_SECOND / 3))).unwrap().to_rgba8();
|
||||
if alpha {
|
||||
assert!((px[3] as i32 - 128).abs() <= 3, "alpha kept: {:?}", &px[..4]);
|
||||
} else {
|
||||
assert_eq!(px[3], 255, "flattened: {:?}", &px[..4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dnxhr_export_roundtrip() {
|
||||
let (p, seq, m) = project();
|
||||
|
|
|
|||
|
|
@ -2985,6 +2985,9 @@
|
|||
Apple ProRes 422 HQ Apple ProRes 422 HQ
|
||||
Apple ProRes 422 LT Apple ProRes 422 LT
|
||||
Apple ProRes 422 Proxy Apple ProRes 422 Proxy
|
||||
Apple ProRes 4444 Apple ProRes 4444
|
||||
Apple ProRes 4444 with Alpha Apple ProRes 4444 con alfa
|
||||
Apple ProRes 4444 XQ Apple ProRes 4444 XQ
|
||||
Application Aplicación
|
||||
Apply Guide Template Aplicar plantilla de guías
|
||||
Auto Save Now Guardar automáticamente ahora
|
||||
|
|
@ -3194,6 +3197,9 @@
|
|||
QuickTime, ProRes 422 HQ, 24-bit 48 kHz PCM QuickTime, ProRes 422 HQ, PCM de 24 bits y 48 kHz
|
||||
QuickTime, ProRes 422 LT, 24-bit 48 kHz PCM QuickTime, ProRes 422 LT, PCM de 24 bits y 48 kHz
|
||||
QuickTime, ProRes 422 Proxy, 24-bit 48 kHz PCM QuickTime, ProRes 422 Proxy, PCM de 24 bits y 48 kHz
|
||||
QuickTime, ProRes 4444 (4:4:4), 24-bit 48 kHz PCM QuickTime, ProRes 4444 (4:4:4), PCM de 24 bits y 48 kHz
|
||||
QuickTime, ProRes 4444 (4:4:4) with alpha channel, 24-bit 48 kHz PCM QuickTime, ProRes 4444 (4:4:4) con canal alfa, PCM de 24 bits y 48 kHz
|
||||
QuickTime, ProRes 4444 XQ (4:4:4), 24-bit 48 kHz PCM QuickTime, ProRes 4444 XQ (4:4:4), PCM de 24 bits y 48 kHz
|
||||
QuickTime, ProRes 422, 24-bit 48 kHz PCM QuickTime, ProRes 422, PCM de 24 bits y 48 kHz
|
||||
Quit FilmCraft Salir de FilmCraft
|
||||
Rate Stretch Tool Herramienta Ajuste de velocidad
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 3 and column 95.
|
|
|
@ -2975,6 +2975,9 @@
|
|||
Apple ProRes 422 HQ Apple ProRes 422 HQ
|
||||
Apple ProRes 422 LT Apple ProRes 422 LT
|
||||
Apple ProRes 422 Proxy Apple ProRes 422 Proxy
|
||||
Apple ProRes 4444 Apple ProRes 4444
|
||||
Apple ProRes 4444 with Alpha Apple ProRes 4444(アルファ付き)
|
||||
Apple ProRes 4444 XQ Apple ProRes 4444 XQ
|
||||
Application アプリケーション
|
||||
Apply Guide Template ガイドテンプレートを適用
|
||||
Auto Save Now 今すぐ自動保存
|
||||
|
|
@ -3184,6 +3187,9 @@
|
|||
QuickTime, ProRes 422 HQ, 24-bit 48 kHz PCM QuickTime、ProRes 422 HQ、24-bit 48 kHz PCM
|
||||
QuickTime, ProRes 422 LT, 24-bit 48 kHz PCM QuickTime、ProRes 422 LT、24-bit 48 kHz PCM
|
||||
QuickTime, ProRes 422 Proxy, 24-bit 48 kHz PCM QuickTime、ProRes 422 Proxy、24-bit 48 kHz PCM
|
||||
QuickTime, ProRes 4444 (4:4:4), 24-bit 48 kHz PCM QuickTime、ProRes 4444 (4:4:4)、24-bit 48 kHz PCM
|
||||
QuickTime, ProRes 4444 (4:4:4) with alpha channel, 24-bit 48 kHz PCM QuickTime、ProRes 4444 (4:4:4) アルファチャンネル付き、24-bit 48 kHz PCM
|
||||
QuickTime, ProRes 4444 XQ (4:4:4), 24-bit 48 kHz PCM QuickTime、ProRes 4444 XQ (4:4:4)、24-bit 48 kHz PCM
|
||||
QuickTime, ProRes 422, 24-bit 48 kHz PCM QuickTime、ProRes 422、24-bit 48 kHz PCM
|
||||
Quit FilmCraft FilmCraft を終了
|
||||
Rate Stretch Tool レートストレッチツール
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 11 and column 59.
|
|
|
@ -2968,6 +2968,9 @@
|
|||
Apple ProRes 422 HQ Apple ProRes 422 HQ
|
||||
Apple ProRes 422 LT Apple ProRes 422 LT
|
||||
Apple ProRes 422 Proxy Apple ProRes 422 Proxy
|
||||
Apple ProRes 4444 Apple ProRes 4444
|
||||
Apple ProRes 4444 with Alpha Apple ProRes 4444(带 Alpha)
|
||||
Apple ProRes 4444 XQ Apple ProRes 4444 XQ
|
||||
Application 应用程序
|
||||
Apply Guide Template 应用参考线模板
|
||||
Auto Save Now 立即自动保存
|
||||
|
|
@ -3177,6 +3180,9 @@
|
|||
QuickTime, ProRes 422 HQ, 24-bit 48 kHz PCM QuickTime,ProRes 422 HQ,24 位 48 kHz PCM
|
||||
QuickTime, ProRes 422 LT, 24-bit 48 kHz PCM QuickTime,ProRes 422 LT,24 位 48 kHz PCM
|
||||
QuickTime, ProRes 422 Proxy, 24-bit 48 kHz PCM QuickTime,ProRes 422 Proxy,24 位 48 kHz PCM
|
||||
QuickTime, ProRes 4444 (4:4:4), 24-bit 48 kHz PCM QuickTime,ProRes 4444 (4:4:4),24 位 48 kHz PCM
|
||||
QuickTime, ProRes 4444 (4:4:4) with alpha channel, 24-bit 48 kHz PCM QuickTime,ProRes 4444 (4:4:4),带 Alpha 通道,24 位 48 kHz PCM
|
||||
QuickTime, ProRes 4444 XQ (4:4:4), 24-bit 48 kHz PCM QuickTime,ProRes 4444 XQ (4:4:4),24 位 48 kHz PCM
|
||||
QuickTime, ProRes 422, 24-bit 48 kHz PCM QuickTime,ProRes 422,24 位 48 kHz PCM
|
||||
Quit FilmCraft 退出 FilmCraft
|
||||
Rate Stretch Tool 速率伸缩工具
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 3 and column 95.
|
|
|
@ -606,7 +606,7 @@ fn video_section(ui: &mut egui::Ui, reg: &mut Reg, s: &mut ExportSettings, t: &T
|
|||
}
|
||||
});
|
||||
}
|
||||
if matches!(s.format, Format::PngSequence | Format::TiffSequence) {
|
||||
if s.supports_alpha() {
|
||||
row(ui, t, tl!("Alpha"), |ui| {
|
||||
check(ui, reg, "export.video.alpha", &mut s.alpha, tl!("Include Alpha Channel"));
|
||||
});
|
||||
|
|
@ -708,8 +708,9 @@ fn video_section(ui: &mut egui::Ui, reg: &mut Reg, s: &mut ExportSettings, t: &T
|
|||
}
|
||||
Format::ProRes => {
|
||||
row(ui, t, tl!("Profile"), |ui| {
|
||||
let keys = ["proxy", "lt", "standard", "hq"];
|
||||
let labels = ["Apple ProRes 422 Proxy", "Apple ProRes 422 LT", "Apple ProRes 422", "Apple ProRes 422 HQ"];
|
||||
let keys = ["proxy", "lt", "standard", "hq", "4444", "4444xq"];
|
||||
let labels =
|
||||
["Apple ProRes 422 Proxy", "Apple ProRes 422 LT", "Apple ProRes 422", "Apple ProRes 422 HQ", "Apple ProRes 4444", "Apple ProRes 4444 XQ"];
|
||||
let cur = keys.iter().position(|k| *k == s.prores_profile).unwrap_or(3);
|
||||
if let Some(i) = combo(ui, reg, "export.video.proresProfile", labels[cur], &opts(&labels), 220.0) {
|
||||
s.prores_profile = keys[i].into();
|
||||
|
|
|
|||
Loading…
Reference in New Issue