Skip to content

Commit 201d226

Browse files
committed
[*] refactor video editor
1 parent 9ad6445 commit 201d226

File tree

16 files changed

+61
-452
lines changed

16 files changed

+61
-452
lines changed

lib/video-editor/examples/play_video_track_demo.rs

Lines changed: 7 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,7 @@ use eframe::egui;
22
use image::RgbaImage;
33
use std::{path::PathBuf, sync::Arc, time::Duration};
44
use video_editor::{
5-
filters::{
6-
subtitle::style::{
7-
colors::PrimaryColorFilter, font_path::FontPathFilter, font_size::FontSizeFilter,
8-
},
9-
traits::OverlayFilterWrapper,
10-
},
11-
metadata::{create_text_overlay_metadata, get_metadata},
5+
metadata::get_metadata,
126
tracks::{
137
manager::Manager,
148
overlay_track::OverlayTrack,
@@ -35,7 +29,7 @@ impl VideoViewerApp {
3529
fn new() -> Self {
3630
let mut manager = Manager::new();
3731

38-
// ===== 添加 Overlay 轨道 1: 图片 overlay (最上层) =====
32+
// ===== 添加 Overlay 轨道: 图片 overlay (最上层) =====
3933
let overlay_image_path = PathBuf::from("data").join("test.png");
4034
if !overlay_image_path.exists() {
4135
log::warn!(
@@ -61,64 +55,10 @@ impl VideoViewerApp {
6155

6256
manager.add_track(Track::Overlay(Arc::new(overlay_image_track)));
6357
log::info!(
64-
"Added image overlay track: 'test.png' (0.5-3.5s) - semi-transparent red [Layer 0 - Top]"
65-
);
66-
67-
// ===== 添加 Overlay 轨道 2: 文字 overlay (第二层) =====
68-
let overlay_text_duration = Duration::from_secs(3);
69-
let overlay_text_metadata = Arc::new(create_text_overlay_metadata(
70-
"Overlay Text - SECOND LAYER",
71-
overlay_text_duration,
72-
));
73-
74-
// 添加字体路径滤镜
75-
let font_path = PathBuf::from("../../wayshot/ui/fonts/SourceHanSansCN.otf");
76-
let mut overlay_text_segment = Segment::new(
77-
Duration::ZERO, // 从 0 秒开始
78-
overlay_text_duration,
79-
overlay_text_metadata.clone(),
58+
"Added image overlay track: 'test.png' (0.5-3.5s) [Layer 0 - Top]"
8059
);
8160

82-
if font_path.exists() {
83-
// 作为 overlay filter 添加字体路径、大小和颜色
84-
overlay_text_segment.add_overlay_filter(OverlayFilterWrapper::new_overlay_text(
85-
true,
86-
Box::new(FontPathFilter::new(font_path.clone())),
87-
));
88-
overlay_text_segment.add_overlay_filter(
89-
OverlayFilterWrapper::new_overlay_text(true, Box::new(FontSizeFilter::new(120))), // 大字体
90-
);
91-
overlay_text_segment.add_overlay_filter(
92-
OverlayFilterWrapper::new_overlay_text(
93-
true,
94-
Box::new(PrimaryColorFilter::new(Some(image::Rgba([
95-
255, 255, 0, 255,
96-
])))),
97-
), // 黄色文字
98-
);
99-
log::info!("Added font path filter: {}", font_path.display());
100-
} else {
101-
log::warn!(
102-
"Font file not found: {}, text overlay may not render correctly",
103-
font_path.display()
104-
);
105-
}
106-
107-
let overlay_text_segment = Arc::new(overlay_text_segment);
108-
109-
let overlay_text_inner_track = InnerTrack::new(overlay_text_metadata, overlay_text_duration, vec![overlay_text_segment]);
110-
111-
let overlay_text_track = OverlayTrack {
112-
name: "Text Overlay".to_string(),
113-
hiding: false,
114-
locked: false,
115-
track: overlay_text_inner_track,
116-
};
117-
118-
manager.add_track(Track::Overlay(Arc::new(overlay_text_track)));
119-
log::info!("Added text overlay track: 'Overlay Text - SECOND LAYER' (0-3s) [Layer 1]");
120-
121-
// ===== 添加第一个视频轨道: test.mkv (第三层) =====
61+
// ===== 添加第一个视频轨道: test.mkv (第二层) =====
12262
let mkv_path = PathBuf::from("data").join("test.mkv");
12363
log::info!("Loading MKV video from: {}", mkv_path.display());
12464

@@ -161,7 +101,7 @@ impl VideoViewerApp {
161101
};
162102

163103
manager.add_track(Track::Video(Arc::new(mkv_video_track)));
164-
log::info!("Added MKV video track: test.mkv [Layer 2]");
104+
log::info!("Added MKV video track: test.mkv [Layer 1]");
165105

166106
// ===== 添加第二个视频轨道: test.mp4 (最底层) =====
167107
let file_path = PathBuf::from("data").join("test.mp4");
@@ -205,7 +145,7 @@ impl VideoViewerApp {
205145
};
206146

207147
manager.add_track(Track::Video(Arc::new(video_track)));
208-
log::info!("Added MP4 video track: test.mp4 [Layer 3 - Bottom]");
148+
log::info!("Added MP4 video track: test.mp4 [Layer 2 - Bottom]");
209149

210150
let output_width = video_meta.width;
211151
let output_height = video_meta.height;
@@ -455,4 +395,4 @@ fn main() -> Result<(), eframe::Error> {
455395
Ok(Box::new(VideoViewerApp::new()))
456396
}),
457397
)
458-
}
398+
}

lib/video-editor/src/filters.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
pub mod audio;
22
pub mod overlay;
33
pub mod subtitle;
4-
pub mod text;
54
pub mod traits;
65
pub mod video;
76

lib/video-editor/src/filters/text/font.rs

Lines changed: 0 additions & 2 deletions
This file was deleted.

lib/video-editor/src/filters/traits.rs

Lines changed: 10 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ pub struct VideoFilterWrapper {
8686
pub inner: Box<dyn VideoFilter>,
8787
}
8888

89+
impl Clone for VideoFilterWrapper {
90+
fn clone(&self) -> Self {
91+
Self {
92+
enabled: AtomicBool::new(self.enabled.load(Ordering::Relaxed)),
93+
inner: self.inner.clone_box(),
94+
}
95+
}
96+
}
97+
8998
impl VideoFilterWrapper {
9099
pub fn new(enabled: bool, inner: Box<dyn VideoFilter>) -> Self {
91100
Self {
@@ -159,81 +168,7 @@ impl SubtitleFilterWrapper {
159168
}
160169
}
161170

162-
pub type OverlayImageFilterWrapper = VideoFilterWrapper;
163-
pub type OverlayTextFilterWrapper = SubtitleFilterWrapper;
164-
165-
pub enum OverlayFilterWrapper {
166-
Image(OverlayImageFilterWrapper),
167-
Text(OverlayTextFilterWrapper),
168-
}
169-
170-
impl Clone for OverlayFilterWrapper {
171-
fn clone(&self) -> Self {
172-
match self {
173-
OverlayFilterWrapper::Image(wrapper) => {
174-
OverlayFilterWrapper::Image(OverlayImageFilterWrapper {
175-
enabled: AtomicBool::new(
176-
wrapper.enabled.load(std::sync::atomic::Ordering::Relaxed),
177-
),
178-
inner: wrapper.inner.clone_box(),
179-
})
180-
}
181-
OverlayFilterWrapper::Text(wrapper) => {
182-
OverlayFilterWrapper::Text(SubtitleFilterWrapper {
183-
enabled: AtomicBool::new(
184-
wrapper.enabled.load(std::sync::atomic::Ordering::Relaxed),
185-
),
186-
inner: wrapper.inner.clone_box(),
187-
})
188-
}
189-
}
190-
}
191-
}
192-
193-
impl OverlayFilterWrapper {
194-
pub fn new_overlay_image(enabled: bool, inner: Box<dyn VideoFilter>) -> Self {
195-
Self::Image(OverlayImageFilterWrapper::new(enabled, inner))
196-
}
197-
198-
pub fn new_overlay_text(enabled: bool, inner: Box<dyn SubtitleFilter>) -> Self {
199-
Self::Text(OverlayTextFilterWrapper::new(enabled, inner))
200-
}
201-
202-
pub fn enabled(&self) -> bool {
203-
match self {
204-
OverlayFilterWrapper::Image(w) => w.enabled(),
205-
OverlayFilterWrapper::Text(w) => w.enabled(),
206-
}
207-
}
208-
209-
pub fn set_enabled(&self, enabled: bool) {
210-
match self {
211-
OverlayFilterWrapper::Image(w) => w.set_enabled(enabled),
212-
OverlayFilterWrapper::Text(w) => w.set_enabled(enabled),
213-
}
214-
}
215-
216-
pub fn toggle(&self) {
217-
match self {
218-
OverlayFilterWrapper::Image(w) => w.toggle(),
219-
OverlayFilterWrapper::Text(w) => w.toggle(),
220-
}
221-
}
222-
223-
pub fn as_image_filter(&self) -> Option<&OverlayImageFilterWrapper> {
224-
match self {
225-
OverlayFilterWrapper::Image(w) => Some(w),
226-
OverlayFilterWrapper::Text(_) => None,
227-
}
228-
}
229-
230-
pub fn as_text_filter(&self) -> Option<&OverlayTextFilterWrapper> {
231-
match self {
232-
OverlayFilterWrapper::Image(_) => None,
233-
OverlayFilterWrapper::Text(w) => Some(w),
234-
}
235-
}
236-
}
171+
pub type OverlayFilterWrapper = VideoFilterWrapper;
237172

238173
#[macro_export]
239174
macro_rules! impl_default_filter {

lib/video-editor/src/media/media_type.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ pub enum MediaType {
77
Audio,
88
Image,
99
Subtitle,
10-
Text,
1110
}
1211

1312
impl MediaType {
@@ -17,7 +16,7 @@ impl MediaType {
1716
MetadataType::Audio => MediaType::Audio,
1817
MetadataType::Subtitle => MediaType::Subtitle,
1918
MetadataType::Image => MediaType::Image,
20-
MetadataType::Text | MetadataType::None => MediaType::Text,
19+
MetadataType::None => MediaType::Video,
2120
}
2221
}
2322

@@ -27,7 +26,6 @@ impl MediaType {
2726
MediaType::Audio => "audio",
2827
MediaType::Image => "image",
2928
MediaType::Subtitle => "subtitle",
30-
MediaType::Text => "text",
3129
}
3230
}
3331

@@ -36,9 +34,9 @@ impl MediaType {
3634
"video" => Some(MediaType::Video),
3735
"audio" => Some(MediaType::Audio),
3836
"image" => Some(MediaType::Image),
39-
"text" => Some(MediaType::Text),
4037
"subtitle" => Some(MediaType::Subtitle),
4138
_ => None,
4239
}
4340
}
4441
}
42+

lib/video-editor/src/metadata.rs

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ pub enum MetadataType {
1414
Video,
1515
Audio,
1616
Subtitle,
17-
Text,
1817
Image,
1918
None,
2019
}
@@ -91,16 +90,13 @@ impl Metadata {
9190
MetadataType::Audio
9291
} else if !self.subtitles.is_empty() {
9392
MetadataType::Subtitle
94-
} else if self.format.iter().any(|item| item == "text") {
95-
MetadataType::Text
9693
} else {
9794
MetadataType::None
9895
}
9996
}
10097

10198
pub fn is_overlay(&self) -> bool {
102-
let ty = self.get_type();
103-
ty == MetadataType::Text || ty == MetadataType::Image
99+
self.get_type() == MetadataType::Image
104100
}
105101
}
106102

@@ -309,16 +305,3 @@ fn get_subtitle_duration_from_packets(
309305
let duration_secs = max_end_time_ts as f64 * time_base_num / time_base_den;
310306
Duration::from_secs_f64(duration_secs.max(0.0))
311307
}
312-
313-
pub fn create_text_overlay_metadata(text: &str, duration: Duration) -> Metadata {
314-
Metadata {
315-
path: PathBuf::from(text), // 文字内容存储在 path 中
316-
size: 0,
317-
bitrate: 0,
318-
duration,
319-
format: vec!["text".to_string()],
320-
videos: vec![],
321-
audios: vec![],
322-
subtitles: vec![],
323-
}
324-
}

lib/video-editor/src/project/filters.rs

Lines changed: 6 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ use crate::{
1515
padding::PaddingFilter,
1616
},
1717
traits::{
18-
AudioFilter, AudioFilterWrapper, OverlayFilterWrapper, OverlayImageFilterWrapper,
19-
OverlayTextFilterWrapper, SubtitleFilter, SubtitleFilterWrapper, VideoFilter,
20-
VideoFilterWrapper,
18+
AudioFilter, AudioFilterWrapper, OverlayFilterWrapper, SubtitleFilter,
19+
SubtitleFilterWrapper, VideoFilter, VideoFilterWrapper,
2120
},
2221
video::{
2322
BrightnessFilter, ChromaKeyFilter, ContrastFilter, CropFilter, FlipFilter,
@@ -492,61 +491,17 @@ pub struct OverlayFilterData {
492491
pub enabled: bool,
493492

494493
#[serde(flatten)]
495-
pub inner: OverlayFilterDataInner,
496-
}
497-
498-
#[derive(Debug, Clone, Serialize, Deserialize)]
499-
#[serde(tag = "category", content = "filter")]
500-
pub enum OverlayFilterDataInner {
501-
#[serde(rename = "video")]
502-
Video(VideoFilterDataInner),
503-
504-
#[serde(rename = "subtitle")]
505-
Subtitle(SubtitleFilterDataInner),
494+
pub inner: VideoFilterDataInner,
506495
}
507496

508497
pub fn overlay_filter_wrapper_to_data(wrapper: &OverlayFilterWrapper) -> OverlayFilterData {
509-
overlay_filter_to_data(wrapper)
510-
}
511-
512-
pub fn overlay_filter_to_data(wrapper: &OverlayFilterWrapper) -> OverlayFilterData {
513498
OverlayFilterData {
514499
enabled: wrapper.enabled(),
515-
inner: overlay_filter_wrapper_to_inner(wrapper),
516-
}
517-
}
518-
519-
fn overlay_filter_wrapper_to_inner(wrapper: &OverlayFilterWrapper) -> OverlayFilterDataInner {
520-
match wrapper {
521-
OverlayFilterWrapper::Image(w) => {
522-
OverlayFilterDataInner::Video(video_filter_to_data(&w.inner))
523-
}
524-
OverlayFilterWrapper::Text(w) => {
525-
OverlayFilterDataInner::Subtitle(subtitle_filter_to_data(&w.inner))
526-
}
500+
inner: video_filter_to_data(&wrapper.inner),
527501
}
528502
}
529503

530504
pub fn data_to_overlay_filter(data: &OverlayFilterData) -> Result<OverlayFilterWrapper> {
531-
data_to_overlay_filter_inner(&data.inner, data.enabled)
532-
}
533-
534-
fn data_to_overlay_filter_inner(
535-
data: &OverlayFilterDataInner,
536-
enabled: bool,
537-
) -> Result<OverlayFilterWrapper> {
538-
match data {
539-
OverlayFilterDataInner::Video(filter_data) => {
540-
let filter = data_to_video_filter_inner(filter_data)?;
541-
Ok(OverlayFilterWrapper::Image(OverlayImageFilterWrapper::new(
542-
enabled, filter,
543-
)))
544-
}
545-
OverlayFilterDataInner::Subtitle(filter_data) => {
546-
let filter = data_to_subtitle_filter_inner(filter_data)?;
547-
Ok(OverlayFilterWrapper::Text(OverlayTextFilterWrapper::new(
548-
enabled, filter,
549-
)))
550-
}
551-
}
505+
let filter = data_to_video_filter_inner(&data.inner)?;
506+
Ok(OverlayFilterWrapper::new(data.enabled, filter))
552507
}

0 commit comments

Comments
 (0)