Skip to content

Commit 2851627

Browse files
authored
Merge pull request #328 from mozilla/unsupported-detail
Communicate more detail about what specifically is unsupported across FFI
2 parents b31d94b + 6d4ed9b commit 2851627

File tree

13 files changed

+258
-83
lines changed

13 files changed

+258
-83
lines changed

mp4parse/av1-avif

Submodule av1-avif updated 347 files

mp4parse/src/boxes.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ box_database!(
126126
CleanApertureBox 0x636c_6170, // "clap"
127127
ImageRotation 0x6972_6f74, // "irot"
128128
ImageMirror 0x696d_6972, // "imir"
129+
OperatingPointSelectorProperty 0x6131_6f70, // "a1op"
130+
AV1LayeredImageIndexingProperty 0x6131_6c78, // "a1lx"
131+
LayerSelectorProperty 0x6c73_656c, // "lsel"
129132
SampleTableBox 0x7374_626c, // "stbl"
130133
SampleDescriptionBox 0x7374_7364, // "stsd"
131134
TimeToSampleBox 0x7374_7473, // "stts"

mp4parse/src/lib.rs

Lines changed: 119 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,87 @@ struct HashMap;
148148
#[allow(dead_code)]
149149
struct String;
150150

151+
/// The return value to the C API
152+
/// Any detail that needs to be communicated to the caller must be encoded here
153+
/// since the [`Error`] type's associated data is part of the FFI.
154+
#[repr(C)]
155+
#[derive(PartialEq, Debug)]
156+
pub enum Status {
157+
Ok = 0,
158+
BadArg = 1,
159+
Invalid = 2,
160+
Unsupported = 3,
161+
Eof = 4,
162+
Io = 5,
163+
Oom = 6,
164+
UnsupportedA1lx,
165+
UnsupportedA1op,
166+
UnsupportedClap,
167+
UnsupportedGrid,
168+
UnsupportedIpro,
169+
UnsupportedLsel,
170+
}
171+
172+
/// For convenience of creating an error for an unsupported feature which we
173+
/// want to communicate the specific feature back to the C API caller
174+
impl From<Status> for Error {
175+
fn from(parse_status: Status) -> Self {
176+
let msg = match parse_status {
177+
Status::Ok
178+
| Status::BadArg
179+
| Status::Invalid
180+
| Status::Unsupported
181+
| Status::Eof
182+
| Status::Io
183+
| Status::Oom => {
184+
panic!("Status -> Error is only for Status:UnsupportedXXX errors")
185+
}
186+
187+
Status::UnsupportedA1lx => "AV1 layered image indexing (a1lx) is unsupported",
188+
Status::UnsupportedA1op => "Operating point selection (a1op) is unsupported",
189+
Status::UnsupportedClap => "Clean aperture (clap) transform is unsupported",
190+
Status::UnsupportedGrid => "Grid-based images are unsupported",
191+
Status::UnsupportedIpro => "Item protection (ipro) is unsupported",
192+
Status::UnsupportedLsel => "Layer selection (lsel) is unsupported",
193+
};
194+
Self::UnsupportedDetail(parse_status, msg)
195+
}
196+
}
197+
198+
impl From<Error> for Status {
199+
fn from(error: Error) -> Self {
200+
match error {
201+
Error::NoMoov | Error::InvalidData(_) => Self::Invalid,
202+
Error::Unsupported(_) => Self::Unsupported,
203+
Error::UnsupportedDetail(parse_status, _msg) => parse_status,
204+
Error::UnexpectedEOF => Self::Eof,
205+
Error::Io(_) => {
206+
// Getting std::io::ErrorKind::UnexpectedEof is normal
207+
// but our From trait implementation should have converted
208+
// those to our Error::UnexpectedEOF variant.
209+
Self::Io
210+
}
211+
Error::OutOfMemory => Self::Oom,
212+
}
213+
}
214+
}
215+
216+
impl From<Result<(), Status>> for Status {
217+
fn from(result: Result<(), Status>) -> Self {
218+
match result {
219+
Ok(()) => Status::Ok,
220+
Err(Status::Ok) => unreachable!(),
221+
Err(e) => e,
222+
}
223+
}
224+
}
225+
226+
impl From<fallible_collections::TryReserveError> for Status {
227+
fn from(_: fallible_collections::TryReserveError) -> Self {
228+
Status::Oom
229+
}
230+
}
231+
151232
/// Describes parser failures.
152233
///
153234
/// This enum wraps the standard `io::Error` type, unified with
@@ -158,6 +239,10 @@ pub enum Error {
158239
InvalidData(&'static str),
159240
/// Parse error caused by limited parser support rather than invalid data.
160241
Unsupported(&'static str),
242+
/// Similar to [`Self::Unsupported`], but for errors that have a specific
243+
/// [`Status`] variant for communicating the detail across FFI.
244+
/// See the helper [`From<Status> for Error`](enum.Error.html#impl-From<Status>)
245+
UnsupportedDetail(Status, &'static str),
161246
/// Reflect `std::io::ErrorKind::UnexpectedEof` for short data.
162247
UnexpectedEOF,
163248
/// Propagate underlying errors from `std::io`.
@@ -1857,9 +1942,15 @@ fn read_avif_meta<T: Read + Offset>(
18571942
let item_infos = item_infos.ok_or(Error::InvalidData("iinf missing"))?;
18581943

18591944
if let Some(item_info) = item_infos.iter().find(|x| x.item_id == primary_item_id) {
1860-
if &item_info.item_type.to_be_bytes() != b"av01" {
1861-
warn!("primary_item_id type: {}", U32BE(item_info.item_type));
1862-
return Err(Error::InvalidData("primary_item_id type is not av01"));
1945+
debug!("primary_item_id type: {}", U32BE(item_info.item_type));
1946+
match &item_info.item_type.to_be_bytes() {
1947+
b"av01" => {}
1948+
b"grid" => return Err(Error::from(Status::UnsupportedGrid)),
1949+
_ => {
1950+
return Err(Error::InvalidData(
1951+
"primary_item_id type is neither 'av01' nor 'grid'",
1952+
))
1953+
}
18631954
}
18641955
} else {
18651956
return Err(Error::InvalidData(
@@ -1964,9 +2055,7 @@ fn read_infe<T: Read>(src: &mut BMFFBox<T>, strictness: ParseStrictness) -> Resu
19642055
let item_protection_index = be_u16(src)?;
19652056

19662057
if item_protection_index != 0 {
1967-
return Err(Error::Unsupported(
1968-
"protected items (infe.item_protection_index != 0) are not supported",
1969-
));
2058+
return Err(Error::from(Status::UnsupportedIpro));
19702059
}
19712060

19722061
let item_type = be_u32(src)?;
@@ -2109,6 +2198,9 @@ fn read_iprp<T: Read>(
21092198
| ItemProperty::Rotation(_) => {
21102199
if !a.essential {
21112200
warn!("{:?} is invalid", property);
2201+
// This is a "shall", but it is likely to change, so only
2202+
// fail if using strict parsing.
2203+
// See https://github.com/mozilla/mp4parse-rust/issues/284
21122204
fail_if(
21132205
strictness == ParseStrictness::Strict,
21142206
"All transformative properties associated with coded and \
@@ -2532,6 +2624,11 @@ fn read_ipma<T: Read>(
25322624

25332625
/// Parse an ItemPropertyContainerBox
25342626
///
2627+
/// For unsupported properties that we know about, return specific
2628+
/// [`Status`] UnsupportedXXXX variants. Unless running in
2629+
/// [`ParseStrictness::Permissive`] mode, in which case, unsupported properties
2630+
/// will be ignored.
2631+
///
25352632
/// See ISOBMFF (ISO 14496-12:2020 § 8.11.14.1
25362633
fn read_ipco<T: Read>(
25372634
src: &mut BMFFBox<T>,
@@ -2545,6 +2642,14 @@ fn read_ipco<T: Read>(
25452642
if let Some(property) = match b.head.name {
25462643
BoxType::AuxiliaryTypeProperty => Some(ItemProperty::AuxiliaryType(read_auxc(&mut b)?)),
25472644
BoxType::AV1CodecConfigurationBox => Some(ItemProperty::AV1Config(read_av1c(&mut b)?)),
2645+
BoxType::AV1LayeredImageIndexingProperty
2646+
if strictness != ParseStrictness::Permissive =>
2647+
{
2648+
return Err(Error::from(Status::UnsupportedA1lx))
2649+
}
2650+
BoxType::CleanApertureBox if strictness != ParseStrictness::Permissive => {
2651+
return Err(Error::from(Status::UnsupportedClap))
2652+
}
25482653
BoxType::ColourInformationBox => {
25492654
Some(ItemProperty::Colour(read_colr(&mut b, strictness)?))
25502655
}
@@ -2553,6 +2658,14 @@ fn read_ipco<T: Read>(
25532658
BoxType::ImageSpatialExtentsProperty => {
25542659
Some(ItemProperty::ImageSpatialExtents(read_ispe(&mut b)?))
25552660
}
2661+
BoxType::LayerSelectorProperty if strictness != ParseStrictness::Permissive => {
2662+
return Err(Error::from(Status::UnsupportedLsel))
2663+
}
2664+
BoxType::OperatingPointSelectorProperty
2665+
if strictness != ParseStrictness::Permissive =>
2666+
{
2667+
return Err(Error::from(Status::UnsupportedA1op))
2668+
}
25562669
BoxType::PixelInformationBox => Some(ItemProperty::Channels(read_pixi(&mut b)?)),
25572670
other_box_type => {
25582671
// Though we don't do anything with other property types, we still store
File renamed without changes.

0 commit comments

Comments
 (0)