mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git
synced 2024-11-26 03:21:03 +00:00
tutorials: Add playback-tutorial-1
This commit is contained in:
parent
890cd03632
commit
ffe6821813
2 changed files with 221 additions and 0 deletions
|
@ -26,3 +26,7 @@ tutorial5-quartz = ["tutorial5"]
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "basic-tutorial-13"
|
name = "basic-tutorial-13"
|
||||||
required-features = ["termion"]
|
required-features = ["termion"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "playback-tutorial-1"
|
||||||
|
required-features = ["termion"]
|
||||||
|
|
217
tutorials/src/bin/playback-tutorial-1.rs
Normal file
217
tutorials/src/bin/playback-tutorial-1.rs
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
use glib::FlagsClass;
|
||||||
|
use gst::prelude::*;
|
||||||
|
|
||||||
|
use anyhow::Error;
|
||||||
|
|
||||||
|
use termion::event::Key;
|
||||||
|
use termion::input::TermRead;
|
||||||
|
|
||||||
|
use std::{thread, time};
|
||||||
|
|
||||||
|
#[path = "../tutorials-common.rs"]
|
||||||
|
mod tutorials_common;
|
||||||
|
|
||||||
|
fn analyze_streams(playbin: &gst::Element) {
|
||||||
|
let n_video = playbin.property("n-video").unwrap().get::<i32>().unwrap();
|
||||||
|
let n_audio = playbin.property("n-audio").unwrap().get::<i32>().unwrap();
|
||||||
|
let n_text = playbin.property("n-text").unwrap().get::<i32>().unwrap();
|
||||||
|
println!(
|
||||||
|
"{} video stream(s), {} audio stream(s), {} text stream(s)",
|
||||||
|
n_video, n_audio, n_text
|
||||||
|
);
|
||||||
|
|
||||||
|
for i in 0..n_video {
|
||||||
|
let tags = playbin
|
||||||
|
.emit_by_name("get-video-tags", &[&i])
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Ok(tags) = tags.get::<gst::TagList>() {
|
||||||
|
println!("video stream {}:", i);
|
||||||
|
if let Some(codec) = tags.get::<gst::tags::VideoCodec>() {
|
||||||
|
println!(" codec: {}", codec.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..n_audio {
|
||||||
|
let tags = playbin
|
||||||
|
.emit_by_name("get-audio-tags", &[&i])
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Ok(tags) = tags.get::<gst::TagList>() {
|
||||||
|
println!("audio stream {}:", i);
|
||||||
|
if let Some(codec) = tags.get::<gst::tags::AudioCodec>() {
|
||||||
|
println!(" codec: {}", codec.get());
|
||||||
|
}
|
||||||
|
if let Some(codec) = tags.get::<gst::tags::LanguageCode>() {
|
||||||
|
println!(" language: {}", codec.get());
|
||||||
|
}
|
||||||
|
if let Some(codec) = tags.get::<gst::tags::Bitrate>() {
|
||||||
|
println!(" bitrate: {}", codec.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..n_text {
|
||||||
|
let tags = playbin
|
||||||
|
.emit_by_name("get-text-tags", &[&i])
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Ok(tags) = tags.get::<gst::TagList>() {
|
||||||
|
println!("subtitle stream {}:", i);
|
||||||
|
if let Some(codec) = tags.get::<gst::tags::LanguageCode>() {
|
||||||
|
println!(" language: {}", codec.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_video = playbin
|
||||||
|
.property("current-video")
|
||||||
|
.unwrap()
|
||||||
|
.get::<i32>()
|
||||||
|
.unwrap();
|
||||||
|
let current_audio = playbin
|
||||||
|
.property("current-audio")
|
||||||
|
.unwrap()
|
||||||
|
.get::<i32>()
|
||||||
|
.unwrap();
|
||||||
|
let current_text = playbin
|
||||||
|
.property("current-text")
|
||||||
|
.unwrap()
|
||||||
|
.get::<i32>()
|
||||||
|
.unwrap();
|
||||||
|
println!(
|
||||||
|
"Currently playing video stream {}, audio stream {}, text stream {}",
|
||||||
|
current_video, current_audio, current_text
|
||||||
|
);
|
||||||
|
println!("Type any number and hit ENTER to select a different audio stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_keyboard(playbin: &gst::Element, main_loop: &glib::MainLoop) {
|
||||||
|
let mut stdin = termion::async_stdin().keys();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Some(Ok(input)) = stdin.next() {
|
||||||
|
match input {
|
||||||
|
Key::Char(index) => {
|
||||||
|
if let Some(index) = index.to_digit(10) {
|
||||||
|
// Here index can only be 0-9
|
||||||
|
let index = index as i32;
|
||||||
|
let n_audio = playbin.property("n-audio").unwrap().get::<i32>().unwrap();
|
||||||
|
|
||||||
|
if index < n_audio {
|
||||||
|
println!("Setting current audio stream to {}", index);
|
||||||
|
playbin.set_property("current-audio", index).unwrap();
|
||||||
|
} else {
|
||||||
|
eprintln!("Index out of bounds");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Key::Ctrl('c') => {
|
||||||
|
main_loop.quit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
thread::sleep(time::Duration::from_millis(50));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tutorial_main() -> Result<(), Error> {
|
||||||
|
// Set up main loop
|
||||||
|
let main_loop = glib::MainLoop::new(None, false);
|
||||||
|
|
||||||
|
// Initialize GStreamer
|
||||||
|
gst::init()?;
|
||||||
|
|
||||||
|
// Create PlayBin element
|
||||||
|
let playbin = gst::ElementFactory::make("playbin", Some("playbin"))?;
|
||||||
|
|
||||||
|
// Set URI to play
|
||||||
|
let uri =
|
||||||
|
"https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_cropped_multilingual.webm";
|
||||||
|
playbin.set_property("uri", uri)?;
|
||||||
|
|
||||||
|
// Set flags to show Audio and Video but ignore Subtitles
|
||||||
|
let flags = playbin.property("flags")?;
|
||||||
|
let flags_class = FlagsClass::new(flags.type_()).unwrap();
|
||||||
|
|
||||||
|
let flags = flags_class
|
||||||
|
.builder_with_value(flags)
|
||||||
|
.unwrap()
|
||||||
|
.set_by_nick("audio")
|
||||||
|
.set_by_nick("video")
|
||||||
|
.unset_by_nick("text")
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
playbin.set_property_from_value("flags", &flags)?;
|
||||||
|
|
||||||
|
// Set connection speed. This will affect some internal decisions of playbin
|
||||||
|
playbin.set_property("connection-speed", 56u64)?;
|
||||||
|
|
||||||
|
// Handle keyboard input
|
||||||
|
let playbin_clone = playbin.clone();
|
||||||
|
let main_loop_clone = main_loop.clone();
|
||||||
|
thread::spawn(move || handle_keyboard(&playbin_clone, &main_loop_clone));
|
||||||
|
|
||||||
|
// Add a bus watch, so we get notified when a message arrives
|
||||||
|
let playbin_clone = playbin.clone();
|
||||||
|
let main_loop_clone = main_loop.clone();
|
||||||
|
let bus = playbin.bus().unwrap();
|
||||||
|
bus.add_watch(move |_bus, message| {
|
||||||
|
use gst::MessageView;
|
||||||
|
match message.view() {
|
||||||
|
MessageView::Error(err) => {
|
||||||
|
eprintln!(
|
||||||
|
"Error received from element {:?} {}",
|
||||||
|
err.src().map(|s| s.path_string()),
|
||||||
|
err.error()
|
||||||
|
);
|
||||||
|
eprintln!("Debugging information: {:?}", err.debug());
|
||||||
|
main_loop_clone.quit();
|
||||||
|
Continue(false)
|
||||||
|
}
|
||||||
|
MessageView::StateChanged(state_changed) => {
|
||||||
|
if state_changed
|
||||||
|
.src()
|
||||||
|
.map(|s| s == playbin_clone)
|
||||||
|
.unwrap_or(false)
|
||||||
|
&& state_changed.current() == gst::State::Playing
|
||||||
|
{
|
||||||
|
analyze_streams(&playbin_clone);
|
||||||
|
}
|
||||||
|
Continue(true)
|
||||||
|
}
|
||||||
|
MessageView::Eos(..) => {
|
||||||
|
println!("Reached end of stream");
|
||||||
|
main_loop_clone.quit();
|
||||||
|
Continue(false)
|
||||||
|
}
|
||||||
|
_ => Continue(true),
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Set to PLAYING
|
||||||
|
playbin.set_state(gst::State::Playing)?;
|
||||||
|
|
||||||
|
// Set GLib mainlooop to run
|
||||||
|
main_loop.run();
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
playbin.set_state(gst::State::Null)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// tutorials_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)
|
||||||
|
match tutorials_common::run(tutorial_main) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => eprintln!("Failed: {}", err),
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue