Merge branch 'mse-example' into 'main'

Draft: Adding example for using the mse rust bindings

See merge request gstreamer/gstreamer-rs!1750
This commit is contained in:
ryankav 2025-08-29 14:38:02 +00:00
commit 1b4a0d4b74
6 changed files with 122 additions and 0 deletions

1
Cargo.lock generated
View file

@ -528,6 +528,7 @@ dependencies = [
"gstreamer-gl",
"gstreamer-gl-egl",
"gstreamer-gl-x11",
"gstreamer-mse",
"gstreamer-pbutils",
"gstreamer-play",
"gstreamer-player",

View file

@ -15,6 +15,7 @@ gst-gl-x11 = { workspace = true, optional = true }
gst-app.workspace = true
gst-audio.workspace = true
gst-base.workspace = true
gst-mse.workspace = true
gst-video.workspace = true
gst-pbutils.workspace = true
gst-play = { workspace = true, optional = true }
@ -109,6 +110,10 @@ name = "events"
[[bin]]
name = "iterator"
[[bin]]
name = "mse-player"
required-features = ["gst-play"]
[[bin]]
name = "launch_glib_main"

Binary file not shown.

BIN
examples/resources/mse.mp4 Normal file

Binary file not shown.

BIN
examples/resources/mse.webm Normal file

Binary file not shown.

View file

@ -0,0 +1,116 @@
// This example shows how to use the GstPlay API.
// The GstPlay API is a convenience API to allow implement playback applications
// without having to write too much code.
// Most of the tasks a play needs to support (such as seeking and switching
// audio / subtitle streams or changing the volume) are all supported by simple
// one-line function calls on the GstPlay.
use std::env::{self};
use std::fs::File;
use std::io::Read;
use anyhow::Error;
#[path = "../examples-common.rs"]
mod examples_common;
use gst_mse::{MediaSource, MediaSourceEOSError};
use gst_play::prelude::*;
use gst_play::{Play, PlayMessage, PlayVideoRenderer};
fn main_loop(file_path: &str, video_type: &str) -> Result<(), Error> {
gst::init()?;
let play = Play::new(None::<PlayVideoRenderer>);
let media_source = MediaSource::new();
play.set_uri(Some("mse://"));
play.pipeline().connect_closure(
"source-setup",
false,
glib::closure!(
#[strong]
media_source,
move |_pipeline: &gst::Element, src: &gst_mse::MseSrc| {
media_source.attach(&src);
}
),
);
media_source.connect_on_source_open(glib::clone!(
#[to_owned]
file_path,
#[to_owned]
video_type,
#[strong]
media_source,
move |source| {
let full_source_buffer = source
.add_source_buffer(&video_type)
.expect("Failed to create source buffer");
full_source_buffer.connect_on_update_end(glib::clone!(
#[strong]
media_source,
move |_| {
let _ = media_source.end_of_stream(MediaSourceEOSError::None);
}
));
let mut file = File::open(&file_path).expect("File should exist");
let mut file_data = Vec::new();
file.read_to_end(&mut file_data)
.expect("Couldn't read file to end");
full_source_buffer
.append_buffer(gst::Buffer::from_slice(file_data))
.expect("Failed to append file buffer to source buffer");
}
));
play.play();
let mut result = Ok(());
for msg in play.message_bus().iter_timed(gst::ClockTime::NONE) {
match PlayMessage::parse(&msg) {
Ok(PlayMessage::EndOfStream(_)) => {
play.stop();
break;
}
Ok(PlayMessage::Error(msg)) => {
result = Err(msg.error().clone());
play.stop();
break;
}
Ok(_) => (),
Err(_) => unreachable!(),
}
}
// Set the message bus to flushing to ensure that all pending messages are dropped and there
// are no further references to the play instance.
play.message_bus().set_flushing(true);
result.map_err(|e| e.into())
}
fn example_main() {
let args: Vec<_> = env::args().collect();
let (file_path, video_type): (&str, &str) = if args.len() == 3 {
(args[1].as_ref(), args[2].as_ref())
} else {
println!("Usage: play uri");
std::process::exit(-1)
};
match main_loop(file_path, video_type) {
Ok(r) => r,
Err(e) => eprintln!("Error! {e}"),
}
}
fn main() {
// examples_common::run is only required to set up the application environment on macOS
// (but not necessary in normal Cocoa applications where this is set up automatically)
examples_common::run(example_main);
}