demux: hls: add adaptative based hls demuxer
[vlc.git] / modules / demux / stl.c
1 /*****************************************************************************
2  * stl.c: EBU STL demuxer
3  *****************************************************************************
4  * Copyright (C) 2010 Laurent Aimar
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 #include <assert.h>
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_demux.h>
35
36 /*****************************************************************************
37  * Module descriptor
38  *****************************************************************************/
39 static int  Open (vlc_object_t *);
40 static void Close(vlc_object_t *);
41
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()
50
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;
60
61 struct demux_sys_t {
62     int         count;
63     stl_entry_t *index;
64
65     es_out_id_t *es;
66
67     int         current;
68     int64_t     next_date;
69 };
70
71 static int ParseInteger(uint8_t *data, size_t size)
72 {
73     char tmp[16];
74     assert(size < sizeof(tmp));
75     memcpy(tmp, data, size);
76     tmp[size] = '\0';
77
78     return strtol(tmp, NULL, 10);
79 }
80 static int64_t ParseTimeCode(uint8_t *data, double fps)
81 {
82     return INT64_C(1000000) * (data[0] * 3600 +
83                                data[1] *   60 +
84                                data[2] *    1 +
85                                data[3] /  fps);
86 }
87 static int64_t ParseTextTimeCode(uint8_t *data, double fps)
88 {
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);
93 }
94
95 static int Control(demux_t *demux, int query, va_list args)
96 {
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;
103     }
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;
108     }
109     case DEMUX_SET_NEXT_DEMUX_TIME: {
110         sys->next_date = va_arg(args, int64_t);
111         return VLC_SUCCESS;
112     }
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;
120             }
121             sys->current++;
122         }
123         return VLC_SUCCESS;
124     }
125     case DEMUX_SET_POSITION:
126     case DEMUX_GET_POSITION:
127     default:
128         return VLC_EGENERIC;
129     }
130 }
131
132 static int Demux(demux_t *demux)
133 {
134     demux_sys_t *sys = demux->p_sys;
135
136     while(sys->current < sys->count) {
137         stl_entry_t *s = &sys->index[sys->current];
138         if (s->start > sys->next_date)
139             break;
140
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);
148         }
149         sys->current++;
150     }
151     return sys->current < sys->count ? 1 : 0;
152 }
153
154 static int Open(vlc_object_t *object)
155 {
156     demux_t *demux = (demux_t*)object;
157
158     const uint8_t *peek;
159     if (stream_Peek(demux->s, &peek, 11) != 11)
160         return VLC_EGENERIC;
161
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;
167
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;
172     }
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);
177
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));
183
184
185     bool comment = false;
186     stl_entry_t *s = &sys->index[0];
187     s->count = 0;
188
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;
195         }
196         const int ebn = tti[3];
197         if (ebn >= 0xf0 && ebn <= 0xfd)
198             continue;
199         if (ebn == 0xfe)
200             continue;
201
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;
207         }
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;
213     }
214     if (sys->count > 0)
215         stream_Seek(demux->s, 1024 + 128LL * sys->index[0].index);
216
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;
221
222     sys->es = es_out_Add(demux->out, &fmt);
223
224     fmt.i_extra = 0;
225     fmt.p_extra = NULL;
226     es_format_Clean(&fmt);
227
228     demux->p_sys      = sys;
229     demux->pf_demux   = Demux;
230     demux->pf_control = Control;
231     return VLC_SUCCESS;
232 }
233
234 static void Close(vlc_object_t *object)
235 {
236     demux_t *demux = (demux_t*)object;
237     demux_sys_t *sys = demux->p_sys;
238
239     free(sys->index);
240     free(sys);
241 }
242