From 69e1fdd529ff068dca1106cb430128151cca4c5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 29 Jul 2017 12:58:54 +0100 Subject: [PATCH] Add Query bindings --- Gir_Gst.toml | 7 + gstreamer/src/auto/enums.rs | 60 +++ gstreamer/src/auto/flags.rs | 49 ++ gstreamer/src/auto/mod.rs | 5 + gstreamer/src/auto/pad.rs | 11 +- gstreamer/src/lib.rs | 2 + gstreamer/src/message.rs | 4 + gstreamer/src/query.rs | 886 ++++++++++++++++++++++++++++++++++++ 8 files changed, 1020 insertions(+), 4 deletions(-) create mode 100644 gstreamer/src/query.rs diff --git a/Gir_Gst.toml b/Gir_Gst.toml index b0a5ceed3..4adf5f931 100644 --- a/Gir_Gst.toml +++ b/Gir_Gst.toml @@ -52,6 +52,8 @@ generate = [ "Gst.CapsIntersectMode", "Gst.BufferFlags", "Gst.SegmentFlags", + "Gst.PadMode", + "Gst.SchedulingFlags", ] manual = [ @@ -289,6 +291,11 @@ status = "generate" [object.function.return] bool_return_is_error = "Failed to activate pad" + [[object.function]] + name = "activate_mode" + [object.function.return] + bool_return_is_error = "Failed to activate mode pad" + [[object.property]] name = "caps" # Caps is not a GObject diff --git a/gstreamer/src/auto/enums.rs b/gstreamer/src/auto/enums.rs index dd534e185..118efb0f9 100644 --- a/gstreamer/src/auto/enums.rs +++ b/gstreamer/src/auto/enums.rs @@ -708,6 +708,66 @@ impl SetValue for PadLinkReturn { } } +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum PadMode { + None, + Push, + Pull, + #[doc(hidden)] + __Unknown(i32), +} + +#[doc(hidden)] +impl ToGlib for PadMode { + type GlibType = ffi::GstPadMode; + + fn to_glib(&self) -> ffi::GstPadMode { + match *self { + PadMode::None => ffi::GST_PAD_MODE_NONE, + PadMode::Push => ffi::GST_PAD_MODE_PUSH, + PadMode::Pull => ffi::GST_PAD_MODE_PULL, + PadMode::__Unknown(value) => unsafe{std::mem::transmute(value)} + } + } +} + +#[doc(hidden)] +impl FromGlib for PadMode { + fn from_glib(value: ffi::GstPadMode) -> Self { + skip_assert_initialized!(); + match value as i32 { + 0 => PadMode::None, + 1 => PadMode::Push, + 2 => PadMode::Pull, + value => PadMode::__Unknown(value), + } + } +} + +impl StaticType for PadMode { + fn static_type() -> Type { + unsafe { from_glib(ffi::gst_pad_mode_get_type()) } + } +} + +impl<'a> FromValueOptional<'a> for PadMode { + unsafe fn from_value_optional(value: &Value) -> Option { + Some(FromValue::from_value(value)) + } +} + +impl<'a> FromValue<'a> for PadMode { + unsafe fn from_value(value: &Value) -> Self { + from_glib(std::mem::transmute::(gobject_ffi::g_value_get_enum(value.to_glib_none().0))) + } +} + +impl SetValue for PadMode { + unsafe fn set_value(value: &mut Value, this: &Self) { + gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, this.to_glib() as i32) + } +} + #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum PadPresence { Always, diff --git a/gstreamer/src/auto/flags.rs b/gstreamer/src/auto/flags.rs index e4b198597..1c161b00e 100644 --- a/gstreamer/src/auto/flags.rs +++ b/gstreamer/src/auto/flags.rs @@ -135,6 +135,55 @@ impl SetValue for PadProbeType { } } +bitflags! { + pub struct SchedulingFlags: u32 { + const SCHEDULING_FLAG_SEEKABLE = 1; + const SCHEDULING_FLAG_SEQUENTIAL = 2; + const SCHEDULING_FLAG_BANDWIDTH_LIMITED = 4; + } +} + +#[doc(hidden)] +impl ToGlib for SchedulingFlags { + type GlibType = ffi::GstSchedulingFlags; + + fn to_glib(&self) -> ffi::GstSchedulingFlags { + ffi::GstSchedulingFlags::from_bits_truncate(self.bits()) + } +} + +#[doc(hidden)] +impl FromGlib for SchedulingFlags { + fn from_glib(value: ffi::GstSchedulingFlags) -> SchedulingFlags { + skip_assert_initialized!(); + SchedulingFlags::from_bits_truncate(value.bits()) + } +} + +impl StaticType for SchedulingFlags { + fn static_type() -> Type { + unsafe { from_glib(ffi::gst_scheduling_flags_get_type()) } + } +} + +impl<'a> FromValueOptional<'a> for SchedulingFlags { + unsafe fn from_value_optional(value: &Value) -> Option { + Some(FromValue::from_value(value)) + } +} + +impl<'a> FromValue<'a> for SchedulingFlags { + unsafe fn from_value(value: &Value) -> Self { + from_glib(ffi::GstSchedulingFlags::from_bits_truncate(gobject_ffi::g_value_get_flags(value.to_glib_none().0))) + } +} + +impl SetValue for SchedulingFlags { + 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()) + } +} + bitflags! { pub struct SeekFlags: u32 { const SEEK_FLAG_NONE = 0; diff --git a/gstreamer/src/auto/mod.rs b/gstreamer/src/auto/mod.rs index a59abfaef..efb66029c 100644 --- a/gstreamer/src/auto/mod.rs +++ b/gstreamer/src/auto/mod.rs @@ -85,6 +85,7 @@ pub use self::enums::Format; pub use self::enums::LibraryError; pub use self::enums::PadDirection; pub use self::enums::PadLinkReturn; +pub use self::enums::PadMode; pub use self::enums::PadPresence; pub use self::enums::PadProbeReturn; pub use self::enums::ParseError; @@ -140,6 +141,10 @@ pub use self::flags::PAD_PROBE_TYPE_EVENT_BOTH; pub use self::flags::PAD_PROBE_TYPE_QUERY_BOTH; pub use self::flags::PAD_PROBE_TYPE_ALL_BOTH; pub use self::flags::PAD_PROBE_TYPE_SCHEDULING; +pub use self::flags::SchedulingFlags; +pub use self::flags::SCHEDULING_FLAG_SEEKABLE; +pub use self::flags::SCHEDULING_FLAG_SEQUENTIAL; +pub use self::flags::SCHEDULING_FLAG_BANDWIDTH_LIMITED; pub use self::flags::SeekFlags; pub use self::flags::SEEK_FLAG_NONE; pub use self::flags::SEEK_FLAG_FLUSH; diff --git a/gstreamer/src/auto/pad.rs b/gstreamer/src/auto/pad.rs index 0117df9e2..04724d01d 100644 --- a/gstreamer/src/auto/pad.rs +++ b/gstreamer/src/auto/pad.rs @@ -8,6 +8,7 @@ use Format; use Object; use PadDirection; use PadLinkReturn; +use PadMode; use PadTemplate; #[cfg(feature = "v1_10")] use Stream; @@ -67,7 +68,7 @@ unsafe impl Send for Pad {} unsafe impl Sync for Pad {} pub trait PadExt { - //fn activate_mode(&self, mode: /*Ignored*/PadMode, active: bool) -> bool; + fn activate_mode(&self, mode: PadMode, active: bool) -> Result<(), glib::error::BoolError>; //fn add_probe>>(&self, mask: PadProbeType, callback: /*Unknown conversion*//*Unimplemented*/PadProbeCallback, user_data: P, destroy_data: /*Unknown conversion*//*Unimplemented*/DestroyNotify) -> libc::c_ulong; @@ -229,9 +230,11 @@ pub trait PadExt { } impl + IsA> PadExt for O { - //fn activate_mode(&self, mode: /*Ignored*/PadMode, active: bool) -> bool { - // unsafe { TODO: call ffi::gst_pad_activate_mode() } - //} + fn activate_mode(&self, mode: PadMode, active: bool) -> Result<(), glib::error::BoolError> { + unsafe { + glib::error::BoolError::from_glib(ffi::gst_pad_activate_mode(self.to_glib_none().0, mode.to_glib(), active.to_glib()), "Failed to activate mode pad") + } + } //fn add_probe>>(&self, mask: PadProbeType, callback: /*Unknown conversion*//*Unimplemented*/PadProbeCallback, user_data: P, destroy_data: /*Unknown conversion*//*Unimplemented*/DestroyNotify) -> libc::c_ulong { // unsafe { TODO: call ffi::gst_pad_add_probe() } diff --git a/gstreamer/src/lib.rs b/gstreamer/src/lib.rs index 549fb9077..e4bb56734 100644 --- a/gstreamer/src/lib.rs +++ b/gstreamer/src/lib.rs @@ -62,6 +62,8 @@ pub mod sample; pub use sample::{Sample, SampleRef}; pub mod bufferlist; pub use bufferlist::{BufferList, BufferListRef}; +pub mod query; +pub use query::{Query, QueryRef, QueryView}; mod element; mod bin; diff --git a/gstreamer/src/message.rs b/gstreamer/src/message.rs index 4138e96c9..963c76f9a 100644 --- a/gstreamer/src/message.rs +++ b/gstreamer/src/message.rs @@ -124,6 +124,10 @@ impl MessageRef { MessageView::Other } } + + pub fn new_eos<'a>() -> EosBuilder<'a> { + EosBuilder::new() + } } impl glib::types::StaticType for GstRc { diff --git a/gstreamer/src/query.rs b/gstreamer/src/query.rs new file mode 100644 index 000000000..c110c3307 --- /dev/null +++ b/gstreamer/src/query.rs @@ -0,0 +1,886 @@ +// Copyright (C) 2016-2017 Sebastian Dröge +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ffi; +use miniobject::*; +use structure::*; + +use std::ptr; +use std::mem; +use std::ops::Deref; + +use glib; +use glib::translate::{from_glib, from_glib_full, ToGlibPtr, ToGlib}; + +#[repr(C)] +pub struct QueryRef(ffi::GstQuery); + +pub type Query = GstRc; + +unsafe impl MiniObject for QueryRef { + type GstType = ffi::GstQuery; +} + +impl Query { + pub fn new_position(fmt: ::Format) -> Self { + unsafe { + from_glib_full(ffi::gst_query_new_position(fmt.to_glib())) + } + } + + pub fn new_duration(fmt: ::Format) -> Self { + unsafe { + from_glib_full(ffi::gst_query_new_duration(fmt.to_glib())) + } + } + + pub fn new_latency() -> Self { + unsafe { + from_glib_full(ffi::gst_query_new_latency()) + } + } + + pub fn new_seeking(fmt: ::Format) -> Self { + unsafe { + from_glib_full(ffi::gst_query_new_seeking(fmt.to_glib())) + } + } + + pub fn new_segment(fmt: ::Format) -> Self { + unsafe { + from_glib_full(ffi::gst_query_new_segment(fmt.to_glib())) + } + } + + pub fn new_convert(src_fmt: ::Format, value: i64, dest_fmt: ::Format) -> Self { + unsafe { + from_glib_full(ffi::gst_query_new_convert(src_fmt.to_glib(), value, dest_fmt.to_glib())) + } + } + + pub fn new_formats() -> Self { + unsafe { + from_glib_full(ffi::gst_query_new_formats()) + } + } + + pub fn new_buffering(fmt: ::Format) -> Self { + unsafe { + from_glib_full(ffi::gst_query_new_buffering(fmt.to_glib())) + } + } + + pub fn new_custom(structure: ::Structure) -> Self { + unsafe { + from_glib_full(ffi::gst_query_new_custom(ffi::GST_QUERY_CUSTOM, structure.into_ptr())) + } + } + + pub fn new_uri() -> Self { + unsafe { + from_glib_full(ffi::gst_query_new_uri()) + } + } + + pub fn new_scheduling() -> Self { + unsafe { + from_glib_full(ffi::gst_query_new_scheduling()) + } + } + + pub fn new_accept_caps(caps: &::Caps) -> Self { + unsafe { + from_glib_full(ffi::gst_query_new_accept_caps(caps.as_mut_ptr())) + } + } + + pub fn new_caps(filter: &::Caps) -> Self { + unsafe { + from_glib_full(ffi::gst_query_new_caps(filter.as_mut_ptr())) + } + } + + pub fn new_drain() -> Self { + unsafe { + from_glib_full(ffi::gst_query_new_drain()) + } + } +} + +impl QueryRef { + pub fn get_structure(&self) -> &StructureRef { + unsafe { + let structure = ffi::gst_query_get_structure(self.as_mut_ptr()); + StructureRef::from_glib_borrow(structure) + } + } + + pub fn get_mut_structure(&mut self) -> &mut StructureRef { + unsafe { + let structure = ffi::gst_query_writable_structure(self.as_mut_ptr()); + StructureRef::from_glib_borrow_mut(structure) + } + } + + pub fn is_downstream(&self) -> bool { + unsafe { + ((*self.as_ptr()).type_ as u32) & (ffi::GST_QUERY_TYPE_DOWNSTREAM.bits()) != 0 + } + } + + pub fn is_upstream(&self) -> bool { + unsafe { + ((*self.as_ptr()).type_ as u32) & (ffi::GST_QUERY_TYPE_UPSTREAM.bits()) != 0 + } + } + + pub fn is_serialized(&self) -> bool { + unsafe { + ((*self.as_ptr()).type_ as u32) & (ffi::GST_QUERY_TYPE_SERIALIZED.bits()) != 0 + } + } + + pub fn view(&self) -> QueryView<&Self> { + let type_ = unsafe { (*self.as_ptr()).type_ }; + + if type_ == ffi::GST_QUERY_POSITION { + QueryView::Position(Position(self)) + } else if type_ == ffi::GST_QUERY_DURATION { + QueryView::Duration(Duration(self)) + } else if type_ == ffi::GST_QUERY_LATENCY { + QueryView::Latency(Latency(self)) + } else if type_ == ffi::GST_QUERY_JITTER { + QueryView::Jitter(Jitter(self)) + } else if type_ == ffi::GST_QUERY_RATE { + QueryView::Rate(Rate(self)) + } else if type_ == ffi::GST_QUERY_SEEKING { + QueryView::Seeking(Seeking(self)) + } else if type_ == ffi::GST_QUERY_SEGMENT { + QueryView::Segment(Segment(self)) + } else if type_ == ffi::GST_QUERY_CONVERT { + QueryView::Convert(Convert(self)) + } else if type_ == ffi::GST_QUERY_FORMATS { + QueryView::Formats(Formats(self)) + } else if type_ == ffi::GST_QUERY_BUFFERING { + QueryView::Buffering(Buffering(self)) + } else if type_ == ffi::GST_QUERY_CUSTOM { + QueryView::Custom(Custom(self)) + } else if type_ == ffi::GST_QUERY_URI { + QueryView::Uri(Uri(self)) + } else if type_ == ffi::GST_QUERY_ALLOCATION { + QueryView::Allocation(Allocation(self)) + } else if type_ == ffi::GST_QUERY_SCHEDULING { + QueryView::Scheduling(Scheduling(self)) + } else if type_ == ffi::GST_QUERY_ACCEPT_CAPS { + QueryView::AcceptCaps(AcceptCaps(self)) + } else if type_ == ffi::GST_QUERY_CAPS { + QueryView::Caps(Caps(self)) + } else if type_ == ffi::GST_QUERY_DRAIN { + QueryView::Drain(Drain(self)) + } else if type_ == ffi::GST_QUERY_CONTEXT { + QueryView::Context(Context(self)) + } else { + QueryView::Other(Other(self)) + } + } + + pub fn view_mut(&mut self) -> QueryView<&mut Self> { + unsafe { + mem::transmute(self.view()) + } + } +} + +impl glib::types::StaticType for GstRc { + fn static_type() -> glib::types::Type { + unsafe { from_glib(ffi::gst_query_get_type()) } + } +} + +pub enum QueryView { + Position(Position), + Duration(Duration), + Latency(Latency), + Jitter(Jitter), + Rate(Rate), + Seeking(Seeking), + Segment(Segment), + Convert(Convert), + Formats(Formats), + Buffering(Buffering), + Custom(Custom), + Uri(Uri), + Allocation(Allocation), + Scheduling(Scheduling), + AcceptCaps(AcceptCaps), + Caps(Caps), + Drain(Drain), + Context(Context), + Other(Other), + __NonExhaustive, +} + +pub struct Position(T); +impl<'a> Position<&'a QueryRef> { + pub fn get(&self) -> (::Format, i64) { + unsafe { + let mut fmt = mem::uninitialized(); + let mut pos = mem::uninitialized(); + + ffi::gst_query_parse_position(self.0.as_mut_ptr(), &mut fmt, &mut pos); + + (from_glib(fmt), pos) + } + } + + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Position<&'a mut QueryRef> { + pub fn set(&mut self, fmt: ::Format, pos: i64) { + unsafe { + ffi::gst_query_set_position(self.0.as_mut_ptr(), fmt.to_glib(), pos); + } + } + + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Duration(T); +impl<'a> Duration<&'a QueryRef> { + pub fn get(&self) -> (::Format, i64) { + unsafe { + let mut fmt = mem::uninitialized(); + let mut pos = mem::uninitialized(); + + ffi::gst_query_parse_duration(self.0.as_mut_ptr(), &mut fmt, &mut pos); + + (from_glib(fmt), pos) + } + } + + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Duration<&'a mut QueryRef> { + pub fn set(&mut self, fmt: ::Format, pos: i64) { + unsafe { + ffi::gst_query_set_duration(self.0.as_mut_ptr(), fmt.to_glib(), pos); + } + } + + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Latency(T); +impl<'a> Latency<&'a QueryRef> { + pub fn get(&self) -> (bool, u64, u64) { + unsafe { + let mut live = mem::uninitialized(); + let mut min = mem::uninitialized(); + let mut max = mem::uninitialized(); + + ffi::gst_query_parse_latency(self.0.as_mut_ptr(), &mut live, &mut min, &mut max); + + (from_glib(live), min, max) + } + } + + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Latency<&'a mut QueryRef> { + pub fn set(&mut self, live: bool, min: u64, max: u64) { + unsafe { + ffi::gst_query_set_latency(self.0.as_mut_ptr(), live.to_glib(), min, max); + } + } + + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Jitter(T); +impl<'a> Jitter<&'a QueryRef> { + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Jitter<&'a mut QueryRef> { + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Rate(T); +impl<'a> Rate<&'a QueryRef> { + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Rate<&'a mut QueryRef> { + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Seeking(T); +impl<'a> Seeking<&'a QueryRef> { + pub fn get(&self) -> (::Format, bool, i64, i64) { + unsafe { + let mut fmt = mem::uninitialized(); + let mut seekable = mem::uninitialized(); + let mut start = mem::uninitialized(); + let mut end = mem::uninitialized(); + ffi::gst_query_parse_seeking(self.0.as_mut_ptr(), &mut fmt, &mut seekable, &mut start, &mut end); + + (from_glib(fmt), from_glib(seekable), start, end) + } + } + + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Seeking<&'a mut QueryRef> { + pub fn set(&mut self, fmt: ::Format, seekable: bool, start: i64, end: i64) { + unsafe { + ffi::gst_query_set_seeking(self.0.as_mut_ptr(), fmt.to_glib(), seekable.to_glib(), start, end); + } + } + + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Segment(T); +impl<'a> Segment<&'a QueryRef> { + pub fn get(&self) -> (f64, ::Format, i64, i64) { + unsafe { + let mut rate = mem::uninitialized(); + let mut fmt = mem::uninitialized(); + let mut start = mem::uninitialized(); + let mut stop = mem::uninitialized(); + + ffi::gst_query_parse_segment(self.0.as_mut_ptr(), &mut rate, &mut fmt, &mut start, &mut stop); + (rate, from_glib(fmt), start, stop) + } + } + + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Segment<&'a mut QueryRef> { + pub fn set(&mut self, rate: f64, fmt: ::Format, start: i64, stop: i64) { + unsafe { + ffi::gst_query_set_segment(self.0.as_mut_ptr(), rate, fmt.to_glib(), start, stop); + } + } + + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Convert(T); +impl<'a> Convert<&'a QueryRef> { + pub fn get(&self) -> (::Format, i64, ::Format, i64) { + unsafe { + let mut src_fmt = mem::uninitialized(); + let mut src = mem::uninitialized(); + let mut dest_fmt = mem::uninitialized(); + let mut dest = mem::uninitialized(); + + ffi::gst_query_parse_convert(self.0.as_mut_ptr(), &mut src_fmt, &mut src, &mut dest_fmt, &mut dest); + (from_glib(src_fmt), src, from_glib(dest_fmt), dest) + } + } + + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Convert<&'a mut QueryRef> { + pub fn set(&mut self, src_fmt: ::Format, src: i64, dest_fmt: ::Format, dest: i64) { + unsafe { + ffi::gst_query_set_convert(self.0.as_mut_ptr(), src_fmt.to_glib(), src, dest_fmt.to_glib(), dest); + } + } + + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Formats(T); +impl<'a> Formats<&'a QueryRef> { + pub fn get(&self) -> Vec<::Format> { + unsafe { + let mut n = mem::uninitialized(); + ffi::gst_query_parse_n_formats(self.0.as_mut_ptr(), &mut n); + let mut res = Vec::with_capacity(n as usize); + + for i in 0..n { + let mut fmt = mem::uninitialized(); + ffi::gst_query_parse_nth_format(self.0.as_mut_ptr(), i, &mut fmt); + res.push(from_glib(fmt)); + } + + res + } + } + + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Formats<&'a mut QueryRef> { + pub fn set(&mut self, formats: &[::Format]) { + unsafe { + let v: Vec<_> = formats.iter().map(|f| f.to_glib()).collect(); + ffi::gst_query_set_formatsv(self.0.as_mut_ptr(), v.len() as i32, v.as_ptr() as *mut _); + } + } + + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Buffering(T); +impl<'a> Buffering<&'a QueryRef> { + pub fn get_percent(&self) -> (bool, i32) { + unsafe { + let mut busy = mem::uninitialized(); + let mut percent = mem::uninitialized(); + + ffi::gst_query_parse_buffering_percent(self.0.as_mut_ptr(), &mut busy, &mut percent); + + (from_glib(busy), percent) + } + } + + pub fn get_range(&self) -> (::Format, i64, i64, i64) { + unsafe { + let mut fmt = mem::uninitialized(); + let mut start = mem::uninitialized(); + let mut stop = mem::uninitialized(); + let mut estimated_total = mem::uninitialized(); + + ffi::gst_query_parse_buffering_range(self.0.as_mut_ptr(), &mut fmt, &mut start, &mut stop, &mut estimated_total); + (from_glib(fmt), start, stop, estimated_total) + } + } + + pub fn get_stats(&self) -> (::BufferingMode, i32, i32, i64) { + unsafe { + let mut mode = mem::uninitialized(); + let mut avg_in = mem::uninitialized(); + let mut avg_out = mem::uninitialized(); + let mut buffering_left = mem::uninitialized(); + + ffi::gst_query_parse_buffering_stats(self.0.as_mut_ptr(), &mut mode, &mut avg_in, &mut avg_out, &mut buffering_left); + + (from_glib(mode), avg_in, avg_out, buffering_left) + } + } + + pub fn get_ranges(&self) -> Vec<(i64, i64)> { + unsafe { + let n = ffi::gst_query_get_n_buffering_ranges(self.0.as_mut_ptr()); + let mut res = Vec::with_capacity(n as usize); + for i in 0..n { + let mut start = mem::uninitialized(); + let mut stop = mem::uninitialized(); + let s: bool = from_glib(ffi::gst_query_parse_nth_buffering_range(self.0.as_mut_ptr(), i, &mut start, &mut stop)); + if s { + res.push((start, stop)); + } + } + + res + } + } + + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Buffering<&'a mut QueryRef> { + pub fn set_percent(&mut self, busy: bool, percent: i32) { + unsafe { + ffi::gst_query_set_buffering_percent(self.0.as_mut_ptr(), busy.to_glib(), percent); + } + } + + pub fn set_range(&mut self, fmt: ::Format, start: i64, stop: i64, estimated_total: i64) { + unsafe { + ffi::gst_query_set_buffering_range(self.0.as_mut_ptr(), fmt.to_glib(), start, stop, estimated_total); + } + } + + pub fn set_stats(&mut self, mode: ::BufferingMode, avg_in: i32, avg_out: i32, buffering_left: i64) { + unsafe { + ffi::gst_query_set_buffering_stats(self.0.as_mut_ptr(), mode.to_glib(), avg_in, avg_out, buffering_left); + } + } + + pub fn add_buffering_ranges(&mut self, ranges: &[(i64, i64)]) { + unsafe { + for &(start, stop) in ranges { + ffi::gst_query_add_buffering_range(self.0.as_mut_ptr(), start, stop); + } + } + } + + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Custom(T); +impl<'a> Custom<&'a QueryRef> { + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Custom<&'a mut QueryRef> { + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Uri(T); +impl<'a> Uri<&'a QueryRef> { + pub fn get_uri(&self) -> Option { + unsafe { + let mut uri = ptr::null_mut(); + ffi::gst_query_parse_uri(self.0.as_mut_ptr(), &mut uri); + from_glib_full(uri) + } + } + + pub fn get_redirection(&self) -> (Option, bool) { + unsafe { + let mut uri = ptr::null_mut(); + ffi::gst_query_parse_uri_redirection(self.0.as_mut_ptr(), &mut uri); + let mut permanent = mem::uninitialized(); + ffi::gst_query_parse_uri_redirection_permanent(self.0.as_mut_ptr(), &mut permanent); + + (from_glib_full(uri), from_glib(permanent)) + } + } + + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Uri<&'a mut QueryRef> { + pub fn set_uri<'b, T: Into<&'b str>>(&mut self, uri: T) { + let uri = uri.into(); + unsafe { + ffi::gst_query_set_uri(self.0.as_mut_ptr(), uri.to_glib_none().0); + } + } + + pub fn set_redirection<'b, T: Into<&'b str>>(&mut self, uri: T, permanent: bool) { + let uri = uri.into(); + unsafe { + ffi::gst_query_set_uri_redirection(self.0.as_mut_ptr(), uri.to_glib_none().0); + ffi::gst_query_set_uri_redirection_permanent(self.0.as_mut_ptr(), permanent.to_glib()); + } + } + + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +// TODO +pub struct Allocation(T); +impl<'a> Allocation<&'a QueryRef> { + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Allocation<&'a mut QueryRef> { + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Scheduling(T); +impl<'a> Scheduling<&'a QueryRef> { + pub fn has_scheduling_mode(&self, mode: ::PadMode) -> bool { + unsafe { + from_glib(ffi::gst_query_has_scheduling_mode(self.0.as_mut_ptr(), mode.to_glib())) + } + } + + pub fn has_scheduling_mode_with_flags(&self, mode: ::PadMode, flags: ::SchedulingFlags) -> bool { + unsafe { + from_glib(ffi::gst_query_has_scheduling_mode_with_flags(self.0.as_mut_ptr(), mode.to_glib(), flags.to_glib())) + } + } + + pub fn get_scheduling_modes(&self) -> Vec<::PadMode> { + unsafe { + let n = ffi::gst_query_get_n_scheduling_modes(self.0.as_mut_ptr()); + let mut res = Vec::with_capacity(n as usize); + for i in 0..n { + res.push(from_glib(ffi::gst_query_parse_nth_scheduling_mode(self.0.as_mut_ptr(), i))); + } + + res + } + } + + pub fn get(&self) -> (::SchedulingFlags, i32, i32, i32) { + unsafe { + let mut flags = mem::uninitialized(); + let mut minsize = mem::uninitialized(); + let mut maxsize = mem::uninitialized(); + let mut align = mem::uninitialized(); + + ffi::gst_query_parse_scheduling(self.0.as_mut_ptr(), &mut flags, &mut minsize, &mut maxsize, &mut align); + + (from_glib(flags), minsize, maxsize, align) + } + } + + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Scheduling<&'a mut QueryRef> { + pub fn add_scheduling_modes(&mut self, modes: &[::PadMode]) { + unsafe { + for mode in modes { + ffi::gst_query_add_scheduling_mode(self.0.as_mut_ptr(), mode.to_glib()); + } + } + } + + pub fn set(&mut self, flags: ::SchedulingFlags, minsize: i32, maxsize: i32, align: i32) { + unsafe { + ffi::gst_query_set_scheduling(self.0.as_mut_ptr(), flags.to_glib(), minsize, maxsize, align); + } + } + + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct AcceptCaps(T); +impl<'a> AcceptCaps<&'a QueryRef> { + pub fn get(&self) -> &::CapsRef { + unsafe { + let mut caps = ptr::null_mut(); + ffi::gst_query_parse_accept_caps(self.0.as_mut_ptr(), &mut caps); + ::CapsRef::from_ptr(caps) + } + } + + pub fn get_result(&self) -> bool { + unsafe { + let mut accepted = mem::uninitialized(); + ffi::gst_query_parse_accept_caps_result(self.0.as_mut_ptr(), &mut accepted); + from_glib(accepted) + } + } + + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> AcceptCaps<&'a mut QueryRef> { + pub fn set_result(&mut self, accepted: bool) { + unsafe { + ffi::gst_query_set_accept_caps_result(self.0.as_mut_ptr(), accepted.to_glib()); + } + } + + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Caps(T); +impl<'a> Caps<&'a QueryRef> { + pub fn get_filter(&self) -> &::CapsRef { + unsafe { + let mut caps = ptr::null_mut(); + ffi::gst_query_parse_caps(self.0.as_mut_ptr(), &mut caps); + ::CapsRef::from_ptr(caps) + } + } + + pub fn get_result(&self) -> &::CapsRef { + unsafe { + let mut caps = ptr::null_mut(); + ffi::gst_query_parse_caps_result(self.0.as_mut_ptr(), &mut caps); + ::CapsRef::from_ptr(caps) + } + } + + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Caps<&'a mut QueryRef> { + pub fn set_result(&mut self, caps: &::Caps) { + unsafe { + ffi::gst_query_set_caps_result(self.0.as_mut_ptr(), caps.as_mut_ptr()); + } + } + + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Drain(T); +impl<'a> Drain<&'a QueryRef> { + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Drain<&'a mut QueryRef> { + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +// TODO +pub struct Context(T); +impl<'a> Context<&'a QueryRef> { + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Context<&'a mut QueryRef> { + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +pub struct Other(T); +impl<'a> Other<&'a QueryRef> { + pub fn get_query(&self) -> &QueryRef { + self.0 + } +} + +impl<'a> Other<&'a mut QueryRef> { + pub fn get_mut_query(&mut self) -> &mut QueryRef { + self.0 + } +} + +macro_rules! impl_deref_view( + ($name:ident) => { + impl<'a> Deref for $name<&'a mut QueryRef> { + type Target = $name<&'a QueryRef>; + + fn deref(&self) -> &Self::Target { + unsafe { + mem::transmute(self) + } + } + } + }; +); + +impl_deref_view!(Position); +impl_deref_view!(Duration); +impl_deref_view!(Latency); +impl_deref_view!(Jitter); +impl_deref_view!(Rate); +impl_deref_view!(Seeking); +impl_deref_view!(Segment); +impl_deref_view!(Convert); +impl_deref_view!(Formats); +impl_deref_view!(Buffering); +impl_deref_view!(Custom); +impl_deref_view!(Uri); +impl_deref_view!(Allocation); +impl_deref_view!(Scheduling); +impl_deref_view!(AcceptCaps); +impl_deref_view!(Caps); +impl_deref_view!(Drain); +impl_deref_view!(Context); +impl_deref_view!(Other); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_writability() { + ::init().unwrap(); + + let mut q = Query::new_position(::Format::Time); + + match q.view() { + QueryView::Position(ref p) => { + let (fmt, pos) = p.get(); + assert_eq!(fmt, ::Format::Time); + assert_eq!(pos, -1); + }, + _ => (), + } + + match q.get_mut().unwrap().view_mut() { + QueryView::Position(ref mut p) => { + let (fmt, pos) = p.get(); + assert_eq!(fmt, ::Format::Time); + assert_eq!(pos, -1); + p.set(::Format::Time, 2); + }, + _ => (), + } + + match q.view() { + QueryView::Position(ref p) => { + let (fmt, pos) = p.get(); + assert_eq!(fmt, ::Format::Time); + assert_eq!(pos, 2); + }, + _ => (), + } + } +}