Skip to main content

gstreamer_tag/
tags.rs

1use gst::glib::translate::*;
2use std::ptr;
3
4pub struct ExtendedComment {
5    pub key: Option<glib::GString>,
6    pub lang: Option<glib::GString>,
7    pub value: glib::GString,
8}
9
10#[doc(alias = "gst_tag_parse_extended_comment")]
11pub fn tag_parse_extended_comment(
12    ext_comment: &str,
13    fail_if_no_key: bool,
14) -> Result<ExtendedComment, gst::glib::BoolError> {
15    skip_assert_initialized!();
16    unsafe {
17        let mut c_key = ptr::null_mut();
18        let mut c_lang = ptr::null_mut();
19        let mut c_value = ptr::null_mut();
20        let res: bool = from_glib(crate::ffi::gst_tag_parse_extended_comment(
21            ext_comment.to_glib_none().0,
22            &mut c_key,
23            &mut c_lang,
24            &mut c_value,
25            fail_if_no_key.into_glib(),
26        ));
27        if !res {
28            Err(glib::bool_error!("Failed to parse extended comment"))
29        } else {
30            let key = from_glib_full(c_key);
31            let lang = from_glib_full(c_lang);
32            let value = from_glib_full(c_value);
33
34            Ok(ExtendedComment { key, lang, value })
35        }
36    }
37}
38
39#[inline]
40fn ensure_tags_registered() {
41    static ONCE: std::sync::Once = std::sync::Once::new();
42    skip_assert_initialized!();
43    ONCE.call_once(
44        #[inline]
45        || {
46            unsafe { crate::ffi::gst_tag_register_musicbrainz_tags() };
47        },
48    );
49}
50
51macro_rules! impl_tag(
52    ($name:ident, $t:ty, $gst_tag:ident) => {
53        pub enum $name {}
54        impl<'a> gst::Tag<'a> for $name {
55            type TagType = $t;
56            const TAG_NAME: &'static glib::GStr = unsafe { glib::GStr::from_utf8_with_nul_unchecked($crate::ffi::$gst_tag) };
57            #[inline]
58            fn ensure() {
59                crate::tags::ensure_tags_registered();
60            }
61        }
62    };
63);
64
65pub mod acoustid {
66    impl_tag!(Fingerprint, &'a str, GST_TAG_ACOUSTID_FINGERPRINT);
67    impl_tag!(Id, &'a str, GST_TAG_ACOUSTID_ID);
68}
69
70pub mod capturing {
71    impl_tag!(Contrast, &'a str, GST_TAG_CAPTURING_CONTRAST);
72    impl_tag!(DigitalZoomRatio, f64, GST_TAG_CAPTURING_DIGITAL_ZOOM_RATIO);
73    impl_tag!(
74        ExposureCompensation,
75        f64,
76        GST_TAG_CAPTURING_EXPOSURE_COMPENSATION
77    );
78    impl_tag!(ExposureMode, &'a str, GST_TAG_CAPTURING_EXPOSURE_MODE);
79    impl_tag!(ExposureProgram, &'a str, GST_TAG_CAPTURING_EXPOSURE_PROGRAM);
80    impl_tag!(FlashFired, bool, GST_TAG_CAPTURING_FLASH_FIRED);
81    impl_tag!(FlashMode, &'a str, GST_TAG_CAPTURING_FLASH_MODE);
82    impl_tag!(FocalLength, f64, GST_TAG_CAPTURING_FOCAL_LENGTH);
83    impl_tag!(FocalLength35MM, f64, GST_TAG_CAPTURING_FOCAL_LENGTH_35_MM);
84    impl_tag!(FocalRatio, f64, GST_TAG_CAPTURING_FOCAL_RATIO);
85    impl_tag!(GainAdjustment, &'a str, GST_TAG_CAPTURING_GAIN_ADJUSTMENT);
86    impl_tag!(IsoSpeed, i32, GST_TAG_CAPTURING_ISO_SPEED);
87    impl_tag!(LightSource, &'a str, GST_TAG_CAPTURING_LIGHT_SOURCE);
88    impl_tag!(MeteringMode, &'a str, GST_TAG_CAPTURING_METERING_MODE);
89    impl_tag!(Saturation, &'a str, GST_TAG_CAPTURING_SATURATION);
90    impl_tag!(
91        SceneCaptureType,
92        &'a str,
93        GST_TAG_CAPTURING_SCENE_CAPTURE_TYPE
94    );
95    impl_tag!(Sharpness, &'a str, GST_TAG_CAPTURING_SHARPNESS);
96    impl_tag!(ShutterSpeed, gst::Fraction, GST_TAG_CAPTURING_SHUTTER_SPEED);
97    impl_tag!(Source, &'a str, GST_TAG_CAPTURING_SOURCE);
98    impl_tag!(WhiteBalance, &'a str, GST_TAG_CAPTURING_WHITE_BALANCE);
99}
100
101pub mod cdda {
102    impl_tag!(CddbDiscid, &'a str, GST_TAG_CDDA_CDDB_DISCID);
103    impl_tag!(CddbDiscidFull, &'a str, GST_TAG_CDDA_CDDB_DISCID_FULL);
104    impl_tag!(MusicbrainzDiscid, &'a str, GST_TAG_CDDA_MUSICBRAINZ_DISCID);
105    impl_tag!(
106        MusicbrainzDiscidFull,
107        &'a str,
108        GST_TAG_CDDA_MUSICBRAINZ_DISCID_FULL
109    );
110}
111
112pub mod image {
113    impl_tag!(HorizontalPPI, f64, GST_TAG_IMAGE_HORIZONTAL_PPI);
114    impl_tag!(VerticalPPI, f64, GST_TAG_IMAGE_VERTICAL_PPI);
115}
116
117impl_tag!(MusicalKey, &'a str, GST_TAG_MUSICAL_KEY);
118
119pub mod musicbrainz {
120    impl_tag!(AlbumArtistId, &'a str, GST_TAG_MUSICBRAINZ_ALBUMARTISTID);
121    impl_tag!(AlbumId, &'a str, GST_TAG_MUSICBRAINZ_ALBUMID);
122    impl_tag!(ArtistId, &'a str, GST_TAG_MUSICBRAINZ_ARTISTID);
123    impl_tag!(ReleaseGroupId, &'a str, GST_TAG_MUSICBRAINZ_RELEASEGROUPID);
124    impl_tag!(ReleaseTrackId, &'a str, GST_TAG_MUSICBRAINZ_RELEASETRACKID);
125    impl_tag!(TrackId, &'a str, GST_TAG_MUSICBRAINZ_TRACKID);
126    impl_tag!(TrmId, &'a str, GST_TAG_MUSICBRAINZ_TRMID);
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132
133    #[test]
134    fn test_tags_are_registered_automatically() {
135        const B_MINOR: &str = "Bm";
136        gst::init().unwrap();
137        let mut tags = gst::TagList::new();
138
139        tags.get_mut()
140            .unwrap()
141            .add::<MusicalKey>(&B_MINOR, gst::TagMergeMode::Replace);
142
143        assert_eq!(B_MINOR, tags.get::<MusicalKey>().unwrap().get());
144    }
145}