Commit 49f76f93 authored by emericg's avatar emericg Committed by Jean-Baptiste Kempf
Browse files

Add support for GoPro HiLight tags as chapters


Signed-off-by: Jean-Baptiste Kempf's avatarJean-Baptiste Kempf <jb@videolan.org>
parent b269f60e
......@@ -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 },
......
......@@ -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' )
......@@ -1200,6 +1201,13 @@ typedef struct
} chapter[256];
} MP4_Box_data_chpl_t;
typedef struct
{
uint32_t i_chapter_count;
uint32_t *pi_chapter_start;
} MP4_Box_data_HMMT_t;
typedef struct
{
uint8_t i_version;
......@@ -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;
......
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment