[vlc-commits] [Git][videolan/vlc][master] 5 commits: codec: ttml: tag nodes with namespaces
Felix Paul Kühne (@fkuehne)
gitlab at videolan.org
Fri Mar 22 20:37:38 UTC 2024
Felix Paul Kühne pushed to branch master at VideoLAN / VLC
Commits:
18800af2 by François Cartegnie at 2024-03-22T20:15:27+00:00
codec: ttml: tag nodes with namespaces
- - - - -
d9a8494f by François Cartegnie at 2024-03-22T20:15:27+00:00
codec: ttml: add tt_node_match for namespaces
- - - - -
29759b71 by François Cartegnie at 2024-03-22T20:15:27+00:00
codec: ttml: add namespaces registry
- - - - -
a55c9e9a by François Cartegnie at 2024-03-22T20:15:27+00:00
codec: ttml add more namespaces defines
- - - - -
44879313 by François Cartegnie at 2024-03-22T20:15:27+00:00
codec/demux: ttml: handle non-default namespaces
- - - - -
5 changed files:
- modules/codec/ttml/encttml.c
- modules/codec/ttml/substtml.c
- modules/codec/ttml/ttml.c
- modules/codec/ttml/ttml.h
- modules/demux/ttml.c
Changes:
=====================================
modules/codec/ttml/encttml.c
=====================================
@@ -48,7 +48,7 @@ static void AddTextNode( tt_node_t *p_parent, const char *psz_text )
if( nl )
{
tt_subtextnode_New( p_parent, psz, nl - psz );
- tt_node_New( p_parent, "br" );
+ tt_node_New( p_parent, "br", NULL );
psz += nl - psz + 1;
if( *psz == '\0' )
break;
@@ -67,21 +67,21 @@ static block_t *Encode( encoder_t *p_enc, subpicture_t *p_spu )
if( p_spu == NULL )
return NULL;
- tt_node_t *p_root = tt_node_New( NULL, "tt" );
+ tt_node_t *p_root = tt_node_New( NULL, "tt", TT_NS );
if( !p_root )
return NULL;
tt_node_AddAttribute( p_root, "xmlns", TT_NS );
tt_node_AddAttribute( p_root, "xmlns:tts", TT_NS_STYLING );
- tt_node_t *p_body = tt_node_New( p_root, "body" );
+ tt_node_t *p_body = tt_node_New( p_root, "body", NULL );
if( !p_body )
{
tt_node_RecursiveDelete( p_root );
return NULL;
}
- tt_node_t *p_div = tt_node_New( p_body, "div" );
+ tt_node_t *p_div = tt_node_New( p_body, "div", NULL );
if( !p_div )
{
tt_node_RecursiveDelete( p_root );
@@ -96,7 +96,7 @@ static block_t *Encode( encoder_t *p_enc, subpicture_t *p_spu )
p_region->p_text->psz_text == NULL )
continue;
- tt_node_t *p_par = tt_node_New( p_div, "p" );
+ tt_node_t *p_par = tt_node_New( p_div, "p", NULL );
if( !p_par )
continue;
@@ -117,7 +117,7 @@ static block_t *Encode( encoder_t *p_enc, subpicture_t *p_spu )
const text_style_t *style = p_segment->style;
if( style && style->i_features )
{
- tt_node_t *p_span = tt_node_New( p_par, "span" );
+ tt_node_t *p_span = tt_node_New( p_par, "span", NULL );
if( !p_span )
continue;
=====================================
modules/codec/ttml/substtml.c
=====================================
@@ -124,7 +124,8 @@ enum
* Then we convert attributes, merging with style by id or region
* style, and sets from parent node.
*/
-static tt_node_t *ParseTTML( decoder_t *, const uint8_t *, size_t );
+static tt_node_t *ParseTTML( decoder_t *, tt_namespaces_t *,
+ const uint8_t *, size_t );
static void ttml_style_Delete( ttml_style_t* p_ttml_style )
{
@@ -280,16 +281,17 @@ static bool ttml_read_coords( const char *value, ttml_length_t *h, ttml_length_t
return false;
}
-static tt_node_t * FindNode( tt_node_t *p_node, const char *psz_nodename,
+static tt_node_t * FindNode( tt_namespaces_t *p_nss, tt_node_t *p_node,
+ const char *psz_nodename, const char *psz_namespace,
size_t i_maxdepth, const char *psz_id )
{
- if( !tt_node_NameCompare( p_node->psz_node_name, psz_nodename ) )
+ if( tt_node_Match( p_node, psz_nodename, psz_namespace ) )
{
if( psz_id != NULL )
{
- char *psz = vlc_dictionary_value_for_key( &p_node->attr_dict, "xml:id" );
+ const char *psz = tt_node_GetAttribute( p_nss, p_node, "id", TT_NS_XML );
if( !psz ) /* People can't do xml properly */
- psz = vlc_dictionary_value_for_key( &p_node->attr_dict, "id" );
+ psz = tt_node_GetAttribute( p_nss, p_node, "id", NULL );
if( psz && !strcmp( psz, psz_id ) )
return p_node;
}
@@ -305,7 +307,9 @@ static tt_node_t * FindNode( tt_node_t *p_node, const char *psz_nodename,
if( p_child->i_type == TT_NODE_TYPE_TEXT )
continue;
- p_node = FindNode( (tt_node_t *) p_child, psz_nodename, i_maxdepth - 1, psz_id );
+ p_node = FindNode( p_nss, (tt_node_t *) p_child,
+ psz_nodename, psz_namespace,
+ i_maxdepth - 1, psz_id );
if( p_node )
return p_node;
}
@@ -316,25 +320,25 @@ static tt_node_t * FindNode( tt_node_t *p_node, const char *psz_nodename,
static void FillTextStyle( const char *psz_attr, const char *psz_val,
text_style_t *p_text_style )
{
- if( !strcasecmp ( "tts:fontFamily", psz_attr ) )
+ if( !strcasecmp ( "fontFamily", psz_attr ) )
{
free( p_text_style->psz_fontname );
p_text_style->psz_fontname = strdup( psz_val );
}
- else if( !strcasecmp( "tts:opacity", psz_attr ) )
+ else if( !strcasecmp( "opacity", psz_attr ) )
{
p_text_style->i_background_alpha = atoi( psz_val );
p_text_style->i_font_alpha = atoi( psz_val );
p_text_style->i_features |= STYLE_HAS_BACKGROUND_ALPHA | STYLE_HAS_FONT_ALPHA;
}
- else if( !strcasecmp( "tts:color", psz_attr ) )
+ else if( !strcasecmp( "color", psz_attr ) )
{
unsigned int i_color = vlc_html_color( psz_val, NULL );
p_text_style->i_font_color = (i_color & 0xffffff);
p_text_style->i_font_alpha = (i_color & 0xFF000000) >> 24;
p_text_style->i_features |= STYLE_HAS_FONT_COLOR | STYLE_HAS_FONT_ALPHA;
}
- else if( !strcasecmp( "tts:backgroundColor", psz_attr ) )
+ else if( !strcasecmp( "backgroundColor", psz_attr ) )
{
unsigned int i_color = vlc_html_color( psz_val, NULL );
p_text_style->i_background_color = i_color & 0xFFFFFF;
@@ -343,7 +347,7 @@ static void FillTextStyle( const char *psz_attr, const char *psz_val,
| STYLE_HAS_BACKGROUND_ALPHA;
p_text_style->i_style_flags |= STYLE_BACKGROUND;
}
- else if( !strcasecmp( "tts:fontStyle", psz_attr ) )
+ else if( !strcasecmp( "fontStyle", psz_attr ) )
{
if( !strcasecmp ( "italic", psz_val ) || !strcasecmp ( "oblique", psz_val ) )
p_text_style->i_style_flags |= STYLE_ITALIC;
@@ -351,7 +355,7 @@ static void FillTextStyle( const char *psz_attr, const char *psz_val,
p_text_style->i_style_flags &= ~STYLE_ITALIC;
p_text_style->i_features |= STYLE_HAS_FLAGS;
}
- else if( !strcasecmp ( "tts:fontWeight", psz_attr ) )
+ else if( !strcasecmp ( "fontWeight", psz_attr ) )
{
if( !strcasecmp ( "bold", psz_val ) )
p_text_style->i_style_flags |= STYLE_BOLD;
@@ -359,7 +363,7 @@ static void FillTextStyle( const char *psz_attr, const char *psz_val,
p_text_style->i_style_flags &= ~STYLE_BOLD;
p_text_style->i_features |= STYLE_HAS_FLAGS;
}
- else if( !strcasecmp ( "tts:textDecoration", psz_attr ) )
+ else if( !strcasecmp ( "textDecoration", psz_attr ) )
{
if( !strcasecmp ( "underline", psz_val ) )
p_text_style->i_style_flags |= STYLE_UNDERLINE;
@@ -371,7 +375,7 @@ static void FillTextStyle( const char *psz_attr, const char *psz_val,
p_text_style->i_style_flags &= ~STYLE_STRIKEOUT;
p_text_style->i_features |= STYLE_HAS_FLAGS;
}
- else if( !strcasecmp( "tts:textOutline", psz_attr ) )
+ else if( !strcasecmp( "textOutline", psz_attr ) )
{
char *value = strdup( psz_val );
char* psz_saveptr = NULL;
@@ -433,10 +437,13 @@ static void FillUpdaterCoords( ttml_context_t *p_ctx, ttml_length_t h, ttml_leng
}
static void FillRegionStyle( ttml_context_t *p_ctx,
- const char *psz_attr, const char *psz_val,
- ttml_region_t *p_region )
+ const char *psz_attr, const char *psz_namespace,
+ const char *psz_val, ttml_region_t *p_region )
{
- if( !strcasecmp( "tts:displayAlign", psz_attr ) )
+ if( strcmp( psz_namespace, TT_NS_STYLING ) )
+ return;
+
+ if( !strcasecmp( "displayAlign", psz_attr ) )
{
p_region->updt.inner_align &= ~(SUBPICTURE_ALIGN_TOP|SUBPICTURE_ALIGN_BOTTOM);
if( !strcasecmp( "after", psz_val ) )
@@ -445,12 +452,12 @@ static void FillRegionStyle( ttml_context_t *p_ctx,
/* "before" */
p_region->updt.inner_align |= SUBPICTURE_ALIGN_TOP;
}
- else if( !strcasecmp ( "tts:origin", psz_attr ) ||
- !strcasecmp ( "tts:extent", psz_attr ) )
+ else if( !strcasecmp ( "origin", psz_attr ) ||
+ !strcasecmp ( "extent", psz_attr ) )
{
ttml_length_t x, y;
if( ttml_read_coords( psz_val, &x, &y ) )
- FillUpdaterCoords( p_ctx, x, y, (psz_attr[4] == 'o'), &p_region->updt );
+ FillUpdaterCoords( p_ctx, x, y, (psz_attr[0] == 'o'), &p_region->updt );
}
}
@@ -483,20 +490,30 @@ static void ComputeTTMLStyles( ttml_context_t *p_ctx, const vlc_dictionary_t *p_
p_text_style->i_font_size = len.i_value;
}
-static void FillTTMLStyle( const char *psz_attr, const char *psz_val,
- ttml_style_t *p_ttml_style )
+static void FillTTMLStyle( const char *psz_attr, const char *psz_namespace,
+ const char *psz_val, ttml_style_t *p_ttml_style )
{
- if( !strcasecmp( "tts:extent", psz_attr ) )
+ if( !strcmp( psz_namespace, TT_NS_XML ) )
+ {
+ if( !strcasecmp( "space", psz_attr ) )
+ p_ttml_style->b_preserve_space = !strcmp( "preserve", psz_val );
+ return;
+ }
+
+ if( strcmp( psz_namespace, TT_NS_STYLING ) )
+ return;
+
+ if( !strcasecmp( "extent", psz_attr ) )
{
ttml_read_coords( psz_val, &p_ttml_style->extent_h,
&p_ttml_style->extent_v );
}
- else if( !strcasecmp( "tts:origin", psz_attr ) )
+ else if( !strcasecmp( "origin", psz_attr ) )
{
ttml_read_coords( psz_val, &p_ttml_style->origin_h,
&p_ttml_style->origin_v );
}
- else if( !strcasecmp( "tts:textAlign", psz_attr ) )
+ else if( !strcasecmp( "textAlign", psz_attr ) )
{
p_ttml_style->i_text_align &= ~(SUBPICTURE_ALIGN_LEFT|SUBPICTURE_ALIGN_RIGHT);
if( !strcasecmp ( "left", psz_val ) )
@@ -513,13 +530,13 @@ static void FillTTMLStyle( const char *psz_attr, const char *psz_val,
printf("**%s %x\n", psz_val, p_ttml_style->i_text_align);
#endif
}
- else if( !strcasecmp( "tts:fontSize", psz_attr ) )
+ else if( !strcasecmp( "fontSize", psz_attr ) )
{
ttml_length_t len = ttml_read_length( psz_val );
if( len.unit != TTML_UNIT_UNKNOWN && len.i_value > 0.0 )
p_ttml_style->font_size = len;
}
- else if( !strcasecmp( "tts:direction", psz_attr ) )
+ else if( !strcasecmp( "direction", psz_attr ) )
{
if( !strcasecmp( "rtl", psz_val ) )
{
@@ -532,14 +549,14 @@ static void FillTTMLStyle( const char *psz_attr, const char *psz_val,
p_ttml_style->b_direction_set = true;
}
}
- else if( !strcasecmp( "tts:unicodeBidi", psz_attr ) )
+ else if( !strcasecmp( "unicodeBidi", psz_attr ) )
{
if( !strcasecmp( "bidiOverride", psz_val ) )
p_ttml_style->i_direction |= UNICODE_BIDI_OVERRIDE & ~UNICODE_BIDI_EMBEDDED;
else if( !strcasecmp( "embed", psz_val ) )
p_ttml_style->i_direction |= UNICODE_BIDI_EMBEDDED & ~UNICODE_BIDI_OVERRIDE;
}
- else if( !strcasecmp( "tts:writingMode", psz_attr ) )
+ else if( !strcasecmp( "writingMode", psz_attr ) )
{
if( !strcasecmp( "rl", psz_val ) || !strcasecmp( "rltb", psz_val ) )
{
@@ -554,17 +571,13 @@ static void FillTTMLStyle( const char *psz_attr, const char *psz_val,
p_ttml_style->b_direction_set = true;
}
}
- else if( !strcmp( "tts:display", psz_attr ) )
+ else if( !strcmp( "display", psz_attr ) )
{
if( !strcmp( "none", psz_val ) )
p_ttml_style->display = TTML_DISPLAY_NONE;
else
p_ttml_style->display = TTML_DISPLAY_AUTO;
}
- else if( !strcasecmp( "xml:space", psz_attr ) )
- {
- p_ttml_style->b_preserve_space = !strcmp( "preserve", psz_val );
- }
else FillTextStyle( psz_attr, psz_val, p_ttml_style->font_style );
}
@@ -576,27 +589,22 @@ static void DictionaryMerge( const vlc_dictionary_t *p_src, vlc_dictionary_t *p_
for ( const vlc_dictionary_entry_t* p_entry = p_src->p_entries[i];
p_entry != NULL; p_entry = p_entry->p_next )
{
- if( !strncmp( "tts:", p_entry->psz_key, 4 ) ||
- !strncmp( "ttp:", p_entry->psz_key, 4 ) ||
- !strcmp( "xml:space", p_entry->psz_key ) )
+ if( vlc_dictionary_has_key( p_dst, p_entry->psz_key ) )
{
- if( vlc_dictionary_has_key( p_dst, p_entry->psz_key ) )
+ if( b_override )
{
- if( b_override )
- {
- vlc_dictionary_remove_value_for_key( p_dst, p_entry->psz_key, NULL, NULL );
- vlc_dictionary_insert( p_dst, p_entry->psz_key, p_entry->p_value );
- }
- }
- else
+ vlc_dictionary_remove_value_for_key( p_dst, p_entry->psz_key, NULL, NULL );
vlc_dictionary_insert( p_dst, p_entry->psz_key, p_entry->p_value );
+ }
}
+ else
+ vlc_dictionary_insert( p_dst, p_entry->psz_key, p_entry->p_value );
}
}
}
-static void DictMergeWithStyleID( ttml_context_t *p_ctx, const char *psz_styles,
- vlc_dictionary_t *p_dst )
+static void DictMergeWithStyleID( ttml_context_t *p_ctx, tt_namespaces_t *p_nss,
+ const char *psz_styles, vlc_dictionary_t *p_dst )
{
assert(p_ctx->p_rootnode);
char *psz_dup;
@@ -612,8 +620,10 @@ static void DictMergeWithStyleID( ttml_context_t *p_ctx, const char *psz_styles,
while( psz_id )
{
/* Lookup referenced style ID */
- const tt_node_t *p_node = FindNode( p_ctx->p_rootnode,
- "style", -1, psz_id );
+ const tt_node_t *p_node = FindNode( p_nss,
+ p_ctx->p_rootnode,
+ "style", TT_NS,
+ -1, psz_id );
if( p_node )
DictionaryMerge( &p_node->attr_dict, &tempdict, true );
@@ -628,23 +638,25 @@ static void DictMergeWithStyleID( ttml_context_t *p_ctx, const char *psz_styles,
}
}
-static void DictMergeWithRegionID( ttml_context_t *p_ctx, const char *psz_id,
- vlc_dictionary_t *p_dst )
+static void DictMergeWithRegionID( ttml_context_t *p_ctx, tt_namespaces_t *p_nss,
+ const char *psz_id, vlc_dictionary_t *p_dst )
{
assert(p_ctx->p_rootnode);
if( psz_id && p_ctx->p_rootnode )
{
- const tt_node_t *p_regionnode = FindNode( p_ctx->p_rootnode,
- "region", -1, psz_id );
+ const tt_node_t *p_regionnode = FindNode( p_nss,
+ p_ctx->p_rootnode,
+ "region", TT_NS,
+ -1, psz_id );
if( !p_regionnode )
return;
DictionaryMerge( &p_regionnode->attr_dict, p_dst, false );
- const char *psz_styleid = (const char *)
- vlc_dictionary_value_for_key( &p_regionnode->attr_dict, "style" );
+ const char *psz_styleid =
+ tt_node_GetAttribute( p_nss, p_regionnode, "style", NULL );
if( psz_styleid )
- DictMergeWithStyleID( p_ctx, psz_styleid, p_dst );
+ DictMergeWithStyleID( p_ctx, p_nss, psz_styleid, p_dst );
for( const tt_basenode_t *p_child = p_regionnode->p_child;
p_child; p_child = p_child->p_next )
@@ -653,7 +665,7 @@ static void DictMergeWithRegionID( ttml_context_t *p_ctx, const char *psz_id,
continue;
const tt_node_t *p_node = (const tt_node_t *) p_child;
- if( !tt_node_NameCompare( p_node->psz_node_name, "style" ) )
+ if( tt_node_Match( p_node, "style", TT_NS ) )
{
DictionaryMerge( &p_node->attr_dict, p_dst, false );
}
@@ -661,7 +673,8 @@ static void DictMergeWithRegionID( ttml_context_t *p_ctx, const char *psz_id,
}
}
-static void DictToTTMLStyle( ttml_context_t *p_ctx, const vlc_dictionary_t *p_dict,
+static void DictToTTMLStyle( ttml_context_t *p_ctx, tt_namespaces_t *p_nss,
+ const vlc_dictionary_t *p_dict,
ttml_style_t *p_ttml_style )
{
for( int i = 0; i < p_dict->i_size; ++i )
@@ -669,13 +682,18 @@ static void DictToTTMLStyle( ttml_context_t *p_ctx, const vlc_dictionary_t *p_di
for ( vlc_dictionary_entry_t* p_entry = p_dict->p_entries[i];
p_entry != NULL; p_entry = p_entry->p_next )
{
- FillTTMLStyle( p_entry->psz_key, p_entry->p_value, p_ttml_style );
+ const char *psz_namespace = tt_namespaces_GetURI( p_nss, p_entry->psz_key );
+ if( !psz_namespace )
+ continue;
+ const char *psz_name = tt_LocalName( p_entry->psz_key );
+ FillTTMLStyle( psz_name, psz_namespace, p_entry->p_value, p_ttml_style );
}
}
ComputeTTMLStyles( p_ctx, p_dict, p_ttml_style );
}
-static ttml_style_t * InheritTTMLStyles( ttml_context_t *p_ctx, tt_node_t *p_node )
+static ttml_style_t * InheritTTMLStyles( ttml_context_t *p_ctx, tt_namespaces_t *p_nss,
+ tt_node_t *p_node )
{
assert( p_node );
ttml_style_t *p_ttml_style = NULL;
@@ -687,20 +705,18 @@ static ttml_style_t * InheritTTMLStyles( ttml_context_t *p_ctx, tt_node_t *p_nod
{
DictionaryMerge( &p_node->attr_dict, &merged, false );
- const char *psz_styleid = (const char *)
- vlc_dictionary_value_for_key( &p_node->attr_dict, "style" );
+ const char *psz_styleid = tt_node_GetAttribute( p_nss, p_node, "style", NULL );
if( psz_styleid )
- DictMergeWithStyleID( p_ctx, psz_styleid, &merged );
+ DictMergeWithStyleID( p_ctx, p_nss, psz_styleid, &merged );
- const char *psz_regionid = (const char *)
- vlc_dictionary_value_for_key( &p_node->attr_dict, "region" );
+ const char *psz_regionid = tt_node_GetAttribute( p_nss, p_node, "region", NULL );
if( psz_regionid )
- DictMergeWithRegionID( p_ctx, psz_regionid, &merged );
+ DictMergeWithRegionID( p_ctx, p_nss, psz_regionid, &merged );
}
if( !vlc_dictionary_is_empty( &merged ) && (p_ttml_style = ttml_style_New()) )
{
- DictToTTMLStyle( p_ctx, &merged, p_ttml_style );
+ DictToTTMLStyle( p_ctx, p_nss, &merged, p_ttml_style );
}
vlc_dictionary_clear( &merged, NULL, NULL );
@@ -708,13 +724,14 @@ static ttml_style_t * InheritTTMLStyles( ttml_context_t *p_ctx, tt_node_t *p_nod
return p_ttml_style;
}
-static int ParseTTMLChunk( xml_reader_t *p_reader, tt_node_t **pp_rootnode )
+static int ParseTTMLChunk( xml_reader_t *p_reader, tt_namespaces_t *p_nss,
+ tt_node_t **pp_rootnode )
{
- const char* psz_node_name;
+ const char *psz_node_name, *psz_node_namespace;
do
{
- int i_type = xml_ReaderNextNode( p_reader, &psz_node_name );
+ int i_type = xml_ReaderNextNodeNS( p_reader, &psz_node_name, &psz_node_namespace );
if( i_type <= XML_READER_NONE )
break;
@@ -725,19 +742,20 @@ static int ParseTTMLChunk( xml_reader_t *p_reader, tt_node_t **pp_rootnode )
break;
case XML_READER_STARTELEM:
- if( tt_node_NameCompare( psz_node_name, "tt" ) ||
+ if( strcmp( psz_node_namespace, TT_NS ) ||
+ strcmp( tt_LocalName( psz_node_name ), "tt" ) ||
*pp_rootnode != NULL )
return VLC_EGENERIC;
-
- *pp_rootnode = tt_node_NewRead( p_reader, NULL, psz_node_name );
+ *pp_rootnode = tt_node_NewRead( p_reader, p_nss, NULL,
+ psz_node_name, psz_node_namespace );
if( !*pp_rootnode ||
- tt_nodes_Read( p_reader, *pp_rootnode ) != VLC_SUCCESS )
+ tt_nodes_Read( p_reader, p_nss, *pp_rootnode ) != VLC_SUCCESS )
return VLC_EGENERIC;
break;
case XML_READER_ENDELEM:
if( !*pp_rootnode ||
- tt_node_NameCompare( psz_node_name, (*pp_rootnode)->psz_node_name ) )
+ strcmp( psz_node_name, (*pp_rootnode)->psz_node_name ) )
return VLC_EGENERIC;
break;
}
@@ -791,7 +809,8 @@ static void StripSpacing( text_segment_t *p_segment )
*p = ' ';
}
-static ttml_region_t *GetTTMLRegion( ttml_context_t *p_ctx, const char *psz_region_id )
+static ttml_region_t *GetTTMLRegion( ttml_context_t *p_ctx, tt_namespaces_t *p_nss,
+ const char *psz_region_id )
{
ttml_region_t *p_region = ( ttml_region_t * )
vlc_dictionary_value_for_key( &p_ctx->regions, psz_region_id ? psz_region_id : "" );
@@ -804,7 +823,7 @@ static ttml_region_t *GetTTMLRegion( ttml_context_t *p_ctx, const char *psz_regi
vlc_dictionary_t merged;
vlc_dictionary_init( &merged, 0 );
/* Get all attributes, including region > style */
- DictMergeWithRegionID( p_ctx, psz_region_id, &merged );
+ DictMergeWithRegionID( p_ctx, p_nss, psz_region_id, &merged );
if( (p_region = ttml_region_New( false )) )
{
/* Fill from its own attributes */
@@ -813,8 +832,12 @@ static ttml_region_t *GetTTMLRegion( ttml_context_t *p_ctx, const char *psz_regi
for ( vlc_dictionary_entry_t* p_entry = merged.p_entries[i];
p_entry != NULL; p_entry = p_entry->p_next )
{
- FillRegionStyle( p_ctx, p_entry->psz_key, p_entry->p_value,
- p_region );
+ const char *psz_namespace = tt_namespaces_GetURI( p_nss, p_entry->psz_key );
+ if( !psz_namespace )
+ continue;
+ const char *psz_name = tt_LocalName( p_entry->psz_key );
+ FillRegionStyle( p_ctx, psz_name, psz_namespace,
+ p_entry->p_value, p_region );
}
}
}
@@ -840,7 +863,8 @@ static void AppendLineBreakToRegion( ttml_region_t *p_region )
}
}
-static void AppendTextToRegion( ttml_context_t *p_ctx, const tt_textnode_t *p_ttnode,
+static void AppendTextToRegion( ttml_context_t *p_ctx, tt_namespaces_t *p_nss,
+ const tt_textnode_t *p_ttnode,
const ttml_style_t *p_set_styles, ttml_region_t *p_region )
{
text_segment_t *p_segment;
@@ -852,7 +876,7 @@ static void AppendTextToRegion( ttml_context_t *p_ctx, const tt_textnode_t *p_tt
if( p_segment )
{
bool b_preserve_space = false;
- ttml_style_t *s = InheritTTMLStyles( p_ctx, p_ttnode->p_parent );
+ ttml_style_t *s = InheritTTMLStyles( p_ctx, p_nss, p_ttnode->p_parent );
if( s )
{
if( p_set_styles )
@@ -899,12 +923,13 @@ static void AppendTextToRegion( ttml_context_t *p_ctx, const tt_textnode_t *p_tt
p_region->pp_last_segment = &p_segment->p_next;
}
-static const char * GetSMPTEImage( ttml_context_t *p_ctx, const char *psz_id )
+static const char * GetSMPTEImage( ttml_context_t *p_ctx, tt_namespaces_t *p_nss,
+ const char *psz_id )
{
if( !p_ctx->p_rootnode )
return NULL;
- tt_node_t *p_head = FindNode( p_ctx->p_rootnode, "head", 1, NULL );
+ tt_node_t *p_head = FindNode( p_nss, p_ctx->p_rootnode, "head", TT_NS, 1, NULL );
if( !p_head )
return NULL;
@@ -915,10 +940,11 @@ static const char * GetSMPTEImage( ttml_context_t *p_ctx, const char *psz_id )
continue;
tt_node_t *p_node = (tt_node_t *) p_child;
- if( tt_node_NameCompare( p_node->psz_node_name, "metadata" ) )
+ if( !tt_node_Match( p_node, "metadata", TT_NS ) )
continue;
- tt_node_t *p_imagenode = FindNode( p_node, "smpte:image", 1, psz_id );
+ tt_node_t *p_imagenode = FindNode( p_nss, p_node, "image", TT_NS_SMPTE_TT_EXT,
+ 1, psz_id );
if( !p_imagenode )
continue;
@@ -935,7 +961,8 @@ static const char * GetSMPTEImage( ttml_context_t *p_ctx, const char *psz_id )
return NULL;
}
-static void ConvertNodesToRegionContent( ttml_context_t *p_ctx, const tt_node_t *p_node,
+static void ConvertNodesToRegionContent( ttml_context_t *p_ctx, tt_namespaces_t *p_nss,
+ const tt_node_t *p_node,
ttml_region_t *p_region,
const ttml_style_t *p_upper_set_styles,
tt_time_t playbacktime )
@@ -944,34 +971,29 @@ static void ConvertNodesToRegionContent( ttml_context_t *p_ctx, const tt_node_t
!tt_timings_Contains( &p_node->timings, &playbacktime ) )
return;
- const char *psz_regionid = (const char *)
- vlc_dictionary_value_for_key( &p_node->attr_dict, "region" );
+ const char *psz_regionid = tt_node_GetAttribute( p_nss, p_node, "region", NULL );
/* Region isn't set or is changing */
if( psz_regionid || p_region == NULL )
- p_region = GetTTMLRegion( p_ctx, psz_regionid );
+ p_region = GetTTMLRegion( p_ctx, p_nss, psz_regionid );
/* Check for bitmap profile defined by ST2052 / SMPTE-TT */
- if( !tt_node_NameCompare( p_node->psz_node_name, "div" ) &&
- vlc_dictionary_has_key( &p_node->attr_dict, "smpte:backgroundImage" ) )
+ if( tt_node_Match( p_node, "div", TT_NS ) )
{
- if( !p_region->bgbitmap.p_bytes )
+ const char *psz_id = tt_node_GetAttribute( p_nss, p_node, "backgroundImage",
+ TT_NS_SMPTE_TT_EXT );
+ if( !p_region->bgbitmap.p_bytes && psz_id && *psz_id == '#' )
{
- const char *psz_id = vlc_dictionary_value_for_key( &p_node->attr_dict,
- "smpte:backgroundImage" );
/* Seems SMPTE can't make diff between html and xml.. */
- if( psz_id && *psz_id == '#' )
- {
- const char *psz_base64 = GetSMPTEImage( p_ctx, &psz_id[1] );
- if( psz_base64 )
- p_region->bgbitmap.i_bytes =
- vlc_b64_decode_binary( &p_region->bgbitmap.p_bytes, psz_base64 );
- }
+ const char *psz_base64 = GetSMPTEImage( p_ctx, p_nss, &psz_id[1] );
+ if( psz_base64 )
+ p_region->bgbitmap.i_bytes =
+ vlc_b64_decode_binary( &p_region->bgbitmap.p_bytes, psz_base64 );
}
}
/* awkward paragraph handling */
- if( !tt_node_NameCompare( p_node->psz_node_name, "p" ) &&
+ if( tt_node_Match( p_node, "p", TT_NS ) &&
p_region->updt.p_segments )
{
AppendLineBreakToRegion( p_region );
@@ -987,10 +1009,10 @@ static void ConvertNodesToRegionContent( ttml_context_t *p_ctx, const tt_node_t
{
if( p_child->i_type == TT_NODE_TYPE_TEXT )
{
- AppendTextToRegion( p_ctx, (const tt_textnode_t *) p_child,
+ AppendTextToRegion( p_ctx, p_nss, (const tt_textnode_t *) p_child,
p_set_styles, p_region );
}
- else if( !tt_node_NameCompare( ((const tt_node_t *)p_child)->psz_node_name, "set" ) )
+ else if( tt_node_Match( (const tt_node_t *)p_child, "set", TT_NS ) )
{
const tt_node_t *p_set = (const tt_node_t *)p_child;
if( !tt_time_Valid( &playbacktime ) ||
@@ -999,17 +1021,17 @@ static void ConvertNodesToRegionContent( ttml_context_t *p_ctx, const tt_node_t
if( p_set_styles != NULL || (p_set_styles = ttml_style_New()) )
{
/* Merge with or create a local set of styles to apply to following childs */
- DictToTTMLStyle( p_ctx, &p_set->attr_dict, p_set_styles );
+ DictToTTMLStyle( p_ctx, p_nss, &p_set->attr_dict, p_set_styles );
}
}
}
- else if( !tt_node_NameCompare( ((const tt_node_t *)p_child)->psz_node_name, "br" ) )
+ else if( tt_node_Match( (const tt_node_t *)p_child, "br", TT_NS ) )
{
AppendLineBreakToRegion( p_region );
}
else
{
- ConvertNodesToRegionContent( p_ctx, (const tt_node_t *) p_child,
+ ConvertNodesToRegionContent( p_ctx, p_nss, (const tt_node_t *) p_child,
p_region, p_set_styles, playbacktime );
}
}
@@ -1018,7 +1040,8 @@ static void ConvertNodesToRegionContent( ttml_context_t *p_ctx, const tt_node_t
ttml_style_Delete( p_set_styles );
}
-static tt_node_t *ParseTTML( decoder_t *p_dec, const uint8_t *p_buffer, size_t i_buffer )
+static tt_node_t *ParseTTML( decoder_t *p_dec, tt_namespaces_t *p_nss,
+ const uint8_t *p_buffer, size_t i_buffer )
{
stream_t* p_sub;
xml_reader_t* p_xml_reader;
@@ -1035,7 +1058,7 @@ static tt_node_t *ParseTTML( decoder_t *p_dec, const uint8_t *p_buffer, size_t i
}
tt_node_t *p_rootnode = NULL;
- if( ParseTTMLChunk( p_xml_reader, &p_rootnode ) != VLC_SUCCESS )
+ if( ParseTTMLChunk( p_xml_reader, p_nss, &p_rootnode ) != VLC_SUCCESS )
{
if( p_rootnode )
tt_node_RecursiveDelete( p_rootnode );
@@ -1048,7 +1071,8 @@ static tt_node_t *ParseTTML( decoder_t *p_dec, const uint8_t *p_buffer, size_t i
return p_rootnode;
}
-static void InitTTMLContext( tt_node_t *p_rootnode, ttml_context_t *p_ctx )
+static void InitTTMLContext( tt_namespaces_t *p_nss, tt_node_t *p_rootnode,
+ ttml_context_t *p_ctx )
{
p_ctx->p_rootnode = p_rootnode;
/* set defaults required for size/cells computation */
@@ -1059,16 +1083,14 @@ static void InitTTMLContext( tt_node_t *p_rootnode, ttml_context_t *p_ctx )
p_ctx->i_cell_resolution_v = TTML_DEFAULT_CELL_RESOLUTION_V;
p_ctx->i_cell_resolution_h = TTML_DEFAULT_CELL_RESOLUTION_H;
/* and override them */
- const char *value = vlc_dictionary_value_for_key( &p_rootnode->attr_dict,
- "tts:extent" );
- if( value != kVLCDictionaryNotFound )
+ const char *value = tt_node_GetAttribute( p_nss, p_rootnode, "extent", TT_NS_STYLING );
+ if( value )
{
ttml_read_coords( value, &p_ctx->root_extent_h,
&p_ctx->root_extent_v );
}
- value = vlc_dictionary_value_for_key( &p_rootnode->attr_dict,
- "ttp:cellResolution" );
- if( value != kVLCDictionaryNotFound )
+ value = tt_node_GetAttribute( p_nss, p_rootnode, "cellResolution", TT_NS_PARAMETER );
+ if( value )
{
unsigned w, h;
if( sscanf( value, "%u %u", &w, &h) == 2 && w && h )
@@ -1079,22 +1101,23 @@ static void InitTTMLContext( tt_node_t *p_rootnode, ttml_context_t *p_ctx )
}
}
-static ttml_region_t *GenerateRegions( tt_node_t *p_rootnode, tt_time_t playbacktime )
+static ttml_region_t *GenerateRegions( tt_namespaces_t *p_nss, tt_node_t *p_rootnode,
+ tt_time_t playbacktime )
{
ttml_region_t* p_regions = NULL;
ttml_region_t** pp_region_last = &p_regions;
- if( !tt_node_NameCompare( p_rootnode->psz_node_name, "tt" ) )
+ if( tt_node_Match( p_rootnode, "tt", TT_NS ) )
{
- const tt_node_t *p_bodynode = FindNode( p_rootnode, "body", 1, NULL );
+ const tt_node_t *p_bodynode = FindNode( p_nss, p_rootnode, "body", TT_NS, 1, NULL );
if( p_bodynode )
{
ttml_context_t context;
- InitTTMLContext( p_rootnode, &context );
+ InitTTMLContext( p_nss, p_rootnode, &context );
context.p_rootnode = p_rootnode;
vlc_dictionary_init( &context.regions, 1 );
- ConvertNodesToRegionContent( &context, p_bodynode, NULL, NULL, playbacktime );
+ ConvertNodesToRegionContent( &context, p_nss, p_bodynode, NULL, NULL, playbacktime );
for( int i = 0; i < context.regions.i_size; ++i )
{
@@ -1109,8 +1132,8 @@ static ttml_region_t *GenerateRegions( tt_node_t *p_rootnode, tt_time_t playback
vlc_dictionary_clear( &context.regions, NULL, NULL );
}
}
- else if ( !tt_node_NameCompare( p_rootnode->psz_node_name, "div" ) ||
- !tt_node_NameCompare( p_rootnode->psz_node_name, "p" ) )
+ else if ( tt_node_Match( p_rootnode, "div", TT_NS ) ||
+ tt_node_Match( p_rootnode, "p", TT_NS ) )
{
/* TODO */
}
@@ -1314,9 +1337,14 @@ static int ParseBlock( decoder_t *p_dec, const block_t *p_block )
return VLCDEC_SUCCESS;
}
- tt_node_t *p_rootnode = ParseTTML( p_dec, p_block->p_buffer, p_block->i_buffer );
+ tt_namespaces_t namespaces;
+ tt_namespaces_Init( &namespaces );
+ tt_node_t *p_rootnode = ParseTTML( p_dec, &namespaces, p_block->p_buffer, p_block->i_buffer );
if( !p_rootnode )
+ {
+ tt_namespaces_Clean( &namespaces );
return VLCDEC_SUCCESS;
+ }
tt_timings_Resolve( (tt_basenode_t *) p_rootnode, &temporal_extent,
&p_timings_array, &i_timings_count );
@@ -1346,7 +1374,7 @@ static int ParseBlock( decoder_t *p_dec, const block_t *p_block )
bool b_bitmap_regions = false;
subpicture_t *p_spu = NULL;
- ttml_region_t *p_regions = GenerateRegions( p_rootnode, p_timings_array[i] );
+ ttml_region_t *p_regions = GenerateRegions( &namespaces, p_rootnode, p_timings_array[i] );
if( p_regions )
{
if( p_regions->bgbitmap.i_bytes > 0 && p_regions->updt.p_segments == NULL )
@@ -1388,6 +1416,7 @@ static int ParseBlock( decoder_t *p_dec, const block_t *p_block )
}
tt_node_RecursiveDelete( p_rootnode );
+ tt_namespaces_Clean( &namespaces );
free( p_timings_array );
=====================================
modules/codec/ttml/ttml.c
=====================================
@@ -65,12 +65,134 @@ vlc_module_begin ()
#endif
vlc_module_end ()
+struct tt_namespace_s
+{
+ char *psz_prefix;
+ char *psz_uri;
+ struct vlc_list links;
+};
-int tt_node_NameCompare( const char* psz_tagname, const char* psz_pattern )
+void tt_namespaces_Clean( tt_namespaces_t *nss )
{
- if( !strncasecmp( "tt:", psz_tagname, 3 ) )
- psz_tagname += 3;
- return strcasecmp( psz_tagname, psz_pattern );
+ struct tt_namespace_s *ns;
+ vlc_list_foreach( ns, &nss->nodes, links )
+ {
+ free( ns->psz_prefix );
+ free( ns->psz_uri );
+ free( ns );
+ }
+}
+
+void tt_namespaces_Init( tt_namespaces_t *nss )
+{
+ vlc_list_init( &nss->nodes );
+}
+
+const char * tt_namespaces_GetURI( const tt_namespaces_t *nss,
+ const char *psz_qn )
+{
+ const struct tt_namespace_s *ns;
+ vlc_list_foreach_const( ns, &nss->nodes, links )
+ {
+ /* compares prefixed name against raw prefix */
+ for( size_t i=0; ; i++ )
+ {
+ if( ns->psz_prefix[i] == psz_qn[i] )
+ {
+ if( psz_qn[i] == '\0' )
+ return ns->psz_uri;
+ }
+ else
+ {
+ if( ns->psz_prefix[i] == '\0' && psz_qn[i] == ':' )
+ return ns->psz_uri;
+ else
+ break;
+ }
+ }
+ }
+ return NULL;
+}
+
+const char * tt_namespaces_GetPrefix( const tt_namespaces_t *nss,
+ const char *psz_uri )
+{
+ const struct tt_namespace_s *ns;
+ vlc_list_foreach_const( ns, &nss->nodes, links )
+ {
+ if( !strcmp( ns->psz_uri, psz_uri ) )
+ return ns->psz_prefix;
+ }
+ return NULL;
+}
+
+void tt_namespaces_Register( tt_namespaces_t *nss, const char *psz_prefix,
+ const char *psz_uri )
+{
+ if( tt_namespaces_GetPrefix( nss, psz_uri ) )
+ return;
+ struct tt_namespace_s *ns = malloc(sizeof(*ns));
+ if( ns )
+ {
+ const char *sep = strchr( psz_prefix, ':' );
+ if( sep )
+ ns->psz_prefix = strndup( psz_prefix, sep - psz_prefix );
+ else
+ ns->psz_prefix = strdup("");
+ ns->psz_uri = strdup( psz_uri );
+ if( !ns->psz_prefix || !ns->psz_uri )
+ {
+ free( ns->psz_prefix );
+ free( ns->psz_uri );
+ free( ns );
+ return;
+ }
+ vlc_list_append( &ns->links, &nss->nodes );
+ }
+}
+
+static const char * tt_node_InheritNS( const tt_node_t *p_node )
+{
+ for( ; p_node ; p_node = p_node->p_parent )
+ {
+ if( p_node->psz_namespace )
+ return p_node->psz_namespace;
+ }
+ return NULL;
+}
+
+bool tt_node_Match( const tt_node_t *p_node, const char *psz_name, const char *psz_namespace )
+{
+ /* compare local part first (should have less chars) */
+ const char *psz_nodelocal = tt_LocalName( p_node->psz_node_name );
+ const char *psz_namelocal = tt_LocalName( psz_name );
+ if( strcmp( psz_namelocal, psz_nodelocal ) )
+ return false;
+
+ const char *psz_nodens = p_node->psz_namespace;
+ if( !psz_nodens )
+ psz_nodens = tt_node_InheritNS( p_node->p_parent );
+ if( psz_namespace && psz_nodens )
+ return !strcmp( psz_namespace, psz_nodens );
+ return !!psz_namespace == !!psz_nodens;
+}
+
+const char * tt_node_GetAttribute( tt_namespaces_t *p_nss, const tt_node_t *p_node,
+ const char *psz_name, const char *psz_namespace )
+{
+ const void *value;
+ char *alloc = NULL;
+ if( psz_namespace )
+ {
+ const char *psz_prefix = tt_namespaces_GetPrefix( p_nss, psz_namespace );
+ if( psz_prefix == NULL ||
+ asprintf( &alloc, "%s:%s", psz_prefix, psz_name ) < 1 )
+ return NULL;
+ psz_name = alloc;
+ }
+ value = vlc_dictionary_value_for_key( &p_node->attr_dict, psz_name );
+ free( alloc );
+ return value != kVLCDictionaryNotFound ? (const char *)value : NULL;
}
bool tt_node_HasChild( const tt_node_t *p_node )
@@ -171,6 +293,7 @@ static void tt_node_FreeDictValue( void* p_value, void* p_obj )
static void tt_node_Delete( tt_node_t *p_node )
{
free( p_node->psz_node_name );
+ free( p_node->psz_namespace );
vlc_dictionary_clear( &p_node->attr_dict, tt_node_FreeDictValue, NULL );
free( p_node );
}
@@ -240,7 +363,9 @@ tt_textnode_t *tt_subtextnode_New( tt_node_t *p_parent, const char *psz_text, si
return tt_textnode_NewImpl( p_parent, strndup( psz_text, len ) );
}
-tt_node_t * tt_node_New( tt_node_t* p_parent, const char* psz_node_name )
+tt_node_t * tt_node_New( tt_node_t* p_parent,
+ const char* psz_node_name,
+ const char *psz_namespace )
{
tt_node_t *p_node = calloc( 1, sizeof( *p_node ) );
if( !p_node )
@@ -248,6 +373,13 @@ tt_node_t * tt_node_New( tt_node_t* p_parent, const char* psz_node_name )
p_node->i_type = TT_NODE_TYPE_ELEMENT;
p_node->psz_node_name = strdup( psz_node_name );
+ const char *psz_parent_ns = tt_node_InheritNS( p_parent );
+ /* set new namespace if not same as parent */
+ if( psz_namespace &&
+ (!psz_parent_ns || strcmp( psz_namespace, psz_parent_ns )) )
+ p_node->psz_namespace = strdup( psz_namespace );
+ else
+ p_node->psz_namespace = NULL;
if( unlikely( p_node->psz_node_name == NULL ) )
{
free( p_node );
@@ -264,17 +396,21 @@ tt_node_t * tt_node_New( tt_node_t* p_parent, const char* psz_node_name )
return p_node;
}
-tt_node_t * tt_node_NewRead( xml_reader_t* reader, tt_node_t* p_parent, const char* psz_node_name )
+tt_node_t * tt_node_NewRead( xml_reader_t* reader,
+ tt_namespaces_t *p_nss, tt_node_t* p_parent,
+ const char* psz_node_name, const char *psz_namespace )
{
- tt_node_t *p_node = tt_node_New( p_parent, psz_node_name );
+ tt_node_t *p_node = tt_node_New( p_parent, psz_node_name, psz_namespace );
if( !p_node )
return NULL;
- const char* psz_value = NULL;
- for( const char* psz_key = xml_ReaderNextAttr( reader, &psz_value );
+ const char* psz_value = NULL, *psz_ns = NULL;
+ for( const char* psz_key = xml_ReaderNextAttrNS( reader, &psz_value, &psz_ns );
psz_key != NULL;
- psz_key = xml_ReaderNextAttr( reader, &psz_value ) )
+ psz_key = xml_ReaderNextAttrNS( reader, &psz_value, &psz_ns ) )
{
+ if( psz_ns && psz_key )
+ tt_namespaces_Register( p_nss, psz_key, psz_ns );
char *psz_val = strdup( psz_value );
if( psz_val )
{
@@ -351,15 +487,15 @@ static int tt_node_Skip( xml_reader_t *p_reader, const char *psz_skipped )
return VLC_EGENERIC;
}
#endif
-int tt_nodes_Read( xml_reader_t *p_reader, tt_node_t *p_root_node )
+int tt_nodes_Read( xml_reader_t *p_reader, tt_namespaces_t *p_nss, tt_node_t *p_root_node )
{
size_t i_depth = 0;
tt_node_t *p_node = p_root_node;
do
{
- const char* psz_node_name;
- int i_type = xml_ReaderNextNode( p_reader, &psz_node_name );
+ const char *psz_node_name, *psz_node_namespace;
+ int i_type = xml_ReaderNextNodeNS( p_reader, &psz_node_name, &psz_node_namespace );
/* !warn read empty state now as attributes reading will **** it up */
bool b_empty = xml_ReaderIsEmptyElement( p_reader );
@@ -373,7 +509,10 @@ int tt_nodes_Read( xml_reader_t *p_reader, tt_node_t *p_root_node )
case XML_READER_STARTELEM:
{
- tt_node_t *p_newnode = tt_node_NewRead( p_reader, p_node, psz_node_name );
+ tt_namespaces_Register( p_nss, psz_node_name, psz_node_namespace );
+ tt_node_t *p_newnode = tt_node_NewRead( p_reader, p_nss, p_node,
+ psz_node_name,
+ psz_node_namespace );
if( !p_newnode )
return VLC_EGENERIC;
if( !b_empty )
@@ -393,7 +532,7 @@ int tt_nodes_Read( xml_reader_t *p_reader, tt_node_t *p_root_node )
case XML_READER_ENDELEM:
{
- if( strcmp( psz_node_name, p_node->psz_node_name ) )
+ if( !tt_node_Match( p_node, psz_node_name, psz_node_namespace ) )
return VLC_EGENERIC;
if( i_depth == 0 )
=====================================
modules/codec/ttml/ttml.h
=====================================
@@ -21,6 +21,7 @@
#include <vlc_tick.h>
#include <vlc_arrays.h>
#include <vlc_memstream.h>
+#include <vlc_list.h>
int tt_OpenDemux( vlc_object_t* p_this );
void tt_CloseDemux( vlc_object_t* p_demux );
@@ -67,6 +68,22 @@ struct tt_searchkey
#define TT_NS_PROFILE TT_NS "/profile/"
#define TT_NS_FEATURE TT_NS "/feature/"
#define TT_NS_EXTENSION TT_NS "/extension/"
+#define TT_NS_XML "http://www.w3.org/XML/1998/namespace"
+#define TT_NS_SMPTE_TT_EXT "http://www.smpte-ra.org/schemas/2052-1/2010/smpte-tt"
+
+typedef struct
+{
+ struct vlc_list nodes;
+} tt_namespaces_t;
+
+void tt_namespaces_Init( tt_namespaces_t *nss );
+void tt_namespaces_Clean( tt_namespaces_t *nss );
+void tt_namespaces_Register( tt_namespaces_t *nss, const char *psz_prefix,
+ const char *psz_uri );
+const char * tt_namespaces_GetURI( const tt_namespaces_t *nss,
+ const char *psz_qn ); /* qn or prefix */
+const char * tt_namespaces_GetPrefix( const tt_namespaces_t *nss,
+ const char *psz_uri );
enum
{
@@ -94,6 +111,7 @@ struct tt_node_t
char *psz_node_name;
tt_timings_t timings;
vlc_dictionary_t attr_dict;
+ char *psz_namespace;
};
typedef struct
@@ -102,17 +120,26 @@ typedef struct
char *psz_text;
} tt_textnode_t;
+static inline const char *tt_LocalName( const char *psz_qname )
+{
+ const char *psz_local = strchr( psz_qname, ':' );
+ return psz_local ? psz_local + 1 : psz_qname;
+}
+
tt_textnode_t *tt_textnode_New( tt_node_t *p_parent, const char *psz_text );
tt_textnode_t *tt_subtextnode_New( tt_node_t *p_parent, const char *psz_text, size_t );
-tt_node_t * tt_node_New( tt_node_t* p_parent, const char* psz_node_name );
-tt_node_t * tt_node_NewRead( xml_reader_t* reader, tt_node_t* p_parent, const char* psz_node_name );
+tt_node_t * tt_node_New( tt_node_t* p_parent, const char* psz_node_name, const char *psz_namespace );
+tt_node_t * tt_node_NewRead( xml_reader_t* reader, tt_namespaces_t *, tt_node_t* p_parent,
+ const char* psz_node_name, const char *psz_namespace );
void tt_node_RecursiveDelete( tt_node_t *p_node );
-int tt_node_NameCompare( const char* psz_tagname, const char* psz_pattern );
+bool tt_node_Match( const tt_node_t *p_node, const char* psz_name, const char* psz_namespace );
+const char * tt_node_GetAttribute( tt_namespaces_t *, const tt_node_t *p_node,
+ const char *psz_name, const char *psz_namespace );
bool tt_node_HasChild( const tt_node_t *p_node );
int tt_node_AddAttribute( tt_node_t *p_node, const char *key, const char *value );
void tt_node_RemoveAttribute( tt_node_t *p_node, const char *key );
-int tt_nodes_Read( xml_reader_t *p_reader, tt_node_t *p_root_node );
+int tt_nodes_Read( xml_reader_t *p_reader, tt_namespaces_t *, tt_node_t *p_root_node );
void tt_timings_Resolve( tt_basenode_t *p_child, const tt_timings_t *p_container_timings,
tt_time_t **pp_array, size_t *pi_count );
=====================================
modules/demux/ttml.c
=====================================
@@ -51,6 +51,7 @@ typedef struct
bool b_first_time;
tt_node_t *p_rootnode;
+ tt_namespaces_t namespaces;
tt_timings_t temporal_extent;
@@ -157,11 +158,11 @@ static int Control( demux_t* p_demux, int i_query, va_list args )
static int ReadTTML( demux_t* p_demux )
{
demux_sys_t* p_sys = p_demux->p_sys;
- const char* psz_node_name;
+ const char* psz_node_name, *psz_node_namespace;
do
{
- int i_type = xml_ReaderNextNode( p_sys->p_reader, &psz_node_name );
+ int i_type = xml_ReaderNextNodeNS( p_sys->p_reader, &psz_node_name, &psz_node_namespace );
bool b_empty = xml_ReaderIsEmptyElement( p_sys->p_reader );
if( i_type <= XML_READER_NONE )
@@ -173,21 +174,25 @@ static int ReadTTML( demux_t* p_demux )
break;
case XML_READER_STARTELEM:
- if( tt_node_NameCompare( psz_node_name, "tt" ) ||
+ if( strcmp( psz_node_namespace, TT_NS ) ||
+ strcmp( tt_LocalName( psz_node_name ), "tt" ) ||
p_sys->p_rootnode != NULL )
return VLC_EGENERIC;
- p_sys->p_rootnode = tt_node_NewRead( p_sys->p_reader, NULL, psz_node_name );
+ p_sys->p_rootnode = tt_node_NewRead( p_sys->p_reader, &p_sys->namespaces, NULL,
+ psz_node_name,
+ psz_node_namespace );
if( b_empty )
break;
if( !p_sys->p_rootnode ||
- tt_nodes_Read( p_sys->p_reader, p_sys->p_rootnode ) != VLC_SUCCESS )
+ tt_nodes_Read( p_sys->p_reader,
+ &p_sys->namespaces, p_sys->p_rootnode ) != VLC_SUCCESS )
return VLC_EGENERIC;
break;
case XML_READER_ENDELEM:
if( !p_sys->p_rootnode ||
- tt_node_NameCompare( psz_node_name, p_sys->p_rootnode->psz_node_name ) )
+ strcmp( psz_node_name, p_sys->p_rootnode->psz_node_name ) )
return VLC_EGENERIC;
break;
}
@@ -341,6 +346,7 @@ int tt_OpenDemux( vlc_object_t* p_this )
tt_time_Init( &p_sys->temporal_extent.end );
tt_time_Init( &p_sys->temporal_extent.dur );
p_sys->temporal_extent.begin.base = 0;
+ tt_namespaces_Init( &p_sys->namespaces );
p_sys->p_xml = xml_Create( p_demux );
if( !p_sys->p_xml )
@@ -418,6 +424,8 @@ void tt_CloseDemux( vlc_object_t* p_this )
if( p_sys->p_xml )
xml_Delete( p_sys->p_xml );
+ tt_namespaces_Clean( &p_sys->namespaces );
+
free( p_sys->times.p_array );
free( p_sys );
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/54c93e010b96eb0ba046b39c4c61a3ecc95bee06...44879313bab5b7208b12cb4968cf03a6f521e531
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/54c93e010b96eb0ba046b39c4c61a3ecc95bee06...44879313bab5b7208b12cb4968cf03a6f521e531
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list