[vlc-commits] codec: webvtt: render timed nodes
Francois Cartegnie
git at videolan.org
Wed Nov 1 15:38:30 CET 2017
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Wed Nov 1 14:19:36 2017 +0100| [bfa3cafdeca2449a0629e5f554ee66960963befb] | committer: Francois Cartegnie
codec: webvtt: render timed nodes
00:00:02.000 --> 00:00:05.000
V<00:00:03.000>L<00:00:04.000>C
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=bfa3cafdeca2449a0629e5f554ee66960963befb
---
modules/codec/webvtt/subsvtt.c | 104 ++++++++++++++++++++++++++++++++++++++---
1 file changed, 97 insertions(+), 7 deletions(-)
diff --git a/modules/codec/webvtt/subsvtt.c b/modules/codec/webvtt/subsvtt.c
index 2a9d0c14e3..3cf4e73acd 100644
--- a/modules/codec/webvtt/subsvtt.c
+++ b/modules/codec/webvtt/subsvtt.c
@@ -125,6 +125,7 @@ typedef struct
typedef struct
{
WEBVTT_NODE_BASE_MEMBERS
+ mtime_t i_start;
char *psz_tag;
char *psz_attrs;
webvtt_dom_node_t *p_child;
@@ -415,6 +416,7 @@ static webvtt_dom_tag_t * webvtt_dom_tag_New( webvtt_dom_node_t *p_parent )
webvtt_dom_tag_t *p_node = calloc( 1, sizeof(*p_node) );
if( p_node )
{
+ p_node->i_start = -1;
p_node->type = NODE_TAG;
p_node->p_parent = p_parent;
}
@@ -436,6 +438,26 @@ static webvtt_dom_node_t * webvtt_domnode_getParentByTag( webvtt_dom_node_t *p_p
return p_parent;
}
+static const webvtt_dom_node_t * webvtt_domnode_getFirstChild( const webvtt_dom_node_t *p_node )
+{
+ webvtt_dom_node_t *p_child = NULL;
+ switch( p_node->type )
+ {
+ case NODE_CUE:
+ p_child = ((webvtt_dom_cue_t *)p_node)->p_child;
+ break;
+ case NODE_REGION:
+ p_child = ((webvtt_region_t *)p_node)->p_child;
+ break;
+ case NODE_TAG:
+ p_child = ((webvtt_dom_tag_t *)p_node)->p_child;
+ break;
+ default:
+ break;
+ }
+ return p_child;
+}
+
static inline bool IsEndTag( const char *psz )
{
return psz[1] == '/';
@@ -788,6 +810,9 @@ static webvtt_dom_node_t * CreateDomNodes( const char *psz_text, unsigned *pi_li
p_node->psz_tag = strndup( psz_name, i_name );
if( psz_attrs != psz_taglast )
p_node->psz_attrs = strndup( psz_attrs, psz_taglast - psz_attrs );
+ /* <hh:mm::ss:fff> time tags */
+ if( p_node->psz_attrs && isdigit(p_node->psz_attrs[0]) )
+ (void) webvtt_scan_time( p_node->psz_attrs, &p_node->i_start );
*pp_append = (webvtt_dom_node_t *) p_node;
p_parent = (webvtt_dom_node_t *) p_node;
pp_append = &p_node->p_child;
@@ -914,7 +939,8 @@ struct render_variables_s
static text_segment_t *ConvertNodesToSegments( decoder_t *p_dec,
struct render_variables_s *p_vars,
const webvtt_dom_cue_t *p_cue,
- const webvtt_dom_node_t *p_node )
+ const webvtt_dom_node_t *p_node,
+ mtime_t i_start )
{
text_segment_t *p_head = NULL;
text_segment_t **pp_append = &p_head;
@@ -939,8 +965,10 @@ static text_segment_t *ConvertNodesToSegments( decoder_t *p_dec,
}
else if( p_node->type == NODE_TAG )
{
- *pp_append = ConvertNodesToSegments( p_dec, p_vars, p_cue,
- ((const webvtt_dom_tag_t *)p_node)->p_child );
+ const webvtt_dom_tag_t *p_tag = (const webvtt_dom_tag_t *)p_node;
+ if( p_tag->i_start <= i_start )
+ *pp_append = ConvertNodesToSegments( p_dec, p_vars, p_cue,
+ p_tag->p_child, i_start );
}
}
return p_head;
@@ -948,9 +976,10 @@ static text_segment_t *ConvertNodesToSegments( decoder_t *p_dec,
static text_segment_t *ConvertCueToSegments( decoder_t *p_dec,
struct render_variables_s *p_vars,
- const webvtt_dom_cue_t *p_cue )
+ const webvtt_dom_cue_t *p_cue,
+ mtime_t i_start )
{
- return ConvertNodesToSegments( p_dec, p_vars, p_cue, p_cue->p_child );
+ return ConvertNodesToSegments( p_dec, p_vars, p_cue, p_cue->p_child, i_start );
}
static text_segment_t * ConvertCuesToSegments( decoder_t *p_dec, mtime_t i_start, mtime_t i_stop,
@@ -970,7 +999,7 @@ static text_segment_t * ConvertCuesToSegments( decoder_t *p_dec, mtime_t i_start
if( p_cue->i_start > i_start || p_cue->i_stop <= i_start )
continue;
- text_segment_t *p_new = ConvertCueToSegments( p_dec, p_vars, p_cue );
+ text_segment_t *p_new = ConvertCueToSegments( p_dec, p_vars, p_cue, i_start );
if( p_new )
{
while( *pp_append )
@@ -989,6 +1018,32 @@ static text_segment_t * ConvertCuesToSegments( decoder_t *p_dec, mtime_t i_start
return p_segments;
}
+static void GetTimedTags( const webvtt_dom_node_t *p_node,
+ mtime_t i_start, mtime_t i_stop, vlc_array_t *p_times )
+{
+ for( ; p_node; p_node = p_node->p_next )
+ {
+ switch( p_node->type )
+ {
+ case NODE_TAG:
+ {
+ const webvtt_dom_tag_t *p_tag = (const webvtt_dom_tag_t *) p_node;
+ if( p_tag->i_start > -1 && p_tag->i_start >= i_start && p_tag->i_start < i_stop )
+ (void) vlc_array_append( p_times, (void *) p_tag );
+ GetTimedTags( p_tag->p_child, i_start, i_stop, p_times );
+ } break;
+ case NODE_REGION:
+ case NODE_CUE:
+ case NODE_VIDEO:
+ GetTimedTags( webvtt_domnode_getFirstChild( p_node ),
+ i_start, i_stop, p_times );
+ break;
+ default:
+ break;
+ }
+ }
+}
+
static void CreateSpuOrNewUpdaterRegion( decoder_t *p_dec,
subpicture_t **pp_spu,
subpicture_updater_sys_region_t **pp_updtregion )
@@ -1096,6 +1151,41 @@ static void RenderRegions( decoder_t *p_dec, mtime_t i_start, mtime_t i_stop )
}
}
+static int timedtagsArrayCmp( const void *a, const void *b )
+{
+ const webvtt_dom_tag_t *ta = *((const webvtt_dom_tag_t **) a);
+ const webvtt_dom_tag_t *tb = *((const webvtt_dom_tag_t **) b);
+ const int64_t result = ta->i_start - tb->i_start;
+ return result == 0 ? 0 : result > 0 ? 1 : -1;
+}
+
+static void Render( decoder_t *p_dec, mtime_t i_start, mtime_t i_stop )
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+
+ vlc_array_t timedtags;
+ vlc_array_init( &timedtags );
+
+ GetTimedTags( p_sys->p_root->p_child, i_start, i_stop, &timedtags );
+ qsort( timedtags.pp_elems, timedtags.i_count, sizeof(*timedtags.pp_elems), timedtagsArrayCmp );
+
+ mtime_t i_substart = i_start;
+ for( size_t i=0; i<timedtags.i_count; i++ )
+ {
+ const webvtt_dom_tag_t *p_tag =
+ (const webvtt_dom_tag_t *) vlc_array_item_at_index( &timedtags, i );
+ if( p_tag->i_start != i_substart ) /* might be duplicates */
+ {
+ RenderRegions( p_dec, i_substart, p_tag->i_start );
+ i_substart = p_tag->i_start;
+ }
+ }
+ if( i_substart != i_stop )
+ RenderRegions( p_dec, i_substart, i_stop );
+
+ vlc_array_clear( &timedtags );
+}
+
static int ProcessISOBMFF( decoder_t *p_dec,
const uint8_t *p_buffer, size_t i_buffer,
mtime_t i_start, mtime_t i_stop )
@@ -1240,7 +1330,7 @@ static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
ProcessISOBMFF( p_dec, p_block->p_buffer, p_block->i_buffer,
p_block->i_pts, p_block->i_pts + p_block->i_length );
- RenderRegions( p_dec, p_block->i_pts, p_block->i_pts + p_block->i_length );
+ Render( p_dec, p_block->i_pts, p_block->i_pts + p_block->i_length );
block_Release( p_block );
return VLCDEC_SUCCESS;
More information about the vlc-commits
mailing list