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

134 lines
4.6 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.
2017-12-24 12:49:27 +00:00
extern crate gstreamer as gst;
use gst::prelude::*;
extern crate glib;
use std::error::Error as StdError;
extern crate failure;
use failure::Error;
#[macro_use]
extern crate failure_derive;
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Fail)]
#[fail(display = "Missing element {}", _0)]
struct MissingElement(String);
#[derive(Debug, Fail)]
2018-07-27 10:36:40 +00:00
#[fail(
display = "Received error from {}: {} (debug: {:?})",
2018-10-28 13:47:02 +00:00
src, error, debug
2018-07-27 10:36:40 +00:00
)]
2017-12-24 12:49:27 +00:00
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
#[cause]
cause: glib::Error,
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::NONE,
) {
Ok(pipeline) => pipeline,
Err(err) => {
if let Some(gst::ParseError::NoSuchElement) = err.kind::<gst::ParseError>() {
2019-02-21 17:30:36 +00:00
return Err(MissingElement(context.get_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(|_| failure::err_msg("Generated pipeline is no pipeline"))?;
// 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
.get_by_interface(gst::TagSetter::static_type())
.ok_or_else(|| failure::err_msg("No TagSetter found"))?;
2017-12-24 12:49:27 +00:00
let tagsetter = tagsetter
.dynamic_cast::<gst::TagSetter>()
.map_err(|_| failure::err_msg("No TagSetter found"))?;
// 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);
let bus = pipeline.get_bus().unwrap();
pipeline.set_state(gst::State::Playing)?;
2017-12-24 12:49:27 +00:00
for msg in bus.iter_timed(gst::CLOCK_TIME_NONE) {
2017-12-24 12:49:27 +00:00
use gst::MessageView;
match msg.view() {
MessageView::Eos(..) => break,
MessageView::Error(err) => {
Err(ErrorMessage {
2018-07-27 10:36:40 +00:00
src: err
.get_src()
2017-12-24 12:49:27 +00:00
.map(|s| s.get_path_string())
.unwrap_or_else(|| "None".into())
.to_string(),
2017-12-24 12:49:27 +00:00
error: err.get_error().description().into(),
debug: Some(err.get_debug().unwrap().to_string()),
2017-12-24 12:49:27 +00:00
cause: err.get_error(),
})?;
break;
}
_ => (),
}
}
pipeline.set_state(gst::State::Null)?;
2017-12-24 12:49:27 +00:00
Ok(())
}
fn main() {
// tutorials_common::run is only required to set up the application environent on macOS
// (but not necessary in normal Cocoa applications where this is set up autmatically)
match examples_common::run(example_main) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
}
}