Compare commits

...

26 commits
main ... 0.10

Author SHA1 Message Date
Sebastian Dröge
c7f5b541cc Fix unused import compiler warning in tokio example 2018-02-21 13:29:03 +01:00
Sebastian Dröge
cb11ab8a9c Update versions to 0.10.2 2018-02-18 23:14:53 +01:00
Sebastian Dröge
3103fc0b2b Update CHANGELOG.md for 0.10.2 2018-02-18 23:13:55 +01:00
Sebastian Dröge
8c54d21066 Add getters for the BaseSrc/Sink/Transform configured segment 2018-02-18 22:54:20 +01:00
fengalin
658be807c1 Fix building argument-less messages
Building an argument-less message such as eos yields an assertion failure due to the inner structure being null. The short term solution consists in checking that the inner `structure` is not `null` before attempting to insert `other_fields`. The consequence is that `others_fields` defined for argument-less messages will be ignored. A correction will be applied when GStreamer 1.14 is released thank to the introduction of `gst_message_writable_structure` (see https://bugzilla.gnome.org/show_bug.cgi?id=792928). Due to the dependency on GStreamer 1.14, the correction will be only available under the activation of a feature "v1_14".

Events are not affected as the build method the availability of `gst_event_writable_structure` and this function "will never return NULL". However, we can avoid a `structure` allocation for argument-less messages without `other_fields`.
2018-01-30 09:57:09 +02:00
Charlie Turner
7fe2216daf Document dependency for libgstreamer-plugins-bad1.0-dev 2018-01-30 09:56:35 +02:00
Sebastian Dröge
1294c28058 Add VideoFrameRef::copy_to_ref() and ::copy_plane_to_ref()
These take a VideoFrameRef instead of a VideoFrame as destination. Next
time we break API, the existing ::copy() and ::copy_plane() functions
should be modified.
2018-01-16 18:55:25 +02:00
Sebastian Dröge
7a779fe940 Don't implement Copy for VideoRectangle and pass by reference to center_video_rectangle() 2018-01-03 17:37:54 +02:00
Sebastian Dröge
24b263acef Update version to 0.10.1 2018-01-03 17:08:21 +02:00
Sebastian Dröge
97097554e7 Update CHANGELOG.md for 0.10.1 2018-01-03 17:08:10 +02:00
Sebastian Dröge
0dd0442fb7 Add VideoFrameRef API
This is like VideoFrame, but can work on gst::BufferRefs and borrows
from it. VideoFrames can be converted into this by borrowing.
2018-01-03 16:54:45 +02:00
Sebastian Dröge
a8c2815c3b Add GstVideoFilter bindings
Not very useful, but will be useful for gst-plugin-rs
2017-12-30 15:35:53 +02:00
Sebastian Dröge
1898599c42 Add gst::Object as parent class of gst_player::Player 2017-12-30 15:35:13 +02:00
Sebastian Dröge
c71623591a Add unit test for gst_video::convert_sample_async() 2017-12-30 15:25:12 +02:00
Sebastian Dröge
7508184557 Fix memory leak for gst_video::convert_sample_async()
Values are passed owned to the callback
2017-12-30 15:25:12 +02:00
Sebastian Dröge
9a63eb6353 Add Sample::get_info() and deprecate get_structure()
For consistency with the C API naming.
2017-12-30 15:25:12 +02:00
Sebastian Dröge
9ba69ad93b Add Sample::with_buffer_list() constructor 2017-12-30 15:25:12 +02:00
Sebastian Dröge
1f0947cda0 Add Debug impl for Sample 2017-12-30 15:25:12 +02:00
Sebastian Dröge
950e5dbc32 Run video_rectangle.rs through rustfmt 2017-12-30 15:25:12 +02:00
Philippe Normand
4ce1221ef4 gstreamer-video: VideoRectangle bindings 2017-12-30 15:25:12 +02:00
Sebastian Dröge
4b71d65283 Add gst::TagSetter example 2017-12-30 15:25:12 +02:00
Sebastian Dröge
93723026eb Add bindings for gst_video::convert_sample() and ::convert_sample_async() 2017-12-30 15:25:12 +02:00
Sebastian Dröge
f2ef2b6bea Correctly mark Stream and StreamType as requiring version 1.10 at least
Should fix https://github.com/sdroege/gstreamer-rs/issues/68
2017-12-26 18:13:57 +01:00
Sebastian Dröge
9321f31d0a Don't require a mutable self for TagSetterExtManual::add()
Like all GObjects, mutation works through interior mutability.
2017-12-23 11:43:52 +02:00
Sebastian Dröge
74527fe9d8 Fix documentation links for gstreamer-base/net 2017-12-22 15:34:21 +02:00
Sebastian Dröge
85f44a0479 Update versions of all dependencies and point to releases instead of GIT 2017-12-22 14:57:27 +02:00
40 changed files with 1236 additions and 91 deletions

View file

@ -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",

View file

@ -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",

View file

@ -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

View file

@ -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"

View 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),
}
}

View file

@ -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;

View file

@ -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">

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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]

View file

@ -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

View file

@ -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"

View 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 _)
}
}
}

View 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 _)
}
}
}

View 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 _)
}
}
}

View file

@ -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;

View 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));
}
}
}

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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"

View file

@ -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(),

View file

@ -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

View file

@ -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"

View file

@ -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;

View 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 {}

View 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]);
}
}
}
}

View file

@ -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

View file

@ -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)]

View 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)
}

View file

@ -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

View file

@ -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 }

View file

@ -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())

View file

@ -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;

View file

@ -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(_)"),
}
}
}

View file

@ -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(_)"),
}
}
}

View file

@ -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 {}

View file

@ -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,
{

View file

@ -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"