1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: MIT
3
4slint::include_modules!();
5
6use anyhow::{bail, Result};
7
8use gst::prelude::*;
9
10fn 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
32fn 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