use crate::frame_handler::FrameHandler;
use crate::streamer::InternalMessage;
use crate::VideoStreamEvent;
use gst::element_error;
use gstreamer as gst;
use gstreamer_app as gst_app;
use gstreamer_app::AppSink;
use gstreamer_video as gst_video;
use std::sync::mpsc::Sender;
pub(crate) fn memory_video_sink(
internal_sender: Sender<InternalMessage>,
external_sender: Sender<VideoStreamEvent>,
frame_data_handler: impl FrameHandler + 'static,
) -> AppSink {
let video_format = gst_video::VideoCapsBuilder::new()
.format(gst_video::VideoFormat::Rgba)
.build();
let appsink = gst_app::AppSink::builder().caps(&video_format).build();
let sink_callback = gst_app::AppSinkCallbacks::builder()
.new_sample(move |appsink| {
let sample = appsink.pull_sample().map_err(|_| gst::FlowError::Eos)?;
let buffer = sample.buffer().ok_or_else(|| {
element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to get buffer from appsink")
);
gst::FlowError::Error
})?;
let map = buffer.map_readable().map_err(|_| {
element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to map buffer readable")
);
gst::FlowError::Error
})?;
let caps = sample.caps().expect("Expect caps to exist");
let info = gst_video::VideoInfo::from_caps(caps).expect("Failed to parse caps");
internal_sender
.send(InternalMessage::RequestPositionUpdate)
.unwrap();
frame_data_handler.handle_new_frame(map.as_slice(), (info.width(), info.height()));
external_sender.send(VideoStreamEvent::NewFrame).unwrap();
Ok(gst::FlowSuccess::Ok)
})
.build();
appsink.set_callbacks(sink_callback);
appsink
}