Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'utils/gst-plugin-togglerecord/examples/gtk_recording.rs')
-rw-r--r--utils/gst-plugin-togglerecord/examples/gtk_recording.rs358
1 files changed, 358 insertions, 0 deletions
diff --git a/utils/gst-plugin-togglerecord/examples/gtk_recording.rs b/utils/gst-plugin-togglerecord/examples/gtk_recording.rs
new file mode 100644
index 000000000..8f0bc0bb1
--- /dev/null
+++ b/utils/gst-plugin-togglerecord/examples/gtk_recording.rs
@@ -0,0 +1,358 @@
+// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
+// Boston, MA 02110-1335, USA.
+
+extern crate glib;
+use glib::prelude::*;
+extern crate gio;
+use gio::prelude::*;
+
+extern crate gstreamer as gst;
+use gst::prelude::*;
+
+extern crate gsttogglerecord;
+
+extern crate gtk;
+use gtk::prelude::*;
+use std::cell::RefCell;
+use std::env;
+
+fn create_pipeline() -> (
+ gst::Pipeline,
+ gst::Pad,
+ gst::Pad,
+ gst::Element,
+ gst::Element,
+ gtk::Widget,
+) {
+ let pipeline = gst::Pipeline::new(None);
+
+ let video_src = gst::ElementFactory::make("videotestsrc", None).unwrap();
+ video_src.set_property("is-live", &true).unwrap();
+ video_src.set_property_from_str("pattern", "ball");
+
+ let timeoverlay = gst::ElementFactory::make("timeoverlay", None).unwrap();
+ timeoverlay
+ .set_property("font-desc", &"Monospace 20")
+ .unwrap();
+
+ let video_tee = gst::ElementFactory::make("tee", None).unwrap();
+ let video_queue1 = gst::ElementFactory::make("queue", None).unwrap();
+ let video_queue2 = gst::ElementFactory::make("queue", None).unwrap();
+
+ let video_convert1 = gst::ElementFactory::make("videoconvert", None).unwrap();
+ let video_convert2 = gst::ElementFactory::make("videoconvert", None).unwrap();
+
+ let (video_sink, video_widget) =
+ if let Ok(gtkglsink) = gst::ElementFactory::make("gtkglsink", None) {
+ let glsinkbin = gst::ElementFactory::make("glsinkbin", None).unwrap();
+ glsinkbin.set_property("sink", &gtkglsink).unwrap();
+
+ let widget = gtkglsink.get_property("widget").unwrap();
+ (glsinkbin, widget.get::<gtk::Widget>().unwrap().unwrap())
+ } else {
+ let sink = gst::ElementFactory::make("gtksink", None).unwrap();
+ let widget = sink.get_property("widget").unwrap();
+ (sink, widget.get::<gtk::Widget>().unwrap().unwrap())
+ };
+
+ let video_enc = gst::ElementFactory::make("x264enc", None).unwrap();
+ video_enc.set_property("rc-lookahead", &10i32).unwrap();
+ video_enc.set_property("key-int-max", &30u32).unwrap();
+ let video_parse = gst::ElementFactory::make("h264parse", None).unwrap();
+
+ let audio_src = gst::ElementFactory::make("audiotestsrc", None).unwrap();
+ audio_src.set_property("is-live", &true).unwrap();
+ audio_src.set_property_from_str("wave", "ticks");
+
+ let audio_tee = gst::ElementFactory::make("tee", None).unwrap();
+ let audio_queue1 = gst::ElementFactory::make("queue", None).unwrap();
+ let audio_queue2 = gst::ElementFactory::make("queue", None).unwrap();
+
+ let audio_convert1 = gst::ElementFactory::make("audioconvert", None).unwrap();
+ let audio_convert2 = gst::ElementFactory::make("audioconvert", None).unwrap();
+
+ let audio_sink = gst::ElementFactory::make("autoaudiosink", None).unwrap();
+
+ let audio_enc = gst::ElementFactory::make("lamemp3enc", None).unwrap();
+ let audio_parse = gst::ElementFactory::make("mpegaudioparse", None).unwrap();
+
+ let togglerecord = gst::ElementFactory::make("togglerecord", None).unwrap();
+
+ let mux_queue1 = gst::ElementFactory::make("queue", None).unwrap();
+ let mux_queue2 = gst::ElementFactory::make("queue", None).unwrap();
+
+ let mux = gst::ElementFactory::make("mp4mux", None).unwrap();
+
+ let file_sink = gst::ElementFactory::make("filesink", None).unwrap();
+ file_sink
+ .set_property("location", &"recording.mp4")
+ .unwrap();
+ file_sink.set_property("async", &false).unwrap();
+ file_sink.set_property("sync", &false).unwrap();
+
+ pipeline
+ .add_many(&[
+ &video_src,
+ &timeoverlay,
+ &video_tee,
+ &video_queue1,
+ &video_queue2,
+ &video_convert1,
+ &video_convert2,
+ &video_sink,
+ &video_enc,
+ &video_parse,
+ &audio_src,
+ &audio_tee,
+ &audio_queue1,
+ &audio_queue2,
+ &audio_convert1,
+ &audio_convert2,
+ &audio_sink,
+ &audio_enc,
+ &audio_parse,
+ &togglerecord,
+ &mux_queue1,
+ &mux_queue2,
+ &mux,
+ &file_sink,
+ ])
+ .unwrap();
+
+ gst::Element::link_many(&[
+ &video_src,
+ &timeoverlay,
+ &video_tee,
+ &video_queue1,
+ &video_convert1,
+ &video_sink,
+ ])
+ .unwrap();
+
+ gst::Element::link_many(&[
+ &video_tee,
+ &video_queue2,
+ &video_convert2,
+ &video_enc,
+ &video_parse,
+ ])
+ .unwrap();
+
+ video_parse
+ .link_pads(Some("src"), &togglerecord, Some("sink"))
+ .unwrap();
+ togglerecord
+ .link_pads(Some("src"), &mux_queue1, Some("sink"))
+ .unwrap();
+ mux_queue1
+ .link_pads(Some("src"), &mux, Some("video_%u"))
+ .unwrap();
+
+ gst::Element::link_many(&[
+ &audio_src,
+ &audio_tee,
+ &audio_queue1,
+ &audio_convert1,
+ &audio_sink,
+ ])
+ .unwrap();
+
+ gst::Element::link_many(&[
+ &audio_tee,
+ &audio_queue2,
+ &audio_convert2,
+ &audio_enc,
+ &audio_parse,
+ ])
+ .unwrap();
+
+ audio_parse
+ .link_pads(Some("src"), &togglerecord, Some("sink_0"))
+ .unwrap();
+ togglerecord
+ .link_pads(Some("src_0"), &mux_queue2, Some("sink"))
+ .unwrap();
+ mux_queue2
+ .link_pads(Some("src"), &mux, Some("audio_%u"))
+ .unwrap();
+
+ gst::Element::link_many(&[&mux, &file_sink]).unwrap();
+
+ (
+ pipeline,
+ video_queue2.get_static_pad("sink").unwrap(),
+ audio_queue2.get_static_pad("sink").unwrap(),
+ togglerecord,
+ video_sink,
+ video_widget,
+ )
+}
+
+fn create_ui(app: &gtk::Application) {
+ let (pipeline, video_pad, audio_pad, togglerecord, video_sink, video_widget) =
+ create_pipeline();
+
+ let window = gtk::Window::new(gtk::WindowType::Toplevel);
+ window.set_default_size(320, 240);
+ let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
+ vbox.pack_start(&video_widget, true, true, 0);
+
+ let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
+ let position_label = gtk::Label::new(Some("Position: 00:00:00"));
+ hbox.pack_start(&position_label, true, true, 5);
+ let recorded_duration_label = gtk::Label::new(Some("Recorded: 00:00:00"));
+ hbox.pack_start(&recorded_duration_label, true, true, 5);
+ vbox.pack_start(&hbox, false, false, 5);
+
+ let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
+ let record_button = gtk::Button::new_with_label("Record");
+ hbox.pack_start(&record_button, true, true, 5);
+ let finish_button = gtk::Button::new_with_label("Finish");
+ hbox.pack_start(&finish_button, true, true, 5);
+ vbox.pack_start(&hbox, false, false, 5);
+
+ window.add(&vbox);
+ window.show_all();
+
+ app.add_window(&window);
+
+ let video_sink_weak = video_sink.downgrade();
+ let togglerecord_weak = togglerecord.downgrade();
+ let timeout_id = gtk::timeout_add(100, move || {
+ let video_sink = match video_sink_weak.upgrade() {
+ Some(video_sink) => video_sink,
+ None => return glib::Continue(true),
+ };
+
+ let togglerecord = match togglerecord_weak.upgrade() {
+ Some(togglerecord) => togglerecord,
+ None => return glib::Continue(true),
+ };
+
+ let position = video_sink
+ .query_position::<gst::ClockTime>()
+ .unwrap_or_else(|| 0.into());
+ position_label.set_text(&format!("Position: {:.1}", position));
+
+ let recording_duration = togglerecord
+ .get_static_pad("src")
+ .unwrap()
+ .query_position::<gst::ClockTime>()
+ .unwrap_or_else(|| 0.into());
+ recorded_duration_label.set_text(&format!("Recorded: {:.1}", recording_duration));
+
+ glib::Continue(true)
+ });
+
+ let togglerecord_weak = togglerecord.downgrade();
+ record_button.connect_clicked(move |button| {
+ let togglerecord = match togglerecord_weak.upgrade() {
+ Some(togglerecord) => togglerecord,
+ None => return,
+ };
+
+ let recording = !togglerecord
+ .get_property("record")
+ .unwrap()
+ .get_some::<bool>()
+ .unwrap();
+ togglerecord.set_property("record", &recording).unwrap();
+
+ button.set_label(if recording { "Stop" } else { "Record" });
+ });
+
+ let record_button_weak = record_button.downgrade();
+ finish_button.connect_clicked(move |button| {
+ let record_button = match record_button_weak.upgrade() {
+ Some(record_button) => record_button,
+ None => return,
+ };
+
+ record_button.set_sensitive(false);
+ button.set_sensitive(false);
+
+ video_pad.send_event(gst::Event::new_eos().build());
+ audio_pad.send_event(gst::Event::new_eos().build());
+ });
+
+ let app_weak = app.downgrade();
+ window.connect_delete_event(move |_, _| {
+ let app = match app_weak.upgrade() {
+ Some(app) => app,
+ None => return Inhibit(false),
+ };
+
+ app.quit();
+ Inhibit(false)
+ });
+
+ let bus = pipeline.get_bus().unwrap();
+ let app_weak = app.downgrade();
+ bus.add_watch_local(move |_, msg| {
+ use gst::MessageView;
+
+ let app = match app_weak.upgrade() {
+ Some(app) => app,
+ None => return glib::Continue(false),
+ };
+
+ match msg.view() {
+ MessageView::Eos(..) => app.quit(),
+ MessageView::Error(err) => {
+ println!(
+ "Error from {:?}: {} ({:?})",
+ msg.get_src().map(|s| s.get_path_string()),
+ err.get_error(),
+ err.get_debug()
+ );
+ app.quit();
+ }
+ _ => (),
+ };
+
+ glib::Continue(true)
+ })
+ .expect("Failed to add bus watch");
+
+ pipeline.set_state(gst::State::Playing).unwrap();
+
+ // Pipeline reference is owned by the closure below, so will be
+ // destroyed once the app is destroyed
+ let timeout_id = RefCell::new(Some(timeout_id));
+ app.connect_shutdown(move |_| {
+ pipeline.set_state(gst::State::Null).unwrap();
+
+ bus.remove_watch().unwrap();
+
+ if let Some(timeout_id) = timeout_id.borrow_mut().take() {
+ glib::source_remove(timeout_id);
+ }
+ });
+}
+
+fn main() {
+ gst::init().unwrap();
+ gtk::init().unwrap();
+
+ gsttogglerecord::plugin_register_static().expect("Failed to register togglerecord plugin");
+
+ let app = gtk::Application::new(None, gio::ApplicationFlags::FLAGS_NONE).unwrap();
+
+ app.connect_activate(create_ui);
+ let args = env::args().collect::<Vec<_>>();
+ app.run(&args);
+}