sreepathi-ravikumar commited on
Commit
1f2ab31
·
verified ·
1 Parent(s): 5d8bb2b

Update rust_highlight/src/lib.rs

Browse files
Files changed (1) hide show
  1. rust_highlight/src/lib.rs +25 -60
rust_highlight/src/lib.rs CHANGED
@@ -1,12 +1,7 @@
1
  use pyo3::prelude::*;
2
- use pyo3::wrap_pyfunction;
3
- use std::fs::File;
4
- use std::io::Write;
5
- use std::path::Path;
6
  use std::process::Command;
7
- use uuid::Uuid;
8
 
9
- /// Renders a video by highlighting regions over time
10
  #[pyfunction]
11
  fn render_video(
12
  id: usize,
@@ -35,26 +30,42 @@ fn render_video(
35
  let n_words = words.len() as f64;
36
  let highlight_duration = duration / n_words;
37
 
38
- // Build filter graph
39
- let mut filters = vec![];
 
 
40
  for (i, (_, (x, y, w, h))) in words.iter().enumerate() {
41
  let start = i as f64 * highlight_duration;
42
  let end = start + highlight_duration;
43
- filters.push(format!(
44
- "drawbox=x={x}:y={y}:w={w}:h={h}:color=yellow@0.5:t=fill:enable='between(t,{start:.2},{end:.2})'"
 
 
 
 
 
 
 
 
 
45
  ));
 
46
  }
47
 
48
- let filter_chain = filters.join(",");
 
49
 
50
  // FFmpeg command
51
  let status = Command::new("ffmpeg")
52
  .args(&[
53
  "-y",
 
54
  "-loop", "1",
55
  "-i", &image_path,
56
  "-i", &audio_path,
57
- "-vf", &filter_chain,
 
 
58
  "-c:v", "libx264",
59
  "-preset", "fast",
60
  "-crf", "18",
@@ -63,17 +74,15 @@ fn render_video(
63
  "-c:a", "aac",
64
  "-b:a", "192k",
65
  "-r", "60",
66
- "-fps_mode", "vfr",
67
  "-t", &duration_str,
 
68
  &output_path,
69
  ])
70
  .status();
71
 
72
  match status {
73
  Ok(exit_status) if exit_status.success() => Ok(output_path),
74
- Ok(_) => Err(pyo3::exceptions::PyRuntimeError::new_err(
75
- "FFmpeg command failed. Check filter syntax.",
76
- )),
77
  Err(e) => Err(pyo3::exceptions::PyRuntimeError::new_err(format!(
78
  "Failed to execute FFmpeg: {}",
79
  e
@@ -81,52 +90,8 @@ fn render_video(
81
  }
82
  }
83
 
84
- /// Combines multiple video clips into one
85
- #[pyfunction]
86
- fn combine_clips(clips: Vec<String>) -> PyResult<String> {
87
- let paths: Vec<&str> = clips.iter().map(|s| s.as_str()).collect();
88
- concat_videos(paths)
89
- }
90
-
91
- fn concat_videos(clips: Vec<&str>) -> PyResult<String> {
92
- // Step 1: Write file list
93
- let list_file = format!("/tmp/clips_{}.txt", Uuid::new_v4());
94
- let mut file = File::create(&list_file)
95
- .map_err(|e| pyo3::exceptions::PyIOError::new_err(e.to_string()))?;
96
- for clip in &clips {
97
- writeln!(file, "file '{}'", clip)
98
- .map_err(|e| pyo3::exceptions::PyIOError::new_err(e.to_string()))?;
99
- }
100
-
101
- // Step 2: Run FFmpeg
102
- let output_file = format!("/tmp/final_video_{}.mp4", Uuid::new_v4());
103
- let status = Command::new("ffmpeg")
104
- .args(&[
105
- "-y",
106
- "-f", "concat",
107
- "-safe", "0",
108
- "-i", &list_file,
109
- "-c", "copy",
110
- &output_file,
111
- ])
112
- .status()
113
- .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
114
-
115
- if status.success() {
116
- Ok(output_file)
117
- } else {
118
- Err(pyo3::exceptions::PyRuntimeError::new_err("FFmpeg command failed"))
119
- }
120
- }
121
-
122
  #[pymodule]
123
  fn rust_highlight(_py: Python, m: &PyModule) -> PyResult<()> {
124
  m.add_function(wrap_pyfunction!(render_video, m)?)?;
125
  Ok(())
126
- }
127
-
128
- #[pymodule]
129
- fn rust_combiner(_py: Python, m: &PyModule) -> PyResult<()> {
130
- m.add_function(wrap_pyfunction!(combine_clips, m)?)?;
131
- Ok(())
132
  }
 
1
  use pyo3::prelude::*;
 
 
 
 
2
  use std::process::Command;
3
+ use std::path::Path;
4
 
 
5
  #[pyfunction]
6
  fn render_video(
7
  id: usize,
 
30
  let n_words = words.len() as f64;
31
  let highlight_duration = duration / n_words;
32
 
33
+ // Build complex filter graph
34
+ let mut filter_complex = String::new();
35
+ let mut last_output = "0:v".to_string();
36
+
37
  for (i, (_, (x, y, w, h))) in words.iter().enumerate() {
38
  let start = i as f64 * highlight_duration;
39
  let end = start + highlight_duration;
40
+
41
+ filter_complex.push_str(&format!(
42
+ "[{last_out}]drawbox=x={x}:y={y}:w={w}:h={h}:[email protected]:t=fill:enable='between(t,{start:.3},{end:.3})'[v{i}];",
43
+ last_out = last_output,
44
+ x = x,
45
+ y = y,
46
+ w = w,
47
+ h = h,
48
+ start = start,
49
+ end = end,
50
+ i = i
51
  ));
52
+ last_output = format!("[v{i}]");
53
  }
54
 
55
+ // Remove trailing semicolon
56
+ filter_complex.pop();
57
 
58
  // FFmpeg command
59
  let status = Command::new("ffmpeg")
60
  .args(&[
61
  "-y",
62
+ "-hwaccel", "auto",
63
  "-loop", "1",
64
  "-i", &image_path,
65
  "-i", &audio_path,
66
+ "-filter_complex", &filter_complex,
67
+ "-map", &last_output,
68
+ "-map", "1:a",
69
  "-c:v", "libx264",
70
  "-preset", "fast",
71
  "-crf", "18",
 
74
  "-c:a", "aac",
75
  "-b:a", "192k",
76
  "-r", "60",
 
77
  "-t", &duration_str,
78
+ "-vsync", "2",
79
  &output_path,
80
  ])
81
  .status();
82
 
83
  match status {
84
  Ok(exit_status) if exit_status.success() => Ok(output_path),
85
+ Ok(_) => Err(pyo3::exceptions::PyRuntimeError::new_err("FFmpeg command failed")),
 
 
86
  Err(e) => Err(pyo3::exceptions::PyRuntimeError::new_err(format!(
87
  "Failed to execute FFmpeg: {}",
88
  e
 
90
  }
91
  }
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  #[pymodule]
94
  fn rust_highlight(_py: Python, m: &PyModule) -> PyResult<()> {
95
  m.add_function(wrap_pyfunction!(render_video, m)?)?;
96
  Ok(())
 
 
 
 
 
 
97
  }