This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 4.2 kB View raw
1use super::Video; 2use crate::Timestamp; 3use crate::ui::{Log, Pretty}; 4use crate::video::encoders::Encoder; 5use crate::video::engine::{EngineControl, EngineController, EngineOutput}; 6use anyhow::{Result, anyhow}; 7use itertools::Itertools; 8use measure_time::debug_time; 9use std::path::PathBuf; 10use std::thread; 11 12impl<C: Default> Video<C> { 13 pub fn encode( 14 &mut self, 15 output_file: impl Into<PathBuf> + Clone, 16 ) -> Result<std::time::Duration> { 17 let actual_ms_range = self.constrained_ms_range(); 18 if actual_ms_range != self.total_ms_range() { 19 self.progress_bars.rendering.log( 20 "Constrained", 21 &Timestamp::from_ms_range(&actual_ms_range).pretty(), 22 ); 23 } 24 25 self.encode_controlled(output_file, &move |ctx| { 26 if actual_ms_range.contains(&ctx.ms) { 27 EngineControl::Render 28 } else if ctx.ms > actual_ms_range.end { 29 EngineControl::Stop 30 } else { 31 EngineControl::Skip 32 } 33 }) 34 } 35 36 pub fn encode_controlled( 37 &mut self, 38 output_file: impl Into<PathBuf> + Clone, 39 engine_controller: &EngineController<C>, 40 ) -> Result<std::time::Duration> { 41 debug_time!("encode"); 42 43 let encoder = self.setup_encoder(output_file.clone())?; 44 let encoder_name = encoder.name(); 45 46 let result = self.encode_with(encoder, engine_controller); 47 48 let _ = notify_rust::Notification::new() 49 .appname("Shapemaker") 50 .summary(&match result { 51 Ok(_) => format!("{} is ready", &output_file.into().pretty()), 52 Err(_) => format!("{} failed", &output_file.into().pretty()), 53 }) 54 .body(&match result { 55 Err(ref e) => format!("Encoding failed: {e}"), 56 Ok(time_taken) => format!( 57 "Encoded with {encoder_name} in {}", 58 time_taken.pretty() 59 ), 60 }) 61 .show(); 62 63 result 64 } 65 66 pub fn encode_with( 67 &mut self, 68 mut encoder: Box<dyn Encoder + Send>, 69 engine_controller: &EngineController<C>, 70 ) -> Result<std::time::Duration> { 71 debug_time!("encode_with"); 72 73 self.progress.remove(&self.progress_bars.loading); 74 75 let pb = self.progress_bars.encoding.clone(); 76 77 pb.set_length(self.ms_to_frames(self.duration_ms()) as _); 78 pb.set_message(""); 79 80 let (tx, rx) = std::sync::mpsc::sync_channel::<EngineOutput>(1_000); 81 82 #[cfg(feature = "hotpath")] 83 let (tx, rx) = hotpath::channel!((tx, rx), capacity = 1_000, log = true); 84 85 let parallelism = std::thread::available_parallelism() 86 .map(|n| n.get()) 87 .unwrap_or(1); 88 89 pb.log( 90 "Starting", 91 &format!("encoder with parallelism of {parallelism}"), 92 ); 93 94 let encoder_thread = 95 thread::spawn(move || -> Result<std::time::Duration> { 96 for outputs in &rx.iter().chunks(parallelism) { 97 match encoder.encode_frames(outputs.collect())? { 98 std::ops::ControlFlow::Break(_) => break, 99 _ => (), 100 } 101 } 102 103 let time_taken = pb.elapsed(); 104 let finish_message = encoder.finish_message(time_taken); 105 106 encoder.finish()?; 107 108 pb.finish(); 109 pb.log("Encoded", &finish_message); 110 111 Ok(time_taken) 112 }); 113 114 self.render(tx, engine_controller)?; 115 116 let time_taken = encoder_thread 117 .join() 118 .map_err(|e| anyhow!("Encoder thread panicked: {e:?}")) 119 .flatten()?; 120 121 let _ = self.progress.clear(); 122 123 Ok(time_taken) 124 } 125 126 #[allow(dead_code)] 127 fn add_audio_track(&mut self, _output_file: String) -> Result<()> { 128 todo!( 129 "Look into https://github.com/zmwangx/rust-ffmpeg/blob/master/examples/transcode-x264.rs and maybe contribute to video-rs (see https://github.com/oddity-ai/video-rs/issues/44)" 130 ); 131 } 132}