@@ -324,7 +324,7 @@ impl TryFrom<&ItemProperty> for Feature {
324324 ItemProperty :: Colour ( _) => Self :: Colr ,
325325 ItemProperty :: ImageSpatialExtents ( _) => Self :: Ispe ,
326326 ItemProperty :: LayeredImageIndexing => Self :: A1lx ,
327- ItemProperty :: LayerSelection => Self :: Lsel ,
327+ ItemProperty :: LayerSelection ( _ ) => Self :: Lsel ,
328328 ItemProperty :: Mirroring ( _) => Self :: Imir ,
329329 ItemProperty :: OperatingPointSelector => Self :: A1op ,
330330 ItemProperty :: PixelAspectRatio ( _) => Self :: Pasp ,
@@ -3024,6 +3024,14 @@ fn read_iprp<T: Read>(
30243024 let mut association_entries = TryVec :: < ItemPropertyAssociationEntry > :: new ( ) ;
30253025 let mut forbidden_items = TryVec :: new ( ) ;
30263026
3027+ // A LayerSelectorProperty with this layer_id enables, but does not require,
3028+ // progressive rendering: a client may render progressively or just show the
3029+ // final image (which is also what ignoring the property does), so no client
3030+ // can get this wrong. It therefore does not need to be treated as an
3031+ // unsupported essential property, and its item is accepted and processed.
3032+ // See <https://aomediacodec.github.io/av1-avif/#layer-selector-property>
3033+ const LSEL_LAYER_ID_NO_SELECTION : u16 = 0xffff ;
3034+
30273035 while let Some ( mut b) = iter. next_box ( ) ? {
30283036 if b. head . name != BoxType :: ItemPropertyAssociationBox {
30293037 return Status :: IprpBadChild . into ( ) ;
@@ -3089,16 +3097,25 @@ fn read_iprp<T: Read>(
30893097 assert ! ( brand == MIF1_BRAND ) ;
30903098
30913099 let feature = Feature :: try_from ( property) ;
3092- let property_supported = match feature {
3093- Ok ( feature) => {
3094- if feature. supported ( ) {
3095- true
3096- } else {
3097- unsupported_features. insert ( feature) ;
3098- false
3100+ let property_supported = if matches ! (
3101+ property,
3102+ ItemProperty :: LayerSelection ( layer_id)
3103+ if * layer_id == LSEL_LAYER_ID_NO_SELECTION
3104+ ) {
3105+ // Not an unsupported feature; see LSEL_LAYER_ID_NO_SELECTION.
3106+ true
3107+ } else {
3108+ match feature {
3109+ Ok ( feature) => {
3110+ if feature. supported ( ) {
3111+ true
3112+ } else {
3113+ unsupported_features. insert ( feature) ;
3114+ false
3115+ }
30993116 }
3117+ Err ( _) => false ,
31003118 }
3101- Err ( _) => false ,
31023119 } ;
31033120
31043121 if !property_supported {
@@ -3169,18 +3186,22 @@ fn read_iprp<T: Read>(
31693186 }
31703187 }
31713188
3172- ItemProperty :: LayerSelection => {
3173- assert ! ( feature. is_ok( ) && unsupported_features. contains( feature?) ) ;
3174- if a. essential {
3175- assert ! (
3176- forbidden_items. contains( & association_entry. item_id)
3177- || strictness == ParseStrictness :: Permissive
3178- ) ;
3179- } else {
3189+ ItemProperty :: LayerSelection ( layer_id) => {
3190+ if !a. essential {
3191+ // lsel shall be marked as essential regardless of its
3192+ // layer_id.
31803193 fail_with_status_if (
31813194 strictness != ParseStrictness :: Permissive ,
31823195 Status :: LselNoEssential ,
31833196 ) ?;
3197+ } else if * layer_id != LSEL_LAYER_ID_NO_SELECTION {
3198+ // A specific layer was requested; selecting a layer is
3199+ // unsupported, so the item shall not be processed.
3200+ assert ! ( feature. is_ok( ) && unsupported_features. contains( feature?) ) ;
3201+ assert ! (
3202+ forbidden_items. contains( & association_entry. item_id)
3203+ || strictness == ParseStrictness :: Permissive
3204+ ) ;
31843205 }
31853206 }
31863207
@@ -3266,7 +3287,7 @@ pub enum ItemProperty {
32663287 Colour ( ColourInformation ) ,
32673288 ImageSpatialExtents ( ImageSpatialExtentsProperty ) ,
32683289 LayeredImageIndexing ,
3269- LayerSelection ,
3290+ LayerSelection ( u16 ) ,
32703291 Mirroring ( ImageMirror ) ,
32713292 OperatingPointSelector ,
32723293 PixelAspectRatio ( PixelAspectRatio ) ,
@@ -3283,7 +3304,7 @@ impl From<&ItemProperty> for BoxType {
32833304 ItemProperty :: CleanAperture => BoxType :: CleanApertureBox ,
32843305 ItemProperty :: Colour ( _) => BoxType :: ColourInformationBox ,
32853306 ItemProperty :: LayeredImageIndexing => BoxType :: AV1LayeredImageIndexingProperty ,
3286- ItemProperty :: LayerSelection => BoxType :: LayerSelectorProperty ,
3307+ ItemProperty :: LayerSelection ( _ ) => BoxType :: LayerSelectorProperty ,
32873308 ItemProperty :: Mirroring ( _) => BoxType :: ImageMirror ,
32883309 ItemProperty :: OperatingPointSelector => BoxType :: OperatingPointSelectorProperty ,
32893310 ItemProperty :: PixelAspectRatio ( _) => BoxType :: PixelAspectRatioBox ,
@@ -3653,6 +3674,7 @@ fn read_ipco<T: Read>(
36533674 }
36543675 BoxType :: PixelAspectRatioBox => ItemProperty :: PixelAspectRatio ( read_pasp ( & mut b) ?) ,
36553676 BoxType :: PixelInformationBox => ItemProperty :: Channels ( read_pixi ( & mut b) ?) ,
3677+ BoxType :: LayerSelectorProperty => ItemProperty :: LayerSelection ( read_lsel ( & mut b) ?) ,
36563678
36573679 other_box_type => {
36583680 // Even if we didn't do anything with other property types, we still store
@@ -3661,7 +3683,6 @@ fn read_ipco<T: Read>(
36613683 let item_property = match other_box_type {
36623684 BoxType :: AV1LayeredImageIndexingProperty => ItemProperty :: LayeredImageIndexing ,
36633685 BoxType :: CleanApertureBox => ItemProperty :: CleanAperture ,
3664- BoxType :: LayerSelectorProperty => ItemProperty :: LayerSelection ,
36653686 BoxType :: OperatingPointSelectorProperty => ItemProperty :: OperatingPointSelector ,
36663687 _ => {
36673688 warn ! ( "No ItemProperty variant for {other_box_type:?}" ) ;
@@ -3687,6 +3708,14 @@ fn read_ipco<T: Read>(
36873708 Ok ( properties)
36883709}
36893710
3711+ /// Parse a LayerSelectorProperty, returning its layer_id.
3712+ ///
3713+ /// See <https://aomediacodec.github.io/av1-avif/#layer-selector-property>
3714+ fn read_lsel < T : Read > ( src : & mut BMFFBox < T > ) -> Result < u16 > {
3715+ let layer_id = be_u16 ( src) ?;
3716+ Ok ( layer_id)
3717+ }
3718+
36903719#[ repr( C ) ]
36913720#[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
36923721pub struct ImageSpatialExtentsProperty {
0 commit comments