Skip to content

Commit cbb89fc

Browse files
committed
Parse ipco
1 parent d4ad2a4 commit cbb89fc

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed

mp4parse/src/lib.rs

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extern crate fallible_collections;
1313
extern crate num_traits;
1414
use bitreader::{BitReader, ReadInto};
1515
use byteorder::{ReadBytesExt, WriteBytesExt};
16+
use fallible_collections::TryClone;
1617
use fallible_collections::TryRead;
1718
use num_traits::Num;
1819
use std::convert::{TryFrom, TryInto as _};
@@ -1294,6 +1295,7 @@ fn read_avif_meta<T: Read + Offset>(src: &mut BMFFBox<T>) -> Result<AvifMeta> {
12941295
let mut item_infos = None;
12951296
let mut iloc_items = None;
12961297
let mut item_references = TryVec::new();
1298+
let mut properties = TryVec::new();
12971299

12981300
let mut iter = src.box_iter();
12991301
while let Some(mut b) = iter.next_box()? {
@@ -1325,6 +1327,9 @@ fn read_avif_meta<T: Read + Offset>(src: &mut BMFFBox<T>) -> Result<AvifMeta> {
13251327
BoxType::ImageReferenceBox => {
13261328
item_references = read_iref(&mut b)?;
13271329
}
1330+
BoxType::ImagePropertiesBox => {
1331+
properties = read_iprp(&mut b)?;
1332+
}
13281333
_ => skip_box_content(&mut b)?,
13291334
}
13301335

@@ -1490,6 +1495,147 @@ fn read_iref<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<ItemReferenceEntry>
14901495
Ok(entries)
14911496
}
14921497

1498+
fn read_iprp<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<AssociatedProperty>> {
1499+
let mut iter = src.box_iter();
1500+
let mut properties = TryVec::new();
1501+
let mut associations = TryVec::new();
1502+
1503+
while let Some(mut b) = iter.next_box()? {
1504+
match b.head.name {
1505+
BoxType::ItemPropertyContainerBox => {
1506+
properties = read_ipco(&mut b)?;
1507+
}
1508+
BoxType::ItemPropertyAssociationBox => {
1509+
associations = read_ipma(&mut b)?;
1510+
}
1511+
_ => return Err(Error::InvalidData("unexpected ipco child")),
1512+
}
1513+
}
1514+
1515+
let mut associated = TryVec::new();
1516+
for a in associations {
1517+
let index = match a.property_index {
1518+
0 => continue,
1519+
x => x as usize - 1,
1520+
};
1521+
if let Some(prop) = properties.get(index) {
1522+
if *prop != ImageProperty::Unsupported {
1523+
associated.push(AssociatedProperty {
1524+
item_id: a.item_id,
1525+
property: prop.clone()?,
1526+
})?;
1527+
}
1528+
}
1529+
}
1530+
Ok(associated)
1531+
}
1532+
1533+
#[derive(Debug, PartialEq)]
1534+
pub enum ImageProperty {
1535+
Channels(TryVec<u8>),
1536+
AuxiliaryType(TryString),
1537+
Unsupported,
1538+
}
1539+
1540+
impl ImageProperty {
1541+
fn clone(&self) -> Result<Self> {
1542+
Ok(match self {
1543+
Self::Channels(val) => Self::Channels(val.clone()?),
1544+
Self::AuxiliaryType(val) => Self::AuxiliaryType(val.clone()?),
1545+
Self::Unsupported => Self::Unsupported,
1546+
})
1547+
}
1548+
}
1549+
1550+
struct Association {
1551+
item_id: u32,
1552+
property_index: u16,
1553+
}
1554+
1555+
pub struct AssociatedProperty {
1556+
pub item_id: u32,
1557+
pub property: ImageProperty,
1558+
}
1559+
1560+
fn read_ipma<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<Association>> {
1561+
let (version, flags) = read_fullbox_extra(src)?;
1562+
1563+
let mut associations = TryVec::new();
1564+
1565+
let entry_count = be_u32(src)?;
1566+
for _ in 0..entry_count {
1567+
let item_id = if version == 0 {
1568+
be_u16(src)? as u32
1569+
} else {
1570+
be_u32(src)?
1571+
};
1572+
let association_count = src.read_u8()?;
1573+
for _ in 0..association_count {
1574+
let first_byte = src.read_u8()?;
1575+
let essential_flag = first_byte & 1 << 7;
1576+
let value = first_byte - essential_flag;
1577+
let property_index = if flags & 1 != 0 {
1578+
((value as u16) << 8) | src.read_u8()? as u16
1579+
} else {
1580+
value as u16
1581+
};
1582+
associations.push(Association {
1583+
item_id,
1584+
property_index,
1585+
})?;
1586+
}
1587+
}
1588+
Ok(associations)
1589+
}
1590+
1591+
fn read_ipco<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<ImageProperty>> {
1592+
let mut properties = TryVec::new();
1593+
1594+
let mut iter = src.box_iter();
1595+
while let Some(mut b) = iter.next_box()? {
1596+
// Must push for every property to have correct index for them
1597+
properties.push(match b.head.name {
1598+
BoxType::PixelInformationBox => ImageProperty::Channels(read_pixi(&mut b)?),
1599+
BoxType::AuxiliaryTypeProperty => ImageProperty::AuxiliaryType(read_auxc(&mut b)?),
1600+
_ => {
1601+
skip_box_remain(&mut b)?;
1602+
ImageProperty::Unsupported
1603+
}
1604+
})?;
1605+
}
1606+
Ok(properties)
1607+
}
1608+
1609+
fn read_pixi<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<u8>> {
1610+
let version = read_fullbox_version_no_flags(src)?;
1611+
if version != 0 {
1612+
return Err(Error::Unsupported("pixi version"));
1613+
}
1614+
1615+
let mut channels = TryVec::new();
1616+
let channel_count = src.read_u8()?;
1617+
for _ in 0..channel_count {
1618+
channels.push(src.read_u8()?)?;
1619+
}
1620+
Ok(channels)
1621+
}
1622+
1623+
fn read_auxc<T: Read>(src: &mut BMFFBox<T>) -> Result<TryString> {
1624+
let version = read_fullbox_version_no_flags(src)?;
1625+
if version != 0 {
1626+
return Err(Error::Unsupported("auxC version"));
1627+
}
1628+
1629+
let mut aux = TryString::new();
1630+
loop {
1631+
match src.read_u8()? {
1632+
0 => break,
1633+
c => aux.push(c)?,
1634+
}
1635+
}
1636+
Ok(aux)
1637+
}
1638+
14931639
/// Parse an item location box inside a meta box
14941640
/// See ISO 14496-12:2015 § 8.11.3
14951641
fn read_iloc<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<ItemLocationBoxItem>> {

0 commit comments

Comments
 (0)