Skip to content

Commit 9eb35ae

Browse files
committed
MP4: Create DataType enum, replacing constants
1 parent 6370529 commit 9eb35ae

File tree

6 files changed

+336
-95
lines changed

6 files changed

+336
-95
lines changed

lofty/src/mp4/ilst/atom.rs

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::error::Result;
22
use crate::macros::err;
3+
use crate::mp4::ilst::data_type::DataType;
34
use crate::mp4::AtomIdent;
45
use crate::picture::Picture;
56

@@ -213,7 +214,10 @@ impl<'a> Atom<'a> {
213214
pub(crate) fn unknown_implicit(ident: AtomIdent<'_>, data: Vec<u8>) -> Self {
214215
Self {
215216
ident: ident.into_owned(),
216-
data: AtomDataStorage::Single(AtomData::Unknown { code: 0, data }),
217+
data: AtomDataStorage::Single(AtomData::Unknown {
218+
code: DataType::Reserved,
219+
data,
220+
}),
217221
}
218222
}
219223

@@ -247,8 +251,7 @@ impl Debug for Atom<'_> {
247251
/// NOTES:
248252
///
249253
/// * This only covers the most common data types.
250-
/// See the list of [well-known data types](https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW34)
251-
/// for codes.
254+
/// See the list of [DataType] for all known types.
252255
/// * There are only two variants for integers, which
253256
/// will come from codes `21` and `22`. All other integer
254257
/// types will be stored as [`AtomData::Unknown`], refer
@@ -290,51 +293,52 @@ pub enum AtomData {
290293
/// variant.
291294
Unknown {
292295
/// The code, or type of the item
293-
code: u32,
296+
code: DataType,
294297
/// The binary data of the atom
295298
data: Vec<u8>,
296299
},
297300
}
298301

299-
/// The parental advisory rating
300-
///
301-
/// See also:
302-
/// <https://docs.mp3tag.de/mapping/#itunesadvisory>
303-
/// <https://exiftool.org/TagNames/QuickTime.html>
304-
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
305-
pub enum AdvisoryRating {
306-
/// *Inoffensive*/*None* (0)
307-
Inoffensive,
308-
/// *Explicit* (1 or 4)
302+
impl AtomData {
303+
/// Get the [`DataType`] of the atom
309304
///
310-
/// In the past Apple used the value 4 for explicit content
311-
/// that has later been replaced by 1. Both values are considered
312-
/// as valid when reading but only the newer value 1 is written.
313-
Explicit,
314-
/// *Clean*/*Edited* (2)
315-
Clean,
316-
}
317-
318-
impl AdvisoryRating {
319-
/// Returns the rating as it appears in the `rtng` atom
320-
pub fn as_u8(&self) -> u8 {
305+
/// Note that for [`AtomData::Picture`], the type is determined by the picture's MIME type.
306+
/// If the MIME type is unknown (or unset), the data type will be [`DataType::Reserved`].
307+
///
308+
/// # Examples
309+
///
310+
/// ```rust
311+
/// use lofty::mp4::{AtomData, DataType};
312+
/// use lofty::picture::{MimeType, Picture, PictureType};
313+
///
314+
/// let data = AtomData::UTF8(String::from("foo"));
315+
/// assert_eq!(data.data_type(), DataType::Utf8);
316+
///
317+
/// let data = AtomData::SignedInteger(42);
318+
/// assert_eq!(data.data_type(), DataType::BeSignedInteger);
319+
///
320+
/// let data = AtomData::Picture(Picture::new_unchecked(
321+
/// PictureType::CoverFront,
322+
/// Some(MimeType::Jpeg),
323+
/// None,
324+
/// Vec::new(),
325+
/// ));
326+
/// assert_eq!(data.data_type(), DataType::Jpeg);
327+
/// ```
328+
pub fn data_type(&self) -> DataType {
321329
match self {
322-
AdvisoryRating::Inoffensive => 0,
323-
AdvisoryRating::Explicit => 1,
324-
AdvisoryRating::Clean => 2,
325-
}
326-
}
327-
}
328-
329-
impl TryFrom<u8> for AdvisoryRating {
330-
type Error = u8;
331-
332-
fn try_from(input: u8) -> std::result::Result<Self, Self::Error> {
333-
match input {
334-
0 => Ok(Self::Inoffensive),
335-
1 | 4 => Ok(Self::Explicit),
336-
2 => Ok(Self::Clean),
337-
value => Err(value),
330+
AtomData::UTF8(_) => DataType::Utf8,
331+
AtomData::UTF16(_) => DataType::Utf16,
332+
AtomData::SignedInteger(_) | AtomData::Bool(_) => DataType::BeSignedInteger,
333+
AtomData::UnsignedInteger(_) => DataType::BeUnsignedInteger,
334+
AtomData::Picture(p) => {
335+
let Some(mime) = p.mime_type() else {
336+
return DataType::Reserved;
337+
};
338+
339+
DataType::from(mime)
340+
},
341+
AtomData::Unknown { code, .. } => *code,
338342
}
339343
}
340344
}

lofty/src/mp4/ilst/data_type.rs

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
use crate::picture::MimeType;
2+
3+
/// The [well known] basic data types
4+
///
5+
/// This should cover all the data types you'll encounter in an MP4 file.
6+
///
7+
/// [well known]: https://developer.apple.com/documentation/quicktime-file-format/well-known_types
8+
// OLD LINKS:
9+
// * https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW35
10+
#[repr(u32)]
11+
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
12+
pub enum DataType {
13+
/// Reserved for use where no type needs to be indicated
14+
Reserved = 0,
15+
/// UTF-8 string without any count or NULL terminator
16+
Utf8 = 1,
17+
/// A big-endian UTF-16 string
18+
Utf16 = 2,
19+
/// Deprecated unless it is needed for special Japanese characters
20+
SJis = 3,
21+
/// The UTF-8 variant storage of a string for sorting only
22+
Utf8Sort = 4,
23+
/// The UTF-16 variant storage of a string for sorting only
24+
Utf16Sort = 5,
25+
/// **DEPRECATED** A GIF image
26+
Gif = 12,
27+
/// A JPEG in a JFIF wrapper
28+
Jpeg = 13,
29+
/// A PNG in a PNG wrapper
30+
Png = 14,
31+
/// A big-endian signed integer in 1,2,3 or 4 bytes
32+
BeSignedInteger = 21,
33+
/// A big-endian unsigned integer in 1,2,3 or 4 bytes; size of value determines integer size
34+
BeUnsignedInteger = 22,
35+
/// A big-endian 32-bit floating point value (IEEE754)
36+
BeFloat32 = 23,
37+
/// A big-endian 64-bit floating point value (IEEE754)
38+
BeFloat64 = 24,
39+
/// Windows bitmap format graphics
40+
Bmp = 27,
41+
/// A QuickTime metadata atom
42+
QuicktimeMetadata = 28,
43+
/// An 8-bit signed integer
44+
Signed8BitInteger = 65,
45+
/// A big-endian 16-bit signed integer
46+
Be16BitSignedInteger = 66,
47+
/// A big-endian 32-bit signed integer
48+
Be32BitSignedInteger = 67,
49+
/// A block of data representing a two dimensional (2D) point with 32-bit big-endian floating point x and y coordinates. It has the structure:
50+
///
51+
/// ```c
52+
/// struct {
53+
/// BEFloat32 x;
54+
/// BEFloat32 y;
55+
/// }
56+
/// ```
57+
BePointF32 = 70,
58+
/// A block of data representing 2D dimensions with 32-bit big-endian floating point width and height. It has the structure:
59+
///
60+
/// ```c
61+
/// struct {
62+
/// BEFloat32 width;
63+
/// BEFloat32 height;
64+
/// }
65+
/// ```
66+
BeDimensionsF32 = 71,
67+
/// A block of data representing a 2D rectangle with 32-bit big-endian floating point x and y coordinates and a 32-bit big-endian floating point width and height size. It has the structure:
68+
///
69+
/// ```c
70+
/// struct {
71+
/// BEFloat32 x;
72+
/// BEFloat32 y;
73+
/// BEFloat32 width;
74+
/// BEFloat32 height;
75+
/// }
76+
/// ```
77+
///
78+
/// or the equivalent structure:
79+
///
80+
/// ```c
81+
/// struct {
82+
/// PointF32 origin;
83+
/// DimensionsF32 size;
84+
/// }
85+
/// ```
86+
BeRectF32 = 72,
87+
/// A big-endian 64-bit signed integer
88+
Be64BitSignedInteger = 74,
89+
/// An 8-bit unsigned integer
90+
Unsigned8BitInteger = 75,
91+
/// A big-endian 16-bit unsigned integer
92+
Be16BitUnsignedInteger = 76,
93+
/// A big-endian 32-bit unsigned integer
94+
Be32BitUnsignedInteger = 77,
95+
/// A big-endian 64-bit unsigned integer
96+
Be64BitUnsignedInteger = 78,
97+
/// A block of data representing a 3x3 transformation matrix. It has the structure:
98+
///
99+
/// ```c
100+
/// struct {
101+
/// BEFloat64 matrix[3][3];
102+
/// }
103+
/// ```
104+
AffineTransformF64 = 79,
105+
/// Some other data type
106+
Other(u32),
107+
}
108+
109+
impl From<u32> for DataType {
110+
fn from(value: u32) -> Self {
111+
match value {
112+
0 => DataType::Reserved,
113+
1 => DataType::Utf8,
114+
2 => DataType::Utf16,
115+
3 => DataType::SJis,
116+
4 => DataType::Utf8Sort,
117+
5 => DataType::Utf16Sort,
118+
12 => DataType::Gif,
119+
13 => DataType::Jpeg,
120+
14 => DataType::Png,
121+
21 => DataType::BeSignedInteger,
122+
22 => DataType::BeUnsignedInteger,
123+
23 => DataType::BeFloat32,
124+
24 => DataType::BeFloat64,
125+
27 => DataType::Bmp,
126+
28 => DataType::QuicktimeMetadata,
127+
65 => DataType::Signed8BitInteger,
128+
66 => DataType::Be16BitSignedInteger,
129+
67 => DataType::Be32BitSignedInteger,
130+
70 => DataType::BePointF32,
131+
71 => DataType::BeDimensionsF32,
132+
72 => DataType::BeRectF32,
133+
74 => DataType::Be64BitSignedInteger,
134+
75 => DataType::Unsigned8BitInteger,
135+
76 => DataType::Be16BitUnsignedInteger,
136+
77 => DataType::Be32BitUnsignedInteger,
137+
78 => DataType::Be64BitUnsignedInteger,
138+
79 => DataType::AffineTransformF64,
139+
other => DataType::Other(other),
140+
}
141+
}
142+
}
143+
144+
impl From<DataType> for u32 {
145+
fn from(value: DataType) -> Self {
146+
match value {
147+
DataType::Reserved => 0,
148+
DataType::Utf8 => 1,
149+
DataType::Utf16 => 2,
150+
DataType::SJis => 3,
151+
DataType::Utf8Sort => 4,
152+
DataType::Utf16Sort => 5,
153+
DataType::Gif => 12,
154+
DataType::Jpeg => 13,
155+
DataType::Png => 14,
156+
DataType::BeSignedInteger => 21,
157+
DataType::BeUnsignedInteger => 22,
158+
DataType::BeFloat32 => 23,
159+
DataType::BeFloat64 => 24,
160+
DataType::Bmp => 27,
161+
DataType::QuicktimeMetadata => 28,
162+
DataType::Signed8BitInteger => 65,
163+
DataType::Be16BitSignedInteger => 66,
164+
DataType::Be32BitSignedInteger => 67,
165+
DataType::BePointF32 => 70,
166+
DataType::BeDimensionsF32 => 71,
167+
DataType::BeRectF32 => 72,
168+
DataType::Be64BitSignedInteger => 74,
169+
DataType::Unsigned8BitInteger => 75,
170+
DataType::Be16BitUnsignedInteger => 76,
171+
DataType::Be32BitUnsignedInteger => 77,
172+
DataType::Be64BitUnsignedInteger => 78,
173+
DataType::AffineTransformF64 => 79,
174+
DataType::Other(other) => other,
175+
}
176+
}
177+
}
178+
179+
impl From<MimeType> for DataType {
180+
fn from(value: MimeType) -> Self {
181+
DataType::from(&value)
182+
}
183+
}
184+
185+
impl From<&MimeType> for DataType {
186+
fn from(value: &MimeType) -> Self {
187+
match value {
188+
MimeType::Gif => DataType::Gif,
189+
MimeType::Jpeg => DataType::Jpeg,
190+
MimeType::Png => DataType::Png,
191+
MimeType::Bmp => DataType::Bmp,
192+
_ => DataType::Reserved,
193+
}
194+
}
195+
}
196+
197+
impl DataType {
198+
/// A data type can only occupy 24 bits
199+
pub const MAX: u32 = 16_777_215;
200+
}

0 commit comments

Comments
 (0)