forked from mirrors/gstreamer-rs
Compare commits
26 commits
Author | SHA1 | Date | |
---|---|---|---|
|
c7f5b541cc | ||
|
cb11ab8a9c | ||
|
3103fc0b2b | ||
|
8c54d21066 | ||
|
658be807c1 | ||
|
7fe2216daf | ||
|
1294c28058 | ||
|
7a779fe940 | ||
|
24b263acef | ||
|
97097554e7 | ||
|
0dd0442fb7 | ||
|
a8c2815c3b | ||
|
1898599c42 | ||
|
c71623591a | ||
|
7508184557 | ||
|
9a63eb6353 | ||
|
9ba69ad93b | ||
|
1f0947cda0 | ||
|
950e5dbc32 | ||
|
4ce1221ef4 | ||
|
4b71d65283 | ||
|
93723026eb | ||
|
f2ef2b6bea | ||
|
9321f31d0a | ||
|
74527fe9d8 | ||
|
85f44a0479 |
40 changed files with 1236 additions and 91 deletions
|
@ -11,6 +11,7 @@ generate_safety_asserts = true
|
|||
external_libraries = [
|
||||
"GLib",
|
||||
"GObject",
|
||||
"Gst",
|
||||
]
|
||||
|
||||
generate = [
|
||||
|
@ -27,6 +28,7 @@ manual = [
|
|||
"GLib.Error",
|
||||
"GLib.MainContext",
|
||||
"GObject.Object",
|
||||
"Gst.Object",
|
||||
"Gst.Element",
|
||||
"GstVideo.VideoMultiviewFlags",
|
||||
"GstVideo.VideoMultiviewFramePacking",
|
||||
|
|
|
@ -12,6 +12,7 @@ external_libraries = [
|
|||
"GLib",
|
||||
"GObject",
|
||||
"Gst",
|
||||
"GstBase",
|
||||
]
|
||||
|
||||
generate = [
|
||||
|
@ -29,11 +30,14 @@ generate = [
|
|||
"GstVideo.VideoFieldOrder",
|
||||
"GstVideo.VideoFrameFlags",
|
||||
"GstVideo.VideoMultiviewFramePacking",
|
||||
"GstVideo.VideoFilter",
|
||||
]
|
||||
|
||||
manual = [
|
||||
"GObject.Object",
|
||||
"Gst.Object",
|
||||
"Gst.Element",
|
||||
"GstBase.BaseTransform",
|
||||
"GstVideo.VideoInfo",
|
||||
"GstVideo.VideoFormatInfo",
|
||||
"GstVideo.VideoColorimetry",
|
||||
|
|
|
@ -46,6 +46,7 @@ On Debian/Ubuntu they can be installed with
|
|||
|
||||
```
|
||||
$ apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
|
||||
libgstreamer-plugins-bad1.0-dev \
|
||||
gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
|
||||
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
|
||||
gstreamer1.0-libav
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
[package]
|
||||
name = "examples"
|
||||
version = "0.10.0"
|
||||
version = "0.10.2"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
|
||||
[dependencies]
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
gstreamer-app = { path = "../gstreamer-app" }
|
||||
gstreamer-audio = { path = "../gstreamer-audio" }
|
||||
gstreamer-video = { path = "../gstreamer-video" }
|
||||
gstreamer-player = { path = "../gstreamer-player", optional = true }
|
||||
gtk = { git = "https://github.com/gtk-rs/gtk", features = ["v3_6"], optional = true }
|
||||
gdk = { git = "https://github.com/gtk-rs/gdk", optional = true }
|
||||
gio = { git = "https://github.com/gtk-rs/gio", optional = true }
|
||||
glib = "0.4"
|
||||
gstreamer = { version = "0.10", path = "../gstreamer" }
|
||||
gstreamer-app = { version = "0.10", path = "../gstreamer-app" }
|
||||
gstreamer-audio = { version = "0.10", path = "../gstreamer-audio" }
|
||||
gstreamer-video = { version = "0.10", path = "../gstreamer-video" }
|
||||
gstreamer-player = { version = "0.10", path = "../gstreamer-player", optional = true }
|
||||
gtk = { version = "0.3", features = ["v3_6"], optional = true }
|
||||
gdk = { version = "0.7", optional = true }
|
||||
gio = { version = "0.3", optional = true }
|
||||
futures = { version = "0.1", optional = true }
|
||||
tokio-core = { version = "0.1", optional = true }
|
||||
send-cell = "0.1"
|
||||
|
|
99
examples/src/bin/tagsetter.rs
Normal file
99
examples/src/bin/tagsetter.rs
Normal file
|
@ -0,0 +1,99 @@
|
|||
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)]
|
||||
#[fail(display = "Received error from {}: {} (debug: {:?})", src, error, debug)]
|
||||
struct ErrorMessage {
|
||||
src: String,
|
||||
error: String,
|
||||
debug: Option<String>,
|
||||
#[cause] cause: glib::Error,
|
||||
}
|
||||
|
||||
fn example_main() -> Result<(), Error> {
|
||||
gst::init()?;
|
||||
|
||||
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>() {
|
||||
return Err(MissingElement(context.get_missing_elements().join(",")).into());
|
||||
} else {
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let pipeline = pipeline
|
||||
.downcast::<gst::Pipeline>()
|
||||
.map_err(|_| failure::err_msg("Generated pipeline is no pipeline"))?;
|
||||
|
||||
let tagsetter = pipeline
|
||||
.get_by_interface(gst::TagSetter::static_type())
|
||||
.ok_or(failure::err_msg("No TagSetter found"))?;
|
||||
let tagsetter = tagsetter
|
||||
.dynamic_cast::<gst::TagSetter>()
|
||||
.map_err(|_| failure::err_msg("No TagSetter found"))?;
|
||||
|
||||
tagsetter.set_tag_merge_mode(gst::TagMergeMode::KeepAll);
|
||||
tagsetter.add::<gst::tags::Title>(&"Special randomized white-noise", gst::TagMergeMode::Append);
|
||||
|
||||
let bus = pipeline.get_bus().unwrap();
|
||||
|
||||
pipeline.set_state(gst::State::Playing).into_result()?;
|
||||
|
||||
while let Some(msg) = bus.timed_pop(gst::CLOCK_TIME_NONE) {
|
||||
use gst::MessageView;
|
||||
|
||||
match msg.view() {
|
||||
MessageView::Eos(..) => break,
|
||||
MessageView::Error(err) => {
|
||||
Err(ErrorMessage {
|
||||
src: msg.get_src()
|
||||
.map(|s| s.get_path_string())
|
||||
.unwrap_or_else(|| String::from("None")),
|
||||
error: err.get_error().description().into(),
|
||||
debug: err.get_debug(),
|
||||
cause: err.get_error(),
|
||||
})?;
|
||||
break;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.set_state(gst::State::Null).into_result()?;
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ use tokio_core::reactor::Core;
|
|||
#[cfg(feature = "tokio")]
|
||||
use std::env;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
#[cfg(feature = "tokio")]
|
||||
#[path = "../examples-common.rs"]
|
||||
mod examples_common;
|
||||
|
||||
|
|
|
@ -35441,6 +35441,7 @@ on the returned caps to modify it.</doc>
|
|||
<class name="Stream"
|
||||
c:symbol-prefix="stream"
|
||||
c:type="GstStream"
|
||||
version="1.10"
|
||||
parent="Object"
|
||||
glib:type-name="GstStream"
|
||||
glib:get-type="gst_stream_get_type"
|
||||
|
@ -36103,6 +36104,7 @@ application of new streaming threads and their status.</doc>
|
|||
</member>
|
||||
</enumeration>
|
||||
<bitfield name="StreamType"
|
||||
version="1.10"
|
||||
glib:type-name="GstStreamType"
|
||||
glib:get-type="gst_stream_type_get_type"
|
||||
c:type="GstStreamType">
|
||||
|
|
|
@ -5,6 +5,33 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.10.2] - 2018-02-18
|
||||
### Fixed
|
||||
- Fix building of messages with custom fields for types that don't have a
|
||||
GstStructure
|
||||
|
||||
### Added
|
||||
- VideoFrameRef::copy_to_ref() and ::copy_plane_to_ref(), which work with
|
||||
VideoFrameRefs instead of full VideoFrames
|
||||
- Getters for the BaseSrc/Sink/Transform configured segment
|
||||
- Document the gstreamer-player-1.0 dependency in the README.md
|
||||
|
||||
## [0.10.1] - 2018-01-03
|
||||
### Fixed
|
||||
- Don't require &mut self for TagSetterExtManual::add()
|
||||
|
||||
### Added
|
||||
- A TagSetter example application
|
||||
- Bindings for gst_video::convert_sample() and ::convert_sample_async()
|
||||
- Bindings for gst_video::VideoRectangle
|
||||
- Debug impl for Sample and ::with_buffer_list() constructor
|
||||
- A borrowing version of VideoFrame: VideoFrameRef
|
||||
- Bindings for GstVideoFilter
|
||||
|
||||
### Changed
|
||||
- Deprecated Sample::get_info() in favour of ::get_structure()
|
||||
- Player has gst::Object as another parent class now
|
||||
|
||||
## [0.10.0] - 2017-12-22
|
||||
### Fixed
|
||||
- Various clippy warnings
|
||||
|
@ -193,7 +220,8 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://github.com/sdroege/gstreamer-rs/compare/0.10.0...HEAD
|
||||
[Unreleased]: https://github.com/sdroege/gstreamer-rs/compare/0.10.1...HEAD
|
||||
[0.10.1]: https://github.com/sdroege/gstreamer-rs/compare/0.10.0...0.10.1
|
||||
[0.10.0]: https://github.com/sdroege/gstreamer-rs/compare/0.9.1...0.10.0
|
||||
[0.9.1]: https://github.com/sdroege/gstreamer-rs/compare/0.9.0...0.9.1
|
||||
[0.9.0]: https://github.com/sdroege/gstreamer-rs/compare/0.8.1...0.9.0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-app"
|
||||
version = "0.10.0"
|
||||
version = "0.10.2"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer App library"
|
||||
|
@ -15,14 +15,14 @@ build = "build.rs"
|
|||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
libc = "0.2"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] }
|
||||
gstreamer-base-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] }
|
||||
gstreamer-app-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
gstreamer-base = { path = "../gstreamer-base" }
|
||||
glib-sys = "0.5"
|
||||
gobject-sys = "0.5"
|
||||
gstreamer-sys = { version = "0.4", features = ["v1_8"] }
|
||||
gstreamer-base-sys = { version = "0.4", features = ["v1_8"] }
|
||||
gstreamer-app-sys = { version = "0.4", features = ["v1_8"] }
|
||||
glib = "0.4"
|
||||
gstreamer = { version = "0.10", path = "../gstreamer" }
|
||||
gstreamer-base = { version = "0.10", path = "../gstreamer-base" }
|
||||
|
||||
[build-dependencies.rustdoc-stripper]
|
||||
version = "0.1"
|
||||
|
|
|
@ -5,6 +5,33 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.10.2] - 2018-02-18
|
||||
### Fixed
|
||||
- Fix building of messages with custom fields for types that don't have a
|
||||
GstStructure
|
||||
|
||||
### Added
|
||||
- VideoFrameRef::copy_to_ref() and ::copy_plane_to_ref(), which work with
|
||||
VideoFrameRefs instead of full VideoFrames
|
||||
- Getters for the BaseSrc/Sink/Transform configured segment
|
||||
- Document the gstreamer-player-1.0 dependency in the README.md
|
||||
|
||||
## [0.10.1] - 2018-01-03
|
||||
### Fixed
|
||||
- Don't require &mut self for TagSetterExtManual::add()
|
||||
|
||||
### Added
|
||||
- A TagSetter example application
|
||||
- Bindings for gst_video::convert_sample() and ::convert_sample_async()
|
||||
- Bindings for gst_video::VideoRectangle
|
||||
- Debug impl for Sample and ::with_buffer_list() constructor
|
||||
- A borrowing version of VideoFrame: VideoFrameRef
|
||||
- Bindings for GstVideoFilter
|
||||
|
||||
### Changed
|
||||
- Deprecated Sample::get_info() in favour of ::get_structure()
|
||||
- Player has gst::Object as another parent class now
|
||||
|
||||
## [0.10.0] - 2017-12-22
|
||||
### Fixed
|
||||
- Various clippy warnings
|
||||
|
@ -193,7 +220,8 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://github.com/sdroege/gstreamer-rs/compare/0.10.0...HEAD
|
||||
[Unreleased]: https://github.com/sdroege/gstreamer-rs/compare/0.10.1...HEAD
|
||||
[0.10.1]: https://github.com/sdroege/gstreamer-rs/compare/0.10.0...0.10.1
|
||||
[0.10.0]: https://github.com/sdroege/gstreamer-rs/compare/0.9.1...0.10.0
|
||||
[0.9.1]: https://github.com/sdroege/gstreamer-rs/compare/0.9.0...0.9.1
|
||||
[0.9.0]: https://github.com/sdroege/gstreamer-rs/compare/0.8.1...0.9.0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-audio"
|
||||
version = "0.10.0"
|
||||
version = "0.10.2"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Audio library"
|
||||
|
@ -14,12 +14,12 @@ build = "build.rs"
|
|||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] }
|
||||
gstreamer-audio-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
glib-sys = "0.5"
|
||||
gobject-sys = "0.5"
|
||||
gstreamer-sys = { version = "0.4", features = ["v1_8"] }
|
||||
gstreamer-audio-sys = { version = "0.4", features = ["v1_8"] }
|
||||
glib = "0.4"
|
||||
gstreamer = { version = "0.10", path = "../gstreamer" }
|
||||
array-init = "0.0"
|
||||
|
||||
[build-dependencies.rustdoc-stripper]
|
||||
|
|
|
@ -5,6 +5,33 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.10.2] - 2018-02-18
|
||||
### Fixed
|
||||
- Fix building of messages with custom fields for types that don't have a
|
||||
GstStructure
|
||||
|
||||
### Added
|
||||
- VideoFrameRef::copy_to_ref() and ::copy_plane_to_ref(), which work with
|
||||
VideoFrameRefs instead of full VideoFrames
|
||||
- Getters for the BaseSrc/Sink/Transform configured segment
|
||||
- Document the gstreamer-player-1.0 dependency in the README.md
|
||||
|
||||
## [0.10.1] - 2018-01-03
|
||||
### Fixed
|
||||
- Don't require &mut self for TagSetterExtManual::add()
|
||||
|
||||
### Added
|
||||
- A TagSetter example application
|
||||
- Bindings for gst_video::convert_sample() and ::convert_sample_async()
|
||||
- Bindings for gst_video::VideoRectangle
|
||||
- Debug impl for Sample and ::with_buffer_list() constructor
|
||||
- A borrowing version of VideoFrame: VideoFrameRef
|
||||
- Bindings for GstVideoFilter
|
||||
|
||||
### Changed
|
||||
- Deprecated Sample::get_info() in favour of ::get_structure()
|
||||
- Player has gst::Object as another parent class now
|
||||
|
||||
## [0.10.0] - 2017-12-22
|
||||
### Fixed
|
||||
- Various clippy warnings
|
||||
|
@ -193,7 +220,8 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://github.com/sdroege/gstreamer-rs/compare/0.10.0...HEAD
|
||||
[Unreleased]: https://github.com/sdroege/gstreamer-rs/compare/0.10.1...HEAD
|
||||
[0.10.1]: https://github.com/sdroege/gstreamer-rs/compare/0.10.0...0.10.1
|
||||
[0.10.0]: https://github.com/sdroege/gstreamer-rs/compare/0.9.1...0.10.0
|
||||
[0.9.1]: https://github.com/sdroege/gstreamer-rs/compare/0.9.0...0.9.1
|
||||
[0.9.0]: https://github.com/sdroege/gstreamer-rs/compare/0.8.1...0.9.0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-base"
|
||||
version = "0.10.0"
|
||||
version = "0.10.2"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Base library"
|
||||
|
@ -8,18 +8,18 @@ repository = "https://github.com/sdroege/gstreamer-rs"
|
|||
license = "MIT/Apache-2.0"
|
||||
readme = "README.md"
|
||||
homepage = "https://gstreamer.freedesktop.org"
|
||||
documentation = "https://sdroege.github.io/rustdoc/gstreamer/gstreamer-base"
|
||||
documentation = "https://sdroege.github.io/rustdoc/gstreamer/gstreamer_base"
|
||||
keywords = ["gstreamer", "multimedia", "audio", "video", "gnome"]
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] }
|
||||
gstreamer-base-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
glib-sys = "0.5"
|
||||
gobject-sys = "0.5"
|
||||
gstreamer-sys = { version = "0.4", features = ["v1_8"] }
|
||||
gstreamer-base-sys = { version = "0.4", features = ["v1_8"] }
|
||||
glib = "0.4"
|
||||
gstreamer = { version = "0.10", path = "../gstreamer" }
|
||||
|
||||
[build-dependencies.rustdoc-stripper]
|
||||
version = "0.1"
|
||||
|
|
28
gstreamer-base/src/base_sink.rs
Normal file
28
gstreamer-base/src/base_sink.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use ffi;
|
||||
use glib::IsA;
|
||||
use glib::translate::*;
|
||||
use gst;
|
||||
use BaseSink;
|
||||
|
||||
pub trait BaseSinkExtManual {
|
||||
fn get_segment(&self) -> gst::Segment;
|
||||
}
|
||||
|
||||
impl<O: IsA<BaseSink>> BaseSinkExtManual for O {
|
||||
fn get_segment(&self) -> gst::Segment {
|
||||
unsafe {
|
||||
let stash = self.to_glib_none();
|
||||
let sink: &ffi::GstBaseSink = &*stash.0;
|
||||
::utils::MutexGuard::lock(&sink.element.object.lock);
|
||||
from_glib_none(&sink.segment as *const _)
|
||||
}
|
||||
}
|
||||
}
|
28
gstreamer-base/src/base_src.rs
Normal file
28
gstreamer-base/src/base_src.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use ffi;
|
||||
use glib::IsA;
|
||||
use glib::translate::*;
|
||||
use gst;
|
||||
use BaseSrc;
|
||||
|
||||
pub trait BaseSrcExtManual {
|
||||
fn get_segment(&self) -> gst::Segment;
|
||||
}
|
||||
|
||||
impl<O: IsA<BaseSrc>> BaseSrcExtManual for O {
|
||||
fn get_segment(&self) -> gst::Segment {
|
||||
unsafe {
|
||||
let stash = self.to_glib_none();
|
||||
let src: &ffi::GstBaseSrc = &*stash.0;
|
||||
::utils::MutexGuard::lock(&src.element.object.lock);
|
||||
from_glib_none(&src.segment as *const _)
|
||||
}
|
||||
}
|
||||
}
|
28
gstreamer-base/src/base_transform.rs
Normal file
28
gstreamer-base/src/base_transform.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use ffi;
|
||||
use glib::IsA;
|
||||
use glib::translate::*;
|
||||
use gst;
|
||||
use BaseTransform;
|
||||
|
||||
pub trait BaseTransformExtManual {
|
||||
fn get_segment(&self) -> gst::Segment;
|
||||
}
|
||||
|
||||
impl<O: IsA<BaseTransform>> BaseTransformExtManual for O {
|
||||
fn get_segment(&self) -> gst::Segment {
|
||||
unsafe {
|
||||
let stash = self.to_glib_none();
|
||||
let trans: &ffi::GstBaseTransform = &*stash.0;
|
||||
::utils::MutexGuard::lock(&trans.element.object.lock);
|
||||
from_glib_none(&trans.segment as *const _)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,6 +45,9 @@ pub use functions::*;
|
|||
mod adapter;
|
||||
mod flow_combiner;
|
||||
pub use flow_combiner::*;
|
||||
mod base_src;
|
||||
mod base_sink;
|
||||
mod base_transform;
|
||||
|
||||
// Re-export all the traits in a prelude module, so that applications
|
||||
// can always "use gst::prelude::*" without getting conflicts
|
||||
|
@ -53,4 +56,9 @@ pub mod prelude {
|
|||
pub use gst::prelude::*;
|
||||
|
||||
pub use auto::traits::*;
|
||||
pub use base_src::BaseSrcExtManual;
|
||||
pub use base_sink::BaseSinkExtManual;
|
||||
pub use base_transform::BaseTransformExtManual;
|
||||
}
|
||||
|
||||
mod utils;
|
||||
|
|
29
gstreamer-base/src/utils.rs
Normal file
29
gstreamer-base/src/utils.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use glib::translate::mut_override;
|
||||
use glib_ffi;
|
||||
|
||||
pub struct MutexGuard<'a>(&'a glib_ffi::GMutex);
|
||||
|
||||
impl<'a> MutexGuard<'a> {
|
||||
pub fn lock(mutex: &'a glib_ffi::GMutex) -> Self {
|
||||
unsafe {
|
||||
glib_ffi::g_mutex_lock(mut_override(mutex));
|
||||
}
|
||||
MutexGuard(mutex)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for MutexGuard<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
glib_ffi::g_mutex_unlock(mut_override(self.0));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,33 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.10.2] - 2018-02-18
|
||||
### Fixed
|
||||
- Fix building of messages with custom fields for types that don't have a
|
||||
GstStructure
|
||||
|
||||
### Added
|
||||
- VideoFrameRef::copy_to_ref() and ::copy_plane_to_ref(), which work with
|
||||
VideoFrameRefs instead of full VideoFrames
|
||||
- Getters for the BaseSrc/Sink/Transform configured segment
|
||||
- Document the gstreamer-player-1.0 dependency in the README.md
|
||||
|
||||
## [0.10.1] - 2018-01-03
|
||||
### Fixed
|
||||
- Don't require &mut self for TagSetterExtManual::add()
|
||||
|
||||
### Added
|
||||
- A TagSetter example application
|
||||
- Bindings for gst_video::convert_sample() and ::convert_sample_async()
|
||||
- Bindings for gst_video::VideoRectangle
|
||||
- Debug impl for Sample and ::with_buffer_list() constructor
|
||||
- A borrowing version of VideoFrame: VideoFrameRef
|
||||
- Bindings for GstVideoFilter
|
||||
|
||||
### Changed
|
||||
- Deprecated Sample::get_info() in favour of ::get_structure()
|
||||
- Player has gst::Object as another parent class now
|
||||
|
||||
## [0.10.0] - 2017-12-22
|
||||
### Fixed
|
||||
- Various clippy warnings
|
||||
|
@ -193,7 +220,8 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://github.com/sdroege/gstreamer-rs/compare/0.10.0...HEAD
|
||||
[Unreleased]: https://github.com/sdroege/gstreamer-rs/compare/0.10.1...HEAD
|
||||
[0.10.1]: https://github.com/sdroege/gstreamer-rs/compare/0.10.0...0.10.1
|
||||
[0.10.0]: https://github.com/sdroege/gstreamer-rs/compare/0.9.1...0.10.0
|
||||
[0.9.1]: https://github.com/sdroege/gstreamer-rs/compare/0.9.0...0.9.1
|
||||
[0.9.0]: https://github.com/sdroege/gstreamer-rs/compare/0.8.1...0.9.0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-net"
|
||||
version = "0.10.0"
|
||||
version = "0.10.2"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Net library"
|
||||
|
@ -8,17 +8,17 @@ repository = "https://github.com/sdroege/gstreamer-rs"
|
|||
license = "MIT/Apache-2.0"
|
||||
readme = "README.md"
|
||||
homepage = "https://gstreamer.freedesktop.org"
|
||||
documentation = "https://sdroege.github.io/rustdoc/gstreamer/gstreamer-net"
|
||||
documentation = "https://sdroege.github.io/rustdoc/gstreamer/gstreamer_net"
|
||||
keywords = ["gstreamer", "multimedia", "audio", "video", "gnome"]
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] }
|
||||
gstreamer-net-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
glib-sys = "0.5"
|
||||
gobject-sys = "0.5"
|
||||
gstreamer-sys = { version = "0.4", features = ["v1_8"] }
|
||||
gstreamer-net-sys = { version = "0.4", features = ["v1_8"] }
|
||||
glib = "0.4"
|
||||
gstreamer = { version = "0.10", path = "../gstreamer" }
|
||||
|
||||
[build-dependencies.rustdoc-stripper]
|
||||
version = "0.1"
|
||||
|
|
|
@ -5,6 +5,33 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.10.2] - 2018-02-18
|
||||
### Fixed
|
||||
- Fix building of messages with custom fields for types that don't have a
|
||||
GstStructure
|
||||
|
||||
### Added
|
||||
- VideoFrameRef::copy_to_ref() and ::copy_plane_to_ref(), which work with
|
||||
VideoFrameRefs instead of full VideoFrames
|
||||
- Getters for the BaseSrc/Sink/Transform configured segment
|
||||
- Document the gstreamer-player-1.0 dependency in the README.md
|
||||
|
||||
## [0.10.1] - 2018-01-03
|
||||
### Fixed
|
||||
- Don't require &mut self for TagSetterExtManual::add()
|
||||
|
||||
### Added
|
||||
- A TagSetter example application
|
||||
- Bindings for gst_video::convert_sample() and ::convert_sample_async()
|
||||
- Bindings for gst_video::VideoRectangle
|
||||
- Debug impl for Sample and ::with_buffer_list() constructor
|
||||
- A borrowing version of VideoFrame: VideoFrameRef
|
||||
- Bindings for GstVideoFilter
|
||||
|
||||
### Changed
|
||||
- Deprecated Sample::get_info() in favour of ::get_structure()
|
||||
- Player has gst::Object as another parent class now
|
||||
|
||||
## [0.10.0] - 2017-12-22
|
||||
### Fixed
|
||||
- Various clippy warnings
|
||||
|
@ -193,7 +220,8 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://github.com/sdroege/gstreamer-rs/compare/0.10.0...HEAD
|
||||
[Unreleased]: https://github.com/sdroege/gstreamer-rs/compare/0.10.1...HEAD
|
||||
[0.10.1]: https://github.com/sdroege/gstreamer-rs/compare/0.10.0...0.10.1
|
||||
[0.10.0]: https://github.com/sdroege/gstreamer-rs/compare/0.9.1...0.10.0
|
||||
[0.9.1]: https://github.com/sdroege/gstreamer-rs/compare/0.9.0...0.9.1
|
||||
[0.9.0]: https://github.com/sdroege/gstreamer-rs/compare/0.8.1...0.9.0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-player"
|
||||
version = "0.10.0"
|
||||
version = "0.10.2"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Player library"
|
||||
|
@ -15,13 +15,13 @@ build = "build.rs"
|
|||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
libc = "0.2"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_12"] }
|
||||
gstreamer-player-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_12"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer", features = ["v1_12"] }
|
||||
gstreamer-video = { path = "../gstreamer-video", features = ["v1_12"] }
|
||||
glib-sys = "0.5"
|
||||
gobject-sys = "0.5"
|
||||
gstreamer-sys = { version = "0.4", features = ["v1_12"] }
|
||||
gstreamer-player-sys = { version = "0.4", features = ["v1_12"] }
|
||||
glib = "0.4"
|
||||
gstreamer = { version = "0.10", path = "../gstreamer", features = ["v1_12"] }
|
||||
gstreamer-video = { version = "0.10", path = "../gstreamer-video", features = ["v1_12"] }
|
||||
|
||||
[build-dependencies.rustdoc-stripper]
|
||||
version = "0.1"
|
||||
|
|
|
@ -20,6 +20,7 @@ use glib::translate::*;
|
|||
use glib_ffi;
|
||||
use gobject_ffi;
|
||||
use gst;
|
||||
use gst_ffi;
|
||||
use gst_video;
|
||||
use libc;
|
||||
use std::boxed::Box as Box_;
|
||||
|
@ -28,7 +29,9 @@ use std::mem::transmute;
|
|||
use std::ptr;
|
||||
|
||||
glib_wrapper! {
|
||||
pub struct Player(Object<ffi::GstPlayer, ffi::GstPlayerClass>);
|
||||
pub struct Player(Object<ffi::GstPlayer, ffi::GstPlayerClass>): [
|
||||
gst::Object => gst_ffi::GstObject,
|
||||
];
|
||||
|
||||
match fn {
|
||||
get_type => || ffi::gst_player_get_type(),
|
||||
|
|
|
@ -5,6 +5,33 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.10.2] - 2018-02-18
|
||||
### Fixed
|
||||
- Fix building of messages with custom fields for types that don't have a
|
||||
GstStructure
|
||||
|
||||
### Added
|
||||
- VideoFrameRef::copy_to_ref() and ::copy_plane_to_ref(), which work with
|
||||
VideoFrameRefs instead of full VideoFrames
|
||||
- Getters for the BaseSrc/Sink/Transform configured segment
|
||||
- Document the gstreamer-player-1.0 dependency in the README.md
|
||||
|
||||
## [0.10.1] - 2018-01-03
|
||||
### Fixed
|
||||
- Don't require &mut self for TagSetterExtManual::add()
|
||||
|
||||
### Added
|
||||
- A TagSetter example application
|
||||
- Bindings for gst_video::convert_sample() and ::convert_sample_async()
|
||||
- Bindings for gst_video::VideoRectangle
|
||||
- Debug impl for Sample and ::with_buffer_list() constructor
|
||||
- A borrowing version of VideoFrame: VideoFrameRef
|
||||
- Bindings for GstVideoFilter
|
||||
|
||||
### Changed
|
||||
- Deprecated Sample::get_info() in favour of ::get_structure()
|
||||
- Player has gst::Object as another parent class now
|
||||
|
||||
## [0.10.0] - 2017-12-22
|
||||
### Fixed
|
||||
- Various clippy warnings
|
||||
|
@ -193,7 +220,8 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://github.com/sdroege/gstreamer-rs/compare/0.10.0...HEAD
|
||||
[Unreleased]: https://github.com/sdroege/gstreamer-rs/compare/0.10.1...HEAD
|
||||
[0.10.1]: https://github.com/sdroege/gstreamer-rs/compare/0.10.0...0.10.1
|
||||
[0.10.0]: https://github.com/sdroege/gstreamer-rs/compare/0.9.1...0.10.0
|
||||
[0.9.1]: https://github.com/sdroege/gstreamer-rs/compare/0.9.0...0.9.1
|
||||
[0.9.0]: https://github.com/sdroege/gstreamer-rs/compare/0.8.1...0.9.0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer-video"
|
||||
version = "0.10.0"
|
||||
version = "0.10.2"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer Video library"
|
||||
|
@ -15,12 +15,14 @@ build = "build.rs"
|
|||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
libc = "0.2"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] }
|
||||
gstreamer-video-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
glib-sys = "0.5"
|
||||
gobject-sys = "0.5"
|
||||
gstreamer-sys = { version = "0.4", features = ["v1_8"] }
|
||||
gstreamer-base-sys = { version = "0.4", features = ["v1_8"] }
|
||||
gstreamer-video-sys = { version = "0.4", features = ["v1_8"] }
|
||||
glib = "0.4"
|
||||
gstreamer = { version = "0.10", path = "../gstreamer" }
|
||||
gstreamer-base = { version = "0.10", path = "../gstreamer-base" }
|
||||
|
||||
[build-dependencies.rustdoc-stripper]
|
||||
version = "0.1"
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
// This file was generated by gir (d50d839) from gir-files (???)
|
||||
// DO NOT EDIT
|
||||
|
||||
mod video_filter;
|
||||
pub use self::video_filter::VideoFilter;
|
||||
|
||||
mod video_overlay;
|
||||
pub use self::video_overlay::VideoOverlay;
|
||||
pub use self::video_overlay::VideoOverlayExt;
|
||||
|
|
30
gstreamer-video/src/auto/video_filter.rs
Normal file
30
gstreamer-video/src/auto/video_filter.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
// This file was generated by gir (d50d839) from gir-files (???)
|
||||
// DO NOT EDIT
|
||||
|
||||
use ffi;
|
||||
use glib::translate::*;
|
||||
use glib_ffi;
|
||||
use gobject_ffi;
|
||||
use gst;
|
||||
use gst_base;
|
||||
use gst_base_ffi;
|
||||
use gst_ffi;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
|
||||
glib_wrapper! {
|
||||
pub struct VideoFilter(Object<ffi::GstVideoFilter, ffi::GstVideoFilterClass>): [
|
||||
gst_base::BaseTransform => gst_base_ffi::GstBaseTransform,
|
||||
gst::Element => gst_ffi::GstElement,
|
||||
gst::Object => gst_ffi::GstObject,
|
||||
];
|
||||
|
||||
match fn {
|
||||
get_type => || ffi::gst_video_filter_get_type(),
|
||||
}
|
||||
}
|
||||
|
||||
impl VideoFilter {}
|
||||
|
||||
unsafe impl Send for VideoFilter {}
|
||||
unsafe impl Sync for VideoFilter {}
|
157
gstreamer-video/src/functions.rs
Normal file
157
gstreamer-video/src/functions.rs
Normal file
|
@ -0,0 +1,157 @@
|
|||
// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use ffi;
|
||||
use gst_ffi;
|
||||
use glib_ffi;
|
||||
|
||||
use gst;
|
||||
use glib;
|
||||
use glib::translate::{from_glib_full, ToGlib, ToGlibPtr};
|
||||
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
|
||||
pub fn convert_sample(
|
||||
sample: &gst::Sample,
|
||||
caps: &gst::Caps,
|
||||
timeout: gst::ClockTime,
|
||||
) -> Result<gst::Sample, glib::Error> {
|
||||
unsafe {
|
||||
let mut error = ptr::null_mut();
|
||||
let ret = ffi::gst_video_convert_sample(
|
||||
sample.to_glib_none().0,
|
||||
caps.to_glib_none().0,
|
||||
timeout.to_glib(),
|
||||
&mut error,
|
||||
);
|
||||
|
||||
if error.is_null() {
|
||||
Ok(from_glib_full(ret))
|
||||
} else {
|
||||
Err(from_glib_full(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_sample_async<F>(
|
||||
sample: &gst::Sample,
|
||||
caps: &gst::Caps,
|
||||
timeout: gst::ClockTime,
|
||||
func: F,
|
||||
) where
|
||||
F: FnOnce(Result<gst::Sample, glib::Error>) + Send + 'static,
|
||||
{
|
||||
unsafe extern "C" fn convert_sample_async_trampoline<F>(
|
||||
sample: *mut gst_ffi::GstSample,
|
||||
error: *mut glib_ffi::GError,
|
||||
user_data: glib_ffi::gpointer,
|
||||
) where
|
||||
F: FnOnce(Result<gst::Sample, glib::Error>) + Send + 'static,
|
||||
{
|
||||
callback_guard!();
|
||||
let callback: &mut Option<Box<F>> = mem::transmute(user_data);
|
||||
let callback = callback.take().unwrap();
|
||||
|
||||
if error.is_null() {
|
||||
callback(Ok(from_glib_full(sample)))
|
||||
} else {
|
||||
callback(Err(from_glib_full(error)))
|
||||
}
|
||||
}
|
||||
unsafe extern "C" fn convert_sample_async_free<F>(user_data: glib_ffi::gpointer)
|
||||
where
|
||||
F: FnOnce(Result<gst::Sample, glib::Error>) + Send + 'static,
|
||||
{
|
||||
callback_guard!();
|
||||
let _: Box<Option<Box<F>>> = Box::from_raw(user_data as *mut _);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let user_data: Box<Option<Box<F>>> = Box::new(Some(Box::new(func)));
|
||||
|
||||
ffi::gst_video_convert_sample_async(
|
||||
sample.to_glib_none().0,
|
||||
caps.to_glib_none().0,
|
||||
timeout.to_glib(),
|
||||
Some(convert_sample_async_trampoline::<F>),
|
||||
Box::into_raw(user_data) as glib_ffi::gpointer,
|
||||
Some(convert_sample_async_free::<F>),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use gst;
|
||||
use glib;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[test]
|
||||
fn test_convert_sample_async() {
|
||||
gst::init().unwrap();
|
||||
|
||||
let l = glib::MainLoop::new(None, false);
|
||||
|
||||
let mut in_buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
|
||||
{
|
||||
let buffer = in_buffer.get_mut().unwrap();
|
||||
let mut data = buffer.map_writable().unwrap();
|
||||
|
||||
for p in data.as_mut_slice().chunks_mut(4) {
|
||||
p[0] = 63;
|
||||
p[1] = 127;
|
||||
p[2] = 191;
|
||||
p[3] = 255;
|
||||
}
|
||||
}
|
||||
let in_caps = ::VideoInfo::new(::VideoFormat::Rgba, 320, 240)
|
||||
.build()
|
||||
.unwrap()
|
||||
.to_caps()
|
||||
.unwrap();
|
||||
let sample = gst::Sample::new(
|
||||
Some(&in_buffer),
|
||||
Some(&in_caps),
|
||||
None::<&gst::Segment>,
|
||||
None,
|
||||
);
|
||||
|
||||
let out_caps = ::VideoInfo::new(::VideoFormat::Abgr, 320, 240)
|
||||
.build()
|
||||
.unwrap()
|
||||
.to_caps()
|
||||
.unwrap();
|
||||
|
||||
let l_clone = l.clone();
|
||||
let res_store = Arc::new(Mutex::new(None));
|
||||
let res_store_clone = res_store.clone();
|
||||
convert_sample_async(&sample, &out_caps, gst::CLOCK_TIME_NONE, move |res| {
|
||||
*res_store_clone.lock().unwrap() = Some(res);
|
||||
l_clone.quit();
|
||||
});
|
||||
|
||||
l.run();
|
||||
|
||||
let res = res_store.lock().unwrap().take().unwrap();
|
||||
assert!(res.is_ok(), "Error {}", res.unwrap_err());
|
||||
let res = res.unwrap();
|
||||
|
||||
let converted_out_caps = res.get_caps().unwrap();
|
||||
assert_eq!(out_caps, converted_out_caps);
|
||||
let out_buffer = res.get_buffer().unwrap();
|
||||
{
|
||||
let data = out_buffer.map_readable().unwrap();
|
||||
|
||||
for p in data.as_slice().chunks(4) {
|
||||
assert_eq!(p, &[255, 191, 127, 63]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,9 @@ extern crate glib;
|
|||
extern crate glib_sys as glib_ffi;
|
||||
extern crate gobject_sys as gobject_ffi;
|
||||
extern crate gstreamer as gst;
|
||||
extern crate gstreamer_base as gst_base;
|
||||
extern crate gstreamer_sys as gst_ffi;
|
||||
extern crate gstreamer_base_sys as gst_base_ffi;
|
||||
extern crate gstreamer_video_sys as ffi;
|
||||
|
||||
macro_rules! assert_initialized_main_thread {
|
||||
|
@ -31,6 +33,12 @@ macro_rules! skip_assert_initialized {
|
|||
)
|
||||
}
|
||||
|
||||
macro_rules! callback_guard {
|
||||
() => (
|
||||
let _guard = ::glib::CallbackGuard::new();
|
||||
)
|
||||
}
|
||||
|
||||
pub use glib::{Cast, Continue, Error, IsA, StaticType, ToValue, Type, TypedValue, Value};
|
||||
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
|
||||
|
@ -46,12 +54,16 @@ mod video_format_info;
|
|||
pub use video_format_info::*;
|
||||
mod video_info;
|
||||
pub use video_info::*;
|
||||
mod video_frame;
|
||||
pub use video_frame::VideoFrame;
|
||||
pub mod video_frame;
|
||||
pub use video_frame::{VideoFrame, VideoFrameRef};
|
||||
mod video_overlay;
|
||||
pub use video_overlay::VideoOverlayExtManual;
|
||||
mod video_event;
|
||||
pub use video_event::*;
|
||||
mod functions;
|
||||
pub use functions::*;
|
||||
mod video_rectangle;
|
||||
pub use video_rectangle::*;
|
||||
|
||||
// Re-export all the traits in a prelude module, so that applications
|
||||
// can always "use gst::prelude::*" without getting conflicts
|
||||
|
|
|
@ -18,6 +18,7 @@ use std::mem;
|
|||
use std::ptr;
|
||||
use std::marker::PhantomData;
|
||||
use std::slice;
|
||||
use std::ops;
|
||||
|
||||
pub struct Readable;
|
||||
pub struct Writable;
|
||||
|
@ -219,6 +220,12 @@ impl VideoFrame<Readable> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_video_frame_ref(&self) -> VideoFrameRef<&gst::BufferRef> {
|
||||
let vframe = unsafe { ptr::read(&self.0) };
|
||||
let info = self.2.clone();
|
||||
VideoFrameRef(vframe, Some(self.buffer()), info, true)
|
||||
}
|
||||
}
|
||||
|
||||
impl VideoFrame<Writable> {
|
||||
|
@ -311,6 +318,332 @@ impl VideoFrame<Writable> {
|
|||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_mut_video_frame_ref(&mut self) -> VideoFrameRef<&mut gst::BufferRef> {
|
||||
let vframe = unsafe { ptr::read(&self.0) };
|
||||
let info = self.2.clone();
|
||||
VideoFrameRef(vframe, Some(self.buffer_mut()), info, true)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VideoFrameRef<T>(ffi::GstVideoFrame, Option<T>, ::VideoInfo, bool);
|
||||
|
||||
impl<'a> VideoFrameRef<&'a gst::BufferRef> {
|
||||
pub fn from_buffer_ref_readable<'b>(
|
||||
buffer: &'a gst::BufferRef,
|
||||
info: &'b ::VideoInfo,
|
||||
) -> Option<VideoFrameRef<&'a gst::BufferRef>> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
unsafe {
|
||||
let mut frame = mem::zeroed();
|
||||
let res: bool = from_glib(ffi::gst_video_frame_map(
|
||||
&mut frame,
|
||||
info.to_glib_none().0 as *mut _,
|
||||
buffer.as_mut_ptr(),
|
||||
mem::transmute(
|
||||
ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF.bits() | gst_ffi::GST_MAP_READ.bits(),
|
||||
),
|
||||
));
|
||||
|
||||
if !res {
|
||||
None
|
||||
} else {
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
Some(VideoFrameRef(frame, Some(buffer), info, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_buffer_ref_id_readable<'b>(
|
||||
buffer: &'a gst::BufferRef,
|
||||
id: i32,
|
||||
info: &'b ::VideoInfo,
|
||||
) -> Option<VideoFrameRef<&'a gst::BufferRef>> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
unsafe {
|
||||
let mut frame = mem::zeroed();
|
||||
let res: bool = from_glib(ffi::gst_video_frame_map_id(
|
||||
&mut frame,
|
||||
info.to_glib_none().0 as *mut _,
|
||||
buffer.as_mut_ptr(),
|
||||
id,
|
||||
mem::transmute(
|
||||
ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF.bits() | gst_ffi::GST_MAP_READ.bits(),
|
||||
),
|
||||
));
|
||||
|
||||
if !res {
|
||||
None
|
||||
} else {
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
Some(VideoFrameRef(frame, Some(buffer), info, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn info(&self) -> &::VideoInfo {
|
||||
&self.2
|
||||
}
|
||||
|
||||
pub fn flags(&self) -> ::VideoFrameFlags {
|
||||
from_glib(self.0.flags)
|
||||
}
|
||||
|
||||
pub fn id(&self) -> i32 {
|
||||
self.0.id
|
||||
}
|
||||
|
||||
pub fn copy(&self, dest: &mut VideoFrame<Writable>) -> Result<(), glib::BoolError> {
|
||||
unsafe {
|
||||
let res: bool = from_glib(ffi::gst_video_frame_copy(&mut dest.0, &self.0));
|
||||
if res {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(glib::BoolError("Failed to copy video frame"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy_plane(
|
||||
&self,
|
||||
dest: &mut VideoFrame<Writable>,
|
||||
plane: u32,
|
||||
) -> Result<(), glib::BoolError> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
unsafe {
|
||||
let res: bool = from_glib(ffi::gst_video_frame_copy_plane(&mut dest.0, &self.0, plane));
|
||||
if res {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(glib::BoolError("Failed to copy video frame plane"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy_to_ref(&self, dest: &mut VideoFrameRef<&mut gst::BufferRef>) -> Result<(), glib::BoolError> {
|
||||
unsafe {
|
||||
let res: bool = from_glib(ffi::gst_video_frame_copy(&mut dest.0, &self.0));
|
||||
if res {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(glib::BoolError("Failed to copy video frame"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy_plane_to_ref(
|
||||
&self,
|
||||
dest: &mut VideoFrameRef<&mut gst::BufferRef>,
|
||||
plane: u32,
|
||||
) -> Result<(), glib::BoolError> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
unsafe {
|
||||
let res: bool = from_glib(ffi::gst_video_frame_copy_plane(&mut dest.0, &self.0, plane));
|
||||
if res {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(glib::BoolError("Failed to copy video frame plane"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format(&self) -> ::VideoFormat {
|
||||
self.info().format()
|
||||
}
|
||||
|
||||
pub fn format_info(&self) -> ::VideoFormatInfo {
|
||||
self.info().format_info()
|
||||
}
|
||||
|
||||
pub fn width(&self) -> u32 {
|
||||
self.info().width()
|
||||
}
|
||||
|
||||
pub fn height(&self) -> u32 {
|
||||
self.info().height()
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.info().size()
|
||||
}
|
||||
|
||||
pub fn is_interlaced(&self) -> bool {
|
||||
self.flags().contains(::VideoFrameFlags::INTERLACED)
|
||||
}
|
||||
|
||||
pub fn is_tff(&self) -> bool {
|
||||
self.flags().contains(::VideoFrameFlags::TFF)
|
||||
}
|
||||
|
||||
pub fn is_rff(&self) -> bool {
|
||||
self.flags().contains(::VideoFrameFlags::RFF)
|
||||
}
|
||||
|
||||
pub fn is_onefield(&self) -> bool {
|
||||
self.flags().contains(::VideoFrameFlags::ONEFIELD)
|
||||
}
|
||||
|
||||
pub fn n_planes(&self) -> u32 {
|
||||
self.info().n_planes()
|
||||
}
|
||||
|
||||
pub fn n_components(&self) -> u32 {
|
||||
self.info().n_components()
|
||||
}
|
||||
|
||||
pub fn plane_stride(&self) -> &[i32] {
|
||||
self.info().stride()
|
||||
}
|
||||
|
||||
pub fn plane_offset(&self) -> &[usize] {
|
||||
self.info().offset()
|
||||
}
|
||||
|
||||
pub fn buffer(&self) -> &gst::BufferRef {
|
||||
self.1.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn plane_data(&self, plane: u32) -> Option<&[u8]> {
|
||||
if plane >= self.n_planes() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let format_info = self.format_info();
|
||||
|
||||
// Just get the palette
|
||||
if format_info.has_palette() && plane == 1 {
|
||||
unsafe {
|
||||
return Some(slice::from_raw_parts(self.0.data[1] as *const u8, 256 * 4));
|
||||
}
|
||||
}
|
||||
|
||||
let w = self.plane_stride()[plane as usize] as u32;
|
||||
// FIXME: This assumes that the horizontal subsampling of all
|
||||
// components in the plane is the same, which is probably safe
|
||||
let h = format_info.scale_height(plane as u8, self.height());
|
||||
|
||||
unsafe {
|
||||
Some(slice::from_raw_parts(
|
||||
self.0.data[plane as usize] as *const u8,
|
||||
(w * h) as usize,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VideoFrameRef<&'a mut gst::BufferRef> {
|
||||
pub fn from_buffer_ref_writable<'b>(
|
||||
buffer: &'a mut gst::BufferRef,
|
||||
info: &'b ::VideoInfo,
|
||||
) -> Option<VideoFrameRef<&'a mut gst::BufferRef>> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
unsafe {
|
||||
let mut frame = mem::zeroed();
|
||||
let res: bool = from_glib(ffi::gst_video_frame_map(
|
||||
&mut frame,
|
||||
info.to_glib_none().0 as *mut _,
|
||||
buffer.as_mut_ptr(),
|
||||
mem::transmute(
|
||||
ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF.bits() | gst_ffi::GST_MAP_READ.bits()
|
||||
| gst_ffi::GST_MAP_WRITE.bits(),
|
||||
),
|
||||
));
|
||||
|
||||
if !res {
|
||||
None
|
||||
} else {
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
Some(VideoFrameRef(frame, Some(buffer), info, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_buffer_ref_id_writable<'b>(
|
||||
buffer: &'a mut gst::BufferRef,
|
||||
id: i32,
|
||||
info: &'b ::VideoInfo,
|
||||
) -> Option<VideoFrameRef<&'a mut gst::BufferRef>> {
|
||||
skip_assert_initialized!();
|
||||
|
||||
unsafe {
|
||||
let mut frame = mem::zeroed();
|
||||
let res: bool = from_glib(ffi::gst_video_frame_map_id(
|
||||
&mut frame,
|
||||
info.to_glib_none().0 as *mut _,
|
||||
buffer.as_mut_ptr(),
|
||||
id,
|
||||
mem::transmute(
|
||||
ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF.bits() | gst_ffi::GST_MAP_READ.bits()
|
||||
| gst_ffi::GST_MAP_WRITE.bits(),
|
||||
),
|
||||
));
|
||||
|
||||
if !res {
|
||||
None
|
||||
} else {
|
||||
let info = ::VideoInfo(ptr::read(&frame.info));
|
||||
Some(VideoFrameRef(frame, Some(buffer), info, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer_mut(&mut self) -> &mut gst::BufferRef {
|
||||
self.1.as_mut().unwrap()
|
||||
}
|
||||
|
||||
pub fn plane_data_mut(&mut self, plane: u32) -> Option<&mut [u8]> {
|
||||
if plane >= self.n_planes() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let format_info = self.format_info();
|
||||
|
||||
// Just get the palette
|
||||
if format_info.has_palette() && plane == 1 {
|
||||
unsafe {
|
||||
return Some(slice::from_raw_parts_mut(
|
||||
self.0.data[1] as *mut u8,
|
||||
256 * 4,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let w = self.plane_stride()[plane as usize] as u32;
|
||||
// FIXME: This assumes that the horizontal subsampling of all
|
||||
// components in the plane is the same, which is probably safe
|
||||
let h = format_info.scale_height(plane as u8, self.height());
|
||||
|
||||
unsafe {
|
||||
Some(slice::from_raw_parts_mut(
|
||||
self.0.data[plane as usize] as *mut u8,
|
||||
(w * h) as usize,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ops::Deref for VideoFrameRef<&'a mut gst::BufferRef> {
|
||||
type Target = VideoFrameRef<&'a gst::BufferRef>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
use std::mem;
|
||||
unsafe { mem::transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for VideoFrameRef<T> {
|
||||
fn drop(&mut self) {
|
||||
if !self.3 {
|
||||
unsafe {
|
||||
ffi::gst_video_frame_unmap(&mut self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
53
gstreamer-video/src/video_rectangle.rs
Normal file
53
gstreamer-video/src/video_rectangle.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright (C) 2017 Philippe Normand <philn@igalia.com~
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use ffi;
|
||||
use glib::translate::ToGlib;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct VideoRectangle {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub w: i32,
|
||||
pub h: i32,
|
||||
}
|
||||
|
||||
impl VideoRectangle {
|
||||
pub fn new(x: i32, y: i32, w: i32, h: i32) -> Self {
|
||||
VideoRectangle { x, y, w, h }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn center_video_rectangle(
|
||||
src: &VideoRectangle,
|
||||
dst: &VideoRectangle,
|
||||
scale: bool,
|
||||
) -> VideoRectangle {
|
||||
let mut result = ffi::GstVideoRectangle {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 0,
|
||||
h: 0,
|
||||
};
|
||||
let src_rect = ffi::GstVideoRectangle {
|
||||
x: src.x,
|
||||
y: src.y,
|
||||
w: src.w,
|
||||
h: src.h,
|
||||
};
|
||||
let dst_rect = ffi::GstVideoRectangle {
|
||||
x: dst.x,
|
||||
y: dst.y,
|
||||
w: dst.w,
|
||||
h: dst.h,
|
||||
};
|
||||
unsafe {
|
||||
ffi::gst_video_sink_center_rect(src_rect, dst_rect, &mut result, scale.to_glib());
|
||||
}
|
||||
VideoRectangle::new(result.x, result.y, result.w, result.h)
|
||||
}
|
|
@ -5,6 +5,33 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
||||
|
||||
## [0.10.2] - 2018-02-18
|
||||
### Fixed
|
||||
- Fix building of messages with custom fields for types that don't have a
|
||||
GstStructure
|
||||
|
||||
### Added
|
||||
- VideoFrameRef::copy_to_ref() and ::copy_plane_to_ref(), which work with
|
||||
VideoFrameRefs instead of full VideoFrames
|
||||
- Getters for the BaseSrc/Sink/Transform configured segment
|
||||
- Document the gstreamer-player-1.0 dependency in the README.md
|
||||
|
||||
## [0.10.1] - 2018-01-03
|
||||
### Fixed
|
||||
- Don't require &mut self for TagSetterExtManual::add()
|
||||
|
||||
### Added
|
||||
- A TagSetter example application
|
||||
- Bindings for gst_video::convert_sample() and ::convert_sample_async()
|
||||
- Bindings for gst_video::VideoRectangle
|
||||
- Debug impl for Sample and ::with_buffer_list() constructor
|
||||
- A borrowing version of VideoFrame: VideoFrameRef
|
||||
- Bindings for GstVideoFilter
|
||||
|
||||
### Changed
|
||||
- Deprecated Sample::get_info() in favour of ::get_structure()
|
||||
- Player has gst::Object as another parent class now
|
||||
|
||||
## [0.10.0] - 2017-12-22
|
||||
### Fixed
|
||||
- Various clippy warnings
|
||||
|
@ -193,7 +220,8 @@ specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-v
|
|||
(< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs).
|
||||
The API of the two is incompatible.
|
||||
|
||||
[Unreleased]: https://github.com/sdroege/gstreamer-rs/compare/0.10.0...HEAD
|
||||
[Unreleased]: https://github.com/sdroege/gstreamer-rs/compare/0.10.1...HEAD
|
||||
[0.10.1]: https://github.com/sdroege/gstreamer-rs/compare/0.10.0...0.10.1
|
||||
[0.10.0]: https://github.com/sdroege/gstreamer-rs/compare/0.9.1...0.10.0
|
||||
[0.9.1]: https://github.com/sdroege/gstreamer-rs/compare/0.9.0...0.9.1
|
||||
[0.9.0]: https://github.com/sdroege/gstreamer-rs/compare/0.8.1...0.9.0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "gstreamer"
|
||||
version = "0.10.0"
|
||||
version = "0.10.2"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
categories = ["api-bindings", "multimedia"]
|
||||
description = "Rust bindings for GStreamer"
|
||||
|
@ -15,10 +15,10 @@ build = "build.rs"
|
|||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
libc = "0.2"
|
||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||
gstreamer-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] }
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
glib-sys = "0.5"
|
||||
gobject-sys = "0.5"
|
||||
gstreamer-sys = { version = "0.4", features = ["v1_8"] }
|
||||
glib = "0.4"
|
||||
num-rational = { version = "0.1.38", default-features = false, features = [] }
|
||||
lazy_static = "1.0"
|
||||
futures = { version = "0.1", optional = true }
|
||||
|
|
|
@ -775,6 +775,7 @@ impl SetValue for StreamFlags {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||
bitflags! {
|
||||
pub struct StreamType: u32 {
|
||||
const UNKNOWN = 1;
|
||||
|
@ -785,6 +786,7 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||
#[doc(hidden)]
|
||||
impl ToGlib for StreamType {
|
||||
type GlibType = ffi::GstStreamType;
|
||||
|
@ -794,6 +796,7 @@ impl ToGlib for StreamType {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||
#[doc(hidden)]
|
||||
impl FromGlib<ffi::GstStreamType> for StreamType {
|
||||
fn from_glib(value: ffi::GstStreamType) -> StreamType {
|
||||
|
@ -802,24 +805,28 @@ impl FromGlib<ffi::GstStreamType> for StreamType {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||
impl StaticType for StreamType {
|
||||
fn static_type() -> Type {
|
||||
unsafe { from_glib(ffi::gst_stream_type_get_type()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||
impl<'a> FromValueOptional<'a> for StreamType {
|
||||
unsafe fn from_value_optional(value: &Value) -> Option<Self> {
|
||||
Some(FromValue::from_value(value))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||
impl<'a> FromValue<'a> for StreamType {
|
||||
unsafe fn from_value(value: &Value) -> Self {
|
||||
from_glib(ffi::GstStreamType::from_bits_truncate(gobject_ffi::g_value_get_flags(value.to_glib_none().0)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||
impl SetValue for StreamType {
|
||||
unsafe fn set_value(value: &mut Value, this: &Self) {
|
||||
gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, this.to_glib().bits())
|
||||
|
|
|
@ -162,6 +162,7 @@ pub use self::flags::SegmentFlags;
|
|||
#[cfg(any(feature = "v1_12", feature = "dox"))]
|
||||
pub use self::flags::StackTraceFlags;
|
||||
pub use self::flags::StreamFlags;
|
||||
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||
pub use self::flags::StreamType;
|
||||
|
||||
mod alias;
|
||||
|
|
|
@ -895,7 +895,7 @@ macro_rules! event_builder_generic_impl {
|
|||
ffi::gst_event_set_running_time_offset(event, running_time_offset);
|
||||
}
|
||||
|
||||
{
|
||||
if !self.other_fields.is_empty() {
|
||||
let s = StructureRef::from_glib_borrow_mut(
|
||||
ffi::gst_event_writable_structure(event)
|
||||
);
|
||||
|
@ -1667,3 +1667,49 @@ impl<'a> CustomBothOobBuilder<'a> {
|
|||
ev
|
||||
});
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_simple() {
|
||||
::init().unwrap();
|
||||
|
||||
// Event without arguments
|
||||
let flush_start_evt = Event::new_flush_start().build();
|
||||
match flush_start_evt.view() {
|
||||
EventView::FlushStart(flush_start_evt) => {
|
||||
assert!(flush_start_evt.0.get_structure().is_none());
|
||||
},
|
||||
_ => panic!("flush_start_evt.view() is not an EventView::FlushStart(_)"),
|
||||
}
|
||||
|
||||
let flush_start_evt = Event::new_flush_start()
|
||||
.other_fields(&[("extra-field", &true)])
|
||||
.build();
|
||||
match flush_start_evt.view() {
|
||||
EventView::FlushStart(flush_start_evt) => {
|
||||
assert!(flush_start_evt.0.get_structure().is_some());
|
||||
if let Some(other_fields) = flush_start_evt.0.get_structure() {
|
||||
assert!(other_fields.has_field("extra-field"));
|
||||
}
|
||||
},
|
||||
_ => panic!("flush_start_evt.view() is not an EventView::FlushStart(_)"),
|
||||
}
|
||||
|
||||
// Event with arguments
|
||||
let flush_stop_evt = Event::new_flush_stop(true)
|
||||
.other_fields(&[("extra-field", &true)])
|
||||
.build();
|
||||
match flush_stop_evt.view() {
|
||||
EventView::FlushStop(flush_stop_evt) => {
|
||||
assert_eq!(flush_stop_evt.get_reset_time(), true);
|
||||
assert!(flush_stop_evt.0.get_structure().is_some());
|
||||
if let Some(other_fields) = flush_stop_evt.0.get_structure() {
|
||||
assert!(other_fields.has_field("extra-field"));
|
||||
}
|
||||
}
|
||||
_ => panic!("flush_stop_evt.view() is not an EventView::FlushStop(_)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1165,6 +1165,8 @@ macro_rules! message_builder_generic_impl {
|
|||
}
|
||||
}
|
||||
|
||||
// Warning: other_fields are ignored with argument-less messages
|
||||
// until GStreamer 1.14 is released
|
||||
pub fn other_fields(self, other_fields: &[(&'a str, &'a ToSendValue)]) -> Self {
|
||||
Self {
|
||||
other_fields: self.other_fields.iter().cloned()
|
||||
|
@ -1183,13 +1185,19 @@ macro_rules! message_builder_generic_impl {
|
|||
ffi::gst_message_set_seqnum(msg, seqnum.to_glib());
|
||||
}
|
||||
|
||||
{
|
||||
let s = StructureRef::from_glib_borrow_mut(
|
||||
ffi::gst_message_get_structure(msg) as *mut _
|
||||
);
|
||||
if !self.other_fields.is_empty() {
|
||||
// issue with argument-less messages. We need the function
|
||||
// ffi::gst_message_writable_structure to sort this out
|
||||
// and this function will be available in GStreamer 1.14
|
||||
// See https://github.com/sdroege/gstreamer-rs/pull/75
|
||||
// and https://bugzilla.gnome.org/show_bug.cgi?id=792928
|
||||
let structure = ffi::gst_message_get_structure(msg);
|
||||
if !structure.is_null() {
|
||||
let structure = StructureRef::from_glib_borrow_mut(structure as *mut _);
|
||||
|
||||
for (k, v) in self.other_fields {
|
||||
s.set_value(k, v.to_send_value());
|
||||
for (k, v) in self.other_fields {
|
||||
structure.set_value(k, v.to_send_value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2442,3 +2450,37 @@ impl<'a> RedirectBuilder<'a> {
|
|||
msg
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_simple() {
|
||||
::init().unwrap();
|
||||
|
||||
// Message without arguments
|
||||
let eos_msg = Message::new_eos().build();
|
||||
match eos_msg.view() {
|
||||
MessageView::Eos(eos_msg) => {
|
||||
assert!(eos_msg.0.get_structure().is_none());
|
||||
},
|
||||
_ => panic!("eos_msg.view() is not a MessageView::Eos(_)"),
|
||||
}
|
||||
|
||||
// Note: can't define other_fields for argument-less messages before GStreamer 1.14
|
||||
|
||||
// Message with arguments
|
||||
let buffering_msg = Message::new_buffering(42)
|
||||
.other_fields(&[("extra-field", &true)])
|
||||
.build();
|
||||
match buffering_msg.view() {
|
||||
MessageView::Buffering(buffering_msg) => {
|
||||
assert_eq!(buffering_msg.get_percent(), 42);
|
||||
assert!(buffering_msg.0.get_structure().is_some());
|
||||
assert!(buffering_msg.0.get_structure().unwrap().has_field("extra-field"));
|
||||
}
|
||||
_ => panic!("buffering_msg.view() is not a MessageView::Buffering(_)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
use std::ptr;
|
||||
use std::fmt;
|
||||
|
||||
use ffi;
|
||||
|
||||
|
@ -49,6 +50,20 @@ impl GstRc<SampleRef> {
|
|||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_buffer_list<F: FormattedValue>(
|
||||
buffer_list: Option<&BufferList>,
|
||||
caps: Option<&Caps>,
|
||||
segment: Option<&FormattedSegment<F>>,
|
||||
info: Option<&StructureRef>,
|
||||
) -> Self {
|
||||
assert_initialized_main_thread!();
|
||||
let sample = Self::new(None, caps, segment, info);
|
||||
unsafe {
|
||||
ffi::gst_sample_set_buffer_list(sample.to_glib_none().0, buffer_list.to_glib_none().0);
|
||||
}
|
||||
sample
|
||||
}
|
||||
}
|
||||
|
||||
impl SampleRef {
|
||||
|
@ -68,7 +83,7 @@ impl SampleRef {
|
|||
unsafe { from_glib_none(ffi::gst_sample_get_segment(self.as_mut_ptr())) }
|
||||
}
|
||||
|
||||
pub fn get_structure(&self) -> Option<&StructureRef> {
|
||||
pub fn get_info(&self) -> Option<&StructureRef> {
|
||||
unsafe {
|
||||
let ptr = ffi::gst_sample_get_info(self.as_mut_ptr());
|
||||
if ptr.is_null() {
|
||||
|
@ -78,6 +93,11 @@ impl SampleRef {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.10.1", note = "please use `get_info` instead")]
|
||||
pub fn get_structure(&self) -> Option<&StructureRef> {
|
||||
self.get_info()
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticType for SampleRef {
|
||||
|
@ -97,5 +117,16 @@ impl ToOwned for SampleRef {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SampleRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Sample")
|
||||
.field("buffer", &self.get_buffer())
|
||||
.field("caps", &self.get_caps())
|
||||
.field("segment", &self.get_segment())
|
||||
.field("info", &self.get_info())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for SampleRef {}
|
||||
unsafe impl Send for SampleRef {}
|
||||
|
|
|
@ -15,13 +15,13 @@ use glib::value::ToSendValue;
|
|||
use tags::*;
|
||||
|
||||
pub trait TagSetterExtManual {
|
||||
fn add<'a, T: Tag<'a>>(&mut self, value: T::TagType, mode: TagMergeMode)
|
||||
fn add<'a, T: Tag<'a>>(&self, value: T::TagType, mode: TagMergeMode)
|
||||
where
|
||||
T::TagType: ToSendValue;
|
||||
}
|
||||
|
||||
impl<O: IsA<TagSetter>> TagSetterExtManual for O {
|
||||
fn add<'a, T: Tag<'a>>(&mut self, value: T::TagType, mode: TagMergeMode)
|
||||
fn add<'a, T: Tag<'a>>(&self, value: T::TagType, mode: TagMergeMode)
|
||||
where
|
||||
T::TagType: ToSendValue,
|
||||
{
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
[package]
|
||||
name = "tutorials"
|
||||
version = "0.10.0"
|
||||
version = "0.10.2"
|
||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
||||
|
||||
[dependencies]
|
||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
||||
gdk = { git = "https://github.com/gtk-rs/gdk", optional = true }
|
||||
gtk = { git = "https://github.com/gtk-rs/gtk", features = ["v3_10"], optional = true }
|
||||
gstreamer = { path = "../gstreamer" }
|
||||
gstreamer-audio = { path = "../gstreamer-audio" }
|
||||
gstreamer-video = { path = "../gstreamer-video" }
|
||||
gstreamer-app = { path = "../gstreamer-app" }
|
||||
glib = "0.4"
|
||||
gdk = { version = "0.7", optional = true }
|
||||
gtk = { version = "0.3", features = ["v3_10"], optional = true }
|
||||
gstreamer = { version = "0.10", path = "../gstreamer" }
|
||||
gstreamer-audio = { version = "0.10", path = "../gstreamer-audio" }
|
||||
gstreamer-video = { version = "0.10", path = "../gstreamer-video" }
|
||||
gstreamer-app = { version = "0.10", path = "../gstreamer-app" }
|
||||
send-cell = "0.1"
|
||||
byte-slice-cast = "0.1"
|
||||
|
||||
|
|
Loading…
Reference in a new issue