vlc | branch: master | Emeric Grange <[email protected]> | Wed Jun 1 22:11:09 2016 +0200| [49f76f935a2de0e836feca10738b9cfa4936710a] | committer: Jean-Baptiste Kempf
Add support for GoPro HiLight tags as chapters Signed-off-by: Jean-Baptiste Kempf <[email protected]> > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=49f76f935a2de0e836feca10738b9cfa4936710a --- modules/demux/mp4/libmp4.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ modules/demux/mp4/libmp4.h | 9 ++++++++ modules/demux/mp4/mp4.c | 26 +++++++++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/modules/demux/mp4/libmp4.c b/modules/demux/mp4/libmp4.c index d049fa4..a411150 100644 --- a/modules/demux/mp4/libmp4.c +++ b/modules/demux/mp4/libmp4.c @@ -3378,6 +3378,55 @@ static int MP4_ReadBox_chpl( stream_t *p_stream, MP4_Box_t *p_box ) MP4_READBOX_EXIT( 1 ); } +/* GoPro HiLight tags support */ +static void MP4_FreeBox_HMMT( MP4_Box_t *p_box ) +{ + FREENULL( p_box->data.p_hmmt->pi_chapter_start ); +} + +static int MP4_ReadBox_HMMT( stream_t *p_stream, MP4_Box_t *p_box ) +{ +#define MAX_CHAPTER_COUNT 100 + + MP4_Box_data_HMMT_t *p_hmmt; + MP4_READBOX_ENTER( MP4_Box_data_HMMT_t, MP4_FreeBox_HMMT ); + + if( i_read < 4 ) + MP4_READBOX_EXIT( 0 ); + + p_hmmt = p_box->data.p_hmmt; + + MP4_GET4BYTES( p_hmmt->i_chapter_count ); + + if( p_hmmt->i_chapter_count <= 0 ) + { + p_hmmt->pi_chapter_start = NULL; + MP4_READBOX_EXIT( 1 ); + } + + if( ( i_read / sizeof(uint32_t) ) < p_hmmt->i_chapter_count ) + MP4_READBOX_EXIT( 0 ); + + /* Cameras are allowing a maximum of 100 tags */ + if( p_hmmt->i_chapter_count > MAX_CHAPTER_COUNT ) + p_hmmt->i_chapter_count = MAX_CHAPTER_COUNT; + + p_hmmt->pi_chapter_start = malloc( p_hmmt->i_chapter_count * sizeof(uint32_t) ); + if( p_hmmt->pi_chapter_start == NULL ) + MP4_READBOX_EXIT( 0 ); + + for( uint32_t i = 0; i < p_hmmt->i_chapter_count; i++ ) + { + MP4_GET4BYTES( p_hmmt->pi_chapter_start[i] ); + } + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream, "read box: \"HMMT\" %d HiLight tags", p_hmmt->i_chapter_count ); +#endif + + MP4_READBOX_EXIT( 1 ); +} + static void MP4_FreeBox_tref_generic( MP4_Box_t *p_box ) { FREENULL( p_box->data.p_tref_generic->i_track_ID ); @@ -4224,6 +4273,7 @@ static const struct { ATOM_name, MP4_ReadBox_String, ATOM_udta }, { ATOM_vndr, MP4_ReadBox_String, ATOM_udta }, { ATOM_SDLN, MP4_ReadBox_String, ATOM_udta }, + { ATOM_HMMT, MP4_ReadBox_HMMT, ATOM_udta }, /* GoPro HiLight tags */ /* udta, non meta */ { ATOM_tsel, MP4_ReadBox_tsel, ATOM_udta }, diff --git a/modules/demux/mp4/libmp4.h b/modules/demux/mp4/libmp4.h index 3e66350..9aff34c 100644 --- a/modules/demux/mp4/libmp4.h +++ b/modules/demux/mp4/libmp4.h @@ -331,6 +331,7 @@ typedef int64_t stime_t; #define ATOM_0xa9xyz VLC_FOURCC( 0xa9, 'x', 'y', 'z' ) #define ATOM_aART VLC_FOURCC( 'a', 'A', 'R', 'T' ) #define ATOM_chpl VLC_FOURCC( 'c', 'h', 'p', 'l' ) +#define ATOM_HMMT VLC_FOURCC( 'H', 'M', 'M', 'T' ) #define ATOM_disk VLC_FOURCC( 'd', 'i', 's', 'k' ) #define ATOM_WLOC VLC_FOURCC( 'W', 'L', 'O', 'C' ) @@ -1202,6 +1203,13 @@ typedef struct typedef struct { + uint32_t i_chapter_count; + uint32_t *pi_chapter_start; + +} MP4_Box_data_HMMT_t; + +typedef struct +{ uint8_t i_version; uint8_t i_profile; uint8_t i_profile_compatibility; @@ -1608,6 +1616,7 @@ typedef union MP4_Box_data_s MP4_Box_data_pnot_t *p_pnot; MP4_Box_data_chpl_t *p_chpl; + MP4_Box_data_HMMT_t *p_hmmt; MP4_Box_data_tref_generic_t *p_tref_generic; MP4_Box_data_tfrf_t *p_tfrf; diff --git a/modules/demux/mp4/mp4.c b/modules/demux/mp4/mp4.c index 0e71a9d..7fc7988 100644 --- a/modules/demux/mp4/mp4.c +++ b/modules/demux/mp4/mp4.c @@ -1813,6 +1813,26 @@ static void LoadChapterGpac( demux_t *p_demux, MP4_Box_t *p_chpl ) TAB_APPEND( p_sys->p_title->i_seekpoint, p_sys->p_title->seekpoint, s ); } } +static void LoadChapterGoPro( demux_t *p_demux, MP4_Box_t *p_hmmt ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + + p_sys->p_title = vlc_input_title_New(); + if( p_sys->p_title ) + for( unsigned i = 0; i < BOXDATA(p_hmmt)->i_chapter_count; i++ ) + { + seekpoint_t *s = vlc_seekpoint_New(); + if( s ) + { + if( asprintf( &s->psz_name, "HiLight tag #%u", i+1 ) != -1 ) + EnsureUTF8( s->psz_name ); + + /* HiLights are stored in ms so we convert them to µs */ + s->i_time_offset = BOXDATA(p_hmmt)->pi_chapter_start[i] * 1000; + TAB_APPEND( p_sys->p_title->i_seekpoint, p_sys->p_title->seekpoint, s ); + } + } +} static void LoadChapterApple( demux_t *p_demux, mp4_track_t *tk ) { demux_sys_t *p_sys = p_demux->p_sys; @@ -1856,12 +1876,18 @@ static void LoadChapter( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; MP4_Box_t *p_chpl; + MP4_Box_t *p_hmmt; if( ( p_chpl = MP4_BoxGet( p_sys->p_root, "/moov/udta/chpl" ) ) && BOXDATA(p_chpl) && BOXDATA(p_chpl)->i_chapter > 0 ) { LoadChapterGpac( p_demux, p_chpl ); } + else if( ( p_hmmt = MP4_BoxGet( p_sys->p_root, "/moov/udta/HMMT" ) ) && + BOXDATA(p_hmmt) && BOXDATA(p_hmmt)->pi_chapter_start && BOXDATA(p_hmmt)->i_chapter_count > 0 ) + { + LoadChapterGoPro( p_demux, p_hmmt ); + } else if( p_sys->p_tref_chap ) { MP4_Box_data_tref_generic_t *p_chap = p_sys->p_tref_chap->data.p_tref_generic; _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
