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 *****************************************************************************/
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>
40 typedef struct sout_cycle sout_cycle_t
;
49 typedef struct sout_stream_id_sys_t sout_stream_id_sys_t
;
50 struct sout_stream_id_sys_t
59 sout_stream_t
*stream
; /*< Current output stream */
60 struct vlc_list ids
; /*< List of elementary streams */
64 vlc_tick_t (*clock
)(const block_t
*);
65 vlc_tick_t period
; /*< Total cycle duration */
68 static vlc_tick_t
get_dts(const block_t
*block
)
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
))
80 if (es_format_Copy(&id
->fmt
, fmt
))
82 es_format_Clean(&id
->fmt
);
87 if (sys
->stream
!= NULL
)
88 id
->id
= sout_StreamIdAdd(sys
->stream
, &id
->fmt
);
90 vlc_list_append(&id
->node
, &sys
->ids
);
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
);
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
);
115 sys
->stream
= sout_StreamChainNew(VLC_OBJECT(stream
), chain
,
117 if (sys
->stream
== NULL
)
120 vlc_list_foreach (id
, &sys
->ids
, node
)
121 id
->id
= sout_StreamIdAdd(sys
->stream
, &id
->fmt
);
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
)
134 vlc_list_foreach (id
, &sys
->ids
, node
)
136 sout_StreamIdDel(sys
->stream
, id
->id
);
138 sout_StreamChainDelete(sys
->stream
, stream
->p_next
);
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
)
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
);
166 block_Release(block
);
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
))
181 cycle
->offset
= offset
;
182 memcpy(cycle
->chain
, chain
, len
+ 1);
189 static vlc_tick_t
ParseTime(const char *str
)
192 unsigned long long u
= strtoull(str
, &end
, 0);
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
);
201 if (u
< ((unsigned long long)INT64_MAX
)/ (60 * 60 * 24 * CLOCK_FREQ
))
202 return vlc_tick_from_sec( 60LU * 60 * 24 * u
);
205 if (u
< ((unsigned long long)INT64_MAX
)/ (60 * 60 * CLOCK_FREQ
))
206 return vlc_tick_from_sec( 60LLU * 60 * u
);
209 if (u
< ((unsigned long long)INT64_MAX
)/ (60 * CLOCK_FREQ
))
210 return vlc_tick_from_sec( 60LLU * u
);
214 if (u
< ((unsigned long long)INT64_MAX
)/CLOCK_FREQ
)
215 return vlc_tick_from_sec( u
);
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
))
233 vlc_list_init(&sys
->ids
);
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
;
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
);
255 AppendPhase(&pp
, offset
, chain
);
261 else if (!strcmp(cfg
->psz_name
, "offset"))
263 vlc_tick_t t
= ParseTime(cfg
->psz_value
);
267 AppendPhase(&pp
, offset
, chain
);
275 msg_Err(stream
, "unknown option \"%s\"", cfg
->psz_name
);
279 if (sys
->start
== NULL
|| offset
== 0)
282 msg_Err(stream
, "unknown or invalid cycle specification");
286 sys
->next
= sys
->start
;
287 sys
->period
= offset
;
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
)
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")
322 add_shortcut("cycle")
323 set_capability("sout filter", 0)
324 set_callbacks(Open
, Close
)