qml: Create MediaGroupDisplay
[vlc.git] / modules / stream_out / cycle.c
blobc715e931fb8cb5ad5bddbfc96fd9a7c2cf9ff300
1 /*****************************************************************************
2 * cycle.c: cycle stream output module
3 *****************************************************************************
4 * Copyright (C) 2015 Rémi Denis-Courmont
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Rémi Denis-Courmont reserves the right to redistribute this file under
12 * the terms of the GNU Lesser General Public License as published by the
13 * the Free Software Foundation; either version 2.1 or the License, or
14 * (at his option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
30 #include <assert.h>
31 #include <stdlib.h>
33 #define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_block.h>
37 #include <vlc_sout.h>
38 #include <vlc_list.h>
40 typedef struct sout_cycle sout_cycle_t;
42 struct sout_cycle
44 sout_cycle_t *next;
45 vlc_tick_t offset;
46 char chain[1];
49 typedef struct sout_stream_id_sys_t sout_stream_id_sys_t;
50 struct sout_stream_id_sys_t
52 struct vlc_list node;
53 es_format_t fmt;
54 void *id;
57 typedef struct
59 sout_stream_t *stream; /*< Current output stream */
60 struct vlc_list ids; /*< List of elementary streams */
62 sout_cycle_t *start;
63 sout_cycle_t *next;
64 vlc_tick_t (*clock)(const block_t *);
65 vlc_tick_t period; /*< Total cycle duration */
66 } sout_stream_sys_t;
68 static vlc_tick_t get_dts(const block_t *block)
70 return block->i_dts;
73 static void *Add(sout_stream_t *stream, const es_format_t *fmt)
75 sout_stream_sys_t *sys = stream->p_sys;
76 sout_stream_id_sys_t *id = malloc(sizeof (*id));
77 if (unlikely(id == NULL))
78 return NULL;
80 if (es_format_Copy(&id->fmt, fmt))
82 es_format_Clean(&id->fmt);
83 free(id);
84 return NULL;
87 if (sys->stream != NULL)
88 id->id = sout_StreamIdAdd(sys->stream, &id->fmt);
90 vlc_list_append(&id->node, &sys->ids);
91 return id;
94 static void Del(sout_stream_t *stream, void *_id)
96 sout_stream_sys_t *sys = stream->p_sys;
97 sout_stream_id_sys_t *id = (sout_stream_id_sys_t *)_id;
99 vlc_list_remove(&id->node);
101 if (sys->stream != NULL)
102 sout_StreamIdDel(sys->stream, id->id);
104 es_format_Clean(&id->fmt);
105 free(id);
108 static int AddStream(sout_stream_t *stream, char *chain)
110 sout_stream_sys_t *sys = stream->p_sys;
111 sout_stream_id_sys_t *id;
113 msg_Dbg(stream, "starting new phase \"%s\"", chain);
114 /* TODO format */
115 sys->stream = sout_StreamChainNew(VLC_OBJECT(stream), chain,
116 stream->p_next);
117 if (sys->stream == NULL)
118 return -1;
120 vlc_list_foreach (id, &sys->ids, node)
121 id->id = sout_StreamIdAdd(sys->stream, &id->fmt);
123 return 0;
126 static void DelStream(sout_stream_t *stream)
128 sout_stream_sys_t *sys = stream->p_sys;
129 sout_stream_id_sys_t *id;
131 if (sys->stream == NULL)
132 return;
134 vlc_list_foreach (id, &sys->ids, node)
135 if (id->id != NULL)
136 sout_StreamIdDel(sys->stream, id->id);
138 sout_StreamChainDelete(sys->stream, stream->p_next);
139 sys->stream = NULL;
142 static int Send(sout_stream_t *stream, void *_id, block_t *block)
144 sout_stream_sys_t *sys = stream->p_sys;
145 sout_stream_id_sys_t *id = (sout_stream_id_sys_t *)_id;
147 for (block_t *next = block->p_next; block != NULL; block = next)
149 block->p_next = NULL;
151 /* FIXME: deal with key frames properly */
152 while (sys->clock(block) >= sys->next->offset)
154 DelStream(stream);
155 AddStream(stream, sys->next->chain);
157 sys->next->offset += sys->period;
158 sys->next = sys->next->next;
159 if (sys->next == NULL)
160 sys->next = sys->start;
163 if (sys->stream != NULL)
164 sout_StreamIdSend(sys->stream, id->id, block);
165 else
166 block_Release(block);
168 return VLC_SUCCESS;
171 static int AppendPhase(sout_cycle_t ***restrict pp,
172 vlc_tick_t offset, const char *chain)
175 size_t len = strlen(chain);
176 sout_cycle_t *cycle = malloc(sizeof (*cycle) + len);
177 if (unlikely(cycle == NULL))
178 return -1;
180 cycle->next = NULL;
181 cycle->offset = offset;
182 memcpy(cycle->chain, chain, len + 1);
184 **pp = cycle;
185 *pp = &cycle->next;
186 return 0;
189 static vlc_tick_t ParseTime(const char *str)
191 char *end;
192 unsigned long long u = strtoull(str, &end, 0);
194 switch (*end)
196 case 'w':
197 if (u < ((unsigned long long)INT64_MAX)/ (60 * 60 * 24 * 7 * CLOCK_FREQ))
198 return vlc_tick_from_sec( 60LU * 60 * 24 * 7 * u );
199 break;
200 case 'd':
201 if (u < ((unsigned long long)INT64_MAX)/ (60 * 60 * 24 * CLOCK_FREQ))
202 return vlc_tick_from_sec( 60LU * 60 * 24 * u );
203 break;
204 case 'h':
205 if (u < ((unsigned long long)INT64_MAX)/ (60 * 60 * CLOCK_FREQ))
206 return vlc_tick_from_sec( 60LLU * 60 * u );
207 break;
208 case 'm':
209 if (u < ((unsigned long long)INT64_MAX)/ (60 * CLOCK_FREQ))
210 return vlc_tick_from_sec( 60LLU * u );
211 break;
212 case 's':
213 case 0:
214 if (u < ((unsigned long long)INT64_MAX)/CLOCK_FREQ)
215 return vlc_tick_from_sec( u );
216 break;
218 return -1;
221 static const struct sout_stream_operations ops = {
222 Add, Del, Send, NULL, NULL,
225 static int Open(vlc_object_t *obj)
227 sout_stream_t *stream = (sout_stream_t *)obj;
228 sout_stream_sys_t *sys = malloc(sizeof (*sys));
229 if (unlikely(sys == NULL))
230 return VLC_ENOMEM;
232 sys->stream = NULL;
233 vlc_list_init(&sys->ids);
234 sys->start = NULL;
235 sys->clock = get_dts;
237 vlc_tick_t offset = 0;
238 sout_cycle_t **pp = &sys->start;
239 const char *chain = "";
241 for (const config_chain_t *cfg = stream->p_cfg;
242 cfg != NULL;
243 cfg = cfg->p_next)
245 if (!strcmp(cfg->psz_name, "dst"))
247 chain = cfg->psz_value;
249 else if (!strcmp(cfg->psz_name, "duration"))
251 vlc_tick_t t = ParseTime(cfg->psz_value);
253 if (t > 0)
255 AppendPhase(&pp, offset, chain);
256 offset += t;
259 chain = "";
261 else if (!strcmp(cfg->psz_name, "offset"))
263 vlc_tick_t t = ParseTime(cfg->psz_value);
265 if (t > offset)
267 AppendPhase(&pp, offset, chain);
268 offset = t;
271 chain = "";
273 else
275 msg_Err(stream, "unknown option \"%s\"", cfg->psz_name);
279 if (sys->start == NULL || offset == 0)
281 free(sys);
282 msg_Err(stream, "unknown or invalid cycle specification");
283 return VLC_EGENERIC;
286 sys->next = sys->start;
287 sys->period = offset;
289 stream->ops = &ops;
290 stream->p_sys = sys;
291 return VLC_SUCCESS;
294 static void Close(vlc_object_t *obj)
296 sout_stream_t *stream = (sout_stream_t *)obj;
297 sout_stream_sys_t *sys = stream->p_sys;
299 assert(vlc_list_is_empty(&sys->ids));
301 if (sys->stream != NULL)
302 sout_StreamChainDelete(sys->stream, stream->p_next);
304 for (sout_cycle_t *cycle = sys->start, *next; cycle != NULL; cycle = next)
306 next = cycle->next;
307 free(cycle);
310 free(sys);
313 vlc_module_begin()
314 set_shortname(N_("cycle"))
315 set_description(N_("Cyclic stream output"))
316 set_capability("sout output", 0)
317 set_category(CAT_SOUT)
318 set_subcategory(SUBCAT_SOUT_STREAM)
319 set_callbacks(Open, Close)
320 add_shortcut("cycle")
321 add_submodule()
322 add_shortcut("cycle")
323 set_capability("sout filter", 0)
324 set_callbacks(Open, Close)
325 vlc_module_end()