[vlc-commits] demux: heif: add support for derived grid images

Francois Cartegnie git at videolan.org
Mon Nov 19 14:04:52 CET 2018


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Sun Nov 18 16:40:23 2018 +0100| [019f891e7d95e204560bf690696f7450eeaa2f3a] | committer: Francois Cartegnie

demux: heif: add support for derived grid images

Apple

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=019f891e7d95e204560bf690696f7450eeaa2f3a
---

 modules/demux/mp4/heif.c | 241 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 232 insertions(+), 9 deletions(-)

diff --git a/modules/demux/mp4/heif.c b/modules/demux/mp4/heif.c
index 842aa27f1d..e923bb3357 100644
--- a/modules/demux/mp4/heif.c
+++ b/modules/demux/mp4/heif.c
@@ -27,6 +27,7 @@
 #include <vlc_common.h>
 #include <vlc_demux.h>
 #include <vlc_input.h>
+#include <vlc_image.h>
 #include <assert.h>
 #include <limits.h>
 
@@ -452,6 +453,212 @@ static int SetupPicture( demux_t *p_demux, const MP4_Box_t *p_infe,
     return SetPictureProperties( p_demux, i_item_id, fmt, p_header );
 }
 
+union heif_derivation_data
+{
+    struct
+    {
+        uint8_t rows_minus_one;
+        uint8_t columns_minus_one;
+        uint32_t output_width;
+        uint32_t output_height;
+    } ImageGrid;
+};
+
+static int ReadDerivationData_Grid( const uint8_t *p_data, size_t i_data,
+                                    union heif_derivation_data *d )
+{
+    if( i_data < 8 || p_data[0] != 0x00 )
+        return VLC_EGENERIC;
+
+    uint8_t i_fieldlength = ((p_data[1] & 0x01) + 1) << 1;
+    /* length is either 2 or 4 bytes */
+    d->ImageGrid.rows_minus_one = p_data[2];
+    d->ImageGrid.columns_minus_one = p_data[3];
+    if(i_fieldlength == 2)
+    {
+        d->ImageGrid.output_width = GetWBE(&p_data[4]);
+        d->ImageGrid.output_height = GetWBE(&p_data[6]);
+    }
+    else
+    {
+        if(i_data < 12)
+            return VLC_EGENERIC;
+        d->ImageGrid.output_width = GetDWBE(&p_data[4]);
+        d->ImageGrid.output_height = GetDWBE(&p_data[8]);
+    }
+    return VLC_SUCCESS;
+}
+
+static int ReadDerivationData( demux_t *p_demux, vlc_fourcc_t type,
+                               uint32_t i_item_id,
+                               union heif_derivation_data *d )
+{
+    int i_ret = VLC_EGENERIC;
+    block_t *p_data = ReadItemExtents( p_demux, i_item_id, NULL );
+    if( p_data )
+    {
+        switch( type )
+        {
+            case VLC_FOURCC('g','r','i','d'):
+                i_ret = ReadDerivationData_Grid( p_data->p_buffer,
+                                                 p_data->i_buffer, d );
+                /* fallthrough */
+            default:
+                break;
+        }
+        block_Release( p_data );
+    }
+    return i_ret;
+}
+
+static int LoadGridImage( demux_t *p_demux, uint32_t i_pic_item_id,
+                               uint8_t *p_buffer,
+                               unsigned tile, unsigned gridcols,
+                               unsigned imagewidth, unsigned imageheight )
+{
+    struct heif_private_t *p_sys = (void *) p_demux->p_sys;
+
+    MP4_Box_t *p_infe = GetAtom( p_sys->p_root, NULL,
+                                 ATOM_infe, "meta/iinf/infe",
+                                 MatchInfeID, &i_pic_item_id );
+    if( !p_infe )
+        return VLC_EGENERIC;
+
+    es_format_t fmt;
+    es_format_Init(&fmt, UNKNOWN_ES, 0);
+
+    const MP4_Box_t *p_shared_header = NULL;
+    if( SetupPicture( p_demux, p_infe, &fmt, &p_shared_header ) != VLC_SUCCESS )
+    {
+        es_format_Clean( &fmt );
+        return VLC_EGENERIC; /* Unsupported picture, goto next */
+    }
+
+    block_t *p_sample = ReadItemExtents( p_demux, i_pic_item_id,
+                                         p_shared_header );
+    if(!p_sample)
+    {
+        es_format_Clean( &fmt );
+        return VLC_EGENERIC;
+    }
+
+    image_handler_t *handler = image_HandlerCreate( p_demux );
+    if (!handler)
+    {
+        block_Release( p_sample );
+        es_format_Clean( &fmt );
+        return VLC_EGENERIC;
+    }
+
+    video_format_t decoded;
+    video_format_Init( &decoded, VLC_CODEC_RGBA );
+
+    fmt.video.i_chroma = fmt.i_codec;
+    picture_t *p_picture = image_ReadExt( handler, p_sample, &fmt.video,
+                                          fmt.p_extra, fmt.i_extra, &decoded );
+    image_HandlerDelete( handler );
+
+    es_format_Clean( &fmt );
+
+    if ( !p_picture )
+        return VLC_EGENERIC;
+
+    const unsigned tilewidth = p_picture->format.i_visible_width;
+    const unsigned tileheight = p_picture->format.i_visible_height;
+    uint8_t *dstline = p_buffer;
+    dstline += (tile / gridcols) * (imagewidth * tileheight * 4);
+    for(;1;)
+    {
+        const unsigned offsetpxw = (tile % gridcols) * tilewidth;
+        const unsigned offsetpxh = (tile / gridcols) * tileheight;
+        if( offsetpxw > imagewidth )
+            break;
+        const uint8_t *srcline = p_picture->p[0].p_pixels;
+        unsigned tocopylines = p_picture->p[0].i_lines;
+        if(offsetpxh + tocopylines >= imageheight)
+            tocopylines = imageheight - offsetpxh;
+        for(unsigned i=0; i<tocopylines; i++)
+        {
+            size_t tocopypx = tilewidth;
+            if( offsetpxw + tilewidth > imagewidth )
+                tocopypx = imagewidth - offsetpxw;
+            memcpy( &dstline[offsetpxw * 4], srcline, tocopypx * 4 );
+            dstline += imagewidth * 4;
+            srcline += p_picture->p[0].i_pitch;
+        }
+
+        break;
+    }
+
+    picture_Release( p_picture );
+
+    return VLC_SUCCESS;
+}
+
+static int DerivedImageAssembleGrid( demux_t *p_demux, uint32_t i_grid_item_id,
+                                     es_format_t *fmt, block_t **pp_block )
+{
+    struct heif_private_t *p_sys = (void *) p_demux->p_sys;
+
+    const MP4_Box_t *p_iref = MP4_BoxGet( p_sys->p_root, "meta/iref" );
+    if(!p_iref)
+        return VLC_EGENERIC;
+
+    const MP4_Box_t *p_refbox;
+    for( p_refbox = p_iref->p_first; p_refbox; p_refbox = p_refbox->p_next )
+    {
+        if( p_refbox->i_type == VLC_FOURCC('d','i','m','g') &&
+            BOXDATA(p_refbox)->i_from_item_id == i_grid_item_id )
+            break;
+    }
+
+    if(!p_refbox)
+        return VLC_EGENERIC;
+
+    union heif_derivation_data derivation_data;
+    if( ReadDerivationData( p_demux,
+                            p_sys->current.BOXDATA(p_infe)->item_type,
+                            i_grid_item_id, &derivation_data ) != VLC_SUCCESS )
+        return VLC_EGENERIC;
+
+    msg_Dbg(p_demux,"%ux%upx image %ux%u tiles composition",
+            derivation_data.ImageGrid.output_width,
+            derivation_data.ImageGrid.output_height,
+            derivation_data.ImageGrid.columns_minus_one + 1,
+            derivation_data.ImageGrid.columns_minus_one + 1);
+
+    block_t *p_block = block_Alloc( derivation_data.ImageGrid.output_width *
+                                    derivation_data.ImageGrid.output_height * 4 );
+    if( !p_block )
+        return VLC_EGENERIC;
+    *pp_block = p_block;
+
+    es_format_Init( fmt, VIDEO_ES, VLC_CODEC_RGBA );
+    fmt->video.i_sar_num =
+    fmt->video.i_width =
+    fmt->video.i_visible_width = derivation_data.ImageGrid.output_width;
+    fmt->video.i_sar_den =
+    fmt->video.i_height =
+    fmt->video.i_visible_height = derivation_data.ImageGrid.output_height;
+
+    for( uint16_t i=0; i<BOXDATA(p_refbox)->i_reference_count; i++ )
+    {
+        msg_Dbg( p_demux, "Loading tile %d/%d", i,
+                 (derivation_data.ImageGrid.rows_minus_one + 1) *
+                 (derivation_data.ImageGrid.columns_minus_one + 1) );
+        LoadGridImage( p_demux,
+                       BOXDATA(p_refbox)->p_references[i].i_to_item_id,
+                       p_block->p_buffer, i,
+                       derivation_data.ImageGrid.columns_minus_one + 1,
+                       derivation_data.ImageGrid.output_width,
+                       derivation_data.ImageGrid.output_height );
+    }
+
+    SetPictureProperties( p_demux, i_grid_item_id, fmt, NULL );
+
+    return VLC_SUCCESS;
+}
+
 static int DemuxHEIF( demux_t *p_demux )
 {
     struct heif_private_t *p_sys = (void *) p_demux->p_sys;
@@ -501,11 +708,32 @@ static int DemuxHEIF( demux_t *p_demux )
     es_format_t fmt;
     es_format_Init(&fmt, UNKNOWN_ES, 0);
 
-    if( SetupPicture( p_demux, p_sys->current.p_infe,
-                      &fmt, &p_sys->current.p_shared_header ) != VLC_SUCCESS )
+    block_t *p_block = NULL;
+    if( p_sys->current.BOXDATA(p_infe)->item_type == VLC_FOURCC('g','r','i','d') )
     {
-        es_format_Clean( &fmt );
-        return VLC_DEMUXER_SUCCESS; /* Unsupported picture, goto next */
+        if( DerivedImageAssembleGrid( p_demux, i_current_item_id,
+                                      &fmt, &p_block ) != VLC_SUCCESS )
+        {
+            es_format_Clean( &fmt );
+            return VLC_DEMUXER_SUCCESS;
+        }
+    }
+    else
+    {
+        if( SetupPicture( p_demux, p_sys->current.p_infe,
+                          &fmt, &p_sys->current.p_shared_header ) != VLC_SUCCESS )
+        {
+            es_format_Clean( &fmt );
+            return VLC_DEMUXER_SUCCESS;
+        }
+
+        p_block = ReadItemExtents( p_demux, i_current_item_id,
+                                   p_sys->current.p_shared_header );
+        if( !p_block )
+        {
+            es_format_Clean( &fmt );
+            return VLC_DEMUXER_SUCCESS; /* Goto next picture */
+        }
     }
 
     es_format_Clean( &p_sys->current.fmt );
@@ -521,11 +749,6 @@ static int DemuxHEIF( demux_t *p_demux )
         return VLC_DEMUXER_SUCCESS;
     }
 
-    block_t *p_block = ReadItemExtents( p_demux, i_current_item_id,
-                                        p_sys->current.p_shared_header );
-    if( !p_block )
-        return VLC_DEMUXER_SUCCESS; /* Goto next picture */
-
     if( p_sys->i_pcr == VLC_TICK_INVALID )
     {
         p_sys->i_pcr = VLC_TICK_0;



More information about the vlc-commits mailing list