Qt: add asserts around p_input access
[vlc.git] / modules / demux / stl.c
blob50a97e119b94f90b216872416e59b815a8e4ba62
1 /*****************************************************************************
2 * stl.c: EBU STL demuxer
3 *****************************************************************************
4 * Copyright (C) 2010 Laurent Aimar
5 * $Id$
7 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 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 General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 #include <assert.h>
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_demux.h>
36 /*****************************************************************************
37 * Module descriptor
38 *****************************************************************************/
39 static int Open (vlc_object_t *);
40 static void Close(vlc_object_t *);
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()
51 /*****************************************************************************
52 * Local definitions/prototypes
53 *****************************************************************************/
54 typedef struct {
55 mtime_t start;
56 mtime_t stop;
57 int index;
58 int count;
59 } stl_entry_t;
61 struct demux_sys_t {
62 int count;
63 stl_entry_t *index;
65 es_out_id_t *es;
67 int current;
68 int64_t next_date;
71 static int ParseInteger(uint8_t *data, int size)
73 char tmp[16];
74 assert(size < sizeof(tmp));
75 memcpy(tmp, data, size);
76 tmp[size] = '\0';
78 return strtol(tmp, NULL, 10);
80 static int64_t ParseTimeCode(uint8_t *data, double fps)
82 return INT64_C(1000000) * (data[0] * 3600 +
83 data[1] * 60 +
84 data[2] * 1 +
85 data[3] / fps);
87 static int64_t ParseTextTimeCode(uint8_t *data, double fps)
89 uint8_t tmp[4];
90 for (int i = 0; i < 4; i++)
91 tmp[i] = ParseInteger(&data[2 * i], 2);
92 return ParseTimeCode(tmp, fps);
95 static int Control(demux_t *demux, int query, va_list args)
97 demux_sys_t *sys = demux->p_sys;
98 switch(query) {
99 case DEMUX_GET_LENGTH: {
100 int64_t *l = va_arg(args, int64_t *);
101 *l = sys->count > 0 ? sys->index[sys->count-1].stop : 0;
102 return VLC_SUCCESS;
104 case DEMUX_GET_TIME: {
105 int64_t *t = va_arg(args, int64_t *);
106 *t = sys->current < sys->count ? sys->index[sys->count-1].start : 0;
107 return VLC_SUCCESS;
109 case DEMUX_SET_NEXT_DEMUX_TIME: {
110 sys->next_date = va_arg(args, int64_t);
111 return VLC_SUCCESS;
113 case DEMUX_SET_TIME: {
114 int64_t t = va_arg(args, int64_t);
115 sys->current = 0;
116 while (sys->current < sys->count) {
117 if (sys->index[sys->current].stop > t) {
118 stream_Seek(demux->s, 1024 + 128LL * sys->index[sys->current].index);
119 break;
121 sys->current++;
123 return VLC_SUCCESS;
125 case DEMUX_SET_POSITION:
126 case DEMUX_GET_POSITION:
127 default:
128 return VLC_EGENERIC;
132 static int Demux(demux_t *demux)
134 demux_sys_t *sys = demux->p_sys;
136 while(sys->current < sys->count) {
137 stl_entry_t *s = &sys->index[sys->current];
138 if (s->start > sys->next_date)
139 break;
141 block_t *b = stream_Block(demux->s, 128 * s->count);
142 if (b) {
143 b->i_dts =
144 b->i_pts = VLC_TS_0 + s->start;
145 if (s->stop > s->start)
146 b->i_length = s->stop - s->start;
147 es_out_Send(demux->out, sys->es, b);
149 sys->current++;
151 return sys->current < sys->count ? 1 : 0;
154 static int Open(vlc_object_t *object)
156 demux_t *demux = (demux_t*)object;
158 const uint8_t *peek;
159 if (stream_Peek(demux->s, &peek, 11) != 11)
160 return VLC_EGENERIC;
162 bool is_stl_25 = !memcmp(&peek[3], "STL25.01", 8);
163 bool is_stl_30 = !memcmp(&peek[3], "STL30.01", 8);
164 if (!is_stl_25 && !is_stl_30)
165 return VLC_EGENERIC;
166 const double fps = is_stl_25 ? 25 : 30;
168 uint8_t header[1024];
169 if (stream_Read(demux->s, header, sizeof(header)) != sizeof(header)) {
170 msg_Err(demux, "Incomplete EBU STL header");
171 return VLC_EGENERIC;
173 const int cct = ParseInteger(&header[12], 2);
174 const mtime_t program_start = ParseTextTimeCode(&header[256], fps);
175 const int tti_count = ParseInteger(&header[238], 5);
176 msg_Dbg(demux, "Detected EBU STL : CCT=%d TTI=%d start=%8.8s %"PRId64, cct, tti_count, &header[256], program_start);
178 demux_sys_t *sys = xmalloc(sizeof(*sys));
179 sys->next_date = 0;
180 sys->current = 0;
181 sys->count = 0;
182 sys->index = xcalloc(tti_count, sizeof(*sys->index));
185 bool comment = false;
186 stl_entry_t *s = &sys->index[0];
187 s->count = 0;
189 for (int i = 0; i < tti_count; i++) {
190 uint8_t tti[16];
191 if (stream_Read(demux->s, tti, 16) != 16 ||
192 stream_Read(demux->s, NULL, 112) != 112) {
193 msg_Warn(demux, "Incomplete EBU STL file");
194 break;
196 const int ebn = tti[3];
197 if (ebn >= 0xf0 && ebn <= 0xfd)
198 continue;
199 if (ebn == 0xfe)
200 continue;
202 if (s->count <= 0) {
203 comment = tti[15] != 0;
204 s->start = ParseTimeCode(&tti[5], fps) - program_start;
205 s->stop = ParseTimeCode(&tti[9], fps) - program_start;
206 s->index = i;
208 s->count++;
209 if (ebn == 0xff && !comment)
210 s = &sys->index[++sys->count];
211 if (ebn == 0xff && sys->count < tti_count)
212 s->count = 0;
214 if (sys->count > 0)
215 stream_Seek(demux->s, 1024 + 128LL * sys->index[0].index);
217 es_format_t fmt;
218 es_format_Init(&fmt, SPU_ES, VLC_CODEC_EBU_STL);
219 fmt.i_extra = sizeof(header);
220 fmt.p_extra = header;
222 sys->es = es_out_Add(demux->out, &fmt);
224 fmt.i_extra = 0;
225 fmt.p_extra = NULL;
226 es_format_Clean(&fmt);
228 demux->p_sys = sys;
229 demux->pf_demux = Demux;
230 demux->pf_control = Control;
231 return VLC_SUCCESS;
234 static void Close(vlc_object_t *object)
236 demux_t *demux = (demux_t*)object;
237 demux_sys_t *sys = demux->p_sys;
239 free(sys->index);
240 free(sys);