Decklink: Fix swapped format arguments
[vlc.git] / modules / stream_out / cycle.c
blob0c7481339eff7309afa16a4cfbd3cb0d1c27dbb7
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>
39 typedef struct sout_cycle sout_cycle_t;
41 struct sout_cycle
43 sout_cycle_t *next;
44 vlc_tick_t offset;
45 char chain[1];
48 typedef struct sout_stream_id_sys_t sout_stream_id_sys_t;
49 struct sout_stream_id_sys_t
51 sout_stream_id_sys_t *prev;
52 sout_stream_id_sys_t *next;
53 es_format_t fmt;
54 void *id;
57 typedef struct
59 sout_stream_t *stream; /*< Current output stream */
60 sout_stream_id_sys_t *first; /*< First elementary stream */
61 sout_stream_id_sys_t *last; /*< Last elementary stream */
63 sout_cycle_t *start;
64 sout_cycle_t *next;
65 vlc_tick_t (*clock)(const block_t *);
66 vlc_tick_t period; /*< Total cycle duration */
67 } sout_stream_sys_t;
69 static vlc_tick_t get_dts(const block_t *block)
71 return block->i_dts;
74 static void *Add(sout_stream_t *stream, const es_format_t *fmt)
76 sout_stream_sys_t *sys = stream->p_sys;
77 sout_stream_id_sys_t *id = malloc(sizeof (*id));
78 if (unlikely(id == NULL))
79 return NULL;
81 id->next = NULL;
83 if (es_format_Copy(&id->fmt, fmt))
85 es_format_Clean(&id->fmt);
86 free(id);
87 return NULL;
90 if (sys->stream != NULL)
91 id->id = sout_StreamIdAdd(sys->stream, &id->fmt);
93 id->prev = sys->last;
94 sys->last = id;
95 if (id->prev != NULL)
96 id->prev->next = id;
97 else
98 sys->first = id;
99 return id;
102 static void Del(sout_stream_t *stream, void *_id)
104 sout_stream_sys_t *sys = stream->p_sys;
105 sout_stream_id_sys_t *id = (sout_stream_id_sys_t *)_id;
107 if (id->prev != NULL)
108 id->prev->next = id->next;
109 else
110 sys->first = id->next;
112 if (id->next != NULL)
113 id->next->prev = id->prev;
114 else
115 sys->last = id->prev;
117 if (sys->stream != NULL)
118 sout_StreamIdDel(sys->stream, id->id);
120 es_format_Clean(&id->fmt);
121 free(id);
124 static int AddStream(sout_stream_t *stream, char *chain)
126 sout_stream_sys_t *sys = stream->p_sys;
128 msg_Dbg(stream, "starting new phase \"%s\"", chain);
129 /* TODO format */
130 sys->stream = sout_StreamChainNew(stream->p_sout, chain,
131 stream->p_next, NULL);
132 if (sys->stream == NULL)
133 return -1;
135 for (sout_stream_id_sys_t *id = sys->first; id != NULL; id = id->next)
136 id->id = sout_StreamIdAdd(sys->stream, &id->fmt);
138 return 0;
141 static void DelStream(sout_stream_t *stream)
143 sout_stream_sys_t *sys = stream->p_sys;
145 if (sys->stream == NULL)
146 return;
148 for (sout_stream_id_sys_t *id = sys->first; id != NULL; id = id->next)
149 if (id->id != NULL)
150 sout_StreamIdDel(sys->stream, id->id);
152 sout_StreamChainDelete(sys->stream, NULL);
153 sys->stream = NULL;
156 static int Send(sout_stream_t *stream, void *_id, block_t *block)
158 sout_stream_sys_t *sys = stream->p_sys;
159 sout_stream_id_sys_t *id = (sout_stream_id_sys_t *)_id;
161 for (block_t *next = block->p_next; block != NULL; block = next)
163 block->p_next = NULL;
165 /* FIXME: deal with key frames properly */
166 while (sys->clock(block) >= sys->next->offset)
168 DelStream(stream);
169 AddStream(stream, sys->next->chain);
171 sys->next->offset += sys->period;
172 sys->next = sys->next->next;
173 if (sys->next == NULL)
174 sys->next = sys->start;
177 if (sys->stream != NULL)
178 sout_StreamIdSend(sys->stream, id->id, block);
179 else
180 block_Release(block);
182 return VLC_SUCCESS;
185 static int AppendPhase(sout_cycle_t ***restrict pp,
186 vlc_tick_t offset, const char *chain)
189 size_t len = strlen(chain);
190 sout_cycle_t *cycle = malloc(sizeof (*cycle) + len);
191 if (unlikely(cycle == NULL))
192 return -1;
194 cycle->next = NULL;
195 cycle->offset = offset;
196 memcpy(cycle->chain, chain, len + 1);
198 **pp = cycle;
199 *pp = &cycle->next;
200 return 0;
203 static vlc_tick_t ParseTime(const char *str)
205 char *end;
206 unsigned long long u = strtoull(str, &end, 0);
208 switch (*end)
210 case 'w':
211 if (u < ((unsigned long long)INT64_MAX)/ (60 * 60 * 24 * 7 * CLOCK_FREQ))
212 return vlc_tick_from_sec( 60LU * 60 * 24 * 7 * u );
213 break;
214 case 'd':
215 if (u < ((unsigned long long)INT64_MAX)/ (60 * 60 * 24 * CLOCK_FREQ))
216 return vlc_tick_from_sec( 60LU * 60 * 24 * u );
217 break;
218 case 'h':
219 if (u < ((unsigned long long)INT64_MAX)/ (60 * 60 * CLOCK_FREQ))
220 return vlc_tick_from_sec( 60LLU * 60 * u );
221 break;
222 case 'm':
223 if (u < ((unsigned long long)INT64_MAX)/ (60 * CLOCK_FREQ))
224 return vlc_tick_from_sec( 60LLU * u );
225 break;
226 case 's':
227 case 0:
228 if (u < ((unsigned long long)INT64_MAX)/CLOCK_FREQ)
229 return vlc_tick_from_sec( u );
230 break;
232 return -1;
235 static int Open(vlc_object_t *obj)
237 sout_stream_t *stream = (sout_stream_t *)obj;
238 sout_stream_sys_t *sys = malloc(sizeof (*sys));
239 if (unlikely(sys == NULL))
240 return VLC_ENOMEM;
242 sys->stream = NULL;
243 sys->first = NULL;
244 sys->last = NULL;
245 sys->start = NULL;
246 sys->clock = get_dts;
248 vlc_tick_t offset = 0;
249 sout_cycle_t **pp = &sys->start;
250 const char *chain = "";
252 for (const config_chain_t *cfg = stream->p_cfg;
253 cfg != NULL;
254 cfg = cfg->p_next)
256 if (!strcmp(cfg->psz_name, "dst"))
258 chain = cfg->psz_value;
260 else if (!strcmp(cfg->psz_name, "duration"))
262 vlc_tick_t t = ParseTime(cfg->psz_value);
264 if (t > 0)
266 AppendPhase(&pp, offset, chain);
267 offset += t;
270 chain = "";
272 else if (!strcmp(cfg->psz_name, "offset"))
274 vlc_tick_t t = ParseTime(cfg->psz_value);
276 if (t > offset)
278 AppendPhase(&pp, offset, chain);
279 offset = t;
282 chain = "";
284 else
286 msg_Err(stream, "unknown option \"%s\"", cfg->psz_name);
290 if (sys->start == NULL || offset == 0)
292 free(sys);
293 msg_Err(stream, "unknown or invalid cycle specification");
294 return VLC_EGENERIC;
297 sys->next = sys->start;
298 sys->period = offset;
300 stream->pf_add = Add;
301 stream->pf_del = Del;
302 stream->pf_send = Send;
303 stream->p_sys = sys;
304 return VLC_SUCCESS;
307 static void Close(vlc_object_t *obj)
309 sout_stream_t *stream = (sout_stream_t *)obj;
310 sout_stream_sys_t *sys = stream->p_sys;
312 assert(sys->first == NULL && sys->last == NULL);
314 if (sys->stream != NULL)
315 sout_StreamChainDelete(sys->stream, NULL);
317 for (sout_cycle_t *cycle = sys->start, *next; cycle != NULL; cycle = next)
319 next = cycle->next;
320 free(cycle);
323 free(sys);
326 vlc_module_begin()
327 set_shortname(N_("cycle"))
328 set_description(N_("Cyclic stream output"))
329 set_capability("sout stream", 0)
330 set_category(CAT_SOUT)
331 set_subcategory(SUBCAT_SOUT_STREAM)
332 set_callbacks(Open, Close)
333 add_shortcut("cycle")
334 vlc_module_end()