1use std::borrow::Cow;
53use std::collections::VecDeque;
54use std::convert::From;
55use std::fmt;
56use std::num::NonZeroU8;
57use std::sync::Arc;
58
59use crate::common::{FourCc, Limit};
60use crate::errors::Result;
61use crate::io::MediaSourceStream;
62use crate::units::Time;
63
64#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
66pub struct MetadataId(u32);
67
68impl MetadataId {
69 pub const fn new(cc: FourCc) -> MetadataId {
71 Self(0x8000_0000 | u32::from_be_bytes(cc.get()))
73 }
74}
75
76impl From<FourCc> for MetadataId {
77 fn from(value: FourCc) -> Self {
78 MetadataId::new(value)
79 }
80}
81
82impl fmt::Display for MetadataId {
83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84 write!(f, "{:#x}", self.0)
85 }
86}
87
88pub const METADATA_ID_NULL: MetadataId = MetadataId(0x0);
90
91#[derive(Copy, Clone, Debug)]
93pub struct MetadataInfo {
94 pub metadata: MetadataId,
96 pub short_name: &'static str,
98 pub long_name: &'static str,
100}
101
102#[non_exhaustive]
104#[derive(Copy, Clone, Debug, Default)]
105pub struct MetadataOptions {
106 pub limit_tag_bytes: Limit,
112
113 pub limit_visual_bytes: Limit,
117}
118
119impl MetadataOptions {
120 pub fn limit_tag_bytes(mut self, limit: Limit) -> Self {
126 self.limit_tag_bytes = limit;
127 self
128 }
129
130 pub fn limit_visual_bytes(mut self, limit: Limit) -> Self {
134 self.limit_visual_bytes = limit;
135 self
136 }
137}
138
139#[non_exhaustive]
146#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
147pub enum StandardVisualKey {
148 FileIcon,
149 OtherIcon,
150 FrontCover,
151 BackCover,
152 Leaflet,
153 Media,
154 LeadArtistPerformerSoloist,
155 ArtistPerformer,
156 Conductor,
157 BandOrchestra,
158 Composer,
159 Lyricist,
160 RecordingLocation,
161 RecordingSession,
162 Performance,
163 ScreenCapture,
164 Illustration,
165 BandArtistLogo,
166 PublisherStudioLogo,
167 Other,
168}
169
170#[derive(Clone, Debug, PartialEq, Eq, Hash)]
172pub enum ContentAdvisory {
173 None,
175 Explicit,
177 Censored,
179}
180
181#[non_exhaustive]
183#[derive(Clone, Debug, PartialEq, Eq, Hash)]
184pub enum StandardTag {
185 AccurateRipCount(Arc<String>),
186 AccurateRipCountAllOffsets(Arc<String>),
187 AccurateRipCountWithOffset(Arc<String>),
188 AccurateRipCrc(Arc<String>),
189 AccurateRipDiscId(Arc<String>),
190 AccurateRipId(Arc<String>),
191 AccurateRipOffset(Arc<String>),
192 AccurateRipResult(Arc<String>),
193 AccurateRipTotal(Arc<String>),
194 AcoustIdFingerprint(Arc<String>),
195 AcoustIdId(Arc<String>),
196 Actor(Arc<String>),
197 Album(Arc<String>),
198 AlbumArtist(Arc<String>),
199 Arranger(Arc<String>),
200 ArtDirector(Arc<String>),
201 Artist(Arc<String>),
202 AssistantDirector(Arc<String>),
203 Author(Arc<String>),
204 Bpm(u64),
205 CdToc(Arc<String>),
206 CdTrackIndex(u8),
207 ChapterTitle(Arc<String>),
208 Choregrapher(Arc<String>),
209 Cinematographer(Arc<String>),
210 CollectionTitle(Arc<String>),
211 Comment(Arc<String>),
212 CompilationFlag(bool),
213 Composer(Arc<String>),
214 Conductor(Arc<String>),
215 ContentAdvisory(ContentAdvisory),
216 ContentRating(Arc<String>),
217 ContentType(Arc<String>),
218 Coproducer(Arc<String>),
219 Copyright(Arc<String>),
220 CostumeDesigner(Arc<String>),
221 CueToolsDbDiscConfidence(Arc<String>),
222 CueToolsDbTrackConfidence(Arc<String>),
223 Description(Arc<String>),
224 DigitizedDate(Arc<String>),
225 Director(Arc<String>),
226 DiscNumber(u64),
227 DiscSubtitle(Arc<String>),
228 DiscTotal(u64),
229 Distributor(Arc<String>),
230 EditedBy(Arc<String>),
231 EditionTitle(Arc<String>),
232 EncodedBy(Arc<String>),
233 Encoder(Arc<String>),
234 EncoderSettings(Arc<String>),
235 EncodingDate(Arc<String>),
236 Engineer(Arc<String>),
237 Ensemble(Arc<String>),
238 ExecutiveProducer(Arc<String>),
239 Genre(Arc<String>),
240 Grouping(Arc<String>),
241 IdentAsin(Arc<String>),
242 IdentBarcode(Arc<String>),
243 IdentCatalogNumber(Arc<String>),
244 IdentEanUpn(Arc<String>),
245 IdentIsbn(Arc<String>),
246 IdentIsrc(Arc<String>),
247 IdentLccn(Arc<String>),
248 IdentPn(Arc<String>),
249 IdentPodcast(Arc<String>),
250 IdentUpc(Arc<String>),
251 ImdbTitleId(Arc<String>),
252 InitialKey(Arc<String>),
253 InternetRadioName(Arc<String>),
254 InternetRadioOwner(Arc<String>),
255 Keywords(Arc<String>),
256 Label(Arc<String>),
257 LabelCode(Arc<String>),
258 Language(Arc<String>),
259 License(Arc<String>),
260 Lyricist(Arc<String>),
261 Lyrics(Arc<String>),
262 Measure(Arc<String>),
263 MediaFormat(Arc<String>),
264 MixDj(Arc<String>),
265 MixEngineer(Arc<String>),
266 Mood(Arc<String>),
267 MovementName(Arc<String>),
268 MovementNumber(u64),
269 MovementTotal(u64),
270 MovieTitle(Arc<String>),
271 Mp3GainAlbumMinMax(Arc<String>),
272 Mp3GainMinMax(Arc<String>),
273 Mp3GainUndo(Arc<String>),
274 MusicBrainzAlbumArtistId(Arc<String>),
275 MusicBrainzAlbumId(Arc<String>),
276 MusicBrainzArtistId(Arc<String>),
277 MusicBrainzDiscId(Arc<String>),
278 MusicBrainzGenreId(Arc<String>),
279 MusicBrainzLabelId(Arc<String>),
280 MusicBrainzOriginalAlbumId(Arc<String>),
281 MusicBrainzOriginalArtistId(Arc<String>),
282 MusicBrainzRecordingId(Arc<String>),
283 MusicBrainzReleaseGroupId(Arc<String>),
284 MusicBrainzReleaseStatus(Arc<String>),
285 MusicBrainzReleaseTrackId(Arc<String>),
286 MusicBrainzReleaseType(Arc<String>),
287 MusicBrainzTrackId(Arc<String>),
288 MusicBrainzTrmId(Arc<String>),
289 MusicBrainzWorkId(Arc<String>),
290 Narrator(Arc<String>),
291 Opus(Arc<String>),
292 OpusNumber(u64),
293 OriginalAlbum(Arc<String>),
294 OriginalArtist(Arc<String>),
295 OriginalFile(Arc<String>),
296 OriginalLyricist(Arc<String>),
297 OriginalRecordingDate(Arc<String>),
298 OriginalRecordingTime(Arc<String>),
299 OriginalRecordingYear(u16),
300 OriginalReleaseDate(Arc<String>),
301 OriginalReleaseTime(Arc<String>),
302 OriginalReleaseYear(u16),
303 OriginalWriter(Arc<String>),
304 Owner(Arc<String>),
305 Part(Arc<String>),
306 PartNumber(u64),
307 PartTitle(Arc<String>),
308 PartTotal(u64),
309 Performer(Arc<String>),
310 Period(Arc<String>),
311 PlayCounter(u64),
312 PodcastCategory(Arc<String>),
313 PodcastDescription(Arc<String>),
314 PodcastFlag(bool),
315 PodcastKeywords(Arc<String>),
316 Producer(Arc<String>),
317 ProductionCopyright(Arc<String>),
318 ProductionDesigner(Arc<String>),
319 ProductionStudio(Arc<String>),
320 PurchaseDate(Arc<String>),
321 Rating(u32), RecordingDate(Arc<String>),
323 RecordingLocation(Arc<String>),
324 RecordingTime(Arc<String>),
325 RecordingYear(u16),
326 ReleaseCountry(Arc<String>),
327 ReleaseDate(Arc<String>),
328 ReleaseTime(Arc<String>),
329 ReleaseYear(u16),
330 Remixer(Arc<String>),
331 ReplayGainAlbumGain(Arc<String>),
332 ReplayGainAlbumPeak(Arc<String>),
333 ReplayGainAlbumRange(Arc<String>),
334 ReplayGainReferenceLoudness(Arc<String>),
335 ReplayGainTrackGain(Arc<String>),
336 ReplayGainTrackPeak(Arc<String>),
337 ReplayGainTrackRange(Arc<String>),
338 ScreenplayAuthor(Arc<String>),
339 Script(Arc<String>),
340 Soloist(Arc<String>),
341 SortAlbum(Arc<String>),
342 SortAlbumArtist(Arc<String>),
343 SortArtist(Arc<String>),
344 SortCollectionTitle(Arc<String>),
345 SortComposer(Arc<String>),
346 SortEditionTitle(Arc<String>),
347 SortMovieTitle(Arc<String>),
348 SortOpusTitle(Arc<String>),
349 SortPartTitle(Arc<String>),
350 SortTrackTitle(Arc<String>),
351 SortTvEpisodeTitle(Arc<String>),
352 SortTvSeasonTitle(Arc<String>),
353 SortTvSeriesTitle(Arc<String>),
354 SortVolumeTitle(Arc<String>),
355 Subject(Arc<String>),
356 Summary(Arc<String>),
357 Synopsis(Arc<String>),
358 TaggingDate(Arc<String>),
359 TermsOfUse(Arc<String>),
360 Thanks(Arc<String>),
361 TmdbMovieId(Arc<String>),
362 TmdbSeriesId(Arc<String>),
363 TrackNumber(u64),
364 TrackSubtitle(Arc<String>),
365 TrackTitle(Arc<String>),
366 TrackTotal(u64),
367 Tuning(Arc<String>),
368 TvdbEpisodeId(Arc<String>),
369 TvdbMovieId(Arc<String>),
370 TvdbSeriesId(Arc<String>),
371 TvEpisodeNumber(u64),
372 TvEpisodeTitle(Arc<String>),
373 TvEpisodeTotal(u64),
374 TvNetwork(Arc<String>),
375 TvSeasonNumber(u64),
376 TvSeasonTitle(Arc<String>),
377 TvSeasonTotal(u64),
378 TvSeriesTitle(Arc<String>),
379 Url(Arc<String>),
380 UrlArtist(Arc<String>),
381 UrlCopyright(Arc<String>),
382 UrlInternetRadio(Arc<String>),
383 UrlLabel(Arc<String>),
384 UrlOfficial(Arc<String>),
385 UrlPayment(Arc<String>),
386 UrlPodcast(Arc<String>),
387 UrlPurchase(Arc<String>),
388 UrlSource(Arc<String>),
389 Version(Arc<String>),
390 VolumeNumber(u64),
391 VolumeTitle(Arc<String>),
392 VolumeTotal(u64),
393 Work(Arc<String>),
394 Writer(Arc<String>),
395 WrittenDate(Arc<String>),
396}
397
398#[non_exhaustive]
404#[derive(Clone, Debug, PartialEq)]
405pub enum RawValue {
406 Binary(Arc<Box<[u8]>>),
408 Boolean(bool),
410 Flag,
413 Float(f64),
415 SignedInt(i64),
417 String(Arc<String>),
419 StringList(Arc<Vec<String>>),
421 UnsignedInt(u64),
423}
424
425macro_rules! impl_from_for_value {
426 ($value:ident, $from:ty, $conv:expr) => {
427 impl From<$from> for RawValue {
428 fn from($value: $from) -> Self {
429 $conv
430 }
431 }
432 };
433}
434
435impl_from_for_value!(v, &[u8], RawValue::Binary(Arc::new(Box::from(v))));
436impl_from_for_value!(v, Box<[u8]>, RawValue::Binary(Arc::new(v)));
437impl_from_for_value!(v, Arc<Box<[u8]>>, RawValue::Binary(v));
438impl_from_for_value!(v, bool, RawValue::Boolean(v));
439impl_from_for_value!(v, f32, RawValue::Float(f64::from(v)));
440impl_from_for_value!(v, f64, RawValue::Float(v));
441impl_from_for_value!(v, i8, RawValue::SignedInt(i64::from(v)));
442impl_from_for_value!(v, i16, RawValue::SignedInt(i64::from(v)));
443impl_from_for_value!(v, i32, RawValue::SignedInt(i64::from(v)));
444impl_from_for_value!(v, i64, RawValue::SignedInt(v));
445impl_from_for_value!(v, u8, RawValue::UnsignedInt(u64::from(v)));
446impl_from_for_value!(v, u16, RawValue::UnsignedInt(u64::from(v)));
447impl_from_for_value!(v, u32, RawValue::UnsignedInt(u64::from(v)));
448impl_from_for_value!(v, u64, RawValue::UnsignedInt(v));
449impl_from_for_value!(v, &str, RawValue::String(Arc::new(v.to_string())));
450impl_from_for_value!(v, String, RawValue::String(Arc::new(v)));
451impl_from_for_value!(v, Arc<String>, RawValue::String(v));
452impl_from_for_value!(v, Cow<'_, str>, RawValue::String(Arc::new(v.into_owned())));
453impl_from_for_value!(v, Vec<String>, RawValue::StringList(Arc::new(v)));
454
455fn buffer_to_hex_string(buf: &[u8]) -> String {
456 let mut output = String::with_capacity(5 * buf.len());
457
458 for ch in buf {
459 let u = (ch & 0xf0) >> 4;
460 let l = ch & 0x0f;
461 output.push_str("\\0x");
462 output.push(if u < 10 { (b'0' + u) as char } else { (b'a' + u - 10) as char });
463 output.push(if l < 10 { (b'0' + l) as char } else { (b'a' + l - 10) as char });
464 }
465
466 output
467}
468
469impl fmt::Display for RawValue {
470 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
471 match self {
473 RawValue::Binary(buf) => f.write_str(&buffer_to_hex_string(buf)),
474 RawValue::Boolean(boolean) => fmt::Display::fmt(boolean, f),
475 RawValue::Flag => write!(f, "<flag>"),
476 RawValue::Float(float) => fmt::Display::fmt(float, f),
477 RawValue::SignedInt(int) => fmt::Display::fmt(int, f),
478 RawValue::String(string) => fmt::Display::fmt(string, f),
479 RawValue::StringList(list) => fmt::Display::fmt(&list.join("\n"), f),
480 RawValue::UnsignedInt(uint) => fmt::Display::fmt(uint, f),
481 }
482 }
483}
484
485#[derive(Clone, Debug)]
487pub struct RawTagSubField {
488 pub field: String,
490 pub value: RawValue,
492}
493
494impl RawTagSubField {
495 pub fn new<F, V>(field: F, value: V) -> Self
497 where
498 F: Into<String>,
499 V: Into<RawValue>,
500 {
501 RawTagSubField { field: field.into(), value: value.into() }
502 }
503}
504
505#[derive(Clone, Debug)]
508pub struct RawTag {
509 pub key: String,
511 pub value: RawValue,
513 pub sub_fields: Option<Box<[RawTagSubField]>>,
515}
516
517impl RawTag {
518 pub fn new<K, V>(key: K, value: V) -> Self
521 where
522 K: Into<String>,
523 V: Into<RawValue>,
524 {
525 RawTag { key: key.into(), value: value.into(), sub_fields: None }
526 }
527
528 pub fn new_with_sub_fields<K, V>(key: K, value: V, sub_fields: Box<[RawTagSubField]>) -> Self
531 where
532 K: Into<String>,
533 V: Into<RawValue>,
534 {
535 RawTag { key: key.into(), value: value.into(), sub_fields: Some(sub_fields) }
536 }
537}
538
539#[derive(Clone, Debug)]
541pub struct Tag {
542 pub raw: RawTag,
544 pub std: Option<StandardTag>,
546}
547
548impl Tag {
549 pub fn new(raw: RawTag) -> Self {
551 Tag { raw, std: None }
552 }
553
554 pub fn new_std(raw: RawTag, std: StandardTag) -> Self {
556 Tag { raw, std: Some(std) }
557 }
558
559 pub fn new_from_parts<K, V>(key: K, value: V, std: Option<StandardTag>) -> Self
562 where
563 K: Into<String>,
564 V: Into<RawValue>,
565 {
566 Tag { raw: RawTag { key: key.into(), value: value.into(), sub_fields: None }, std }
567 }
568
569 pub fn has_std_tag(&self) -> bool {
572 self.std.is_some()
573 }
574}
575
576#[derive(Copy, Clone, Debug, Default)]
578pub struct Size {
579 pub width: u32,
581 pub height: u32,
583}
584
585#[derive(Copy, Clone, Debug, PartialEq, Eq)]
586#[non_exhaustive]
588pub enum ColorModel {
589 Y(NonZeroU8),
591 YA(NonZeroU8),
593 RGB(NonZeroU8),
595 RGBA(NonZeroU8),
597 CMYK(NonZeroU8),
599}
600
601impl ColorModel {
602 pub fn bits_per_pixel(&self) -> u32 {
604 match self {
605 ColorModel::Y(bits) => u32::from(bits.get()),
606 ColorModel::YA(bits) => 2 * u32::from(bits.get()),
607 ColorModel::RGB(bits) => 3 * u32::from(bits.get()),
608 ColorModel::RGBA(bits) => 4 * u32::from(bits.get()),
609 ColorModel::CMYK(bits) => 4 * u32::from(bits.get()),
610 }
611 }
612
613 pub fn has_alpha_channel(&self) -> bool {
615 matches!(self, ColorModel::YA(_) | ColorModel::RGBA(_))
616 }
617}
618
619#[derive(Copy, Clone, Debug, PartialEq, Eq)]
621pub struct ColorPaletteInfo {
622 pub bits_per_pixel: NonZeroU8,
624 pub color_model: ColorModel,
626}
627
628#[derive(Copy, Clone, Debug, PartialEq, Eq)]
630pub enum ColorMode {
631 Direct(ColorModel),
636 Indexed(ColorPaletteInfo),
639}
640
641#[derive(Clone, Debug)]
643pub struct Visual {
644 pub media_type: Option<String>,
646 pub dimensions: Option<Size>,
651 pub color_mode: Option<ColorMode>,
656 pub usage: Option<StandardVisualKey>,
658 pub tags: Vec<Tag>,
660 pub data: Box<[u8]>,
662}
663
664#[derive(Clone, Debug)]
666pub struct ChapterGroup {
667 pub items: Vec<ChapterGroupItem>,
669 pub tags: Vec<Tag>,
671 pub visuals: Vec<Visual>,
673}
674
675#[derive(Clone, Debug)]
677pub struct Chapter {
678 pub start_time: Time,
680 pub end_time: Option<Time>,
682 pub start_byte: Option<u64>,
685 pub end_byte: Option<u64>,
688 pub tags: Vec<Tag>,
690 pub visuals: Vec<Visual>,
692}
693
694#[derive(Clone, Debug)]
696pub enum ChapterGroupItem {
697 Group(ChapterGroup),
699 Chapter(Chapter),
701}
702
703#[derive(Clone, Debug, Default)]
705pub struct MetadataContainer {
706 pub tags: Vec<Tag>,
708 pub visuals: Vec<Visual>,
710}
711
712#[derive(Clone, Debug, Default)]
715pub struct PerTrackMetadata {
716 pub track_id: u64,
718 pub metadata: MetadataContainer,
720}
721
722#[derive(Clone, Debug)]
727pub struct MetadataRevision {
728 pub info: MetadataInfo,
730 pub media: MetadataContainer,
734 pub per_track: Vec<PerTrackMetadata>,
736}
737
738#[derive(Clone, Debug)]
740pub struct MetadataBuilder {
741 revision: MetadataRevision,
742}
743
744impl MetadataBuilder {
745 pub fn new(info: MetadataInfo) -> Self {
747 let revision =
748 MetadataRevision { info, media: Default::default(), per_track: Default::default() };
749 MetadataBuilder { revision }
750 }
751
752 pub fn add_tag(&mut self, tag: Tag) -> &mut Self {
754 self.revision.media.tags.push(tag);
755 self
756 }
757
758 pub fn add_visual(&mut self, visual: Visual) -> &mut Self {
760 self.revision.media.visuals.push(visual);
761 self
762 }
763
764 pub fn add_track(&mut self, per_track: PerTrackMetadata) -> &mut Self {
766 self.revision.per_track.push(per_track);
767 self
768 }
769
770 pub fn build(self) -> MetadataRevision {
772 self.revision
773 }
774}
775
776#[derive(Clone, Debug)]
778pub struct PerTrackMetadataBuilder {
779 per_track: PerTrackMetadata,
780}
781
782impl PerTrackMetadataBuilder {
783 pub fn new(track_id: u64) -> Self {
785 PerTrackMetadataBuilder {
786 per_track: PerTrackMetadata { track_id, metadata: Default::default() },
787 }
788 }
789
790 pub fn add_tag(&mut self, tag: Tag) -> &mut Self {
792 self.per_track.metadata.tags.push(tag);
793 self
794 }
795
796 pub fn add_visual(&mut self, visual: Visual) -> &mut Self {
798 self.per_track.metadata.visuals.push(visual);
799 self
800 }
801
802 pub fn build(self) -> PerTrackMetadata {
804 self.per_track
805 }
806}
807
808#[derive(Debug)]
810pub struct Metadata<'a> {
811 revisions: &'a mut VecDeque<MetadataRevision>,
812}
813
814impl Metadata<'_> {
815 pub fn is_latest(&self) -> bool {
817 self.revisions.len() <= 1
818 }
819
820 pub fn current(&self) -> Option<&MetadataRevision> {
822 self.revisions.front()
823 }
824
825 pub fn skip_to_latest(&mut self) -> Option<&MetadataRevision> {
828 loop {
829 if self.pop().is_none() {
830 break;
831 }
832 }
833 self.current()
834 }
835
836 pub fn pop(&mut self) -> Option<MetadataRevision> {
841 if self.revisions.len() > 1 { self.revisions.pop_front() } else { None }
842 }
843}
844
845#[derive(Clone, Debug, Default)]
847pub struct MetadataLog {
848 revisions: VecDeque<MetadataRevision>,
849}
850
851impl MetadataLog {
852 pub fn metadata(&mut self) -> Metadata<'_> {
854 Metadata { revisions: &mut self.revisions }
855 }
856
857 pub fn push(&mut self, rev: MetadataRevision) {
859 self.revisions.push_back(rev);
860 }
861
862 pub fn append(&mut self, other: &mut MetadataLog) {
864 self.revisions.append(&mut other.revisions);
865 }
866
867 pub fn push_front(&mut self, rev: MetadataRevision) {
869 self.revisions.push_front(rev);
870 }
871
872 pub fn append_front(&mut self, other: &mut MetadataLog) {
874 while let Some(revision) = other.revisions.pop_back() {
876 self.revisions.push_front(revision)
877 }
878 }
879}
880
881#[non_exhaustive]
883pub enum MetadataSideData {
884 Chapters(ChapterGroup),
886}
887
888pub struct MetadataBuffer {
890 pub revision: MetadataRevision,
892 pub side_data: Vec<MetadataSideData>,
895}
896
897pub trait MetadataReader: Send + Sync {
899 fn metadata_info(&self) -> &MetadataInfo;
901
902 fn read_all(&mut self) -> Result<MetadataBuffer>;
904
905 fn into_inner<'s>(self: Box<Self>) -> MediaSourceStream<'s>
907 where
908 Self: 's;
909}
910
911pub mod well_known {
913 use super::MetadataId;
914
915 pub const METADATA_ID_VORBIS_COMMENT: MetadataId = MetadataId(0x100);
919 pub const METADATA_ID_FLAC: MetadataId = MetadataId(0x101);
921
922 pub const METADATA_ID_ID3V1: MetadataId = MetadataId(0x200);
926 pub const METADATA_ID_ID3V2: MetadataId = MetadataId(0x201);
928
929 pub const METADATA_ID_APEV1: MetadataId = MetadataId(0x300);
933 pub const METADATA_ID_APEV2: MetadataId = MetadataId(0x301);
935
936 pub const METADATA_ID_WAVE: MetadataId = MetadataId(0x400);
940 pub const METADATA_ID_AIFF: MetadataId = MetadataId(0x401);
942 pub const METADATA_ID_EXIF: MetadataId = MetadataId(0x402);
944 pub const METADATA_ID_MATROSKA: MetadataId = MetadataId(0x403);
946 pub const METADATA_ID_ISOMP4: MetadataId = MetadataId(0x404);
948}