1 /*****************************************************************************
2 * stl.c: EBU STL demuxer
3 *****************************************************************************
4 * Copyright (C) 2010 Laurent Aimar
5 * $Id: 238b515cc66f481b889d219a14b1e871e7440aff $
6 *
7 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
23
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 #include <assert.h>
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_demux.h>
35
36 /*****************************************************************************
37 * Module descriptor
38 *****************************************************************************/
39 static int Open (vlc_object_t *);
40 static void Close(vlc_object_t *);
41
42 vlc_module_begin()
43 set_description(N_("EBU STL subtitles parser"))
44 set_category(CAT_INPUT)
45 set_subcategory(SUBCAT_INPUT_DEMUX)
46 set_capability("demux", 1)
47 set_callbacks(Open, Close)
48 add_shortcut("stl", "subtitle")
49 vlc_module_end()
50
51 /*****************************************************************************
52 * Local definitions/prototypes
53 *****************************************************************************/
54 typedef struct {
55 mtime_t start;
56 mtime_t stop;
57 size_t blocknumber;
58 size_t count;
59 } stl_entry_t;
60
61 struct demux_sys_t {
62 size_t count;
63 stl_entry_t *index;
64
65 es_out_id_t *es;
66
67 size_t current;
68 int64_t next_date;
69 bool b_slave;
70 bool b_first_time;
71 };
72
ParseInteger(uint8_t * data,size_t size)73 static size_t ParseInteger(uint8_t *data, size_t size)
74 {
75 char tmp[16];
76 assert(size < sizeof(tmp));
77 memcpy(tmp, data, size);
78 tmp[size] = '\0';
79
80 return strtol(tmp, NULL, 10);
81 }
ParseTimeCode(uint8_t * data,double fps)82 static int64_t ParseTimeCode(uint8_t *data, double fps)
83 {
84 return INT64_C(1000000) * (data[0] * 3600 +
85 data[1] * 60 +
86 data[2] * 1 +
87 data[3] / fps);
88 }
ParseTextTimeCode(uint8_t * data,double fps)89 static int64_t ParseTextTimeCode(uint8_t *data, double fps)
90 {
91 uint8_t tmp[4];
92 for (int i = 0; i < 4; i++)
93 tmp[i] = ParseInteger(&data[2 * i], 2);
94 return ParseTimeCode(tmp, fps);
95 }
96
Control(demux_t * demux,int query,va_list args)97 static int Control(demux_t *demux, int query, va_list args)
98 {
99 demux_sys_t *sys = demux->p_sys;
100 switch(query) {
101 case DEMUX_CAN_SEEK:
102 return vlc_stream_vaControl(demux->s, query, args);
103 case DEMUX_GET_LENGTH: {
104 int64_t *l = va_arg(args, int64_t *);
105 *l = sys->count > 0 ? sys->index[sys->count-1].stop : 0;
106 return VLC_SUCCESS;
107 }
108 case DEMUX_GET_TIME: {
109 int64_t *t = va_arg(args, int64_t *);
110 *t = sys->next_date - var_GetInteger(demux->obj.parent, "spu-delay");
111 if( *t < 0 )
112 *t = sys->next_date;
113 return VLC_SUCCESS;
114 }
115 case DEMUX_SET_NEXT_DEMUX_TIME: {
116 sys->b_slave = true;
117 sys->next_date = va_arg(args, int64_t);
118 return VLC_SUCCESS;
119 }
120 case DEMUX_SET_TIME: {
121 int64_t t = va_arg(args, int64_t);
122 for( size_t i = 0; i + 1< sys->count; i++ )
123 {
124 if( sys->index[i + 1].start >= t &&
125 vlc_stream_Seek(demux->s, 1024 + 128LL * sys->index[i].blocknumber) == VLC_SUCCESS )
126 {
127 sys->current = i;
128 sys->next_date = t;
129 sys->b_first_time = true;
130 return VLC_SUCCESS;
131 }
132 }
133 break;
134 }
135 case DEMUX_SET_POSITION:
136 {
137 double f = va_arg( args, double );
138 if(sys->count && sys->index[sys->count-1].stop > 0)
139 {
140 int64_t i64 = f * sys->index[sys->count-1].stop;
141 return demux_Control(demux, DEMUX_SET_TIME, i64);
142 }
143 break;
144 }
145 case DEMUX_GET_POSITION:
146 {
147 double *pf = va_arg(args, double *);
148 if(sys->current >= sys->count)
149 {
150 *pf = 1.0;
151 }
152 else if(sys->count > 0 && sys->index[sys->count-1].stop > 0)
153 {
154 *pf = sys->next_date - var_GetInteger(demux->obj.parent, "spu-delay");
155 if(*pf < 0)
156 *pf = sys->next_date;
157 *pf /= sys->index[sys->count-1].stop;
158 }
159 else
160 {
161 *pf = 0.0;
162 }
163 return VLC_SUCCESS;
164 }
165 default:
166 break;
167 }
168 return VLC_EGENERIC;
169 }
170
Demux(demux_t * demux)171 static int Demux(demux_t *demux)
172 {
173 demux_sys_t *sys = demux->p_sys;
174
175 int64_t i_barrier = sys->next_date - var_GetInteger(demux->obj.parent, "spu-delay");
176 if(i_barrier < 0)
177 i_barrier = sys->next_date;
178
179 while(sys->current < sys->count &&
180 sys->index[sys->current].start <= i_barrier)
181 {
182 stl_entry_t *s = &sys->index[sys->current];
183
184 if (!sys->b_slave && sys->b_first_time)
185 {
186 es_out_SetPCR(demux->out, VLC_TS_0 + i_barrier);
187 sys->b_first_time = false;
188 }
189
190 /* Might be a gap in block # */
191 const uint64_t i_pos = 1024 + 128LL * s->blocknumber;
192 if(i_pos != vlc_stream_Tell(demux->s) &&
193 vlc_stream_Seek( demux->s, i_pos ) != VLC_SUCCESS )
194 return VLC_DEMUXER_EOF;
195
196 block_t *b = vlc_stream_Block(demux->s, 128);
197 if (b && b->i_buffer == 128)
198 {
199 b->i_dts =
200 b->i_pts = VLC_TS_0 + s->start;
201 if (s->stop > s->start)
202 b->i_length = s->stop - s->start;
203 es_out_Send(demux->out, sys->es, b);
204 }
205 else
206 {
207 if(b)
208 block_Release(b);
209 return VLC_DEMUXER_EOF;
210 }
211 sys->current++;
212 }
213
214 if (!sys->b_slave)
215 {
216 es_out_SetPCR(demux->out, VLC_TS_0 + i_barrier);
217 sys->next_date += CLOCK_FREQ / 8;
218 }
219
220 return sys->current < sys->count ? VLC_DEMUXER_SUCCESS : VLC_DEMUXER_EOF;
221 }
222
Open(vlc_object_t * object)223 static int Open(vlc_object_t *object)
224 {
225 demux_t *demux = (demux_t*)object;
226
227 const uint8_t *peek;
228 if (vlc_stream_Peek(demux->s, &peek, 11) != 11)
229 return VLC_EGENERIC;
230
231 bool is_stl_25 = !memcmp(&peek[3], "STL25.01", 8);
232 bool is_stl_30 = !memcmp(&peek[3], "STL30.01", 8);
233 if (!is_stl_25 && !is_stl_30)
234 return VLC_EGENERIC;
235 const double fps = is_stl_25 ? 25 : 30;
236
237 uint8_t header[1024];
238 if (vlc_stream_Read(demux->s, header, sizeof(header)) != sizeof(header)) {
239 msg_Err(demux, "Incomplete EBU STL header");
240 return VLC_EGENERIC;
241 }
242 const int cct = ParseInteger(&header[12], 2);
243 const mtime_t program_start = ParseTextTimeCode(&header[256], fps);
244 const size_t tti_count = ParseInteger(&header[238], 5);
245 if (!tti_count)
246 return VLC_EGENERIC;
247 msg_Dbg(demux, "Detected EBU STL : CCT=%d TTI=%zu start=%8.8s %"PRId64, cct, tti_count, &header[256], program_start);
248
249 demux_sys_t *sys = malloc(sizeof(*sys));
250 if(!sys)
251 return VLC_EGENERIC;
252
253 sys->b_slave = false;
254 sys->b_first_time = true;
255 sys->next_date = 0;
256 sys->current = 0;
257 sys->count = 0;
258 sys->index = calloc(tti_count, sizeof(*sys->index));
259 if(!sys->index)
260 {
261 free(sys);
262 return VLC_EGENERIC;
263 }
264
265 bool comment = false;
266 stl_entry_t *s = &sys->index[0];
267 s->count = 0;
268
269 for (size_t i = 0; i < tti_count; i++) {
270 uint8_t tti[16];
271 if (vlc_stream_Read(demux->s, tti, 16) != 16 ||
272 vlc_stream_Read(demux->s, NULL, 112) != 112) {
273 msg_Warn(demux, "Incomplete EBU STL file");
274 break;
275 }
276 const int ebn = tti[3];
277 if (ebn >= 0xf0 && ebn <= 0xfd)
278 continue;
279 if (ebn == 0xfe)
280 continue;
281
282 if (s->count <= 0) {
283 comment = tti[15] != 0;
284 s->start = ParseTimeCode(&tti[5], fps) - program_start;
285 s->stop = ParseTimeCode(&tti[9], fps) - program_start;
286 s->blocknumber = i;
287 }
288 s->count++;
289 if (ebn == 0xff && !comment)
290 s = &sys->index[++sys->count];
291 if (ebn == 0xff && sys->count < tti_count)
292 s->count = 0;
293 }
294
295 demux->p_sys = sys;
296 if (sys->count == 0 ||
297 vlc_stream_Seek(demux->s, 1024 + 128LL * sys->index[0].blocknumber) != VLC_SUCCESS)
298 {
299 Close(object);
300 return VLC_EGENERIC;
301 }
302
303 es_format_t fmt;
304 es_format_Init(&fmt, SPU_ES, VLC_CODEC_EBU_STL);
305 fmt.i_extra = sizeof(header);
306 fmt.p_extra = header;
307
308 sys->es = es_out_Add(demux->out, &fmt);
309 fmt.i_extra = 0;
310 fmt.p_extra = NULL;
311 es_format_Clean(&fmt);
312
313 if(sys->es == NULL)
314 {
315 Close(object);
316 return VLC_EGENERIC;
317 }
318
319 demux->p_sys = sys;
320 demux->pf_demux = Demux;
321 demux->pf_control = Control;
322 return VLC_SUCCESS;
323 }
324
Close(vlc_object_t * object)325 static void Close(vlc_object_t *object)
326 {
327 demux_t *demux = (demux_t*)object;
328 demux_sys_t *sys = demux->p_sys;
329
330 free(sys->index);
331 free(sys);
332 }
333
334