/src/vlc/modules/codec/ttml/genttml.c
Line | Count | Source (jump to first uncovered line) |
1 | | /***************************************************************************** |
2 | | * genttml.c : TTML formatter |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2015-2018 VLC authors and VideoLAN |
5 | | * Copyright (C) 2017-2018 VideoLabs |
6 | | * |
7 | | * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr> |
8 | | * Sushma Reddy <sushma.reddy@research.iiit.ac.in> |
9 | | * |
10 | | * This program is free software; you can redistribute it and/or modify it |
11 | | * under the terms of the GNU Lesser General Public License as published by |
12 | | * the Free Software Foundation; either version 2.1 of the License, or |
13 | | * (at your option) any later version. |
14 | | * |
15 | | * This program is distributed in the hope that it will be useful, |
16 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | | * GNU Lesser General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU Lesser General Public License |
21 | | * along with this program; if not, write to the Free Software Foundation, |
22 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
23 | | *****************************************************************************/ |
24 | | |
25 | | #ifdef HAVE_CONFIG_H |
26 | | # include "config.h" |
27 | | #endif |
28 | | |
29 | | //#define TTML_GEN_DEBUG |
30 | | |
31 | | #include <vlc_common.h> |
32 | | #include <vlc_strings.h> |
33 | | |
34 | | #include <assert.h> |
35 | | #include <stdlib.h> |
36 | | #include <ctype.h> |
37 | | |
38 | | #include "ttml.h" |
39 | | |
40 | | char *tt_genTiming( tt_time_t t ) |
41 | 0 | { |
42 | 0 | if( !tt_time_Valid( &t ) ) |
43 | 0 | t.base = 0; |
44 | 0 | unsigned f = t.base % CLOCK_FREQ; |
45 | 0 | t.base /= CLOCK_FREQ; |
46 | 0 | unsigned h = t.base / 3600; |
47 | 0 | unsigned m = t.base % 3600 / 60; |
48 | 0 | unsigned s = t.base % 60; |
49 | |
|
50 | 0 | int i_ret; |
51 | 0 | char *psz; |
52 | 0 | if( f ) |
53 | 0 | { |
54 | 0 | const char *lz = "000000"; |
55 | 0 | const char *psz_lz = &lz[6]; |
56 | | /* add leading zeroes */ |
57 | 0 | for( unsigned i=10*f; i<CLOCK_FREQ; i *= 10 ) |
58 | 0 | psz_lz--; |
59 | | /* strip trailing zeroes */ |
60 | 0 | for( ; f > 0 && (f % 10) == 0; f /= 10 ); |
61 | 0 | i_ret = asprintf( &psz, "%02u:%02u:%02u.%s%u", |
62 | 0 | h, m, s, psz_lz, f ); |
63 | 0 | } |
64 | 0 | else if( t.frames ) |
65 | 0 | { |
66 | 0 | i_ret = asprintf( &psz, "%02u:%02u:%02u:%s%u", |
67 | 0 | h, m, s, t.frames < 10 ? "0" : "", t.frames ); |
68 | 0 | } |
69 | 0 | else |
70 | 0 | { |
71 | 0 | i_ret = asprintf( &psz, "%02u:%02u:%02u", |
72 | 0 | h, m, s ); |
73 | 0 | } |
74 | |
|
75 | 0 | return i_ret < 0 ? NULL : psz; |
76 | 0 | } |
77 | | |
78 | | static void tt_MemstreamPutEntities( struct vlc_memstream *p_stream, const char *psz ) |
79 | 0 | { |
80 | 0 | char *psz_entities = vlc_xml_encode( psz ); |
81 | 0 | if( psz_entities ) |
82 | 0 | { |
83 | 0 | vlc_memstream_puts( p_stream, psz_entities ); |
84 | 0 | free( psz_entities ); |
85 | 0 | } |
86 | 0 | } |
87 | | |
88 | | void tt_node_AttributesToText( struct vlc_memstream *p_stream, const tt_node_t* p_node ) |
89 | 0 | { |
90 | 0 | bool b_timed_node = false; |
91 | 0 | const vlc_dictionary_t* p_attr_dict = &p_node->attr_dict; |
92 | 0 | for (size_t i = 0; i < p_attr_dict->i_size; ++i) |
93 | 0 | { |
94 | 0 | for ( vlc_dictionary_entry_t* p_entry = p_attr_dict->p_entries[i]; |
95 | 0 | p_entry != NULL; p_entry = p_entry->p_next ) |
96 | 0 | { |
97 | 0 | const char *psz_value = NULL; |
98 | |
|
99 | 0 | if( !strcmp(p_entry->psz_key, "begin") || |
100 | 0 | !strcmp(p_entry->psz_key, "end") || |
101 | 0 | !strcmp(p_entry->psz_key, "dur") ) |
102 | 0 | { |
103 | 0 | b_timed_node = true; |
104 | | /* will remove duration */ |
105 | 0 | continue; |
106 | 0 | } |
107 | 0 | else if( !strcmp(p_entry->psz_key, "timeContainer") ) |
108 | 0 | { |
109 | | /* also remove sequential timings info (all abs now) */ |
110 | 0 | continue; |
111 | 0 | } |
112 | 0 | else |
113 | 0 | { |
114 | 0 | psz_value = p_entry->p_value; |
115 | 0 | } |
116 | | |
117 | 0 | if( psz_value == NULL ) |
118 | 0 | continue; |
119 | | |
120 | 0 | vlc_memstream_printf( p_stream, " %s=\"", p_entry->psz_key ); |
121 | 0 | tt_MemstreamPutEntities( p_stream, psz_value ); |
122 | 0 | vlc_memstream_putc( p_stream, '"' ); |
123 | 0 | } |
124 | 0 | } |
125 | |
|
126 | 0 | if( b_timed_node ) |
127 | 0 | { |
128 | 0 | if( tt_time_Valid( &p_node->timings.begin ) ) |
129 | 0 | { |
130 | 0 | char *psz = tt_genTiming( p_node->timings.begin ); |
131 | 0 | vlc_memstream_printf( p_stream, " begin=\"%s\"", psz ); |
132 | 0 | free( psz ); |
133 | 0 | } |
134 | |
|
135 | 0 | if( tt_time_Valid( &p_node->timings.end ) ) |
136 | 0 | { |
137 | 0 | char *psz = tt_genTiming( p_node->timings.end ); |
138 | 0 | vlc_memstream_printf( p_stream, " end=\"%s\"", psz ); |
139 | 0 | free( psz ); |
140 | 0 | } |
141 | 0 | } |
142 | 0 | } |
143 | | |
144 | | void tt_node_ToText( struct vlc_memstream *p_stream, const tt_basenode_t *p_basenode, |
145 | | const tt_time_t *playbacktime ) |
146 | 0 | { |
147 | 0 | if( p_basenode->i_type == TT_NODE_TYPE_ELEMENT ) |
148 | 0 | { |
149 | 0 | const tt_node_t *p_node = (const tt_node_t *) p_basenode; |
150 | |
|
151 | 0 | if( tt_time_Valid( playbacktime ) && |
152 | 0 | !tt_timings_Contains( &p_node->timings, playbacktime ) ) |
153 | 0 | return; |
154 | | |
155 | 0 | vlc_memstream_putc( p_stream, '<' ); |
156 | 0 | tt_MemstreamPutEntities( p_stream, p_node->psz_node_name ); |
157 | |
|
158 | 0 | tt_node_AttributesToText( p_stream, p_node ); |
159 | |
|
160 | 0 | if( tt_node_HasChild( p_node ) ) |
161 | 0 | { |
162 | 0 | vlc_memstream_putc( p_stream, '>' ); |
163 | |
|
164 | | #ifdef TTML_DEMUX_DEBUG |
165 | | vlc_memstream_printf( p_stream, "<!-- starts %ld ends %ld -->", |
166 | | tt_time_Convert( &p_node->timings.begin ), |
167 | | tt_time_Convert( &p_node->timings.end ) ); |
168 | | #endif |
169 | |
|
170 | 0 | for( const tt_basenode_t *p_child = p_node->p_child; |
171 | 0 | p_child; p_child = p_child->p_next ) |
172 | 0 | { |
173 | 0 | tt_node_ToText( p_stream, p_child, playbacktime ); |
174 | 0 | } |
175 | |
|
176 | 0 | vlc_memstream_puts( p_stream, "</" ); |
177 | 0 | tt_MemstreamPutEntities( p_stream, p_node->psz_node_name ); |
178 | 0 | vlc_memstream_putc( p_stream, '>' ); |
179 | 0 | } |
180 | 0 | else |
181 | 0 | vlc_memstream_puts( p_stream, "/>" ); |
182 | 0 | } |
183 | 0 | else |
184 | 0 | { |
185 | 0 | const tt_textnode_t *p_textnode = (const tt_textnode_t *) p_basenode; |
186 | 0 | tt_MemstreamPutEntities( p_stream, p_textnode->psz_text ); |
187 | 0 | } |
188 | 0 | } |