Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
403 results
Show changes
Commits on Source (5)
......@@ -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;
......
......@@ -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 );
......
......@@ -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 )
......
......@@ -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 );
......
......@@ -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 );
......