forked from slint-ui/slint
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.rs
98 lines (77 loc) · 2.97 KB
/
main.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Copyright © SixtyFPS GmbH <[email protected]>
// SPDX-License-Identifier: MIT
slint::include_modules!();
use ffmpeg_next::format::Pixel;
mod player;
fn main() {
let app = App::new().unwrap();
let mut to_rgba_rescaler: Option<Rescaler> = None;
let mut player = player::Player::start(
"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4".into(),
{
let app_weak = app.as_weak();
move |new_frame| {
// TODO: use OpenGL bridge
let rebuild_rescaler =
to_rgba_rescaler.as_ref().map_or(true, |existing_rescaler| {
existing_rescaler.input().format != new_frame.format()
});
if rebuild_rescaler {
to_rgba_rescaler = Some(rgba_rescaler_for_frame(new_frame));
}
let rescaler = to_rgba_rescaler.as_mut().unwrap();
let mut rgb_frame = ffmpeg_next::util::frame::Video::empty();
rescaler.run(&new_frame, &mut rgb_frame).unwrap();
let pixel_buffer = video_frame_to_pixel_buffer(&rgb_frame);
app_weak
.upgrade_in_event_loop(|app| {
app.set_video_frame(slint::Image::from_rgb8(pixel_buffer))
})
.unwrap();
}
},
{
let app_weak = app.as_weak();
move |playing| {
app_weak.upgrade_in_event_loop(move |app| app.set_playing(playing)).unwrap();
}
},
)
.unwrap();
app.on_toggle_pause_play(move || {
player.toggle_pause_playing();
});
app.run().unwrap();
}
// Work around https://github.com/zmwangx/rust-ffmpeg/issues/102
#[derive(derive_more::Deref, derive_more::DerefMut)]
struct Rescaler(ffmpeg_next::software::scaling::Context);
unsafe impl std::marker::Send for Rescaler {}
fn rgba_rescaler_for_frame(frame: &ffmpeg_next::util::frame::Video) -> Rescaler {
Rescaler(
ffmpeg_next::software::scaling::Context::get(
frame.format(),
frame.width(),
frame.height(),
Pixel::RGB24,
frame.width(),
frame.height(),
ffmpeg_next::software::scaling::Flags::BILINEAR,
)
.unwrap(),
)
}
fn video_frame_to_pixel_buffer(
frame: &ffmpeg_next::util::frame::Video,
) -> slint::SharedPixelBuffer<slint::Rgb8Pixel> {
let mut pixel_buffer =
slint::SharedPixelBuffer::<slint::Rgb8Pixel>::new(frame.width(), frame.height());
let ffmpeg_line_iter = frame.data(0).chunks_exact(frame.stride(0));
let slint_pixel_line_iter = pixel_buffer
.make_mut_bytes()
.chunks_mut(frame.width() as usize * core::mem::size_of::<slint::Rgb8Pixel>());
for (source_line, dest_line) in ffmpeg_line_iter.zip(slint_pixel_line_iter) {
dest_line.copy_from_slice(&source_line[..dest_line.len()])
}
pixel_buffer
}