1 /*****************************************************************************
2 * stl.c: EBU STL demuxer
3 *****************************************************************************
4 * Copyright (C) 2010 Laurent Aimar
7 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_demux.h>
36 /*****************************************************************************
38 *****************************************************************************/
39 static int Open (vlc_object_t
*);
40 static void Close(vlc_object_t
*);
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")
51 /*****************************************************************************
52 * Local definitions/prototypes
53 *****************************************************************************/
74 static size_t ParseInteger(uint8_t *data
, size_t size
)
77 assert(size
< sizeof(tmp
));
78 memcpy(tmp
, data
, size
);
81 return strtol(tmp
, NULL
, 10);
83 static vlc_tick_t
ParseTimeCode(uint8_t *data
, double fps
)
85 return CLOCK_FREQ
* (data
[0] * 3600 +
90 static vlc_tick_t
ParseTextTimeCode(uint8_t *data
, double fps
)
93 for (int i
= 0; i
< 4; i
++)
94 tmp
[i
] = ParseInteger(&data
[2 * i
], 2);
95 return ParseTimeCode(tmp
, fps
);
98 static int Control(demux_t
*demux
, int query
, va_list args
)
100 demux_sys_t
*sys
= demux
->p_sys
;
103 return vlc_stream_vaControl(demux
->s
, query
, args
);
104 case DEMUX_GET_LENGTH
: {
105 *va_arg(args
, vlc_tick_t
*) =
106 sys
->count
> 0 ? sys
->index
[sys
->count
-1].stop
: 0;
109 case DEMUX_GET_TIME
: {
110 vlc_tick_t
*t
= va_arg(args
, vlc_tick_t
*);
111 *t
= sys
->next_date
- var_GetInteger(demux
->obj
.parent
, "spu-delay");
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(demux
->obj
.parent
, "spu-delay");
157 *pf
= sys
->next_date
;
158 *pf
/= sys
->index
[sys
->count
-1].stop
;
166 case DEMUX_CAN_PAUSE
:
167 case DEMUX_SET_PAUSE_STATE
:
168 case DEMUX_CAN_CONTROL_PACE
:
169 case DEMUX_GET_PTS_DELAY
: {
170 return demux_vaControlHelper( demux
->s
, 0, -1, 0, 1, query
, args
);
178 static int Demux(demux_t
*demux
)
180 demux_sys_t
*sys
= demux
->p_sys
;
182 vlc_tick_t i_barrier
= sys
->next_date
- var_GetInteger(demux
->obj
.parent
, "spu-delay");
184 i_barrier
= sys
->next_date
;
186 while(sys
->current
< sys
->count
&&
187 sys
->index
[sys
->current
].start
<= i_barrier
)
189 stl_entry_t
*s
= &sys
->index
[sys
->current
];
191 if (!sys
->b_slave
&& sys
->b_first_time
)
193 es_out_SetPCR(demux
->out
, VLC_TICK_0
+ i_barrier
);
194 sys
->b_first_time
= false;
197 /* Might be a gap in block # */
198 const uint64_t i_pos
= 1024 + 128LL * s
->blocknumber
;
199 if(i_pos
!= vlc_stream_Tell(demux
->s
) &&
200 vlc_stream_Seek( demux
->s
, i_pos
) != VLC_SUCCESS
)
201 return VLC_DEMUXER_EOF
;
203 block_t
*b
= vlc_stream_Block(demux
->s
, 128);
204 if (b
&& b
->i_buffer
== 128)
207 b
->i_pts
= VLC_TICK_0
+ s
->start
;
208 if (s
->stop
> s
->start
)
209 b
->i_length
= s
->stop
- s
->start
;
210 es_out_Send(demux
->out
, sys
->es
, b
);
216 return VLC_DEMUXER_EOF
;
223 es_out_SetPCR(demux
->out
, VLC_TICK_0
+ i_barrier
);
224 sys
->next_date
+= VLC_TICK_FROM_MS(125);
227 return sys
->current
< sys
->count
? VLC_DEMUXER_SUCCESS
: VLC_DEMUXER_EOF
;
230 static int Open(vlc_object_t
*object
)
232 demux_t
*demux
= (demux_t
*)object
;
235 if (vlc_stream_Peek(demux
->s
, &peek
, 11) != 11)
238 bool is_stl_25
= !memcmp(&peek
[3], "STL25.01", 8);
239 bool is_stl_30
= !memcmp(&peek
[3], "STL30.01", 8);
240 if (!is_stl_25
&& !is_stl_30
)
242 const double fps
= is_stl_25
? 25 : 30;
244 uint8_t header
[1024];
245 if (vlc_stream_Read(demux
->s
, header
, sizeof(header
)) != sizeof(header
)) {
246 msg_Err(demux
, "Incomplete EBU STL header");
249 const int cct
= ParseInteger(&header
[12], 2);
250 const vlc_tick_t program_start
= ParseTextTimeCode(&header
[256], fps
);
251 const size_t tti_count
= ParseInteger(&header
[238], 5);
254 msg_Dbg(demux
, "Detected EBU STL : CCT=%d TTI=%zu start=%8.8s %"PRId64
, cct
, tti_count
, &header
[256], program_start
);
256 demux_sys_t
*sys
= malloc(sizeof(*sys
));
260 sys
->b_slave
= false;
261 sys
->b_first_time
= true;
265 sys
->index
= calloc(tti_count
, sizeof(*sys
->index
));
272 bool comment
= false;
273 stl_entry_t
*s
= &sys
->index
[0];
276 for (size_t i
= 0; i
< tti_count
; i
++) {
278 if (vlc_stream_Read(demux
->s
, tti
, 16) != 16 ||
279 vlc_stream_Read(demux
->s
, NULL
, 112) != 112) {
280 msg_Warn(demux
, "Incomplete EBU STL file");
283 const int ebn
= tti
[3];
284 if (ebn
>= 0xf0 && ebn
<= 0xfd)
290 comment
= tti
[15] != 0;
291 s
->start
= ParseTimeCode(&tti
[5], fps
) - program_start
;
292 s
->stop
= ParseTimeCode(&tti
[9], fps
) - program_start
;
296 if (ebn
== 0xff && !comment
)
297 s
= &sys
->index
[++sys
->count
];
298 if (ebn
== 0xff && sys
->count
< tti_count
)
303 if (sys
->count
== 0 ||
304 vlc_stream_Seek(demux
->s
, 1024 + 128LL * sys
->index
[0].blocknumber
) != VLC_SUCCESS
)
311 es_format_Init(&fmt
, SPU_ES
, VLC_CODEC_EBU_STL
);
312 fmt
.i_extra
= sizeof(header
);
313 fmt
.p_extra
= header
;
315 sys
->es
= es_out_Add(demux
->out
, &fmt
);
318 es_format_Clean(&fmt
);
327 demux
->pf_demux
= Demux
;
328 demux
->pf_control
= Control
;
332 static void Close(vlc_object_t
*object
)
334 demux_t
*demux
= (demux_t
*)object
;
335 demux_sys_t
*sys
= demux
->p_sys
;