add assets; some cmd building
This commit is contained in:
parent
ffad525857
commit
c55906f70a
4 changed files with 307 additions and 3 deletions
8
assets/fastforward.svg
Normal file
8
assets/fastforward.svg
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<style type="text/css" id="current-color-scheme">
|
||||||
|
.ColorScheme-Text {
|
||||||
|
color:#eff0f1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<path d="m8 2v12l7-6zm-7 0v12l7-6z" class="ColorScheme-Text" fill="currentColor"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 287 B |
199
assets/logo.svg
Normal file
199
assets/logo.svg
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="299.99982"
|
||||||
|
height="300.00003"
|
||||||
|
id="svg2"
|
||||||
|
sodipodi:version="0.32"
|
||||||
|
inkscape:version="0.46"
|
||||||
|
sodipodi:docbase="C:\Eigene Dateien\Video AG"
|
||||||
|
sodipodi:docname="logo.svg"
|
||||||
|
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||||
|
version="1.0"
|
||||||
|
inkscape:export-filename="Q:\video AG\fs-pub-video\folien\logo-1024.png"
|
||||||
|
inkscape:export-xdpi="307.20001"
|
||||||
|
inkscape:export-ydpi="307.20001">
|
||||||
|
<defs
|
||||||
|
id="defs4">
|
||||||
|
<inkscape:perspective
|
||||||
|
sodipodi:type="inkscape:persp3d"
|
||||||
|
inkscape:vp_x="0 : 526.18109 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||||
|
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||||
|
id="perspective21" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2041">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1.0000000;"
|
||||||
|
offset="0.00000000"
|
||||||
|
id="stop2043" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#7d7d7d;stop-opacity:1.0000000;"
|
||||||
|
offset="1.0000000"
|
||||||
|
id="stop2045" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2041"
|
||||||
|
id="linearGradient2047"
|
||||||
|
x1="194.17578"
|
||||||
|
y1="139.59265"
|
||||||
|
x2="250.03906"
|
||||||
|
y2="139.59265"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(317,-57)" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1.4889823"
|
||||||
|
inkscape:cx="71.681092"
|
||||||
|
inkscape:cy="217.8489"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:window-width="1400"
|
||||||
|
inkscape:window-height="988"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:snap-bbox="false"
|
||||||
|
inkscape:snap-nodes="true"
|
||||||
|
inkscape:object-paths="false"
|
||||||
|
inkscape:object-nodes="true"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10000"
|
||||||
|
guidetolerance="10000"
|
||||||
|
showborder="true"
|
||||||
|
inkscape:showpageshadow="true"
|
||||||
|
borderlayer="false" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-438.99979,0.6379836)">
|
||||||
|
<path
|
||||||
|
sodipodi:type="arc"
|
||||||
|
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||||
|
id="path2393"
|
||||||
|
sodipodi:cx="454"
|
||||||
|
sodipodi:cy="112.36218"
|
||||||
|
sodipodi:rx="87"
|
||||||
|
sodipodi:ry="56"
|
||||||
|
d="M 541,112.36218 A 87,56 0 1 1 367,112.36218 A 87,56 0 1 1 541,112.36218 z"
|
||||||
|
transform="matrix(-1.977323e-3,-1.724137,2.678569,-3.071905e-3,288.9275,932.4654)"
|
||||||
|
inkscape:export-filename="C:\Eigene Dateien\Video AG\logo.png"
|
||||||
|
inkscape:export-xdpi="90.000000"
|
||||||
|
inkscape:export-ydpi="90.000000" />
|
||||||
|
<path
|
||||||
|
sodipodi:type="arc"
|
||||||
|
style="opacity:1;fill:#000000;fill-opacity:1;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||||
|
id="path1306"
|
||||||
|
sodipodi:cx="281.42856"
|
||||||
|
sodipodi:cy="270.93362"
|
||||||
|
sodipodi:rx="38.57143"
|
||||||
|
sodipodi:ry="44.285713"
|
||||||
|
d="M 319.99999,270.93362 A 38.57143,44.285713 0 1 1 242.85713,270.93362 A 38.57143,44.285713 0 1 1 319.99999,270.93362 z"
|
||||||
|
transform="matrix(0.972222,0,0,0.846774,264.7456,-151.7001)"
|
||||||
|
inkscape:export-filename="C:\Eigene Dateien\Video AG\logo.png"
|
||||||
|
inkscape:export-xdpi="90.000000"
|
||||||
|
inkscape:export-ydpi="90.000000" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:72px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:url(#linearGradient2047);fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial Black"
|
||||||
|
x="511"
|
||||||
|
y="108.36218"
|
||||||
|
id="text1308"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
inkscape:export-filename="C:\Eigene Dateien\Video AG\logo.png"
|
||||||
|
inkscape:export-xdpi="90.000000"
|
||||||
|
inkscape:export-ydpi="90.000000"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan1312"
|
||||||
|
x="511"
|
||||||
|
y="108.36218"
|
||||||
|
style="fill:url(#linearGradient2047);fill-opacity:1">V</tspan></text>
|
||||||
|
<path
|
||||||
|
sodipodi:type="arc"
|
||||||
|
style="opacity:1;fill:#000000;fill-opacity:1;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0"
|
||||||
|
id="path3517"
|
||||||
|
sodipodi:cx="454"
|
||||||
|
sodipodi:cy="112.36218"
|
||||||
|
sodipodi:rx="87"
|
||||||
|
sodipodi:ry="56"
|
||||||
|
d="M 541,112.36218 A 87,56 0 1 1 454,56.362183 L 454,112.36218 z"
|
||||||
|
transform="matrix(-1.977323e-3,-1.724137,2.678569,-3.071905e-3,288.9275,932.4654)"
|
||||||
|
sodipodi:start="0"
|
||||||
|
sodipodi:end="4.712389"
|
||||||
|
inkscape:export-filename="C:\Eigene Dateien\Video AG\logo.png"
|
||||||
|
inkscape:export-xdpi="90.000000"
|
||||||
|
inkscape:export-ydpi="90.000000" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:28px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial Black"
|
||||||
|
x="598"
|
||||||
|
y="105.36218"
|
||||||
|
id="text2055"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
inkscape:export-filename="C:\Eigene Dateien\Video AG\logo.png"
|
||||||
|
inkscape:export-xdpi="90.000000"
|
||||||
|
inkscape:export-ydpi="90.000000"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan2785"
|
||||||
|
x="598"
|
||||||
|
y="105.36218"
|
||||||
|
style="font-size:36px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Arial Black">ideo</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:100px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial Black"
|
||||||
|
x="511"
|
||||||
|
y="243.36218"
|
||||||
|
id="text2051"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
inkscape:export-filename="C:\Eigene Dateien\Video AG\logo.png"
|
||||||
|
inkscape:export-xdpi="90.000000"
|
||||||
|
inkscape:export-ydpi="90.000000"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan2053"
|
||||||
|
x="511"
|
||||||
|
y="243.36218"
|
||||||
|
style="font-size:100px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;font-family:Arial Black">AG</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:72px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:0.25098039;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial Black"
|
||||||
|
x="471"
|
||||||
|
y="108.36218"
|
||||||
|
id="text4979"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
inkscape:export-filename="C:\Eigene Dateien\Video AG\logo.png"
|
||||||
|
inkscape:export-xdpi="90.000000"
|
||||||
|
inkscape:export-ydpi="90.000000"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan4981"
|
||||||
|
x="471"
|
||||||
|
y="108.36218">V</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 8.2 KiB |
|
@ -2,9 +2,10 @@ use super::cmd;
|
||||||
use crate::time::{format_time, Time};
|
use crate::time::{format_time, Time};
|
||||||
use camino::{Utf8Path as Path, Utf8PathBuf as PathBuf};
|
use camino::{Utf8Path as Path, Utf8PathBuf as PathBuf};
|
||||||
use rational::Rational;
|
use rational::Rational;
|
||||||
use std::process::Command;
|
use std::{borrow::Cow, process::Command};
|
||||||
|
|
||||||
pub(crate) struct FfmpegInput {
|
pub(crate) struct FfmpegInput {
|
||||||
|
pub(crate) concat: bool,
|
||||||
pub(crate) loop_input: bool,
|
pub(crate) loop_input: bool,
|
||||||
pub(crate) fps: Option<Rational>,
|
pub(crate) fps: Option<Rational>,
|
||||||
pub(crate) start: Option<Time>,
|
pub(crate) start: Option<Time>,
|
||||||
|
@ -15,6 +16,7 @@ pub(crate) struct FfmpegInput {
|
||||||
impl FfmpegInput {
|
impl FfmpegInput {
|
||||||
pub(crate) fn new(path: PathBuf) -> Self {
|
pub(crate) fn new(path: PathBuf) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
concat: false,
|
||||||
loop_input: false,
|
loop_input: false,
|
||||||
fps: None,
|
fps: None,
|
||||||
start: None,
|
start: None,
|
||||||
|
@ -24,6 +26,9 @@ impl FfmpegInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_to_cmd(self, cmd: &mut Command) {
|
fn append_to_cmd(self, cmd: &mut Command) {
|
||||||
|
if self.concat {
|
||||||
|
cmd.arg("-f").arg("concat").arg("-safe").arg("0");
|
||||||
|
}
|
||||||
if self.loop_input {
|
if self.loop_input {
|
||||||
cmd.arg("-loop").arg("1");
|
cmd.arg("-loop").arg("1");
|
||||||
}
|
}
|
||||||
|
@ -40,8 +45,65 @@ impl FfmpegInput {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) enum Filter {
|
||||||
|
Concat {
|
||||||
|
inputs: Vec<Cow<'static, str>>,
|
||||||
|
n: usize,
|
||||||
|
output: Cow<'static, str>
|
||||||
|
},
|
||||||
|
|
||||||
|
FadeIn {
|
||||||
|
input: Cow<'static, str>,
|
||||||
|
start: Time,
|
||||||
|
duration: Time,
|
||||||
|
output: Cow<'static, str>
|
||||||
|
},
|
||||||
|
|
||||||
|
FadeOut {
|
||||||
|
input: Cow<'static, str>,
|
||||||
|
start: Time,
|
||||||
|
duration: Time,
|
||||||
|
output: Cow<'static, str>
|
||||||
|
},
|
||||||
|
|
||||||
|
Overlay {
|
||||||
|
video_input: Cow<'static, str>,
|
||||||
|
overlay_input: Cow<'static, str>,
|
||||||
|
x: Cow<'static, str>,
|
||||||
|
y: Cow<'static, str>,
|
||||||
|
output: Cow<'static, str>
|
||||||
|
},
|
||||||
|
|
||||||
|
GenerateSilence {
|
||||||
|
output: Cow<'static, str>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Filter {
|
||||||
|
fn is_video_filter(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
Self::Concat { .. }
|
||||||
|
| Self::FadeIn { .. }
|
||||||
|
| Self::FadeOut { .. }
|
||||||
|
| Self::Overlay { .. }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_audio_filter(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
Self::Concat { .. }
|
||||||
|
| Self::FadeIn { .. }
|
||||||
|
| Self::FadeOut { .. }
|
||||||
|
| Self::GenerateSilence { .. }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct Ffmpeg {
|
pub(crate) struct Ffmpeg {
|
||||||
inputs: Vec<FfmpegInput>,
|
inputs: Vec<FfmpegInput>,
|
||||||
|
filters: Vec<Filter>,
|
||||||
output: PathBuf
|
output: PathBuf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +111,7 @@ impl Ffmpeg {
|
||||||
pub fn new(output: PathBuf) -> Self {
|
pub fn new(output: PathBuf) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inputs: Vec::new(),
|
inputs: Vec::new(),
|
||||||
|
filters: Vec::new(),
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,9 +120,13 @@ impl Ffmpeg {
|
||||||
let mut cmd = cmd();
|
let mut cmd = cmd();
|
||||||
cmd.arg("ffmpeg").arg("-hide_banner");
|
cmd.arg("ffmpeg").arg("-hide_banner");
|
||||||
|
|
||||||
|
// determine whether the video need to be re-encoded
|
||||||
|
let venc = self.filters.iter().any(|f| f.is_video_filter());
|
||||||
|
let aenc = self.filters.iter().any(|f| f.is_audio_filter());
|
||||||
|
|
||||||
// initialise a vaapi device if one exists
|
// initialise a vaapi device if one exists
|
||||||
let vaapi_device: PathBuf = "/dev/dri/renderD128".into();
|
let vaapi_device: PathBuf = "/dev/dri/renderD128".into();
|
||||||
let vaapi = vaapi_device.exists();
|
let vaapi = venc && vaapi_device.exists();
|
||||||
if vaapi {
|
if vaapi {
|
||||||
cmd.arg("-vaapi_device").arg(&vaapi_device);
|
cmd.arg("-vaapi_device").arg(&vaapi_device);
|
||||||
}
|
}
|
||||||
|
@ -72,6 +139,20 @@ impl Ffmpeg {
|
||||||
// always try to synchronise audio
|
// always try to synchronise audio
|
||||||
cmd.arg("-async").arg("1");
|
cmd.arg("-async").arg("1");
|
||||||
|
|
||||||
|
// TODO apply filters
|
||||||
|
|
||||||
|
// append encoding options
|
||||||
|
if vaapi {
|
||||||
|
cmd.arg("-c:v").arg("h264_vaapi");
|
||||||
|
cmd.arg("-rc_mode").arg("CQP");
|
||||||
|
cmd.arg("-global_quality").arg("22");
|
||||||
|
} else if venc {
|
||||||
|
cmd.arg("-c:v").arg("libx264");
|
||||||
|
cmd.arg("-crf").arg("22");
|
||||||
|
} else {
|
||||||
|
cmd.arg("-c:v").arg("copy");
|
||||||
|
}
|
||||||
|
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ pub mod ffmpeg;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
iotro::intro,
|
iotro::intro,
|
||||||
|
render::ffmpeg::Ffmpeg,
|
||||||
time::{format_date, Time},
|
time::{format_date, Time},
|
||||||
Project, ProjectSourceMetadata, Resolution
|
Project, ProjectSourceMetadata, Resolution
|
||||||
};
|
};
|
||||||
|
@ -133,6 +134,20 @@ impl<'a> Renderer<'a> {
|
||||||
pub(crate) fn preprocess(&self, project: &mut Project) -> anyhow::Result<()> {
|
pub(crate) fn preprocess(&self, project: &mut Project) -> anyhow::Result<()> {
|
||||||
assert!(!project.progress.preprocessed);
|
assert!(!project.progress.preprocessed);
|
||||||
|
|
||||||
|
let logo = self.target.join("logo.svg");
|
||||||
|
fs::write(
|
||||||
|
&logo,
|
||||||
|
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/logo.svg"))
|
||||||
|
)?;
|
||||||
|
let fastforward = self.target.join("fastforward.svg");
|
||||||
|
fs::write(
|
||||||
|
&fastforward,
|
||||||
|
include_bytes!(concat!(
|
||||||
|
env!("CARGO_MANIFEST_DIR"),
|
||||||
|
"/assets/fastforward.svg"
|
||||||
|
))
|
||||||
|
)?;
|
||||||
|
|
||||||
let recording_txt = self.target.join("recording.txt");
|
let recording_txt = self.target.join("recording.txt");
|
||||||
let mut file = File::create(recording_txt)?;
|
let mut file = File::create(recording_txt)?;
|
||||||
for filename in &project.source.files {
|
for filename in &project.source.files {
|
||||||
|
@ -141,7 +156,8 @@ impl<'a> Renderer<'a> {
|
||||||
drop(file);
|
drop(file);
|
||||||
|
|
||||||
println!("\x1B[1m ==> Concatenating Video and Normalising Audio ...");
|
println!("\x1B[1m ==> Concatenating Video and Normalising Audio ...");
|
||||||
let mut ffmpeg = Ffmpeg::new();
|
let recording_mp4 = self.target.join("recording.mp4");
|
||||||
|
let mut ffmpeg = Ffmpeg::new(recording_mp4);
|
||||||
|
|
||||||
// project.source.metadata = Some(ProjectSourceMetadata {
|
// project.source.metadata = Some(ProjectSourceMetadata {
|
||||||
// source_duration: ffprobe_video("format=duration", input)?.parse()?
|
// source_duration: ffprobe_video("format=duration", input)?.parse()?
|
||||||
|
|
Loading…
Reference in a new issue