/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 | 669k | { |
42 | 669k | if( !tt_time_Valid( &t ) ) |
43 | 0 | t.base = 0; |
44 | 669k | unsigned f = t.base % CLOCK_FREQ; |
45 | 669k | t.base /= CLOCK_FREQ; |
46 | 669k | unsigned h = t.base / 3600; |
47 | 669k | unsigned m = t.base % 3600 / 60; |
48 | 669k | unsigned s = t.base % 60; |
49 | | |
50 | 669k | int i_ret; |
51 | 669k | char *psz; |
52 | 669k | if( f ) |
53 | 599k | { |
54 | 599k | const char *lz = "000000"; |
55 | 599k | const char *psz_lz = &lz[6]; |
56 | | /* add leading zeroes */ |
57 | 632k | for( unsigned i=10*f; i<CLOCK_FREQ; i *= 10 ) |
58 | 33.0k | psz_lz--; |
59 | | /* strip trailing zeroes */ |
60 | 1.69M | for( ; f > 0 && (f % 10) == 0; f /= 10 ); |
61 | 599k | i_ret = asprintf( &psz, "%02u:%02u:%02u.%s%u", |
62 | 599k | h, m, s, psz_lz, f ); |
63 | 599k | } |
64 | 69.4k | else if( t.frames ) |
65 | 6 | { |
66 | 6 | i_ret = asprintf( &psz, "%02u:%02u:%02u:%s%u", |
67 | 6 | h, m, s, t.frames < 10 ? "0" : "", t.frames ); |
68 | 6 | } |
69 | 69.4k | else |
70 | 69.4k | { |
71 | 69.4k | i_ret = asprintf( &psz, "%02u:%02u:%02u", |
72 | 69.4k | h, m, s ); |
73 | 69.4k | } |
74 | | |
75 | 669k | return i_ret < 0 ? NULL : psz; |
76 | 669k | } |
77 | | |
78 | | static void tt_MemstreamPutEntities( struct vlc_memstream *p_stream, const char *psz ) |
79 | 1.50M | { |
80 | 1.50M | char *psz_entities = vlc_xml_encode( psz ); |
81 | 1.50M | if( psz_entities ) |
82 | 1.50M | { |
83 | 1.50M | vlc_memstream_puts( p_stream, psz_entities ); |
84 | 1.50M | free( psz_entities ); |
85 | 1.50M | } |
86 | 1.50M | } |
87 | | |
88 | | void tt_node_AttributesToText( struct vlc_memstream *p_stream, const tt_node_t* p_node ) |
89 | 594k | { |
90 | 594k | bool b_timed_node = false; |
91 | 594k | const vlc_dictionary_t* p_attr_dict = &p_node->attr_dict; |
92 | 1.15M | for (size_t i = 0; i < p_attr_dict->i_size; ++i) |
93 | 564k | { |
94 | 564k | for ( vlc_dictionary_entry_t* p_entry = p_attr_dict->p_entries[i]; |
95 | 1.61M | p_entry != NULL; p_entry = p_entry->p_next ) |
96 | 1.04M | { |
97 | 1.04M | const char *psz_value = NULL; |
98 | | |
99 | 1.04M | if( !strcmp(p_entry->psz_key, "begin") || |
100 | 1.04M | !strcmp(p_entry->psz_key, "end") || |
101 | 1.04M | !strcmp(p_entry->psz_key, "dur") ) |
102 | 732k | { |
103 | 732k | b_timed_node = true; |
104 | | /* will remove duration */ |
105 | 732k | continue; |
106 | 732k | } |
107 | 317k | else if( !strcmp(p_entry->psz_key, "timeContainer") ) |
108 | 305 | { |
109 | | /* also remove sequential timings info (all abs now) */ |
110 | 305 | continue; |
111 | 305 | } |
112 | 316k | else |
113 | 316k | { |
114 | 316k | psz_value = p_entry->p_value; |
115 | 316k | } |
116 | | |
117 | 316k | if( psz_value == NULL ) |
118 | 0 | continue; |
119 | | |
120 | 316k | vlc_memstream_printf( p_stream, " %s=\"", p_entry->psz_key ); |
121 | 316k | tt_MemstreamPutEntities( p_stream, psz_value ); |
122 | 316k | vlc_memstream_putc( p_stream, '"' ); |
123 | 316k | } |
124 | 564k | } |
125 | | |
126 | 594k | if( b_timed_node ) |
127 | 418k | { |
128 | 418k | if( tt_time_Valid( &p_node->timings.begin ) ) |
129 | 418k | { |
130 | 418k | char *psz = tt_genTiming( p_node->timings.begin ); |
131 | 418k | vlc_memstream_printf( p_stream, " begin=\"%s\"", psz ); |
132 | 418k | free( psz ); |
133 | 418k | } |
134 | | |
135 | 418k | if( tt_time_Valid( &p_node->timings.end ) ) |
136 | 251k | { |
137 | 251k | char *psz = tt_genTiming( p_node->timings.end ); |
138 | 251k | vlc_memstream_printf( p_stream, " end=\"%s\"", psz ); |
139 | 251k | free( psz ); |
140 | 251k | } |
141 | 418k | } |
142 | 594k | } |
143 | | |
144 | | void tt_node_ToText( struct vlc_memstream *p_stream, const tt_basenode_t *p_basenode, |
145 | | const tt_time_t *playbacktime ) |
146 | 668k | { |
147 | 668k | if( p_basenode->i_type == TT_NODE_TYPE_ELEMENT ) |
148 | 626k | { |
149 | 626k | const tt_node_t *p_node = (const tt_node_t *) p_basenode; |
150 | | |
151 | 626k | if( tt_time_Valid( playbacktime ) && |
152 | 626k | !tt_timings_Contains( &p_node->timings, playbacktime ) ) |
153 | 32.2k | return; |
154 | | |
155 | 594k | vlc_memstream_putc( p_stream, '<' ); |
156 | 594k | tt_MemstreamPutEntities( p_stream, p_node->psz_node_name ); |
157 | | |
158 | 594k | tt_node_AttributesToText( p_stream, p_node ); |
159 | | |
160 | 594k | if( tt_node_HasChild( p_node ) ) |
161 | 553k | { |
162 | 553k | 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 | 553k | for( const tt_basenode_t *p_child = p_node->p_child; |
171 | 1.19M | p_child; p_child = p_child->p_next ) |
172 | 644k | { |
173 | 644k | tt_node_ToText( p_stream, p_child, playbacktime ); |
174 | 644k | } |
175 | | |
176 | 553k | vlc_memstream_puts( p_stream, "</" ); |
177 | 553k | tt_MemstreamPutEntities( p_stream, p_node->psz_node_name ); |
178 | 553k | vlc_memstream_putc( p_stream, '>' ); |
179 | 553k | } |
180 | 40.7k | else |
181 | 40.7k | vlc_memstream_puts( p_stream, "/>" ); |
182 | 594k | } |
183 | 42.2k | else |
184 | 42.2k | { |
185 | 42.2k | const tt_textnode_t *p_textnode = (const tt_textnode_t *) p_basenode; |
186 | 42.2k | tt_MemstreamPutEntities( p_stream, p_textnode->psz_text ); |
187 | 42.2k | } |
188 | 668k | } |