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 /*****************************************************************************
25 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_demux.h>
35 /*****************************************************************************
37 *****************************************************************************/
38 static int Open (vlc_object_t
*);
39 static void Close(vlc_object_t
*);
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")
50 /*****************************************************************************
51 * Local definitions/prototypes
52 *****************************************************************************/
73 static size_t ParseInteger(uint8_t *data
, size_t size
)
76 assert(size
< sizeof(tmp
));
77 memcpy(tmp
, data
, size
);
80 return strtol(tmp
, NULL
, 10);
82 static vlc_tick_t
ParseTimeCode(uint8_t *data
, double fps
)
84 return CLOCK_FREQ
* (data
[0] * 3600 +
89 static vlc_tick_t
ParseTextTimeCode(uint8_t *data
, double fps
)
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
;
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;
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
),
116 case DEMUX_SET_NEXT_DEMUX_TIME
: {
118 sys
->next_date
= va_arg(args
, vlc_tick_t
);
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
)
130 sys
->b_first_time
= true;
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
);
146 case DEMUX_GET_POSITION
:
148 double *pf
= va_arg(args
, double *);
149 if(sys
->current
>= sys
->count
)
153 else if(sys
->count
> 0 && sys
->index
[sys
->count
-1].stop
> 0)
155 *pf
= sys
->next_date
- var_GetInteger(vlc_object_parent(demux
),
158 *pf
= sys
->next_date
;
159 *pf
/= sys
->index
[sys
->count
-1].stop
;
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
);
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");
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)
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
);
218 return VLC_DEMUXER_EOF
;
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
;
237 if (vlc_stream_Peek(demux
->s
, &peek
, 11) != 11)
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
)
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");
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);
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
));
262 sys
->b_slave
= false;
263 sys
->b_first_time
= true;
267 sys
->index
= calloc(tti_count
, sizeof(*sys
->index
));
274 bool comment
= false;
275 stl_entry_t
*s
= &sys
->index
[0];
278 for (size_t i
= 0; i
< tti_count
; i
++) {
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");
285 const int ebn
= tti
[3];
286 if (ebn
>= 0xf0 && ebn
<= 0xfd)
292 comment
= tti
[15] != 0;
293 s
->start
= ParseTimeCode(&tti
[5], fps
) - program_start
;
294 s
->stop
= ParseTimeCode(&tti
[9], fps
) - program_start
;
298 if (ebn
== 0xff && !comment
)
299 s
= &sys
->index
[++sys
->count
];
300 if (ebn
== 0xff && sys
->count
< tti_count
)
305 if (sys
->count
== 0 ||
306 vlc_stream_Seek(demux
->s
, 1024 + 128LL * sys
->index
[0].blocknumber
) != VLC_SUCCESS
)
313 es_format_Init(&fmt
, SPU_ES
, VLC_CODEC_EBU_STL
);
314 fmt
.i_extra
= sizeof(header
);
315 fmt
.p_extra
= header
;
318 sys
->es
= es_out_Add(demux
->out
, &fmt
);
321 es_format_Clean(&fmt
);
330 demux
->pf_demux
= Demux
;
331 demux
->pf_control
= Control
;
335 static void Close(vlc_object_t
*object
)
337 demux_t
*demux
= (demux_t
*)object
;
338 demux_sys_t
*sys
= demux
->p_sys
;