Skip to content

Commit 240b6a4

Browse files
committed
core (meta): Per-track metadata.
1 parent de483fb commit 240b6a4

File tree

21 files changed

+265
-145
lines changed

21 files changed

+265
-145
lines changed

symphonia-bundle-flac/src/demuxer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ impl<'s> FlacReader<'s> {
7575

7676
/// Reads all the metadata blocks, returning a fully populated `FlacReader`.
7777
fn init_with_metadata(mss: MediaSourceStream<'s>, opts: FormatOptions) -> Result<Self> {
78-
let mut metadata_builder = MetadataBuilder::new();
78+
let mut metadata_builder = MetadataBuilder::new(FLAC_METADATA_INFO);
7979

8080
let mut reader = mss;
8181
let mut track = None;
@@ -174,7 +174,7 @@ impl<'s> FlacReader<'s> {
174174

175175
// Commit any read metadata to the metadata log.
176176
let mut metadata = opts.external_data.metadata.unwrap_or_default();
177-
metadata.push(metadata_builder.metadata());
177+
metadata.push(metadata_builder.build());
178178

179179
// Synchronize the packet parser to the first audio frame.
180180
let _ = parser.resync(&mut reader)?;

symphonia-core/src/common.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,33 @@ pub enum Tier {
6565
/// Use as a fallback if nothing else is available.
6666
Fallback,
6767
}
68+
69+
/// `Limit` defines an upper-bound of how much of a resource should be allocated when the amount to
70+
/// be allocated is specified by the media stream, which is untrusted. A limit will place an
71+
/// upper-bound on this allocation at the risk of breaking potentially valid streams. Limits are
72+
/// used to prevent denial-of-service attacks.
73+
///
74+
/// All limits can be defaulted to a reasonable value specific to the situation. These defaults will
75+
/// generally not break any normal streams.
76+
#[derive(Copy, Clone, Debug, Default)]
77+
pub enum Limit {
78+
/// Do not impose any limit.
79+
None,
80+
/// Use the a reasonable default specified by the `FormatReader` or `Decoder` implementation.
81+
#[default]
82+
Default,
83+
/// Specify the upper limit of the resource. Units are case specific.
84+
Maximum(usize),
85+
}
86+
87+
impl Limit {
88+
/// Gets the numeric limit of the limit, or default value. If there is no limit, None is
89+
/// returned.
90+
pub fn limit_or_default(&self, default: usize) -> Option<usize> {
91+
match self {
92+
Limit::None => None,
93+
Limit::Default => Some(default),
94+
Limit::Maximum(max) => Some(*max),
95+
}
96+
}
97+
}

symphonia-core/src/meta.rs

Lines changed: 89 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ use std::fmt;
5656
use std::num::NonZeroU8;
5757
use std::sync::Arc;
5858

59-
use crate::common::FourCc;
59+
use crate::common::{FourCc, Limit};
6060
use crate::errors::Result;
6161
use crate::io::MediaSourceStream;
6262
use crate::units::Time;
6363

64-
/// A `MetadataType` is a unique identifier used to identify a metadata format.
64+
/// A `MetadataId` is a unique identifier used to identify a specific metadata format.
6565
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
6666
pub struct MetadataId(u32);
6767

@@ -89,7 +89,7 @@ impl fmt::Display for MetadataId {
8989
pub const METADATA_ID_NULL: MetadataId = MetadataId(0x0);
9090

9191
/// Basic information about a metadata format.
92-
#[derive(Copy, Clone)]
92+
#[derive(Copy, Clone, Debug)]
9393
pub struct MetadataInfo {
9494
/// The `MetadataType` identifier.
9595
pub metadata: MetadataId,
@@ -99,37 +99,7 @@ pub struct MetadataInfo {
9999
pub long_name: &'static str,
100100
}
101101

102-
/// `Limit` defines an upper-bound on how much of a resource should be allocated when the amount to
103-
/// be allocated is specified by the media stream, which is untrusted. A limit will place an
104-
/// upper-bound on this allocation at the risk of breaking potentially valid streams. Limits are
105-
/// used to prevent denial-of-service attacks.
106-
///
107-
/// All limits can be defaulted to a reasonable value specific to the situation. These defaults will
108-
/// generally not break any normal streams.
109-
#[derive(Copy, Clone, Debug, Default)]
110-
pub enum Limit {
111-
/// Do not impose any limit.
112-
None,
113-
/// Use the a reasonable default specified by the `FormatReader` or `Decoder` implementation.
114-
#[default]
115-
Default,
116-
/// Specify the upper limit of the resource. Units are case specific.
117-
Maximum(usize),
118-
}
119-
120-
impl Limit {
121-
/// Gets the numeric limit of the limit, or default value. If there is no limit, None is
122-
/// returned.
123-
pub fn limit_or_default(&self, default: usize) -> Option<usize> {
124-
match self {
125-
Limit::None => None,
126-
Limit::Default => Some(default),
127-
Limit::Maximum(max) => Some(*max),
128-
}
129-
}
130-
}
131-
132-
/// `MetadataOptions` is a common set of options that all metadata readers use.
102+
/// A common set of options that all metadata readers use.
133103
#[derive(Copy, Clone, Debug, Default)]
134104
pub struct MetadataOptions {
135105
/// The maximum size limit in bytes that a tag may occupy in memory once decoded. Tags exceeding
@@ -705,60 +675,108 @@ pub enum ChapterGroupItem {
705675
Chapter(Chapter),
706676
}
707677

708-
/// A metadata revision is a container for a single discrete revision of media metadata.
709-
///
710-
/// A metadata revision contains what a user typically associates with metadata: tags, pictures,
711-
/// etc.
678+
/// A container of metadata tags and pictures.
712679
#[derive(Clone, Debug, Default)]
713-
pub struct MetadataRevision {
680+
pub struct MetadataContainer {
714681
/// Key-value pairs of metadata.
715-
tags: Vec<Tag>,
682+
pub tags: Vec<Tag>,
716683
/// Attached pictures.
717-
visuals: Vec<Visual>,
684+
pub visuals: Vec<Visual>,
685+
}
686+
687+
/// Container for metadata associated with a specific track. A [`MetadataContainer`] wrapper
688+
/// associating it with a track ID.
689+
#[derive(Clone, Debug, Default)]
690+
pub struct PerTrackMetadata {
691+
/// The ID of the track the metadata is associated with.
692+
pub track_id: u64,
693+
/// Track-specific metadata.
694+
pub metadata: MetadataContainer,
718695
}
719696

720-
impl MetadataRevision {
721-
/// Gets an immutable slice to the `Tag`s in this revision.
697+
/// A metadata revision is a container for a single discrete version of media metadata.
698+
///
699+
/// A metadata revision contains what a user typically associates with metadata: tags, pictures,
700+
/// etc., for the media as a whole and, optionally, for each contained track.
701+
#[derive(Clone, Debug)]
702+
pub struct MetadataRevision {
703+
/// Information about the source of this revision of metadata.
704+
pub info: MetadataInfo,
705+
/// Media-level, global, metadata.
722706
///
723-
/// If a tag read from the source contained multiple values, then there will be one `Tag` item
724-
/// per value, with each item having the same key and standard key.
725-
pub fn tags(&self) -> &[Tag] {
726-
&self.tags
707+
/// The vast majority of metadata is media-level metadata.
708+
pub media: MetadataContainer,
709+
/// Per-track metadata.
710+
pub per_track: Vec<PerTrackMetadata>,
711+
}
712+
713+
/// A builder for [`MetadataRevision`].
714+
#[derive(Clone, Debug)]
715+
pub struct MetadataBuilder {
716+
revision: MetadataRevision,
717+
}
718+
719+
impl MetadataBuilder {
720+
/// Instantiate a new `MetadataBuilder`.
721+
pub fn new(info: MetadataInfo) -> Self {
722+
let revision =
723+
MetadataRevision { info, media: Default::default(), per_track: Default::default() };
724+
MetadataBuilder { revision }
727725
}
728726

729-
/// Gets an immutable slice to the `Visual`s in this revision.
730-
pub fn visuals(&self) -> &[Visual] {
731-
&self.visuals
727+
/// Add a media-level `Tag` to the metadata.
728+
pub fn add_tag(&mut self, tag: Tag) -> &mut Self {
729+
self.revision.media.tags.push(tag);
730+
self
731+
}
732+
733+
/// Add a media-level `Visual` to the metadata.
734+
pub fn add_visual(&mut self, visual: Visual) -> &mut Self {
735+
self.revision.media.visuals.push(visual);
736+
self
737+
}
738+
739+
/// Add track-specific metadata.
740+
pub fn add_track(&mut self, per_track: PerTrackMetadata) -> &mut Self {
741+
self.revision.per_track.push(per_track);
742+
self
743+
}
744+
745+
/// Build and return the metadata revision.
746+
pub fn build(self) -> MetadataRevision {
747+
self.revision
732748
}
733749
}
734750

735-
/// `MetadataBuilder` is the builder for [`Metadata`] revisions.
736-
#[derive(Clone, Debug, Default)]
737-
pub struct MetadataBuilder {
738-
metadata: MetadataRevision,
751+
/// A builder for [`PerTrackMetadata`].
752+
#[derive(Clone, Debug)]
753+
pub struct PerTrackMetadataBuilder {
754+
per_track: PerTrackMetadata,
739755
}
740756

741-
impl MetadataBuilder {
757+
impl PerTrackMetadataBuilder {
742758
/// Instantiate a new `MetadataBuilder`.
743-
pub fn new() -> Self {
744-
MetadataBuilder { metadata: Default::default() }
759+
pub fn new(track_id: u64) -> Self {
760+
PerTrackMetadataBuilder {
761+
per_track: PerTrackMetadata { track_id, metadata: Default::default() },
762+
}
745763
}
746764

747-
/// Add a `Tag` to the metadata.
765+
/// Add a `Tag` to the per-track metadata.
748766
pub fn add_tag(&mut self, tag: Tag) -> &mut Self {
749-
self.metadata.tags.push(tag);
767+
self.per_track.metadata.tags.push(tag);
750768
self
751769
}
752770

753-
/// Add a `Visual` to the metadata.
771+
/// Add a `Visual` to the per-track metadata.
754772
pub fn add_visual(&mut self, visual: Visual) -> &mut Self {
755-
self.metadata.visuals.push(visual);
773+
self.per_track.metadata.visuals.push(visual);
756774
self
757775
}
758776

759-
/// Yield the constructed `Metadata` revision.
760-
pub fn metadata(self) -> MetadataRevision {
761-
self.metadata
777+
/// Build and return the track-specific metadata.
778+
pub fn build(self) -> PerTrackMetadata {
779+
self.per_track
762780
}
763781
}
764782

@@ -804,7 +822,7 @@ impl Metadata<'_> {
804822
}
805823
}
806824

807-
/// `MetadataLog` is a container for time-ordered [`Metadata`] revisions.
825+
/// A queue for time-ordered [`MetadataRevision`]s.
808826
#[derive(Clone, Debug, Default)]
809827
pub struct MetadataLog {
810828
revisions: VecDeque<MetadataRevision>,
@@ -898,11 +916,13 @@ pub mod well_known {
898916
// Format-native tags
899917

900918
/// RIFF tags
901-
pub const METADATA_ID_RIFF: MetadataId = MetadataId(0x400);
919+
pub const METADATA_ID_WAVE: MetadataId = MetadataId(0x400);
920+
/// RIFF tags
921+
pub const METADATA_ID_AIFF: MetadataId = MetadataId(0x401);
902922
/// EXIF
903-
pub const METADATA_ID_EXIF: MetadataId = MetadataId(0x401);
923+
pub const METADATA_ID_EXIF: MetadataId = MetadataId(0x402);
904924
/// Matroska tags
905-
pub const METADATA_ID_MATROSKA: MetadataId = MetadataId(0x402);
925+
pub const METADATA_ID_MATROSKA: MetadataId = MetadataId(0x403);
906926
/// ISOMP4 tags
907-
pub const METADATA_ID_ISOMP4: MetadataId = MetadataId(0x403);
927+
pub const METADATA_ID_ISOMP4: MetadataId = MetadataId(0x404);
908928
}

symphonia-format-isomp4/src/atoms/ilst.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ use std::sync::Arc;
99

1010
use symphonia_core::errors::{decode_error, Error, Result};
1111
use symphonia_core::io::{BufReader, ReadBytes};
12+
use symphonia_core::meta::well_known::METADATA_ID_ISOMP4;
1213
use symphonia_core::meta::{
13-
ContentAdvisory, MetadataBuilder, MetadataRevision, RawTag, StandardTag, StandardVisualKey, Tag,
14+
ContentAdvisory, MetadataBuilder, MetadataInfo, MetadataRevision, RawTag, StandardTag,
15+
StandardVisualKey, Tag,
1416
};
1517
use symphonia_core::meta::{RawValue, Visual};
1618
use symphonia_core::util::{bits, text};
@@ -21,6 +23,12 @@ use crate::atoms::{Atom, AtomHeader, AtomIterator, AtomType};
2123

2224
use log::{debug, warn};
2325

26+
const ISOMP4_METADATA_INFO: MetadataInfo = MetadataInfo {
27+
metadata: METADATA_ID_ISOMP4,
28+
short_name: "isomp4",
29+
long_name: "ISO Base Media File Format",
30+
};
31+
2432
/// Data type enumeration for metadata value atoms as defined in the QuickTime File Format standard.
2533
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2634
pub enum DataType {
@@ -720,7 +728,7 @@ impl Atom for IlstAtom {
720728
fn read<B: ReadBytes>(reader: &mut B, header: AtomHeader) -> Result<Self> {
721729
let mut iter = AtomIterator::new(reader, header);
722730

723-
let mut mb = MetadataBuilder::new();
731+
let mut mb = MetadataBuilder::new(ISOMP4_METADATA_INFO);
724732

725733
while let Some(header) = iter.next()? {
726734
// Ignore standard atoms, check if other is a metadata atom.
@@ -925,7 +933,7 @@ impl Atom for IlstAtom {
925933
}
926934
}
927935

928-
Ok(IlstAtom { metadata: mb.metadata() })
936+
Ok(IlstAtom { metadata: mb.build() })
929937
}
930938
}
931939

0 commit comments

Comments
 (0)