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 *****************************************************************************/
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 int64_t ParseTimeCode(uint8_t *data
, double fps
)
84 return INT64_C(1000000) * (data
[0] * 3600 +
89 static int64_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 int64_t *l
= va_arg(args
, int64_t *);
105 *l
= sys
->count
> 0 ? sys
->index
[sys
->count
-1].stop
: 0;
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");
115 case DEMUX_SET_NEXT_DEMUX_TIME
: {
117 sys
->next_date
= va_arg(args
, int64_t);
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
++ )
124 if( sys
->index
[i
+ 1].start
>= t
&&
125 vlc_stream_Seek(demux
->s
, 1024 + 128LL * sys
->index
[i
].blocknumber
) == VLC_SUCCESS
)
129 sys
->b_first_time
= true;
135 case DEMUX_SET_POSITION
:
137 double f
= va_arg( args
, double );
138 if(sys
->count
&& sys
->index
[sys
->count
-1].stop
> 0)
140 int64_t i64
= f
* sys
->index
[sys
->count
-1].stop
;
141 return demux_Control(demux
, DEMUX_SET_TIME
, i64
);
145 case DEMUX_GET_POSITION
:
147 double *pf
= va_arg(args
, double *);
148 if(sys
->current
>= sys
->count
)
152 else if(sys
->count
> 0 && sys
->index
[sys
->count
-1].stop
> 0)
154 *pf
= sys
->next_date
- var_GetInteger(demux
->obj
.parent
, "spu-delay");
156 *pf
= sys
->next_date
;
157 *pf
/= sys
->index
[sys
->count
-1].stop
;
171 static int Demux(demux_t
*demux
)
173 demux_sys_t
*sys
= demux
->p_sys
;
175 int64_t i_barrier
= sys
->next_date
- var_GetInteger(demux
->obj
.parent
, "spu-delay");
177 i_barrier
= sys
->next_date
;
179 while(sys
->current
< sys
->count
&&
180 sys
->index
[sys
->current
].start
<= i_barrier
)
182 stl_entry_t
*s
= &sys
->index
[sys
->current
];
184 if (!sys
->b_slave
&& sys
->b_first_time
)
186 es_out_SetPCR(demux
->out
, VLC_TS_0
+ i_barrier
);
187 sys
->b_first_time
= false;
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
;
196 block_t
*b
= vlc_stream_Block(demux
->s
, 128);
197 if (b
&& b
->i_buffer
== 128)
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
);
209 return VLC_DEMUXER_EOF
;
216 es_out_SetPCR(demux
->out
, VLC_TS_0
+ i_barrier
);
217 sys
->next_date
+= CLOCK_FREQ
/ 8;
220 return sys
->current
< sys
->count
? VLC_DEMUXER_SUCCESS
: VLC_DEMUXER_EOF
;
223 static int Open(vlc_object_t
*object
)
225 demux_t
*demux
= (demux_t
*)object
;
228 if (vlc_stream_Peek(demux
->s
, &peek
, 11) != 11)
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
)
235 const double fps
= is_stl_25
? 25 : 30;
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");
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);
247 msg_Dbg(demux
, "Detected EBU STL : CCT=%d TTI=%zu start=%8.8s %"PRId64
, cct
, tti_count
, &header
[256], program_start
);
249 demux_sys_t
*sys
= malloc(sizeof(*sys
));
253 sys
->b_slave
= false;
254 sys
->b_first_time
= true;
258 sys
->index
= calloc(tti_count
, sizeof(*sys
->index
));
265 bool comment
= false;
266 stl_entry_t
*s
= &sys
->index
[0];
269 for (size_t i
= 0; i
< tti_count
; i
++) {
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");
276 const int ebn
= tti
[3];
277 if (ebn
>= 0xf0 && ebn
<= 0xfd)
283 comment
= tti
[15] != 0;
284 s
->start
= ParseTimeCode(&tti
[5], fps
) - program_start
;
285 s
->stop
= ParseTimeCode(&tti
[9], fps
) - program_start
;
289 if (ebn
== 0xff && !comment
)
290 s
= &sys
->index
[++sys
->count
];
291 if (ebn
== 0xff && sys
->count
< tti_count
)
296 if (sys
->count
== 0 ||
297 vlc_stream_Seek(demux
->s
, 1024 + 128LL * sys
->index
[0].blocknumber
) != VLC_SUCCESS
)
304 es_format_Init(&fmt
, SPU_ES
, VLC_CODEC_EBU_STL
);
305 fmt
.i_extra
= sizeof(header
);
306 fmt
.p_extra
= header
;
308 sys
->es
= es_out_Add(demux
->out
, &fmt
);
311 es_format_Clean(&fmt
);
320 demux
->pf_demux
= Demux
;
321 demux
->pf_control
= Control
;
325 static void Close(vlc_object_t
*object
)
327 demux_t
*demux
= (demux_t
*)object
;
328 demux_sys_t
*sys
= demux
->p_sys
;