[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