Advertisement
Guest User

Untitled

a guest
Sep 13th, 2021
12
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 24.68 KB | None | 0 0
  1. // This example demonstrates how to output GL textures, within an
  2. // EGL/X11 context provided by the application, and render those
  3. // textures in the GL application.
  4.  
  5. // {videotestsrc} - { glsinkbin }
  6.  
  7. use gst::element_error;
  8.  
  9. use gst_gl::prelude::*;
  10.  
  11. use std::ffi::CStr;
  12. use std::mem;
  13. use std::ptr;
  14. use std::sync;
  15.  
  16. use anyhow::Error;
  17. use derive_more::{Display, Error};
  18.  
  19. #[derive(Debug, Display, Error)]
  20. #[display(fmt = "Missing element {}", _0)]
  21. struct MissingElement(#[error(not(source))] &'static str);
  22.  
  23. #[derive(Debug, Display, Error)]
  24. #[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
  25. struct ErrorMessage {
  26.    src: String,
  27.    error: String,
  28.    debug: Option<String>,
  29.    source: glib::Error,
  30. }
  31.  
  32. #[rustfmt::skip]
  33. static VERTICES: [f32; 20] = [
  34.     1.0,  1.0, 0.0, 1.0, 0.0,
  35.    -1.0,  1.0, 0.0, 0.0, 0.0,
  36.    -1.0, -1.0, 0.0, 0.0, 1.0,
  37.     1.0, -1.0, 0.0, 1.0, 1.0,
  38. ];
  39.  
  40. static INDICES: [u16; 6] = [0, 1, 2, 0, 2, 3];
  41.  
  42. #[rustfmt::skip]
  43. static IDENTITY: [f32; 16] = [
  44.    1.0, 0.0, 0.0, 0.0,
  45.    0.0, 1.0, 0.0, 0.0,
  46.    0.0, 0.0, 1.0, 0.0,
  47.    0.0, 0.0, 0.0, 1.0,
  48. ];
  49.  
  50. const VS_SRC: &[u8] = b"
  51. uniform mat4 u_transformation;
  52. attribute vec4 a_position;
  53. attribute vec2 a_texcoord;
  54. varying vec2 v_texcoord;
  55.  
  56. void main() {
  57.    gl_Position = u_transformation * a_position;
  58.    v_texcoord = a_texcoord;
  59. }
  60. \0";
  61.  
  62. const FS_SRC: &[u8] = b"
  63. #ifdef GL_ES
  64. precision mediump float;
  65. #endif
  66. varying vec2 v_texcoord;
  67. uniform sampler2D tex;
  68.  
  69. void main() {
  70.    gl_FragColor = texture2D(tex, v_texcoord);
  71. }
  72. \0";
  73.  
  74. #[allow(clippy::unreadable_literal)]
  75. #[allow(clippy::unused_unit)]
  76. #[allow(clippy::too_many_arguments)]
  77. #[allow(clippy::manual_non_exhaustive)]
  78. #[allow(clippy::upper_case_acronyms)]
  79. pub(crate) mod gl {
  80.    pub use self::Gles2 as Gl;
  81.    include!(concat!(env!("OUT_DIR"), "/test_gl_bindings.rs"));
  82. }
  83.  
  84. struct Gl {
  85.    gl: gl::Gl,
  86.    program: gl::types::GLuint,
  87.    attr_position: gl::types::GLint,
  88.    attr_texture: gl::types::GLint,
  89.    vao: Option<gl::types::GLuint>,
  90.    vertex_buffer: gl::types::GLuint,
  91.    vbo_indices: gl::types::GLuint,
  92. }
  93.  
  94. impl Gl {
  95.    fn draw_frame(&self, texture_id: gl::types::GLuint) {
  96.        unsafe {
  97.            // render
  98.            self.gl.ClearColor(0.0, 0.0, 0.0, 1.0);
  99.            self.gl.Clear(gl::COLOR_BUFFER_BIT);
  100.  
  101.            self.gl.BlendColor(0.0, 0.0, 0.0, 1.0);
  102.            if self.gl.BlendFuncSeparate.is_loaded() {
  103.                self.gl.BlendFuncSeparate(
  104.                    gl::SRC_ALPHA,
  105.                    gl::CONSTANT_COLOR,
  106.                    gl::ONE,
  107.                    gl::ONE_MINUS_SRC_ALPHA,
  108.                );
  109.            } else {
  110.                self.gl.BlendFunc(gl::SRC_ALPHA, gl::CONSTANT_COLOR);
  111.            }
  112.            self.gl.BlendEquation(gl::FUNC_ADD);
  113.            self.gl.Enable(gl::BLEND);
  114.  
  115.            self.gl.UseProgram(self.program);
  116.  
  117.            if self.gl.BindVertexArray.is_loaded() {
  118.                self.gl.BindVertexArray(self.vao.unwrap());
  119.            }
  120.  
  121.            {
  122.                self.gl
  123.                    .BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.vbo_indices);
  124.                self.gl.BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer);
  125.  
  126.                // Load the vertex position
  127.                self.gl.VertexAttribPointer(
  128.                    self.attr_position as gl::types::GLuint,
  129.                    3,
  130.                    gl::FLOAT,
  131.                    gl::FALSE,
  132.                    (5 * mem::size_of::<f32>()) as gl::types::GLsizei,
  133.                    ptr::null(),
  134.                );
  135.  
  136.                // Load the texture coordinate
  137.                self.gl.VertexAttribPointer(
  138.                    self.attr_texture as gl::types::GLuint,
  139.                    2,
  140.                    gl::FLOAT,
  141.                    gl::FALSE,
  142.                    (5 * mem::size_of::<f32>()) as gl::types::GLsizei,
  143.                    (3 * mem::size_of::<f32>()) as *const () as *const _,
  144.                );
  145.  
  146.                self.gl.EnableVertexAttribArray(self.attr_position as _);
  147.                self.gl.EnableVertexAttribArray(self.attr_texture as _);
  148.            }
  149.  
  150.            self.gl.ActiveTexture(gl::TEXTURE0);
  151.            self.gl.BindTexture(gl::TEXTURE_2D, texture_id);
  152.  
  153.            let location = self
  154.                .gl
  155.                .GetUniformLocation(self.program, b"tex\0".as_ptr() as *const _);
  156.            self.gl.Uniform1i(location, 0);
  157.  
  158.            let location = self
  159.                .gl
  160.                .GetUniformLocation(self.program, b"u_transformation\0".as_ptr() as *const _);
  161.            self.gl
  162.                .UniformMatrix4fv(location, 1, gl::FALSE, IDENTITY.as_ptr() as *const _);
  163.  
  164.            self.gl
  165.                .DrawElements(gl::TRIANGLES, 6, gl::UNSIGNED_SHORT, ptr::null());
  166.  
  167.            self.gl.BindTexture(gl::TEXTURE_2D, 0);
  168.            self.gl.UseProgram(0);
  169.  
  170.            if self.gl.BindVertexArray.is_loaded() {
  171.                self.gl.BindVertexArray(0);
  172.            }
  173.  
  174.            {
  175.                self.gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
  176.                self.gl.BindBuffer(gl::ARRAY_BUFFER, 0);
  177.  
  178.                self.gl.DisableVertexAttribArray(self.attr_position as _);
  179.                self.gl.DisableVertexAttribArray(self.attr_texture as _);
  180.            }
  181.        }
  182.    }
  183.  
  184.    fn resize(&self, size: glutin::dpi::PhysicalSize<u32>) {
  185.        unsafe {
  186.            self.gl
  187.                .Viewport(0, 0, size.width as i32, size.height as i32);
  188.        }
  189.    }
  190. }
  191.  
  192. fn load(gl_context: &glutin::WindowedContext<glutin::PossiblyCurrent>) -> Gl {
  193.    let gl = gl::Gl::load_with(|ptr| gl_context.get_proc_address(ptr) as *const _);
  194.  
  195.    let version = unsafe {
  196.        let data = CStr::from_ptr(gl.GetString(gl::VERSION) as *const _)
  197.            .to_bytes()
  198.            .to_vec();
  199.        String::from_utf8(data).unwrap()
  200.    };
  201.  
  202.    println!("OpenGL version {}", version);
  203.  
  204.    let (program, attr_position, attr_texture, vao, vertex_buffer, vbo_indices) = unsafe {
  205.        let vs = gl.CreateShader(gl::VERTEX_SHADER);
  206.        gl.ShaderSource(vs, 1, [VS_SRC.as_ptr() as *const _].as_ptr(), ptr::null());
  207.        gl.CompileShader(vs);
  208.  
  209.        let fs = gl.CreateShader(gl::FRAGMENT_SHADER);
  210.        gl.ShaderSource(fs, 1, [FS_SRC.as_ptr() as *const _].as_ptr(), ptr::null());
  211.        gl.CompileShader(fs);
  212.  
  213.        let program = gl.CreateProgram();
  214.        gl.AttachShader(program, vs);
  215.        gl.AttachShader(program, fs);
  216.        gl.LinkProgram(program);
  217.  
  218.        {
  219.            let mut success: gl::types::GLint = 1;
  220.            gl.GetProgramiv(fs, gl::LINK_STATUS, &mut success);
  221.            assert!(success != 0);
  222.        }
  223.  
  224.        let attr_position = gl.GetAttribLocation(program, b"a_position\0".as_ptr() as *const _);
  225.        let attr_texture = gl.GetAttribLocation(program, b"a_texcoord\0".as_ptr() as *const _);
  226.  
  227.        let vao = if gl.BindVertexArray.is_loaded() {
  228.            let mut vao = mem::MaybeUninit::uninit();
  229.            gl.GenVertexArrays(1, vao.as_mut_ptr());
  230.            let vao = vao.assume_init();
  231.            gl.BindVertexArray(vao);
  232.            Some(vao)
  233.        } else {
  234.            None
  235.        };
  236.  
  237.        let mut vertex_buffer = mem::MaybeUninit::uninit();
  238.        gl.GenBuffers(1, vertex_buffer.as_mut_ptr());
  239.        let vertex_buffer = vertex_buffer.assume_init();
  240.        gl.BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);
  241.        gl.BufferData(
  242.            gl::ARRAY_BUFFER,
  243.            (VERTICES.len() * mem::size_of::<f32>()) as gl::types::GLsizeiptr,
  244.            VERTICES.as_ptr() as *const _,
  245.            gl::STATIC_DRAW,
  246.        );
  247.  
  248.        let mut vbo_indices = mem::MaybeUninit::uninit();
  249.        gl.GenBuffers(1, vbo_indices.as_mut_ptr());
  250.        let vbo_indices = vbo_indices.assume_init();
  251.        gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, vbo_indices);
  252.        gl.BufferData(
  253.            gl::ELEMENT_ARRAY_BUFFER,
  254.            (INDICES.len() * mem::size_of::<u16>()) as gl::types::GLsizeiptr,
  255.            INDICES.as_ptr() as *const _,
  256.            gl::STATIC_DRAW,
  257.        );
  258.  
  259.        if gl.BindVertexArray.is_loaded() {
  260.            gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, vbo_indices);
  261.            gl.BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);
  262.  
  263.            // Load the vertex position
  264.            gl.VertexAttribPointer(
  265.                attr_position as gl::types::GLuint,
  266.                3,
  267.                gl::FLOAT,
  268.                gl::FALSE,
  269.                (5 * mem::size_of::<f32>()) as gl::types::GLsizei,
  270.                ptr::null(),
  271.            );
  272.  
  273.            // Load the texture coordinate
  274.            gl.VertexAttribPointer(
  275.                attr_texture as gl::types::GLuint,
  276.                2,
  277.                gl::FLOAT,
  278.                gl::FALSE,
  279.                (5 * mem::size_of::<f32>()) as gl::types::GLsizei,
  280.                (3 * mem::size_of::<f32>()) as *const () as *const _,
  281.            );
  282.  
  283.            gl.EnableVertexAttribArray(attr_position as _);
  284.            gl.EnableVertexAttribArray(attr_texture as _);
  285.  
  286.            gl.BindVertexArray(0);
  287.        }
  288.  
  289.        gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
  290.        gl.BindBuffer(gl::ARRAY_BUFFER, 0);
  291.  
  292.        (
  293.            program,
  294.            attr_position,
  295.            attr_texture,
  296.            vao,
  297.            vertex_buffer,
  298.            vbo_indices,
  299.        )
  300.    };
  301.  
  302.    Gl {
  303.        gl,
  304.        program,
  305.        attr_position,
  306.        attr_texture,
  307.        vao,
  308.        vertex_buffer,
  309.        vbo_indices,
  310.    }
  311. }
  312.  
  313. #[derive(Debug)]
  314. enum Message {
  315.    Sample(gst::Sample),
  316.    BusEvent,
  317. }
  318.  
  319. pub(crate) struct App {
  320.    pipeline: gst::Pipeline,
  321.    appsink: gst_app::AppSink,
  322.    glupload: gst::Element,
  323.    bus: gst::Bus,
  324.    event_loop: glutin::event_loop::EventLoop<Message>,
  325.    windowed_context: glutin::WindowedContext<glutin::PossiblyCurrent>,
  326.    shared_context: gst_gl::GLContext,
  327. }
  328.  
  329. impl App {
  330.    pub(crate) fn new(gl_element: Option<&gst::Element>) -> Result<App, Error> {
  331.        gst::init()?;
  332.  
  333.        let (pipeline, appsink, glupload) = App::create_pipeline(gl_element)?;
  334.        let bus = pipeline
  335.            .bus()
  336.            .expect("Pipeline without bus. Shouldn't happen!");
  337.  
  338.        let event_loop = glutin::event_loop::EventLoop::with_user_event();
  339.        let window = glutin::window::WindowBuilder::new().with_title("GL rendering");
  340.        let windowed_context = glutin::ContextBuilder::new()
  341.            .with_vsync(true)
  342.            .build_windowed(window, &event_loop)?;
  343.  
  344.        let windowed_context = unsafe { windowed_context.make_current().map_err(|(_, err)| err)? };
  345.  
  346.        #[cfg(any(feature = "gst-gl-x11", feature = "gst-gl-wayland"))]
  347.        let inner_window = windowed_context.window();
  348.  
  349.        let shared_context: gst_gl::GLContext;
  350.        if cfg!(target_os = "linux") {
  351.            use glutin::platform::unix::RawHandle;
  352.            #[cfg(any(feature = "gst-gl-x11", feature = "gst-gl-wayland"))]
  353.            use glutin::platform::unix::WindowExtUnix;
  354.            use glutin::platform::ContextTraitExt;
  355.  
  356.            let api = App::map_gl_api(windowed_context.get_api());
  357.  
  358.            let (gl_context, gl_display, platform): (usize, _, gst_gl::GLPlatform) = match unsafe {
  359.                windowed_context.raw_handle()
  360.            } {
  361.                #[cfg(any(feature = "gst-gl-egl", feature = "gst-gl-wayland"))]
  362.                RawHandle::Egl(egl_context) => {
  363.                    let mut gl_display = None;
  364.  
  365.                    #[cfg(feature = "gst-gl-egl")]
  366.                    if let Some(display) = unsafe { windowed_context.get_egl_display() } {
  367.                        gl_display = Some(
  368.                            unsafe { gst_gl_egl::GLDisplayEGL::with_egl_display(display as usize) }
  369.                                .unwrap()
  370.                                .upcast::<gst_gl::GLDisplay>(),
  371.                        )
  372.                    };
  373.  
  374.                    #[cfg(feature = "gst-gl-wayland")]
  375.                    if let Some(display) = inner_window.wayland_display() {
  376.                        gl_display = Some(
  377.                            unsafe {
  378.                                gst_gl_wayland::GLDisplayWayland::with_display(display as usize)
  379.                            }
  380.                            .unwrap()
  381.                            .upcast::<gst_gl::GLDisplay>(),
  382.                        )
  383.                    };
  384.  
  385.                    (
  386.                        egl_context as usize,
  387.                        gl_display.expect("Could not retrieve GLDisplay through EGL context and/or Wayland display"),
  388.                        gst_gl::GLPlatform::EGL,
  389.                    )
  390.                }
  391.                #[cfg(feature = "gst-gl-x11")]
  392.                RawHandle::Glx(glx_context) => {
  393.                    let gl_display = if let Some(display) = inner_window.xlib_display() {
  394.                        unsafe { gst_gl_x11::GLDisplayX11::with_display(display as usize) }.unwrap()
  395.                    } else {
  396.                        panic!("X11 window without X Display");
  397.                    };
  398.  
  399.                    (
  400.                        glx_context as usize,
  401.                        gl_display.upcast::<gst_gl::GLDisplay>(),
  402.                        gst_gl::GLPlatform::GLX,
  403.                    )
  404.                }
  405.                #[allow(unreachable_patterns)]
  406.                handler => panic!("Unsupported platform: {:?}.", handler),
  407.            };
  408.  
  409.            shared_context =
  410.                unsafe { gst_gl::GLContext::new_wrapped(&gl_display, gl_context, platform, api) }
  411.                    .unwrap();
  412.  
  413.            shared_context
  414.                .activate(true)
  415.                .expect("Couldn't activate wrapped GL context");
  416.  
  417.            shared_context.fill_info()?;
  418.  
  419.            let gl_context = shared_context.clone();
  420.            let event_proxy = sync::Mutex::new(event_loop.create_proxy());
  421.  
  422.            #[allow(clippy::single_match)]
  423.            bus.set_sync_handler(move |_, msg| {
  424.                match msg.view() {
  425.                    gst::MessageView::NeedContext(ctxt) => {
  426.                        let context_type = ctxt.context_type();
  427.                        if context_type == *gst_gl::GL_DISPLAY_CONTEXT_TYPE {
  428.                            if let Some(el) =
  429.                                msg.src().map(|s| s.downcast::<gst::Element>().unwrap())
  430.                            {
  431.                                let context = gst::Context::new(context_type, true);
  432.                                context.set_gl_display(&gl_display);
  433.                                el.set_context(&context);
  434.                            }
  435.                        }
  436.                        if context_type == "gst.gl.app_context" {
  437.                            if let Some(el) =
  438.                                msg.src().map(|s| s.downcast::<gst::Element>().unwrap())
  439.                            {
  440.                                let mut context = gst::Context::new(context_type, true);
  441.                                {
  442.                                    let context = context.get_mut().unwrap();
  443.                                    let s = context.structure_mut();
  444.                                    s.set("context", &gl_context);
  445.                                }
  446.                                el.set_context(&context);
  447.                            }
  448.                        }
  449.                    }
  450.                    _ => (),
  451.                }
  452.  
  453.                if let Err(e) = event_proxy.lock().unwrap().send_event(Message::BusEvent) {
  454.                    eprintln!("Failed to send BusEvent to event proxy: {}", e)
  455.                }
  456.  
  457.                gst::BusSyncReply::Pass
  458.            });
  459.        } else {
  460.            panic!("This example only has Linux support");
  461.        }
  462.  
  463.        Ok(App {
  464.            pipeline,
  465.            appsink,
  466.            glupload,
  467.            bus,
  468.            event_loop,
  469.            windowed_context,
  470.            shared_context,
  471.        })
  472.    }
  473.  
  474.    fn setup(&self, event_loop: &glutin::event_loop::EventLoop<Message>) -> Result<(), Error> {
  475.        let event_proxy = event_loop.create_proxy();
  476.        self.appsink.set_callbacks(
  477.            gst_app::AppSinkCallbacks::builder()
  478.                .new_sample(move |appsink| {
  479.                    let sample = appsink.pull_sample().map_err(|_| gst::FlowError::Eos)?;
  480.  
  481.                    {
  482.                        let _buffer = sample.buffer().ok_or_else(|| {
  483.                            element_error!(
  484.                                appsink,
  485.                                gst::ResourceError::Failed,
  486.                                ("Failed to get buffer from appsink")
  487.                            );
  488.  
  489.                            gst::FlowError::Error
  490.                        })?;
  491.  
  492.                        let _info = sample
  493.                            .caps()
  494.                            .and_then(|caps| gst_video::VideoInfo::from_caps(caps).ok())
  495.                            .ok_or_else(|| {
  496.                                element_error!(
  497.                                    appsink,
  498.                                    gst::ResourceError::Failed,
  499.                                    ("Failed to get video info from sample")
  500.                                );
  501.  
  502.                                gst::FlowError::Error
  503.                            })?;
  504.                    }
  505.  
  506.                    event_proxy
  507.                        .send_event(Message::Sample(sample))
  508.                        .map(|()| gst::FlowSuccess::Ok)
  509.                        .map_err(|e| {
  510.                            element_error!(
  511.                                appsink,
  512.                                gst::ResourceError::Failed,
  513.                                ("Failed to send sample to event loop: {}", e)
  514.                            );
  515.  
  516.                            gst::FlowError::Error
  517.                        })
  518.                })
  519.                .build(),
  520.        );
  521.  
  522.        self.pipeline.set_state(gst::State::Playing)?;
  523.  
  524.        Ok(())
  525.    }
  526.  
  527.    fn map_gl_api(api: glutin::Api) -> gst_gl::GLAPI {
  528.        match api {
  529.            glutin::Api::OpenGl => gst_gl::GLAPI::OPENGL3,
  530.            glutin::Api::OpenGlEs => gst_gl::GLAPI::GLES2,
  531.            _ => gst_gl::GLAPI::empty(),
  532.        }
  533.    }
  534.  
  535.    fn create_pipeline(
  536.        gl_element: Option<&gst::Element>,
  537.    ) -> Result<(gst::Pipeline, gst_app::AppSink, gst::Element), Error> {
  538.        let playbin = gst::ElementFactory::make("playbin", None).unwrap();
  539.        playbin.set_property(
  540.            "uri",
  541.            "https://upload.wikimedia.org/wikipedia/commons/0/08/Visit_of_the_Mandelbulb_%284K_UHD%3B_50FPS%29.webm",
  542.        )?;
  543.  
  544.        let appsink = gst::ElementFactory::make("appsink", None)
  545.            .map_err(|_| MissingElement("appsink"))?
  546.            .dynamic_cast::<gst_app::AppSink>()
  547.            .expect("Sink element is expected to be an appsink!");
  548.  
  549.        appsink.set_property("enable-last-sample", &false)?;
  550.        appsink.set_property("emit-signals", &false)?;
  551.        appsink.set_property("max-buffers", &1u32)?;
  552.  
  553.        let caps = gst::Caps::builder("video/x-raw")
  554.            .features(&[&gst_gl::CAPS_FEATURE_MEMORY_GL_MEMORY])
  555.            .field("format", &gst_video::VideoFormat::Rgba.to_str())
  556.            .field("texture-target", &"2D")
  557.            .build();
  558.        appsink.set_caps(Some(&caps));
  559.  
  560.        let sink = gst::ElementFactory::make("glsinkbin", None)
  561.            .map_err(|_| MissingElement("glsinkbin"))?;
  562.  
  563.        sink.set_property("sink", &appsink)?;
  564.  
  565.        playbin.set_property("video-sink", &sink)?;
  566.  
  567.        let pipeline = playbin.downcast::<gst::Pipeline>().unwrap();
  568.  
  569.        // get the glupload element to extract later the used context in it
  570.        let mut iter = sink.dynamic_cast::<gst::Bin>().unwrap().iterate_elements();
  571.        let glupload = loop {
  572.            match iter.next() {
  573.                Ok(Some(element)) => {
  574.                    if "glupload" == element.factory().unwrap().name() {
  575.                        break Some(element);
  576.                    }
  577.                }
  578.                Err(gst::IteratorError::Resync) => iter.resync(),
  579.                _ => break None,
  580.            }
  581.        };
  582.  
  583.        Ok((pipeline, appsink, glupload.unwrap()))
  584.    }
  585.  
  586.    fn handle_messages(bus: &gst::Bus) -> Result<(), Error> {
  587.        use gst::MessageView;
  588.  
  589.        for msg in bus.iter() {
  590.            match msg.view() {
  591.                MessageView::Eos(..) => break,
  592.                MessageView::Error(err) => {
  593.                    return Err(ErrorMessage {
  594.                        src: msg
  595.                            .src()
  596.                            .map(|s| String::from(s.path_string()))
  597.                            .unwrap_or_else(|| String::from("None")),
  598.                        error: err.error().to_string(),
  599.                        debug: err.debug(),
  600.                        source: err.error(),
  601.                    }
  602.                    .into());
  603.                }
  604.                _ => (),
  605.            }
  606.        }
  607.  
  608.        Ok(())
  609.    }
  610. }
  611.  
  612. pub(crate) fn main_loop(app: App) -> Result<(), Error> {
  613.    app.setup(&app.event_loop)?;
  614.  
  615.    println!(
  616.        "Pixel format of the window's GL context {:?}",
  617.        app.windowed_context.get_pixel_format()
  618.    );
  619.  
  620.    let gl = load(&app.windowed_context);
  621.  
  622.    let mut curr_frame: Option<gst_video::VideoFrame<gst_video::video_frame::Readable>> = None;
  623.    let mut gst_gl_context: Option<gst_gl::GLContext> = None;
  624.  
  625.    let App {
  626.        bus,
  627.        event_loop,
  628.        glupload,
  629.        pipeline,
  630.        shared_context,
  631.        windowed_context,
  632.        ..
  633.    } = app;
  634.  
  635.    event_loop.run(move |event, _, cf| {
  636.        *cf = glutin::event_loop::ControlFlow::Wait;
  637.  
  638.        let mut needs_redraw = false;
  639.        match event {
  640.            glutin::event::Event::LoopDestroyed => {
  641.                pipeline.send_event(gst::event::Eos::new());
  642.                pipeline.set_state(gst::State::Null).unwrap();
  643.            }
  644.            glutin::event::Event::WindowEvent { event, .. } => match event {
  645.                glutin::event::WindowEvent::CloseRequested
  646.                | glutin::event::WindowEvent::KeyboardInput {
  647.                    input:
  648.                        glutin::event::KeyboardInput {
  649.                            state: glutin::event::ElementState::Released,
  650.                            virtual_keycode: Some(glutin::event::VirtualKeyCode::Escape),
  651.                            ..
  652.                        },
  653.                    ..
  654.                } => *cf = glutin::event_loop::ControlFlow::Exit,
  655.                glutin::event::WindowEvent::Resized(physical_size) => {
  656.                    windowed_context.resize(physical_size);
  657.                    gl.resize(physical_size);
  658.                }
  659.                _ => (),
  660.            },
  661.            glutin::event::Event::RedrawRequested(_) => needs_redraw = true,
  662.            // Receive a frame
  663.            glutin::event::Event::UserEvent(Message::Sample(sample)) => {
  664.                let buffer = sample.buffer_owned().unwrap();
  665.                let info = sample
  666.                    .caps()
  667.                    .and_then(|caps| gst_video::VideoInfo::from_caps(caps).ok())
  668.                    .unwrap();
  669.  
  670.                {
  671.                    if gst_gl_context.is_none() {
  672.                        gst_gl_context = glupload
  673.                            .property("context")
  674.                            .unwrap()
  675.                            .get::<Option<gst_gl::GLContext>>()
  676.                            .unwrap();
  677.                    }
  678.  
  679.                    if let Some(sync_meta) = buffer.meta::<gst_gl::GLSyncMeta>() {
  680.                        sync_meta.set_sync_point(gst_gl_context.as_ref().unwrap());
  681.                    }
  682.                }
  683.  
  684.                if let Ok(frame) = gst_video::VideoFrame::from_buffer_readable_gl(buffer, &info) {
  685.                    curr_frame = Some(frame);
  686.                    needs_redraw = true;
  687.                }
  688.            }
  689.            // Handle all pending messages when we are awaken by set_sync_handler
  690.            glutin::event::Event::UserEvent(Message::BusEvent) => {
  691.                App::handle_messages(&bus).unwrap();
  692.            }
  693.            _ => (),
  694.        }
  695.  
  696.        if needs_redraw {
  697.            if let Some(frame) = curr_frame.as_ref() {
  698.                if let Some(sync_meta) = frame.buffer().meta::<gst_gl::GLSyncMeta>() {
  699.                    sync_meta.wait(&shared_context);
  700.                }
  701.                if let Some(texture) = frame.texture_id(0) {
  702.                    gl.draw_frame(texture as gl::types::GLuint);
  703.                }
  704.            }
  705.            windowed_context.swap_buffers().unwrap();
  706.        }
  707.    })
  708. }
  709.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement