packetizer: hevc: don't double store poc prev msb/lsb
[vlc.git] / modules / stream_out / cycle.c
blobbb031f81ae0eeceeb993bed3927d63aa29bb53eb
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 mtime_t offset;
45 char chain[1];
48 struct sout_stream_id_sys_t
50 sout_stream_id_sys_t *prev;
51 sout_stream_id_sys_t *next;
52 es_format_t fmt;
53 void *id;
56 struct sout_stream_sys_t
58 sout_stream_t *stream; /*< Current output stream */
59 sout_stream_id_sys_t *first; /*< First elementary stream */
60 sout_stream_id_sys_t *last; /*< Last elementary stream */
62 sout_cycle_t *start;
63 sout_cycle_t *next;
64 mtime_t (*clock)(const block_t *);
65 mtime_t period; /*< Total cycle duration */
68 static mtime_t get_dts(const block_t *block)
70 return block->i_dts;
73 static sout_stream_id_sys_t *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 id->next = NULL;
82 if (es_format_Copy(&id->fmt, fmt))
84 es_format_Clean(&id->fmt);
85 free(id);
86 return NULL;
89 if (sys->stream != NULL)
90 id->id = sout_StreamIdAdd(sys->stream, &id->fmt);
92 id->prev = sys->last;
93 sys->last = id;
94 if (id->prev != NULL)
95 id->prev->next = id;
96 else
97 sys->first = id;
98 return id;
101 static void Del(sout_stream_t *stream, sout_stream_id_sys_t *id)
103 sout_stream_sys_t *sys = stream->p_sys;
105 if (id->prev != NULL)
106 id->prev->next = id->next;
107 else
108 sys->first = id->next;
110 if (id->next != NULL)
111 id->next->prev = id->prev;
112 else
113 sys->last = id->prev;
115 if (sys->stream != NULL)
116 sout_StreamIdDel(sys->stream, id->id);
118 es_format_Clean(&id->fmt);
119 free(id);
122 static int AddStream(sout_stream_t *stream, char *chain)
124 sout_stream_sys_t *sys = stream->p_sys;
126 msg_Dbg(stream, "starting new phase \"%s\"", chain);
127 /* TODO format */
128 sys->stream = sout_StreamChainNew(stream->p_sout, chain,
129 stream->p_next, NULL);
130 if (sys->stream == NULL)
131 return -1;
133 for (sout_stream_id_sys_t *id = sys->first; id != NULL; id = id->next)
134 id->id = sout_StreamIdAdd(sys->stream, &id->fmt);
136 return 0;
139 static void DelStream(sout_stream_t *stream)
141 sout_stream_sys_t *sys = stream->p_sys;
143 if (sys->stream == NULL)
144 return;
146 for (sout_stream_id_sys_t *id = sys->first; id != NULL; id = id->next)
147 if (id->id != NULL)
148 sout_StreamIdDel(sys->stream, id->id);
150 sout_StreamChainDelete(sys->stream, NULL);
151 sys->stream = NULL;
154 static int Send(sout_stream_t *stream, sout_stream_id_sys_t *id,
155 block_t *block)
157 sout_stream_sys_t *sys = stream->p_sys;
159 for (block_t *next = block->p_next; block != NULL; block = next)
161 block->p_next = NULL;
163 /* FIXME: deal with key frames properly */
164 while (sys->clock(block) >= sys->next->offset)
166 DelStream(stream);
167 AddStream(stream, sys->next->chain);
169 sys->next->offset += sys->period;
170 sys->next = sys->next->next;
171 if (sys->next == NULL)
172 sys->next = sys->start;
175 if (sys->stream != NULL)
176 sout_StreamIdSend(sys->stream, id->id, block);
177 else
178 block_Release(block);
180 return VLC_SUCCESS;
183 static int AppendPhase(sout_cycle_t ***restrict pp,
184 mtime_t offset, const char *chain)
187 size_t len = strlen(chain);
188 sout_cycle_t *cycle = malloc(sizeof (*cycle) + len);
189 if (unlikely(cycle == NULL))
190 return -1;
192 cycle->next = NULL;
193 cycle->offset = offset;
194 memcpy(cycle->chain, chain, len + 1);
196 **pp = cycle;
197 *pp = &cycle->next;
198 return 0;
201 static mtime_t ParseTime(const char *str)
203 char *end;
204 unsigned long long u = strtoull(str, &end, 0);
206 switch (*end)
208 case 'w':
209 if (u > 15250284U)
210 return -1;
211 return CLOCK_FREQ * 604800LLU * u;
212 case 'd':
213 if (u > 106751991U)
214 return -1;
215 return CLOCK_FREQ * 86400LLU * u;
216 case 'h':
217 if (u > 2562047788U)
218 return -1;
219 return CLOCK_FREQ * 3600LLU * u;
220 case 'm':
221 if (u > 153722867280U)
222 return -1;
223 return CLOCK_FREQ * 60LLU * u;
224 case 's':
225 case 0:
226 if (u > 9223372036854U)
227 return -1;
228 return CLOCK_FREQ * u;
230 return -1;
233 static int Open(vlc_object_t *obj)
235 sout_stream_t *stream = (sout_stream_t *)obj;
236 sout_stream_sys_t *sys = malloc(sizeof (*sys));
237 if (unlikely(sys == NULL))
238 return VLC_ENOMEM;
240 sys->stream = NULL;
241 sys->first = NULL;
242 sys->last = NULL;
243 sys->start = NULL;
244 sys->clock = get_dts;
246 mtime_t offset = 0;
247 sout_cycle_t **pp = &sys->start;
248 const char *chain = "";
250 for (const config_chain_t *cfg = stream->p_cfg;
251 cfg != NULL;
252 cfg = cfg->p_next)
254 if (!strcmp(cfg->psz_name, "dst"))
256 chain = cfg->psz_value;
258 else if (!strcmp(cfg->psz_name, "duration"))
260 mtime_t t = ParseTime(cfg->psz_value);
262 if (t > 0)
264 AppendPhase(&pp, offset, chain);
265 offset += t;
268 chain = "";
270 else if (!strcmp(cfg->psz_name, "offset"))
272 mtime_t t = ParseTime(cfg->psz_value);
274 if (t > offset)
276 AppendPhase(&pp, offset, chain);
277 offset = t;
280 chain = "";
282 else
284 msg_Err(stream, "unknown option \"%s\"", cfg->psz_name);
288 if (sys->start == NULL || offset <= 0)
290 free(sys);
291 msg_Err(stream, "unknown or invalid cycle specification");
292 return VLC_EGENERIC;
295 sys->next = sys->start;
296 sys->period = offset;
298 stream->pf_add = Add;
299 stream->pf_del = Del;
300 stream->pf_send = Send;
301 stream->p_sys = sys;
302 return VLC_SUCCESS;
305 static void Close(vlc_object_t *obj)
307 sout_stream_t *stream = (sout_stream_t *)obj;
308 sout_stream_sys_t *sys = stream->p_sys;
310 assert(sys->first == NULL && sys->last == NULL);
312 if (sys->stream != NULL)
313 sout_StreamChainDelete(sys->stream, NULL);
315 for (sout_cycle_t *cycle = sys->start, *next; cycle != NULL; cycle = next)
317 next = cycle->next;
318 free(cycle);
321 free(sys);
324 vlc_module_begin()
325 set_shortname(N_("cycle"))
326 set_description(N_("Cyclic stream output"))
327 set_capability("sout stream", 0)
328 set_category(CAT_SOUT)
329 set_subcategory(SUBCAT_SOUT_STREAM)
330 set_callbacks(Open, Close)
331 add_shortcut("cycle")
332 vlc_module_end()