[vlc-commits] demux: mp4: rework attachments handling

Francois Cartegnie git at videolan.org
Wed Dec 4 18:51:50 CET 2019


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Mon Dec  2 19:21:39 2019 +0100| [405e6b1abc01e651600c1e1664f6e7b2b6816cab] | committer: Francois Cartegnie

demux: mp4: rework attachments handling

Splits code and ensures match between attachment
uri and atom index.
Cleans up the pnot stuff (not really testable)

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

 modules/demux/Makefile.am       |   1 +
 modules/demux/mp4/attachments.c | 269 ++++++++++++++++++++++++++++++++++++++++
 modules/demux/mp4/attachments.h |  29 +++++
 modules/demux/mp4/meta.c        |   2 +-
 modules/demux/mp4/mp4.c         | 177 ++------------------------
 modules/demux/mp4/mp4.h         |   2 +-
 6 files changed, 311 insertions(+), 169 deletions(-)

diff --git a/modules/demux/Makefile.am b/modules/demux/Makefile.am
index 091834efea..76ba9a6762 100644
--- a/modules/demux/Makefile.am
+++ b/modules/demux/Makefile.am
@@ -211,6 +211,7 @@ EXTRA_LTLIBRARIES += libmkv_plugin.la
 libmp4_plugin_la_SOURCES = demux/mp4/mp4.c demux/mp4/mp4.h \
                            demux/mp4/fragments.c demux/mp4/fragments.h \
                            demux/mp4/libmp4.c demux/mp4/libmp4.h \
+                           demux/mp4/attachments.c demux/mp4/attachments.h \
                            demux/mp4/languages.h \
                            demux/mp4/heif.c demux/mp4/heif.h \
                            demux/mp4/avci.h \
diff --git a/modules/demux/mp4/attachments.c b/modules/demux/mp4/attachments.c
new file mode 100644
index 0000000000..6ff926e185
--- /dev/null
+++ b/modules/demux/mp4/attachments.c
@@ -0,0 +1,269 @@
+/*****************************************************************************
+ * attachments.c : MP4 attachments handling
+ *****************************************************************************
+ * Copyright (C) 2001-2015 VLC authors and VideoLAN
+ *               2019 VideoLabs
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_input.h>
+
+#include "libmp4.h"
+#include "attachments.h"
+#include <limits.h>
+
+static const char *psz_meta_roots[] = { "/moov/udta/meta/ilst",
+                                        "/moov/meta/ilst",
+                                        "/moov/udta/meta",
+                                        "/moov/udta",
+                                        "/meta/ilst",
+                                        "/udta" };
+
+const MP4_Box_t *MP4_GetMetaRoot( const MP4_Box_t *p_root, const char **ppsz_path )
+{
+    for( size_t i = 0; i < ARRAY_SIZE(psz_meta_roots); i++ )
+    {
+        MP4_Box_t *p_udta = MP4_BoxGet( p_root, psz_meta_roots[i] );
+        if ( p_udta )
+        {
+            *ppsz_path = psz_meta_roots[i];
+            return p_udta;
+        }
+    }
+    return NULL;
+}
+
+static bool imageTypeCompatible( const MP4_Box_data_data_t *p_data )
+{
+    return p_data && (
+    p_data->e_wellknowntype == DATA_WKT_PNG ||
+    p_data->e_wellknowntype == DATA_WKT_JPEG ||
+    p_data->e_wellknowntype == DATA_WKT_BMP );
+}
+
+static const MP4_Box_t * GetValidCovrMeta( const MP4_Box_t *p_data,
+                                           unsigned *pi_index,
+                                           const void **ctx )
+{
+    for( ; p_data; p_data = p_data->p_next )
+    {
+        if( p_data->i_type != ATOM_data || p_data == *ctx )
+            continue;
+        (*pi_index)++;
+        if ( !imageTypeCompatible( BOXDATA(p_data) ) )
+            continue;
+        *ctx = p_data;
+        return p_data;
+    }
+    return NULL;
+}
+
+static const MP4_Box_t * GetValidPnotMeta( const MP4_Box_t *p_pnot,
+                                           unsigned *pi_index,
+                                           const void **ctx )
+{
+    for( ; p_pnot; p_pnot = p_pnot->p_next )
+    {
+        if( p_pnot->i_type != ATOM_pnot || p_pnot == *ctx )
+            continue;
+        (*pi_index)++;
+        if( BOXDATA(p_pnot)->i_type != ATOM_PICT &&
+            BOXDATA(p_pnot)->i_type != ATOM_pict )
+            continue;
+        *ctx = p_pnot;
+        return p_pnot;
+    }
+    return NULL;
+}
+
+int MP4_GetCoverMetaURI( const MP4_Box_t *p_root,
+                         const MP4_Box_t *p_metaroot,
+                         const char *psz_metapath,
+                         vlc_meta_t *p_meta )
+{
+    bool b_attachment_set = false;
+
+    if( !p_meta )
+        return VLC_EGENERIC;
+
+    if ( p_metaroot )
+    {
+        const MP4_Box_t *p_data = MP4_BoxGet( p_metaroot, "covr/data" );
+        unsigned i_index = 0;
+        const void *ctx = NULL;
+        if( (p_data = GetValidCovrMeta( p_data, &i_index, &ctx )) )
+        {
+            char *psz_attachment;
+            if ( -1 != asprintf( &psz_attachment,
+                                 "attachment://%s/covr/data[%u]",
+                                 psz_metapath, i_index - 1 ) )
+            {
+                vlc_meta_SetArtURL( p_meta, psz_attachment );
+                b_attachment_set = true;
+                free( psz_attachment );
+            }
+        }
+    }
+
+    const MP4_Box_t *p_pnot;
+    if ( !b_attachment_set && (p_pnot = MP4_BoxGet( p_root, "pnot" )) )
+    {
+        unsigned i_index = 0;
+        const void *ctx = NULL;
+        if( (p_pnot = GetValidPnotMeta( p_pnot, &i_index, &ctx )) )
+        {
+            char *psz_attachment;
+            if ( -1 != asprintf( &psz_attachment,
+                                 "attachment://pnot[%u]", i_index - 1 ) )
+            {
+                vlc_meta_SetArtURL( p_meta, psz_attachment );
+                b_attachment_set = true;
+                free( psz_attachment );
+            }
+        }
+    }
+
+    if( !b_attachment_set )
+        return VLC_EGENERIC;
+
+    return VLC_SUCCESS;
+}
+
+int MP4_GetAttachments( const MP4_Box_t *p_root, input_attachment_t ***ppp_attach )
+{
+    const MP4_Box_t *p_metaroot = NULL;
+    const char *psz_metarootpath;
+    unsigned i_count = 0;
+    input_attachment_t **pp_attach = NULL;
+    *ppp_attach = NULL;
+
+    /* Count MAX number of total attachments */
+    p_metaroot = MP4_GetMetaRoot( p_root, &psz_metarootpath );
+    if( p_metaroot )
+    {
+        unsigned i_covercount = MP4_BoxCount( p_metaroot, "covr/data" );
+        if( unlikely(i_covercount > INT_MAX - i_count) )
+            return 0;
+        i_count += i_covercount;
+    }
+
+    unsigned i_pictcount = MP4_BoxCount( p_root, "pnot" );
+    if( unlikely(i_pictcount > INT_MAX - i_count) )
+        return 0;
+    i_count += i_pictcount;
+
+    unsigned i_thmb_count = MP4_BoxCount( p_root, "thum" );
+    if( unlikely(i_thmb_count > INT_MAX - i_count) )
+        return 0;
+    i_count += i_thmb_count;
+
+    if ( i_count == 0 )
+        return 0;
+
+    pp_attach = vlc_alloc( i_count, sizeof(input_attachment_t*) );
+    if( !(pp_attach) )
+        return 0;
+
+    /* Create and add valid attachments */
+    i_count = 0;
+
+    /* First add cover attachments */
+    if ( p_metaroot )
+    {
+        const MP4_Box_t *p_data = MP4_BoxGet( p_metaroot, "covr/data" );
+        unsigned i_index = 0;
+        const void *ctx = NULL;
+        while( (p_data = GetValidCovrMeta( p_data, &i_index, &ctx )) )
+        {
+            char *psz_mime;
+            char *psz_filename;
+
+            switch( BOXDATA(p_data)->e_wellknowntype )
+            {
+            case DATA_WKT_PNG:
+                psz_mime = strdup( "image/png" );
+                break;
+            case DATA_WKT_JPEG:
+                psz_mime = strdup( "image/jpeg" );
+                break;
+            case DATA_WKT_BMP:
+                psz_mime = strdup( "image/bmp" );
+                break;
+            default:
+                psz_mime = NULL;
+                break;
+            }
+
+            if ( asprintf( &psz_filename, "%s/covr/data[%u]",
+                           psz_metarootpath,
+                           i_index - 1 ) > -1 )
+            {
+                input_attachment_t *p_attach =
+                    vlc_input_attachment_New(
+                            psz_filename,
+                            psz_mime,
+                            "Cover picture",
+                            BOXDATA(p_data)->p_blob,
+                            BOXDATA(p_data)->i_blob );
+                free( psz_filename );
+                if( p_attach )
+                    pp_attach[i_count++] = p_attach;
+            }
+
+            free( psz_mime );
+        }
+    }
+
+    /* Then quickdraw pict ones */
+    const MP4_Box_t *p_pnot = MP4_BoxGet( p_root, "pnot" );
+    if( p_pnot )
+    {
+        unsigned i_index = 0;
+        const void *ctx = NULL;
+        while( (p_pnot = GetValidPnotMeta( p_pnot, &i_index, &ctx )) )
+        {
+            char *psz_location;
+            if ( asprintf( &psz_location, "pnot[%u]", i_index - 1 ) > -1 )
+            {
+                input_attachment_t *p_attach =
+                        vlc_input_attachment_New(
+                            psz_location,
+                            "image/x-pict",
+                            "Quickdraw image",
+                            p_pnot->data.p_binary->p_blob,
+                            p_pnot->data.p_binary->i_blob );
+                free( psz_location );
+                if( p_attach )
+                    pp_attach[i_count++] = p_attach;
+            }
+        }
+    }
+
+    /* errors in adding attachments */
+    if ( i_count == 0 )
+    {
+        free( pp_attach );
+        return 0;
+    }
+
+    *ppp_attach = pp_attach;
+
+    return i_count;
+}
diff --git a/modules/demux/mp4/attachments.h b/modules/demux/mp4/attachments.h
new file mode 100644
index 0000000000..ee0eb771a7
--- /dev/null
+++ b/modules/demux/mp4/attachments.h
@@ -0,0 +1,29 @@
+/*****************************************************************************
+ * attachments.h : MP4 attachments handling
+ *****************************************************************************
+ * Copyright (C) 2001-2015 VLC authors and VideoLAN
+ *               2019 VideoLabs
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifndef VLC_MP4_ATTACHMENTS_H_
+#define VLC_MP4_ATTACHMENTS_H_
+
+int MP4_GetAttachments( const MP4_Box_t *, input_attachment_t *** );
+const MP4_Box_t *MP4_GetMetaRoot( const MP4_Box_t *, const char ** );
+int MP4_GetCoverMetaURI( const MP4_Box_t *,  const MP4_Box_t *,
+                         const char *, vlc_meta_t * );
+
+#endif
diff --git a/modules/demux/mp4/meta.c b/modules/demux/mp4/meta.c
index 3288549244..97799196f5 100644
--- a/modules/demux/mp4/meta.c
+++ b/modules/demux/mp4/meta.c
@@ -513,7 +513,7 @@ static void SetupID3v2Meta( vlc_meta_t *p_meta, MP4_Box_t *p_box )
                   ID3TAG_Parse_Handler, p_meta );
 }
 
-void SetupMeta( vlc_meta_t *p_meta, MP4_Box_t *p_udta )
+void SetupMeta( vlc_meta_t *p_meta, const MP4_Box_t *p_udta )
 {
     uint32_t i_handler = 0;
     if ( p_udta->p_father )
diff --git a/modules/demux/mp4/mp4.c b/modules/demux/mp4/mp4.c
index 3dc813ce2a..be9eee33fe 100644
--- a/modules/demux/mp4/mp4.c
+++ b/modules/demux/mp4/mp4.c
@@ -37,8 +37,9 @@
 #include <vlc_url.h>
 #include <assert.h>
 #include <limits.h>
-#include "../../codec/cc.h"
+#include "attachments.h"
 #include "heif.h"
+#include "../../codec/cc.h"
 #include "../av1_unpack.h"
 
 /*****************************************************************************
@@ -149,15 +150,6 @@ typedef struct
 #define VLC_DEMUXER_EOS (VLC_DEMUXER_EGENERIC - 1)
 #define VLC_DEMUXER_FATAL (VLC_DEMUXER_EGENERIC - 2)
 
-const uint32_t rgi_pict_atoms[2] = { ATOM_PICT, ATOM_pict };
-const char *psz_meta_roots[] = { "/moov/udta/meta/ilst",
-                                 "/moov/meta/ilst",
-                                 "/moov/udta/meta",
-                                 "/moov/udta",
-                                 "/meta/ilst",
-                                 "/udta",
-                                 NULL };
-
 /*****************************************************************************
  * Declaration of local function
  *****************************************************************************/
@@ -1932,65 +1924,18 @@ static int FragSeekToPos( demux_t *p_demux, double f, bool b_accurate )
                            MP4_rescale_mtime( i_duration, p_sys->i_timescale ) ), b_accurate );
 }
 
-static bool imageTypeCompatible( const MP4_Box_data_data_t *p_data )
-{
-    return p_data && (
-    p_data->e_wellknowntype == DATA_WKT_PNG ||
-    p_data->e_wellknowntype == DATA_WKT_JPEG ||
-    p_data->e_wellknowntype == DATA_WKT_BMP );
-}
-
 static int MP4_LoadMeta( demux_sys_t *p_sys, vlc_meta_t *p_meta )
 {
-    MP4_Box_t *p_data = NULL;
-    MP4_Box_t *p_udta = NULL;
-    bool b_attachment_set = false;
-
     if( !p_meta )
         return VLC_EGENERIC;
 
-    for( int i_index = 0; psz_meta_roots[i_index] && !p_udta; i_index++ )
-    {
-        p_udta = MP4_BoxGet( p_sys->p_root, psz_meta_roots[i_index] );
-        if ( p_udta )
-        {
-            p_data = MP4_BoxGet( p_udta, "covr/data" );
-            if ( p_data && imageTypeCompatible( BOXDATA(p_data) ) )
-            {
-                char *psz_attachment;
-                if ( -1 != asprintf( &psz_attachment, "attachment://%s/covr/data[0]",
-                                     psz_meta_roots[i_index] ) )
-                {
-                    vlc_meta_SetArtURL( p_meta, psz_attachment );
-                    b_attachment_set = true;
-                    free( psz_attachment );
-                }
-            }
-        }
-    }
+    const char *psz_metapath;
+    const MP4_Box_t *p_metaroot = MP4_GetMetaRoot( p_sys->p_root, &psz_metapath );
 
-    const MP4_Box_t *p_pnot;
-    if ( !b_attachment_set && (p_pnot = MP4_BoxGet( p_sys->p_root, "pnot" )) )
-    {
-        for ( size_t i=0; i< ARRAY_SIZE(rgi_pict_atoms) && !b_attachment_set; i++ )
-        {
-            if ( rgi_pict_atoms[i] == BOXDATA(p_pnot)->i_type )
-            {
-                char rgsz_path[26];
-                snprintf( rgsz_path, 26, "attachment://%4.4s[%"PRIu16"]",
-                          (char*)&rgi_pict_atoms[i], BOXDATA(p_pnot)->i_index - 1 );
-                vlc_meta_SetArtURL( p_meta, rgsz_path );
-                b_attachment_set = true;
-            }
-        }
-    }
+    MP4_GetCoverMetaURI( p_sys->p_root, p_metaroot, psz_metapath, p_meta );
 
-    if( p_udta == NULL )
-    {
-        if( !b_attachment_set )
-            return VLC_EGENERIC;
-    }
-    else SetupMeta( p_meta, p_udta );
+    if( p_metaroot )
+        SetupMeta( p_meta, p_metaroot );
 
     return VLC_SUCCESS;
 }
@@ -2075,111 +2020,9 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
             input_attachment_t ***ppp_attach = va_arg( args, input_attachment_t*** );
             int *pi_int = va_arg( args, int * );
 
-            MP4_Box_t *p_udta = NULL;
-            size_t i_count = 0;
-            int i_index = 0;
-
-            /* Count number of total attachments */
-            for( ; psz_meta_roots[i_index] && !p_udta; i_index++ )
-            {
-                p_udta = MP4_BoxGet( p_sys->p_root, psz_meta_roots[i_index] );
-                if ( p_udta )
-                    i_count += MP4_BoxCount( p_udta, "covr/data" );
-            }
-
-            for ( size_t i=0; i< ARRAY_SIZE(rgi_pict_atoms); i++ )
-            {
-                char rgsz_path[5];
-                snprintf( rgsz_path, 5, "%4.4s", (char*)&rgi_pict_atoms[i] );
-                i_count += MP4_BoxCount( p_sys->p_root, rgsz_path );
-            }
-
-            if ( i_count == 0 )
-                return VLC_EGENERIC;
-
-            *ppp_attach = (input_attachment_t**)
-                    vlc_alloc( i_count, sizeof(input_attachment_t*) );
-            if( !(*ppp_attach) ) return VLC_ENOMEM;
-
-            /* First add cover attachments */
-            i_count = 0;
-            size_t i_box_count = 0;
-            if ( p_udta )
-            {
-                const MP4_Box_t *p_data = MP4_BoxGet( p_udta, "covr/data" );
-                for( ; p_data; p_data = p_data->p_next )
-                {
-                    char *psz_mime;
-                    char *psz_filename;
-                    i_box_count++;
-
-                    if ( p_data->i_type != ATOM_data || !imageTypeCompatible( BOXDATA(p_data) ) )
-                        continue;
-
-                    switch( BOXDATA(p_data)->e_wellknowntype )
-                    {
-                    case DATA_WKT_PNG:
-                        psz_mime = strdup( "image/png" );
-                        break;
-                    case DATA_WKT_JPEG:
-                        psz_mime = strdup( "image/jpeg" );
-                        break;
-                    case DATA_WKT_BMP:
-                        psz_mime = strdup( "image/bmp" );
-                        break;
-                    default:
-                        continue;
-                    }
-
-                    if ( asprintf( &psz_filename, "%s/covr/data[%"PRIu64"]", psz_meta_roots[i_index - 1],
-                                   (uint64_t) i_box_count - 1 ) >= 0 )
-                    {
-                        (*ppp_attach)[i_count++] =
-                            vlc_input_attachment_New( psz_filename, psz_mime, "Cover picture",
-                                BOXDATA(p_data)->p_blob, BOXDATA(p_data)->i_blob );
-                        msg_Dbg( p_demux, "adding attachment %s", psz_filename );
-                        free( psz_filename );
-                    }
-
-                    free( psz_mime );
-                }
-            }
-
-            /* Then quickdraw pict ones */
-            for ( size_t i=0; i< ARRAY_SIZE(rgi_pict_atoms); i++ )
-            {
-                char rgsz_path[5];
-                snprintf( rgsz_path, 5, "%4.4s", (char*)&rgi_pict_atoms[i] );
-                const MP4_Box_t *p_pict = MP4_BoxGet( p_sys->p_root, rgsz_path );
-                i_box_count = 0;
-                for( ; p_pict; p_pict = p_pict->p_next )
-                {
-                    if ( i_box_count++ == UINT16_MAX ) /* pnot only handles 2^16 */
-                        break;
-                    if ( p_pict->i_type != rgi_pict_atoms[i] )
-                        continue;
-                    char rgsz_location[12];
-                    snprintf( rgsz_location, 12, "%4.4s[%"PRIu16"]", (char*)&rgi_pict_atoms[i],
-                              (uint16_t) i_box_count - 1 );
-                    (*ppp_attach)[i_count] = vlc_input_attachment_New( rgsz_location, "image/x-pict",
-                        "Quickdraw image", p_pict->data.p_binary->p_blob, p_pict->data.p_binary->i_blob );
-                    if ( !(*ppp_attach)[i_count] )
-                    {
-                        i_count = 0;
-                        break;
-                    }
-                    i_count++;
-                    msg_Dbg( p_demux, "adding attachment %s", rgsz_location );
-                }
-            }
-
-            if ( i_count == 0 )
-            {
-                free( *ppp_attach );
-                return VLC_EGENERIC;
-            }
-
-            *pi_int = i_count;
+            *pi_int = MP4_GetAttachments( p_sys->p_root, ppp_attach );
+            for( int i=0; i<*pi_int; i++ )
+                msg_Dbg( p_demux, "adding attachment %s", (*ppp_attach)[i]->psz_name );
 
             return VLC_SUCCESS;
         }
diff --git a/modules/demux/mp4/mp4.h b/modules/demux/mp4/mp4.h
index ca56ca3f99..90a9f70675 100644
--- a/modules/demux/mp4/mp4.h
+++ b/modules/demux/mp4/mp4.h
@@ -188,7 +188,7 @@ int SetupVideoES( demux_t *p_demux, mp4_track_t *p_track, MP4_Box_t *p_sample );
 int SetupAudioES( demux_t *p_demux, mp4_track_t *p_track, MP4_Box_t *p_sample );
 int SetupSpuES( demux_t *p_demux, mp4_track_t *p_track, MP4_Box_t *p_sample );
 int SetupCCES( demux_t *p_demux, mp4_track_t *p_track, MP4_Box_t *p_sample );
-void SetupMeta( vlc_meta_t *p_meta, MP4_Box_t *p_udta );
+void SetupMeta( vlc_meta_t *p_meta, const MP4_Box_t *p_udta );
 
 /* format of RTP reception hint track sample constructor */
 typedef struct



More information about the vlc-commits mailing list