contrib/gpg-error: simplify darwin triplet handling
[vlc.git] / modules / demux / stl.c
bloba635766872749a22e655ab20417fbd2f3273c683
1 /*****************************************************************************
2 * stl.c: EBU STL demuxer
3 *****************************************************************************
4 * Copyright (C) 2010 Laurent Aimar
6 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
24 * Preamble
25 *****************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29 #include <assert.h>
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_demux.h>
35 /*****************************************************************************
36 * Module descriptor
37 *****************************************************************************/
38 static int Open (vlc_object_t *);
39 static void Close(vlc_object_t *);
41 vlc_module_begin()
42 set_description(N_("EBU STL subtitles parser"))
43 set_category(CAT_INPUT)
44 set_subcategory(SUBCAT_INPUT_DEMUX)
45 set_capability("demux", 1)
46 set_callbacks(Open, Close)
47 add_shortcut("stl", "subtitle")
48 vlc_module_end()
50 /*****************************************************************************
51 * Local definitions/prototypes
52 *****************************************************************************/
53 typedef struct {
54 vlc_tick_t start;
55 vlc_tick_t stop;
56 size_t blocknumber;
57 size_t count;
58 } stl_entry_t;
60 typedef struct
62 size_t count;
63 stl_entry_t *index;
65 es_out_id_t *es;
67 size_t current;
68 vlc_tick_t next_date;
69 bool b_slave;
70 bool b_first_time;
71 } demux_sys_t;
73 static size_t ParseInteger(uint8_t *data, size_t size)
75 char tmp[16];
76 assert(size < sizeof(tmp));
77 memcpy(tmp, data, size);
78 tmp[size] = '\0';
80 return strtol(tmp, NULL, 10);
82 static vlc_tick_t ParseTimeCode(uint8_t *data, double fps)
84 return CLOCK_FREQ * (data[0] * 3600 +
85 data[1] * 60 +
86 data[2] * 1 +
87 data[3] / fps);
89 static vlc_tick_t ParseTextTimeCode(uint8_t *data, double fps)
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);
97 static int Control(demux_t *demux, int query, va_list args)
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 *va_arg(args, vlc_tick_t *) =
105 sys->count > 0 ? sys->index[sys->count-1].stop : 0;
106 return VLC_SUCCESS;
108 case DEMUX_GET_TIME: {
109 vlc_tick_t *t = va_arg(args, vlc_tick_t *);
110 *t = sys->next_date - var_GetInteger(vlc_object_parent(demux),
111 "spu-delay");
112 if( *t < 0 )
113 *t = sys->next_date;
114 return VLC_SUCCESS;
116 case DEMUX_SET_NEXT_DEMUX_TIME: {
117 sys->b_slave = true;
118 sys->next_date = va_arg(args, vlc_tick_t);
119 return VLC_SUCCESS;
121 case DEMUX_SET_TIME: {
122 vlc_tick_t t = va_arg(args, vlc_tick_t);
123 for( size_t i = 0; i + 1< sys->count; i++ )
125 if( sys->index[i + 1].start >= t &&
126 vlc_stream_Seek(demux->s, 1024 + 128LL * sys->index[i].blocknumber) == VLC_SUCCESS )
128 sys->current = i;
129 sys->next_date = t;
130 sys->b_first_time = true;
131 return VLC_SUCCESS;
134 break;
136 case DEMUX_SET_POSITION:
138 double f = va_arg( args, double );
139 if(sys->count && sys->index[sys->count-1].stop > 0)
141 vlc_tick_t i64 = f * sys->index[sys->count-1].stop;
142 return demux_Control(demux, DEMUX_SET_TIME, i64);
144 break;
146 case DEMUX_GET_POSITION:
148 double *pf = va_arg(args, double *);
149 if(sys->current >= sys->count)
151 *pf = 1.0;
153 else if(sys->count > 0 && sys->index[sys->count-1].stop > 0)
155 *pf = sys->next_date - var_GetInteger(vlc_object_parent(demux),
156 "spu-delay");
157 if(*pf < 0)
158 *pf = sys->next_date;
159 *pf /= sys->index[sys->count-1].stop;
161 else
163 *pf = 0.0;
165 return VLC_SUCCESS;
167 case DEMUX_CAN_PAUSE:
168 case DEMUX_SET_PAUSE_STATE:
169 case DEMUX_CAN_CONTROL_PACE:
170 case DEMUX_GET_PTS_DELAY: {
171 return demux_vaControlHelper( demux->s, 0, -1, 0, 1, query, args );
173 default:
174 break;
176 return VLC_EGENERIC;
179 static int Demux(demux_t *demux)
181 demux_sys_t *sys = demux->p_sys;
183 vlc_tick_t i_barrier = sys->next_date
184 - var_GetInteger(vlc_object_parent(demux), "spu-delay");
185 if(i_barrier < 0)
186 i_barrier = sys->next_date;
188 while(sys->current < sys->count &&
189 sys->index[sys->current].start <= i_barrier)
191 stl_entry_t *s = &sys->index[sys->current];
193 if (!sys->b_slave && sys->b_first_time)
195 es_out_SetPCR(demux->out, VLC_TICK_0 + i_barrier);
196 sys->b_first_time = false;
199 /* Might be a gap in block # */
200 const uint64_t i_pos = 1024 + 128LL * s->blocknumber;
201 if(i_pos != vlc_stream_Tell(demux->s) &&
202 vlc_stream_Seek( demux->s, i_pos ) != VLC_SUCCESS )
203 return VLC_DEMUXER_EOF;
205 block_t *b = vlc_stream_Block(demux->s, 128);
206 if (b && b->i_buffer == 128)
208 b->i_dts =
209 b->i_pts = VLC_TICK_0 + s->start;
210 if (s->stop > s->start)
211 b->i_length = s->stop - s->start;
212 es_out_Send(demux->out, sys->es, b);
214 else
216 if(b)
217 block_Release(b);
218 return VLC_DEMUXER_EOF;
220 sys->current++;
223 if (!sys->b_slave)
225 es_out_SetPCR(demux->out, VLC_TICK_0 + i_barrier);
226 sys->next_date += VLC_TICK_FROM_MS(125);
229 return sys->current < sys->count ? VLC_DEMUXER_SUCCESS : VLC_DEMUXER_EOF;
232 static int Open(vlc_object_t *object)
234 demux_t *demux = (demux_t*)object;
236 const uint8_t *peek;
237 if (vlc_stream_Peek(demux->s, &peek, 11) != 11)
238 return VLC_EGENERIC;
240 bool is_stl_25 = !memcmp(&peek[3], "STL25.01", 8);
241 bool is_stl_30 = !memcmp(&peek[3], "STL30.01", 8);
242 if (!is_stl_25 && !is_stl_30)
243 return VLC_EGENERIC;
244 const double fps = is_stl_25 ? 25 : 30;
246 uint8_t header[1024];
247 if (vlc_stream_Read(demux->s, header, sizeof(header)) != sizeof(header)) {
248 msg_Err(demux, "Incomplete EBU STL header");
249 return VLC_EGENERIC;
251 const int cct = ParseInteger(&header[12], 2);
252 const vlc_tick_t program_start = ParseTextTimeCode(&header[256], fps);
253 const size_t tti_count = ParseInteger(&header[238], 5);
254 if (!tti_count)
255 return VLC_EGENERIC;
256 msg_Dbg(demux, "Detected EBU STL : CCT=%d TTI=%zu start=%8.8s %"PRId64, cct, tti_count, &header[256], program_start);
258 demux_sys_t *sys = malloc(sizeof(*sys));
259 if(!sys)
260 return VLC_EGENERIC;
262 sys->b_slave = false;
263 sys->b_first_time = true;
264 sys->next_date = 0;
265 sys->current = 0;
266 sys->count = 0;
267 sys->index = calloc(tti_count, sizeof(*sys->index));
268 if(!sys->index)
270 free(sys);
271 return VLC_EGENERIC;
274 bool comment = false;
275 stl_entry_t *s = &sys->index[0];
276 s->count = 0;
278 for (size_t i = 0; i < tti_count; i++) {
279 uint8_t tti[16];
280 if (vlc_stream_Read(demux->s, tti, 16) != 16 ||
281 vlc_stream_Read(demux->s, NULL, 112) != 112) {
282 msg_Warn(demux, "Incomplete EBU STL file");
283 break;
285 const int ebn = tti[3];
286 if (ebn >= 0xf0 && ebn <= 0xfd)
287 continue;
288 if (ebn == 0xfe)
289 continue;
291 if (s->count <= 0) {
292 comment = tti[15] != 0;
293 s->start = ParseTimeCode(&tti[5], fps) - program_start;
294 s->stop = ParseTimeCode(&tti[9], fps) - program_start;
295 s->blocknumber = i;
297 s->count++;
298 if (ebn == 0xff && !comment)
299 s = &sys->index[++sys->count];
300 if (ebn == 0xff && sys->count < tti_count)
301 s->count = 0;
304 demux->p_sys = sys;
305 if (sys->count == 0 ||
306 vlc_stream_Seek(demux->s, 1024 + 128LL * sys->index[0].blocknumber) != VLC_SUCCESS)
308 Close(object);
309 return VLC_EGENERIC;
312 es_format_t fmt;
313 es_format_Init(&fmt, SPU_ES, VLC_CODEC_EBU_STL);
314 fmt.i_extra = sizeof(header);
315 fmt.p_extra = header;
317 fmt.i_id = 0;
318 sys->es = es_out_Add(demux->out, &fmt);
319 fmt.i_extra = 0;
320 fmt.p_extra = NULL;
321 es_format_Clean(&fmt);
323 if(sys->es == NULL)
325 Close(object);
326 return VLC_EGENERIC;
329 demux->p_sys = sys;
330 demux->pf_demux = Demux;
331 demux->pf_control = Control;
332 return VLC_SUCCESS;
335 static void Close(vlc_object_t *object)
337 demux_t *demux = (demux_t*)object;
338 demux_sys_t *sys = demux->p_sys;
340 free(sys->index);
341 free(sys);