gstreamer-rs/examples/src/bin/tagsetter.rs

118 lines
4.3 KiB
Rust
Raw Normal View History

// This example demonstrates how to set and store metadata using
// GStreamer. Some elements support setting tags on a media stream.
// An example would be id3v2mux. The element signals this by implementing
// The GstTagsetter interface. You can query any element implementing this
// interface from the pipeline, and then tell the returned implementation
// of GstTagsetter what tags to apply to the media stream.
// This example's pipeline creates a new flac file from the testaudiosrc
// that the example application will add tags to using GstTagsetter.
// The operated pipeline looks like this:
// {audiotestsrc} - {flacenc} - {filesink}
// For example for pipelines that transcode a multimedia file, the input
// already has tags. For cases like this, the GstTagsetter has the merge
// setting, which the application can configure to tell the element
// implementing the interface whether to merge newly applied tags to the
// already existing ones, or if all existing ones should replace, etc.
// (More modes of operation are possible, see: gst::TagMergeMode)
// This merge-mode can also be supplied to any method that adds new tags.
use anyhow::{anyhow, Error};
use derive_more::{Display, Error};
use gst::prelude::*;
2017-12-24 12:49:27 +00:00
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Display, Error)]
#[display(fmt = "Missing element {_0}")]
struct MissingElement(#[error(not(source))] String);
2017-12-24 12:49:27 +00:00
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
2017-12-24 12:49:27 +00:00
struct ErrorMessage {
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
2017-12-24 12:49:27 +00:00
}
fn example_main() -> Result<(), Error> {
gst::init()?;
// Parse the pipeline we want to probe from a static in-line string.
2017-12-24 12:49:27 +00:00
let mut context = gst::ParseContext::new();
let pipeline = match gst::parse_launch_full(
"audiotestsrc wave=white-noise num-buffers=100 ! flacenc ! filesink location=test.flac",
Some(&mut context),
gst::ParseFlags::empty(),
2017-12-24 12:49:27 +00:00
) {
Ok(pipeline) => pipeline,
Err(err) => {
if let Some(gst::ParseError::NoSuchElement) = err.kind::<gst::ParseError>() {
2021-04-11 19:39:50 +00:00
return Err(MissingElement(context.missing_elements().join(",")).into());
2017-12-24 12:49:27 +00:00
} else {
return Err(err.into());
}
}
};
let pipeline = pipeline
.downcast::<gst::Pipeline>()
.map_err(|_| anyhow!("Generated pipeline is no pipeline"))?;
2017-12-24 12:49:27 +00:00
// Query the pipeline for elements implementing the GstTagsetter interface.
// In our case, this will return the flacenc element.
2017-12-24 12:49:27 +00:00
let tagsetter = pipeline
2021-04-20 10:24:17 +00:00
.by_interface(gst::TagSetter::static_type())
.ok_or_else(|| anyhow!("No TagSetter found"))?;
2017-12-24 12:49:27 +00:00
let tagsetter = tagsetter
.dynamic_cast::<gst::TagSetter>()
.map_err(|_| anyhow!("No TagSetter found"))?;
2017-12-24 12:49:27 +00:00
// Tell the element implementing the GstTagsetter interface how to handle already existing
// metadata.
2017-12-24 12:49:27 +00:00
tagsetter.set_tag_merge_mode(gst::TagMergeMode::KeepAll);
// Set the "title" tag to "Special randomized white-noise".
// The second parameter gst::TagMergeMode::Append tells the tagsetter to append this title
// if there already is one.
2017-12-24 12:49:27 +00:00
tagsetter.add::<gst::tags::Title>(&"Special randomized white-noise", gst::TagMergeMode::Append);
2021-04-11 19:39:50 +00:00
let bus = pipeline.bus().unwrap();
2017-12-24 12:49:27 +00:00
pipeline.set_state(gst::State::Playing)?;
2017-12-24 12:49:27 +00:00
2021-04-28 22:29:13 +00:00
for msg in bus.iter_timed(gst::ClockTime::NONE) {
2017-12-24 12:49:27 +00:00
use gst::MessageView;
match msg.view() {
MessageView::Eos(..) => break,
MessageView::Error(err) => {
2019-10-04 07:47:48 +00:00
return Err(ErrorMessage {
src: msg
2021-04-11 19:39:50 +00:00
.src()
.map(|s| s.path_string())
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
2021-04-11 19:39:50 +00:00
debug: err.debug(),
2019-10-04 07:47:48 +00:00
}
.into());
2017-12-24 12:49:27 +00:00
}
_ => (),
}
}
pipeline.set_state(gst::State::Null)?;
2017-12-24 12:49:27 +00:00
Ok(())
}
fn main() {
2021-04-10 11:42:04 +00:00
// 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)
2017-12-24 12:49:27 +00:00
match examples_common::run(example_main) {
Ok(r) => r,
Err(e) => eprintln!("Error! {e}"),
2017-12-24 12:49:27 +00:00
}
}