1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
2 | // SPDX-License-Identifier: MIT |
3 | |
4 | slint::include_modules!(); |
5 | |
6 | use anyhow::{bail, Result}; |
7 | |
8 | use gst::prelude::*; |
9 | |
10 | fn try_gstreamer_video_frame_to_pixel_buffer( |
11 | frame: &gst_video::VideoFrame<gst_video::video_frame::Readable>, |
12 | ) -> Result<slint::SharedPixelBuffer<slint::Rgb8Pixel>> { |
13 | match frame.format() { |
14 | gst_video::VideoFormat::Rgb => { |
15 | let mut slint_pixel_buffer: SharedPixelBuffer> = |
16 | slint::SharedPixelBuffer::<slint::Rgb8Pixel>::new(frame.width(), frame.height()); |
17 | frame |
18 | .buffer() |
19 | .copy_to_slice(0, slint_pixel_buffer.make_mut_bytes()) |
20 | .expect(msg:"Unable to copy to slice!" ); // Copies! |
21 | Ok(slint_pixel_buffer) |
22 | } |
23 | _ => { |
24 | bail!( |
25 | "Cannot convert frame to a slint RGB frame because it is format {}" , |
26 | frame.format().to_str() |
27 | ) |
28 | } |
29 | } |
30 | } |
31 | |
32 | fn main() { |
33 | let app = App::new().unwrap(); |
34 | let app_weak = app.as_weak(); |
35 | |
36 | gst::init().unwrap(); |
37 | let source = gst::ElementFactory::make("videotestsrc" ) |
38 | .name("source" ) |
39 | .property_from_str("pattern" , "smpte" ) |
40 | .build() |
41 | .expect("Could not create source element." ); |
42 | |
43 | let width: u32 = 1024; |
44 | let height: u32 = 1024; |
45 | |
46 | let appsink = gst_app::AppSink::builder() |
47 | .caps( |
48 | &gst_video::VideoCapsBuilder::new() |
49 | .format(gst_video::VideoFormat::Rgb) |
50 | .width(width as i32) |
51 | .height(height as i32) |
52 | .build(), |
53 | ) |
54 | .build(); |
55 | |
56 | let pipeline = gst::Pipeline::with_name("test-pipeline" ); |
57 | |
58 | pipeline.add_many([&source, &appsink.upcast_ref()]).unwrap(); |
59 | source.link(&appsink).expect("Elements could not be linked." ); |
60 | |
61 | appsink.set_callbacks( |
62 | gst_app::AppSinkCallbacks::builder() |
63 | .new_sample(move |appsink| { |
64 | let sample = appsink.pull_sample().map_err(|_| gst::FlowError::Eos)?; |
65 | let buffer = sample.buffer_owned().unwrap(); // Probably copies! |
66 | let video_info = |
67 | gst_video::VideoInfo::builder(gst_video::VideoFormat::Rgb, width, height) |
68 | .build() |
69 | .expect("couldn't build video info!" ); |
70 | let video_frame = |
71 | gst_video::VideoFrame::from_buffer_readable(buffer, &video_info).unwrap(); |
72 | let slint_frame = try_gstreamer_video_frame_to_pixel_buffer(&video_frame) |
73 | .expect("Unable to convert the video frame to a slint video frame!" ); |
74 | |
75 | app_weak |
76 | .upgrade_in_event_loop(|app| { |
77 | app.set_video_frame(slint::Image::from_rgb8(slint_frame)) |
78 | }) |
79 | .unwrap(); |
80 | |
81 | Ok(gst::FlowSuccess::Ok) |
82 | }) |
83 | .build(), |
84 | ); |
85 | |
86 | pipeline |
87 | .set_state(gst::State::Playing) |
88 | .expect("Unable to set the pipeline to the `Playing` state" ); |
89 | |
90 | app.run().unwrap(); |
91 | } |
92 | |