libspa/buffer/
meta.rs

1// Copyright The pipewire-rs contributors
2// SPDX-License-Identifier: MIT
3
4//! Buffer metadata
5
6use crate::param::video::VideoFormat;
7use crate::utils::{Point, Rectangle, Region};
8
9use std::fmt::Debug;
10
11pub trait Metadata {
12    const META_TYPE: u32;
13}
14
15bitflags::bitflags! {
16    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
17    /// Flags for [`MetaHeader::flags`]
18    pub struct MetaHeaderFlags: u32 {
19        /// Data is not continuous with previous buffer
20        const DISCONT = spa_sys::SPA_META_HEADER_FLAG_DISCONT;
21        /// Data might be corrupted
22        const CORRUPTED = spa_sys::SPA_META_HEADER_FLAG_CORRUPTED;
23        /// Data contains a media specific marker
24        const MARKER = spa_sys::SPA_META_HEADER_FLAG_MARKER;
25        /// Data contains a codec specific header
26        const HEADER = spa_sys::SPA_META_HEADER_FLAG_HEADER;
27        /// Data contains media neutral data
28        const GAP = spa_sys::SPA_META_HEADER_FLAG_GAP;
29        /// Data cannot be decoded independently
30        const DELTA_UNIT = spa_sys::SPA_META_HEADER_FLAG_DELTA_UNIT;
31    }
32}
33
34/// Describes essential buffer header metadata such as flags and timestamps.
35#[derive(Clone)]
36#[repr(transparent)]
37pub struct MetaHeader(spa_sys::spa_meta_header);
38
39impl MetaHeader {
40    pub fn as_raw(&self) -> &spa_sys::spa_meta_header {
41        &self.0
42    }
43
44    pub fn flags(&self) -> MetaHeaderFlags {
45        MetaHeaderFlags::from_bits_retain(self.0.flags)
46    }
47
48    /// Offset in current cycle
49    pub fn offset(&self) -> u32 {
50        self.0.offset
51    }
52
53    /// Presentation timestamp in nanoseconds
54    pub fn pts(&self) -> i64 {
55        self.0.pts
56    }
57
58    /// Decoding timestamp as a difference with pts
59    pub fn dts_offset(&self) -> i64 {
60        self.0.dts_offset
61    }
62
63    /// Sequence number, increments with a media specific frequency
64    pub fn seq(&self) -> u64 {
65        self.0.seq
66    }
67}
68
69impl Debug for MetaHeader {
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        f.debug_struct("MetaHeader")
72            .field("flags", &self.flags())
73            .field("offset", &self.offset())
74            .field("pts", &self.pts())
75            .field("dts_offset", &self.dts_offset())
76            .field("seq", &self.seq())
77            .finish()
78    }
79}
80
81impl Metadata for MetaHeader {
82    const META_TYPE: u32 = spa_sys::SPA_META_Header;
83}
84
85#[derive(Clone)]
86#[repr(transparent)]
87pub struct MetaRegion(spa_sys::spa_meta_region);
88
89impl MetaRegion {
90    pub fn as_raw(&self) -> &spa_sys::spa_meta_region {
91        &self.0
92    }
93
94    pub fn region(&self) -> &Region {
95        &self.0.region
96    }
97
98    pub fn position(&self) -> Point {
99        self.0.region.position
100    }
101
102    pub fn size(&self) -> Rectangle {
103        self.0.region.size
104    }
105
106    pub fn is_valid(&self) -> bool {
107        unsafe { spa_sys::spa_meta_region_is_valid(self.as_raw()) }
108    }
109}
110
111impl Debug for MetaRegion {
112    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113        f.debug_struct("MetaRegion")
114            .field("region", &self.region())
115            .finish()
116    }
117}
118
119/// MetaRegion with cropping data
120#[derive(Clone, Debug)]
121#[repr(transparent)]
122pub struct MetaVideoCrop(MetaRegion);
123
124impl MetaVideoCrop {
125    pub fn meta_region(&self) -> &MetaRegion {
126        &self.0
127    }
128}
129
130impl Metadata for MetaVideoCrop {
131    const META_TYPE: u32 = spa_sys::SPA_META_VideoCrop;
132}
133
134/// Array of [`MetaRegion`] with damage data. Use [`iter`][Self::iter] to access the regions.
135#[repr(transparent)]
136pub struct MetaVideoDamage(spa_sys::spa_meta);
137
138impl MetaVideoDamage {
139    pub fn as_raw(&self) -> &spa_sys::spa_meta {
140        &self.0
141    }
142
143    pub fn iter(&self) -> VideoDamageIter<'_> {
144        VideoDamageIter::new(self)
145    }
146}
147
148pub struct VideoDamageIter<'a> {
149    video_damage: &'a MetaVideoDamage,
150    pos: *const spa_sys::spa_meta_region,
151}
152
153impl<'a> VideoDamageIter<'a> {
154    fn new(video_damage: &'a MetaVideoDamage) -> Self {
155        Self {
156            video_damage,
157            pos: unsafe { spa_sys::spa_meta_first(video_damage.as_raw()) }.cast(),
158        }
159    }
160}
161
162impl<'a> Iterator for VideoDamageIter<'a> {
163    type Item = &'a MetaRegion;
164
165    fn next(&mut self) -> Option<Self::Item> {
166        if !unsafe { spa_sys::spa_meta_check(self.pos.cast(), self.video_damage.as_raw()) } {
167            return None;
168        }
169
170        let region = unsafe { self.pos.cast::<MetaRegion>().as_ref()? };
171        if !region.is_valid() {
172            return None;
173        }
174
175        self.pos = unsafe { self.pos.add(1) };
176
177        Some(region)
178    }
179}
180
181impl Metadata for MetaVideoDamage {
182    const META_TYPE: u32 = spa_sys::SPA_META_VideoDamage;
183}
184
185/// Bitmap information
186///
187/// This metadata contains a bitmap image in the given format and size.
188/// It is typically used for cursor images or other small images that are
189/// better transferred inline.
190#[repr(transparent)]
191pub struct MetaBitmap(spa_sys::spa_meta_bitmap);
192
193impl MetaBitmap {
194    pub fn as_raw(&self) -> &spa_sys::spa_meta_bitmap {
195        &self.0
196    }
197
198    /// Bitmap video format
199    pub fn format(&self) -> VideoFormat {
200        VideoFormat(self.0.format)
201    }
202
203    /// Width and height of bitmap
204    pub fn size(&self) -> Rectangle {
205        self.0.size
206    }
207
208    /// Stride of bitmap data
209    pub fn stride(&self) -> i32 {
210        self.0.stride
211    }
212
213    /// Offset of bitmap data in this structure.
214    /// Use [`bitmap_data`](Self::bitmap_data) to access the data.
215    pub fn offset(&self) -> u32 {
216        self.0.offset
217    }
218
219    pub fn is_valid(&self) -> bool {
220        unsafe { spa_sys::spa_meta_bitmap_is_valid(self.as_raw()) }
221    }
222
223    /// Returns a slice with the bitmap data if this bitmap is valid and [`offset`](Self::offset) points to memory after this structure.
224    pub fn bitmap_data(&self) -> Option<&[u8]> {
225        if !self.is_valid()
226            || (self.0.offset as usize) < std::mem::size_of::<spa_sys::spa_meta_bitmap>()
227        {
228            return None;
229        }
230
231        let height = self.0.size.height as usize;
232        let stride = self.0.stride.unsigned_abs() as usize;
233        let data_size = height * stride;
234
235        unsafe {
236            let base_ptr = self as *const _ as *const u8;
237            let data_ptr = base_ptr.add(self.0.offset as usize);
238            Some(std::slice::from_raw_parts(data_ptr, data_size))
239        }
240    }
241}
242
243impl Debug for MetaBitmap {
244    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245        f.debug_struct("MetaBitmap")
246            .field("format", &self.format())
247            .field("size", &self.size())
248            .field("stride", &self.stride())
249            .field("offset", &self.offset())
250            .finish()
251    }
252}
253
254impl Metadata for MetaBitmap {
255    const META_TYPE: u32 = spa_sys::SPA_META_Bitmap;
256}
257
258/// Cursor information
259///
260/// Metadata to describe the position and appearance of a pointing device.
261#[repr(transparent)]
262pub struct MetaCursor(spa_sys::spa_meta_cursor);
263
264impl MetaCursor {
265    pub fn as_raw(&self) -> &spa_sys::spa_meta_cursor {
266        &self.0
267    }
268
269    /// Cursor id. An id of `0` is an invalid id and means there is no new cursor data.
270    pub fn id(&self) -> u32 {
271        self.0.id
272    }
273
274    /// Extra flags
275    pub fn flags(&self) -> u32 {
276        self.0.flags
277    }
278
279    /// Position on screen
280    pub fn position(&self) -> Point {
281        self.0.position
282    }
283
284    /// Offsets for hotspot in bitmap, this has no meaning when there is no valid bitmap.
285    pub fn hotspot(&self) -> Point {
286        self.0.hotspot
287    }
288
289    /// Offset of bitmap meta in this structure. Use [`bitmap`](Self::bitmap) to access the bitmap
290    /// meta.
291    pub fn bitmap_offset(&self) -> u32 {
292        self.0.bitmap_offset
293    }
294
295    pub fn is_valid(&self) -> bool {
296        unsafe { spa_sys::spa_meta_cursor_is_valid(self.as_raw()) }
297    }
298
299    /// Returns the bitmap meta if the cursor is valid and [`bitmap_offset`](Self::bitmap_offset)
300    /// points to memory after this structure.
301    pub fn bitmap(&self) -> Option<&MetaBitmap> {
302        if !self.is_valid()
303            || (self.0.bitmap_offset as usize) < std::mem::size_of::<spa_sys::spa_meta_cursor>()
304        {
305            return None;
306        }
307
308        unsafe {
309            let base_ptr = self as *const _ as *const u8;
310            let bitmap_ptr = base_ptr.add(self.0.bitmap_offset as usize);
311            let bitmap_ptr = bitmap_ptr as *const MetaBitmap;
312            bitmap_ptr.as_ref()
313        }
314    }
315}
316
317impl Debug for MetaCursor {
318    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
319        f.debug_struct("MetaCursor")
320            .field("id", &self.id())
321            .field("flags", &self.flags())
322            .field("position", &self.position())
323            .field("hotspot", &self.hotspot())
324            .field("bitmap_offset", &self.bitmap_offset())
325            .finish()
326    }
327}
328
329impl Metadata for MetaCursor {
330    const META_TYPE: u32 = spa_sys::SPA_META_Cursor;
331}
332
333/// A timed set of events associated with the buffer
334#[repr(transparent)]
335pub struct MetaControl(spa_sys::spa_meta_control);
336
337impl MetaControl {
338    pub fn as_raw(&self) -> &spa_sys::spa_meta_control {
339        &self.0
340    }
341
342    pub fn sequence(&self) -> &spa_sys::spa_pod_sequence {
343        &self.0.sequence
344    }
345}
346
347impl Metadata for MetaControl {
348    const META_TYPE: u32 = spa_sys::SPA_META_Control;
349}
350
351/// A busy counter for the buffer
352#[cfg(feature = "v0_3_21")]
353#[derive(Clone)]
354#[repr(transparent)]
355pub struct MetaBusy(spa_sys::spa_meta_busy);
356
357#[cfg(feature = "v0_3_21")]
358impl MetaBusy {
359    pub fn as_raw(&self) -> &spa_sys::spa_meta_busy {
360        &self.0
361    }
362
363    pub fn flags(&self) -> u32 {
364        self.0.flags
365    }
366
367    /// Number of users busy with the buffer
368    pub fn count(&self) -> u32 {
369        self.0.count
370    }
371}
372
373#[cfg(feature = "v0_3_21")]
374impl Debug for MetaBusy {
375    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
376        f.debug_struct("MetaBusy")
377            .field("flags", &self.flags())
378            .field("count", &self.count())
379            .finish()
380    }
381}
382
383#[cfg(feature = "v0_3_21")]
384impl Metadata for MetaBusy {
385    const META_TYPE: u32 = spa_sys::SPA_META_Busy;
386}
387
388#[cfg(feature = "v0_3_62")]
389#[derive(Copy, Clone, PartialEq, Eq)]
390#[repr(transparent)]
391pub struct MetaVideoTransformValue(spa_sys::spa_meta_videotransform_value);
392
393#[cfg(feature = "v0_3_62")]
394impl MetaVideoTransformValue {
395    /// No transform
396    pub const NONE: Self = Self(spa_sys::SPA_META_TRANSFORMATION_None);
397    /// 90 degree counter-clockwise
398    pub const ROTATED90: Self = Self(spa_sys::SPA_META_TRANSFORMATION_90);
399    /// 180 degree counter-clockwise
400    pub const ROTATED180: Self = Self(spa_sys::SPA_META_TRANSFORMATION_180);
401    /// 270 degree counter-clockwise
402    pub const ROTATED270: Self = Self(spa_sys::SPA_META_TRANSFORMATION_270);
403    /// 180 degree flipped around the vertical axis. Equivalent
404    /// to a reflection through the vertical line splitting the
405    /// buffer in two equal sized parts
406    pub const FLIPPED: Self = Self(spa_sys::SPA_META_TRANSFORMATION_Flipped);
407    /// Flip then rotate around 90 degree counter-clockwise
408    pub const FLIPPED90: Self = Self(spa_sys::SPA_META_TRANSFORMATION_Flipped90);
409    /// Flip then rotate around 180 degree counter-clockwise
410    pub const FLIPPED180: Self = Self(spa_sys::SPA_META_TRANSFORMATION_Flipped180);
411    /// Flip then rotate around 270 degree counter-clockwise
412    pub const FLIPPED270: Self = Self(spa_sys::SPA_META_TRANSFORMATION_Flipped270);
413
414    pub fn from_raw(raw: spa_sys::spa_meta_videotransform_value) -> Self {
415        Self(raw)
416    }
417
418    pub fn as_raw(&self) -> spa_sys::spa_meta_videotransform_value {
419        self.0
420    }
421}
422
423#[cfg(feature = "v0_3_62")]
424impl Debug for MetaVideoTransformValue {
425    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
426        write!(
427            f,
428            "MetaVideoTransformValue::{}",
429            match *self {
430                Self::NONE => "None",
431                Self::ROTATED90 => "ROTATED90",
432                Self::ROTATED180 => "ROTATED180",
433                Self::ROTATED270 => "ROTATED270",
434                Self::FLIPPED => "FLIPPED",
435                Self::FLIPPED90 => "FLIPPED90",
436                Self::FLIPPED180 => "FLIPPED180",
437                Self::FLIPPED270 => "FLIPPED270",
438                _ => "Unknown",
439            }
440        )
441    }
442}
443
444/// A transformation of the buffer
445#[cfg(feature = "v0_3_62")]
446#[repr(transparent)]
447pub struct MetaVideoTransform(spa_sys::spa_meta_videotransform);
448
449#[cfg(feature = "v0_3_62")]
450impl MetaVideoTransform {
451    pub fn as_raw(&self) -> &spa_sys::spa_meta_videotransform {
452        &self.0
453    }
454
455    pub fn transform(&self) -> MetaVideoTransformValue {
456        MetaVideoTransformValue::from_raw(self.0.transform)
457    }
458}
459
460#[cfg(feature = "v0_3_62")]
461impl Debug for MetaVideoTransform {
462    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
463        f.debug_struct("MetaVideoTransform")
464            .field("transform", &self.transform())
465            .finish()
466    }
467}
468
469#[cfg(feature = "v0_3_62")]
470impl Metadata for MetaVideoTransform {
471    const META_TYPE: u32 = spa_sys::SPA_META_VideoTransform;
472}
473
474#[cfg(feature = "v1_2_0")]
475bitflags::bitflags! {
476    /// Flags for [`MetaSyncTimeline::flags`]
477    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
478    pub struct MetaSyncTimelineFlags: u32 {
479        /// This flag is set by the producer and cleared by the consumer
480        /// when it promises to signal the release point.
481        #[cfg(feature = "v1_6_0")]
482        const UNSCHEDULED_RELEASE = spa_sys::SPA_META_SYNC_TIMELINE_UNSCHEDULED_RELEASE;
483
484    }
485}
486
487/// A timeline point for explicit sync
488///
489/// Metadata to describe the time on the timeline when the buffer can be acquired and when it can be reused.
490///
491/// This metadata will require negotiation of 2 extra fds for the acquire
492/// and release timelines respectively.  One way to achieve this is to place
493/// this metadata as SPA_PARAM_BUFFERS_metaType when negotiating a buffer
494/// layout with 2 extra fds.
495#[cfg(feature = "v1_2_0")]
496#[repr(transparent)]
497pub struct MetaSyncTimeline(spa_sys::spa_meta_sync_timeline);
498
499#[cfg(feature = "v1_2_0")]
500impl MetaSyncTimeline {
501    pub fn as_raw(&self) -> &spa_sys::spa_meta_sync_timeline {
502        &self.0
503    }
504
505    pub fn flags(&self) -> MetaSyncTimelineFlags {
506        MetaSyncTimelineFlags::from_bits_retain(self.0.flags)
507    }
508
509    pub fn padding(&self) -> u32 {
510        self.0.padding
511    }
512
513    /// The timeline acquire point, this is when the data can be accessed.
514    pub fn acquire_point(&self) -> u64 {
515        self.0.acquire_point
516    }
517
518    /// The timeline release point, this timeline point should be signaled when data is no longer accessed.
519    pub fn release_point(&self) -> u64 {
520        self.0.release_point
521    }
522}
523
524#[cfg(feature = "v1_2_0")]
525impl Debug for MetaSyncTimeline {
526    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
527        f.debug_struct("MetaSyncTimeline")
528            .field("flags", &self.flags())
529            .field("padding", &self.padding())
530            .field("acquire_point", &self.acquire_point())
531            .field("release_point", &self.release_point())
532            .finish()
533    }
534}
535
536#[cfg(feature = "v1_2_0")]
537impl Metadata for MetaSyncTimeline {
538    const META_TYPE: u32 = spa_sys::SPA_META_SyncTimeline;
539}