mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git
synced 2024-11-25 19:11:06 +00:00
Add basic-tutorial-4 from the GStreamer tutorials
https://cgit.freedesktop.org/gstreamer/gst-docs/tree/examples/tutorials/basic-tutorial-4.c Fixes https://github.com/sdroege/gstreamer-rs/pull/39
This commit is contained in:
parent
d85be4fe03
commit
f253caac19
1 changed files with 149 additions and 0 deletions
149
tutorials/src/bin/basic-tutorial-4.rs
Normal file
149
tutorials/src/bin/basic-tutorial-4.rs
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
extern crate gstreamer as gst;
|
||||||
|
use std::io;
|
||||||
|
use std::io::Write;
|
||||||
|
use gst::prelude::*;
|
||||||
|
use gst::MessageView;
|
||||||
|
|
||||||
|
struct CustomData {
|
||||||
|
playbin: gst::Element, // Our one and only element
|
||||||
|
playing: bool, // Are we in the PLAYING state?
|
||||||
|
terminate: bool, // Should we terminate execution?
|
||||||
|
seek_enabled: bool, // Is seeking enabled for this media?
|
||||||
|
seek_done: bool, // Have we performed the seek already?
|
||||||
|
duration: gst::ClockTime, // How long does this media last, in nanoseconds
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Initialize GStreamer
|
||||||
|
gst::init().unwrap();
|
||||||
|
|
||||||
|
// Creat the playbin element
|
||||||
|
let playbin =
|
||||||
|
gst::ElementFactory::make("playbin", "playbin").expect("Failed to create playbin element");
|
||||||
|
|
||||||
|
// Set the URI to play
|
||||||
|
let uri = "https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm";
|
||||||
|
playbin
|
||||||
|
.set_property("uri", &uri)
|
||||||
|
.expect("Can't set uri property on playbin");
|
||||||
|
|
||||||
|
// Start playing
|
||||||
|
let ret = playbin.set_state(gst::State::Playing);
|
||||||
|
assert_ne!(ret, gst::StateChangeReturn::Failure);
|
||||||
|
|
||||||
|
// Listen to the bus
|
||||||
|
let bus = playbin.get_bus().unwrap();
|
||||||
|
let mut custom_data = CustomData {
|
||||||
|
playbin: playbin,
|
||||||
|
playing: false,
|
||||||
|
terminate: false,
|
||||||
|
seek_enabled: false,
|
||||||
|
seek_done: false,
|
||||||
|
duration: gst::CLOCK_TIME_NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
while !custom_data.terminate {
|
||||||
|
let msg = bus.timed_pop(100 * gst::MSECOND);
|
||||||
|
|
||||||
|
match msg {
|
||||||
|
Some(msg) => {
|
||||||
|
handle_message(&mut custom_data, &msg);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if custom_data.playing {
|
||||||
|
let position = custom_data
|
||||||
|
.playbin
|
||||||
|
.query_position(gst::Format::Time)
|
||||||
|
.expect("Could not query current position.");
|
||||||
|
let position = position as gst::ClockTime;
|
||||||
|
|
||||||
|
// If we didn't know it yet, query the stream duration
|
||||||
|
if custom_data.duration == gst::CLOCK_TIME_NONE {
|
||||||
|
custom_data.duration = custom_data
|
||||||
|
.playbin
|
||||||
|
.query_duration(gst::Format::Time)
|
||||||
|
.expect("Could not query current duration.") as
|
||||||
|
gst::ClockTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print current position and total duration
|
||||||
|
print!("\rPosition {} / {}", position, custom_data.duration);
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
|
||||||
|
if custom_data.seek_enabled && !custom_data.seek_done &&
|
||||||
|
position > 10 * gst::SECOND
|
||||||
|
{
|
||||||
|
println!("\nReached 10s, performing seek...");
|
||||||
|
custom_data
|
||||||
|
.playbin
|
||||||
|
.seek_simple(
|
||||||
|
gst::Format::Time,
|
||||||
|
gst::SeekFlags::FLUSH | gst::SeekFlags::KEY_UNIT,
|
||||||
|
(30 * gst::SECOND) as i64,
|
||||||
|
)
|
||||||
|
.expect("Failed to seek.");
|
||||||
|
custom_data.seek_done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown pipeline
|
||||||
|
let ret = custom_data.playbin.set_state(gst::State::Null);
|
||||||
|
assert_ne!(ret, gst::StateChangeReturn::Failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_message(custom_data: &mut CustomData, msg: &gst::GstRc<gst::MessageRef>) {
|
||||||
|
match msg.view() {
|
||||||
|
MessageView::Error(err) => {
|
||||||
|
println!(
|
||||||
|
"Error received from element {}: {} ({:?})",
|
||||||
|
msg.get_src().get_path_string(),
|
||||||
|
err.get_error(),
|
||||||
|
err.get_debug()
|
||||||
|
);
|
||||||
|
custom_data.terminate = true;
|
||||||
|
}
|
||||||
|
MessageView::Eos(..) => {
|
||||||
|
println!("End-Of-Stream reached.");
|
||||||
|
custom_data.terminate = true;
|
||||||
|
}
|
||||||
|
MessageView::DurationChanged(_) => {
|
||||||
|
// The duration has changed, mark the current one as invalid
|
||||||
|
custom_data.duration = gst::CLOCK_TIME_NONE;
|
||||||
|
}
|
||||||
|
MessageView::StateChanged(state) => if msg.get_src() == custom_data.playbin {
|
||||||
|
let new_state = state.get_current();
|
||||||
|
let old_state = state.get_old();
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Pipeline state changed from {:?} to {:?}",
|
||||||
|
old_state,
|
||||||
|
new_state
|
||||||
|
);
|
||||||
|
|
||||||
|
custom_data.playing = new_state == gst::State::Playing;
|
||||||
|
if custom_data.playing {
|
||||||
|
let query = gst::Query::new_seeking(gst::Format::Time);
|
||||||
|
if custom_data.playbin.query(query.get_mut().unwrap()) {
|
||||||
|
match query.view() {
|
||||||
|
gst::QueryView::Seeking(seek) => {
|
||||||
|
let (_fmt, seekable, start, end) = seek.get();
|
||||||
|
custom_data.seek_enabled = seekable;
|
||||||
|
if seekable {
|
||||||
|
println!("Seeking is ENABLED from {} to {}", start, end)
|
||||||
|
} else {
|
||||||
|
println!("Seeking is DISABLED for this stream.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eprintln!("Seeking query failed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue