caps.rs 11.9 KB
Newer Older
Sebastian Dröge's avatar
Sebastian Dröge committed
1 2 3 4 5 6 7 8 9
// Copyright (C) 2016-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 std::fmt;
10
use std::str;
Sebastian Dröge's avatar
Sebastian Dröge committed
11 12 13
use miniobject::*;
use structure::*;

14 15
use CapsIntersectMode;

Sebastian Dröge's avatar
Sebastian Dröge committed
16 17
use glib;
use ffi;
18
use glib::translate::{from_glib, from_glib_full, ToGlib, ToGlibPtr};
19
use glib::value::ToSendValue;
Sebastian Dröge's avatar
Sebastian Dröge committed
20 21 22 23 24 25 26 27 28 29

#[repr(C)]
pub struct CapsRef(ffi::GstCaps);

pub type Caps = GstRc<CapsRef>;

unsafe impl MiniObject for CapsRef {
    type GstType = ffi::GstCaps;
}

Sebastian Dröge's avatar
Sebastian Dröge committed
30
impl GstRc<CapsRef> {
31 32 33 34 35
    pub fn builder(name: &str) -> Builder {
        assert_initialized_main_thread!();
        Builder::new(name)
    }

Sebastian Dröge's avatar
Sebastian Dröge committed
36 37
    pub fn new_empty() -> Self {
        assert_initialized_main_thread!();
Sebastian Dröge's avatar
Sebastian Dröge committed
38 39 40
        unsafe { from_glib_full(ffi::gst_caps_new_empty()) }
    }

Sebastian Dröge's avatar
Sebastian Dröge committed
41 42
    pub fn new_any() -> Self {
        assert_initialized_main_thread!();
Sebastian Dröge's avatar
Sebastian Dröge committed
43 44 45
        unsafe { from_glib_full(ffi::gst_caps_new_any()) }
    }

46
    pub fn new_simple(name: &str, values: &[(&str, &ToSendValue)]) -> Self {
Sebastian Dröge's avatar
Sebastian Dröge committed
47
        assert_initialized_main_thread!();
48
        let mut caps = Caps::new_empty();
Sebastian Dröge's avatar
Sebastian Dröge committed
49

Sebastian Dröge's avatar
Sebastian Dröge committed
50 51
        let structure = Structure::new(name, values);
        caps.get_mut().unwrap().append_structure(structure);
Sebastian Dröge's avatar
Sebastian Dröge committed
52 53 54 55

        caps
    }

Sebastian Dröge's avatar
Sebastian Dröge committed
56 57
    pub fn from_string(value: &str) -> Option<Self> {
        assert_initialized_main_thread!();
58
        unsafe { from_glib_full(ffi::gst_caps_from_string(value.to_glib_none().0)) }
Sebastian Dröge's avatar
Sebastian Dröge committed
59
    }
60 61

    pub fn fixate(caps: Self) -> Self {
62
        skip_assert_initialized!();
63 64 65 66
        unsafe { from_glib_full(ffi::gst_caps_fixate(caps.into_ptr())) }
    }

    pub fn merge(caps: Self, other: Self) -> Self {
67
        skip_assert_initialized!();
68 69 70 71
        unsafe { from_glib_full(ffi::gst_caps_merge(caps.into_ptr(), other.into_ptr())) }
    }

    pub fn merge_structure(caps: Self, other: Structure) -> Self {
72
        skip_assert_initialized!();
73 74 75 76 77 78 79 80 81
        unsafe {
            from_glib_full(ffi::gst_caps_merge_structure(
                caps.into_ptr(),
                other.into_ptr(),
            ))
        }
    }

    pub fn normalize(caps: Self) -> Self {
82
        skip_assert_initialized!();
83 84 85 86
        unsafe { from_glib_full(ffi::gst_caps_normalize(caps.into_ptr())) }
    }

    pub fn simplify(caps: Self) -> Self {
87
        skip_assert_initialized!();
88 89 90 91
        unsafe { from_glib_full(ffi::gst_caps_simplify(caps.into_ptr())) }
    }

    pub fn subtract(caps: Self, other: Self) -> Self {
92
        skip_assert_initialized!();
93 94 95 96
        unsafe { from_glib_full(ffi::gst_caps_subtract(caps.into_ptr(), other.into_ptr())) }
    }

    pub fn truncate(caps: Self) -> Self {
97
        skip_assert_initialized!();
98 99
        unsafe { from_glib_full(ffi::gst_caps_truncate(caps.into_ptr())) }
    }
Sebastian Dröge's avatar
Sebastian Dröge committed
100
}
Sebastian Dröge's avatar
Sebastian Dröge committed
101

102 103 104 105
impl str::FromStr for Caps {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, ()> {
106
        skip_assert_initialized!();
107 108 109 110
        Caps::from_string(s).ok_or(())
    }
}

Sebastian Dröge's avatar
Sebastian Dröge committed
111
impl CapsRef {
112
    pub fn set_simple(&mut self, values: &[(&str, &ToSendValue)]) {
Sebastian Dröge's avatar
Sebastian Dröge committed
113
        for &(name, value) in values {
114 115
            let value = value.to_value();

Sebastian Dröge's avatar
Sebastian Dröge committed
116
            unsafe {
117 118 119 120 121
                ffi::gst_caps_set_value(
                    self.as_mut_ptr(),
                    name.to_glib_none().0,
                    value.to_glib_none().0,
                );
Sebastian Dröge's avatar
Sebastian Dröge committed
122 123 124 125 126
            }
        }
    }

    pub fn to_string(&self) -> String {
127
        unsafe { from_glib_full(ffi::gst_caps_to_string(self.as_ptr())) }
Sebastian Dröge's avatar
Sebastian Dröge committed
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
    }

    pub fn get_structure(&self, idx: u32) -> Option<&StructureRef> {
        unsafe {
            let structure = ffi::gst_caps_get_structure(self.as_ptr(), idx);
            if structure.is_null() {
                return None;
            }

            Some(StructureRef::from_glib_borrow(
                structure as *const ffi::GstStructure,
            ))
        }
    }

Sebastian Dröge's avatar
Sebastian Dröge committed
143
    pub fn get_mut_structure(&mut self, idx: u32) -> Option<&mut StructureRef> {
Sebastian Dröge's avatar
Sebastian Dröge committed
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
        unsafe {
            let structure = ffi::gst_caps_get_structure(self.as_ptr(), idx);
            if structure.is_null() {
                return None;
            }

            Some(StructureRef::from_glib_borrow_mut(
                structure as *mut ffi::GstStructure,
            ))
        }
    }

    pub fn get_size(&self) -> u32 {
        unsafe { ffi::gst_caps_get_size(self.as_ptr()) }
    }

    pub fn iter(&self) -> Iter {
        Iter::new(self)
    }

Sebastian Dröge's avatar
Sebastian Dröge committed
164 165 166
    pub fn iter_mut(&mut self) -> IterMut {
        IterMut::new(self)
    }
Sebastian Dröge's avatar
Sebastian Dröge committed
167

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
    pub fn append_structure(&mut self, structure: Structure) {
        unsafe { ffi::gst_caps_append_structure(self.as_mut_ptr(), structure.into_ptr()) }
    }

    pub fn remove_structure(&mut self, idx: u32) {
        unsafe { ffi::gst_caps_remove_structure(self.as_mut_ptr(), idx) }
    }

    pub fn append(&mut self, other: Caps) {
        unsafe { ffi::gst_caps_append(self.as_mut_ptr(), other.into_ptr()) }
    }

    pub fn can_intersect(&self, other: &Caps) -> bool {
        unsafe { from_glib(ffi::gst_caps_can_intersect(self.as_ptr(), other.as_ptr())) }
    }

    pub fn intersect(&self, other: &Caps) -> Caps {
        unsafe {
            from_glib_full(ffi::gst_caps_intersect(
                self.as_mut_ptr(),
                other.as_mut_ptr(),
            ))
        }
    }

    pub fn intersect_with_mode(&self, other: &Caps, mode: CapsIntersectMode) -> Caps {
        unsafe {
            from_glib_full(ffi::gst_caps_intersect_full(
                self.as_mut_ptr(),
                other.as_mut_ptr(),
                mode.to_glib(),
            ))
        }
    }

    pub fn is_always_compatible(&self, other: &Caps) -> bool {
        unsafe {
            from_glib(ffi::gst_caps_is_always_compatible(
                self.as_ptr(),
                other.as_ptr(),
            ))
        }
    }

    pub fn is_any(&self) -> bool {
        unsafe { from_glib(ffi::gst_caps_is_any(self.as_ptr())) }
    }

    pub fn is_empty(&self) -> bool {
        unsafe { from_glib(ffi::gst_caps_is_empty(self.as_ptr())) }
    }

    pub fn is_fixed(&self) -> bool {
        unsafe { from_glib(ffi::gst_caps_is_fixed(self.as_ptr())) }
    }

    pub fn is_equal_fixed(&self, other: &Caps) -> bool {
        unsafe { from_glib(ffi::gst_caps_is_equal_fixed(self.as_ptr(), other.as_ptr())) }
    }

    pub fn is_strictly_equal(&self, other: &Caps) -> bool {
        unsafe {
            from_glib(ffi::gst_caps_is_strictly_equal(
                self.as_ptr(),
                other.as_ptr(),
            ))
        }
    }

    pub fn is_subset(&self, superset: &Caps) -> bool {
        unsafe { from_glib(ffi::gst_caps_is_subset(self.as_ptr(), superset.as_ptr())) }
    }

    pub fn is_subset_structure(&self, structure: &StructureRef) -> bool {
        unsafe {
            from_glib(ffi::gst_caps_is_subset_structure(
                self.as_ptr(),
                structure.as_ptr(),
            ))
        }
    }
Sebastian Dröge's avatar
Sebastian Dröge committed
249 250
}

251
impl glib::types::StaticType for CapsRef {
Sebastian Dröge's avatar
Sebastian Dröge committed
252
    fn static_type() -> glib::types::Type {
253
        unsafe { from_glib(ffi::gst_caps_get_type()) }
Sebastian Dröge's avatar
Sebastian Dröge committed
254 255 256 257
    }
}

macro_rules! define_iter(
Sebastian Dröge's avatar
Sebastian Dröge committed
258
    ($name:ident, $typ:ty, $styp:ty) => {
259 260 261 262 263
    pub struct $name<'a> {
        caps: $typ,
        idx: u32,
        n_structures: u32,
    }
Sebastian Dröge's avatar
Sebastian Dröge committed
264

265 266 267 268
    impl<'a> $name<'a> {
        fn new(caps: $typ) -> $name<'a> {
            skip_assert_initialized!();
            let n_structures = caps.get_size();
Sebastian Dröge's avatar
Sebastian Dröge committed
269

270 271 272 273 274
            $name {
                caps: caps,
                idx: 0,
                n_structures: n_structures,
            }
Sebastian Dröge's avatar
Sebastian Dröge committed
275 276 277
        }
    }

278 279
    impl<'a> Iterator for $name<'a> {
        type Item = $styp;
Sebastian Dröge's avatar
Sebastian Dröge committed
280

281 282
        fn next(&mut self) -> Option<Self::Item> {
            if self.idx >= self.n_structures {
Sebastian Dröge's avatar
Sebastian Dröge committed
283 284 285
                return None;
            }

286 287 288 289 290 291 292 293 294 295 296
            unsafe {
                let structure = ffi::gst_caps_get_structure(self.caps.as_ptr(), self.idx);
                if structure.is_null() {
                    return None;
                }

                self.idx += 1;
                Some(StructureRef::from_glib_borrow_mut(
                    structure as *mut ffi::GstStructure,
                ))
            }
Sebastian Dröge's avatar
Sebastian Dröge committed
297 298
        }

299 300 301 302
        fn size_hint(&self) -> (usize, Option<usize>) {
            if self.idx == self.n_structures {
                return (0, Some(0));
            }
Sebastian Dröge's avatar
Sebastian Dröge committed
303

304
            let remaining = (self.n_structures - self.idx) as usize;
Sebastian Dröge's avatar
Sebastian Dröge committed
305

306
            (remaining, Some(remaining))
Sebastian Dröge's avatar
Sebastian Dröge committed
307
        }
308
    }
Sebastian Dröge's avatar
Sebastian Dröge committed
309

310 311 312
    impl<'a> DoubleEndedIterator for $name<'a> {
        fn next_back(&mut self) -> Option<Self::Item> {
            if self.idx == self.n_structures {
Sebastian Dröge's avatar
Sebastian Dröge committed
313 314 315
                return None;
            }

316 317 318 319 320 321 322 323 324 325 326 327
            self.n_structures -= 1;

            unsafe {
                let structure = ffi::gst_caps_get_structure(self.caps.as_ptr(), self.n_structures);
                if structure.is_null() {
                    return None;
                }

                Some(StructureRef::from_glib_borrow_mut(
                    structure as *mut ffi::GstStructure,
                ))
            }
Sebastian Dröge's avatar
Sebastian Dröge committed
328 329 330
        }
    }

331 332
    impl<'a> ExactSizeIterator for $name<'a> {}
    }
Sebastian Dröge's avatar
Sebastian Dröge committed
333 334
);

Sebastian Dröge's avatar
Sebastian Dröge committed
335 336
define_iter!(Iter, &'a CapsRef, &'a StructureRef);
define_iter!(IterMut, &'a mut CapsRef, &'a mut StructureRef);
Sebastian Dröge's avatar
Sebastian Dröge committed
337 338

impl fmt::Debug for CapsRef {
339
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
340
        f.debug_tuple("Caps").field(&self.to_string()).finish()
341 342 343 344
    }
}

impl fmt::Display for CapsRef {
Sebastian Dröge's avatar
Sebastian Dröge committed
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.to_string())
    }
}

impl PartialEq for CapsRef {
    fn eq(&self, other: &CapsRef) -> bool {
        unsafe { from_glib(ffi::gst_caps_is_equal(self.as_ptr(), other.as_ptr())) }
    }
}

impl Eq for CapsRef {}

impl ToOwned for CapsRef {
    type Owned = GstRc<CapsRef>;

    fn to_owned(&self) -> GstRc<CapsRef> {
362
        unsafe { from_glib_full(ffi::gst_mini_object_copy(self.as_ptr() as *const _) as *mut _) }
Sebastian Dröge's avatar
Sebastian Dröge committed
363 364 365 366 367 368
    }
}

unsafe impl Sync for CapsRef {}
unsafe impl Send for CapsRef {}

369 370 371 372 373 374 375 376 377 378 379
pub struct Builder {
    s: ::Structure,
}

impl Builder {
    fn new(name: &str) -> Self {
        Builder {
            s: ::Structure::new_empty(name),
        }
    }

380
    pub fn field<V: ToSendValue>(mut self, name: &str, value: &V) -> Self {
381 382 383 384 385 386 387 388 389 390 391
        self.s.set(name, value);
        self
    }

    pub fn build(self) -> Caps {
        let mut caps = Caps::new_empty();
        caps.get_mut().unwrap().append_structure(self.s);
        caps
    }
}

Sebastian Dröge's avatar
Sebastian Dröge committed
392 393 394
#[cfg(test)]
mod tests {
    use super::*;
Sebastian Dröge's avatar
Sebastian Dröge committed
395
    use Fraction;
396
    use Array;
Sebastian Dröge's avatar
Sebastian Dröge committed
397 398 399

    #[test]
    fn test_simple() {
Sebastian Dröge's avatar
Sebastian Dröge committed
400
        ::init().unwrap();
Sebastian Dröge's avatar
Sebastian Dröge committed
401

402
        let caps = Caps::new_simple(
Sebastian Dröge's avatar
Sebastian Dröge committed
403 404
            "foo/bar",
            &[
405 406 407 408
                ("int", &12),
                ("bool", &true),
                ("string", &"bla"),
                ("fraction", &Fraction::new(1, 2)),
409
                ("array", &Array::new(&[&1, &2])),
Sebastian Dröge's avatar
Sebastian Dröge committed
410 411 412 413
            ],
        );
        assert_eq!(
            caps.to_string(),
414 415
            "foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, fraction=(fraction)1/2, array=(int)< 1, 2 >"
        );
Sebastian Dröge's avatar
Sebastian Dröge committed
416 417 418 419

        let s = caps.get_structure(0).unwrap();
        assert_eq!(
            s,
Sebastian Dröge's avatar
Sebastian Dröge committed
420
            Structure::new(
Sebastian Dröge's avatar
Sebastian Dröge committed
421 422
                "foo/bar",
                &[
423 424 425
                    ("int", &12),
                    ("bool", &true),
                    ("string", &"bla"),
426
                    ("fraction", &Fraction::new(1, 2)),
427
                    ("array", &Array::new(&[&1, &2]))
Sebastian Dröge's avatar
Sebastian Dröge committed
428 429 430 431
                ],
            ).as_ref()
        );
    }
432 433 434 435 436 437

    #[test]
    fn test_builder() {
        ::init().unwrap();

        let caps = Caps::builder("foo/bar")
438 439 440 441 442
            .field("int", &12)
            .field("bool", &true)
            .field("string", &"bla")
            .field("fraction", &Fraction::new(1, 2))
            .field("array", &Array::new(&[&1, &2]))
443 444 445 446 447 448
            .build();
        assert_eq!(
            caps.to_string(),
            "foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, fraction=(fraction)1/2, array=(int)< 1, 2 >"
        );
    }
Sebastian Dröge's avatar
Sebastian Dröge committed
449
}