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>
39 typedef struct sout_cycle sout_cycle_t
;
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
;
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 */
65 vlc_tick_t (*clock
)(const block_t
*);
66 vlc_tick_t period
; /*< Total cycle duration */
69 static vlc_tick_t
get_dts(const block_t
*block
)
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
))
83 if (es_format_Copy(&id
->fmt
, fmt
))
85 es_format_Clean(&id
->fmt
);
90 if (sys
->stream
!= NULL
)
91 id
->id
= sout_StreamIdAdd(sys
->stream
, &id
->fmt
);
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
;
110 sys
->first
= id
->next
;
112 if (id
->next
!= NULL
)
113 id
->next
->prev
= id
->prev
;
115 sys
->last
= id
->prev
;
117 if (sys
->stream
!= NULL
)
118 sout_StreamIdDel(sys
->stream
, id
->id
);
120 es_format_Clean(&id
->fmt
);
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
);
130 sys
->stream
= sout_StreamChainNew(stream
->p_sout
, chain
,
131 stream
->p_next
, NULL
);
132 if (sys
->stream
== NULL
)
135 for (sout_stream_id_sys_t
*id
= sys
->first
; id
!= NULL
; id
= id
->next
)
136 id
->id
= sout_StreamIdAdd(sys
->stream
, &id
->fmt
);
141 static void DelStream(sout_stream_t
*stream
)
143 sout_stream_sys_t
*sys
= stream
->p_sys
;
145 if (sys
->stream
== NULL
)
148 for (sout_stream_id_sys_t
*id
= sys
->first
; id
!= NULL
; id
= id
->next
)
150 sout_StreamIdDel(sys
->stream
, id
->id
);
152 sout_StreamChainDelete(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
)
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
);
180 block_Release(block
);
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
))
195 cycle
->offset
= offset
;
196 memcpy(cycle
->chain
, chain
, len
+ 1);
203 static vlc_tick_t
ParseTime(const char *str
)
206 unsigned long long u
= strtoull(str
, &end
, 0);
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
);
215 if (u
< ((unsigned long long)INT64_MAX
)/ (60 * 60 * 24 * CLOCK_FREQ
))
216 return vlc_tick_from_sec( 60LU * 60 * 24 * u
);
219 if (u
< ((unsigned long long)INT64_MAX
)/ (60 * 60 * CLOCK_FREQ
))
220 return vlc_tick_from_sec( 60LLU * 60 * u
);
223 if (u
< ((unsigned long long)INT64_MAX
)/ (60 * CLOCK_FREQ
))
224 return vlc_tick_from_sec( 60LLU * u
);
228 if (u
< ((unsigned long long)INT64_MAX
)/CLOCK_FREQ
)
229 return vlc_tick_from_sec( u
);
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
))
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
;
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
);
266 AppendPhase(&pp
, offset
, chain
);
272 else if (!strcmp(cfg
->psz_name
, "offset"))
274 vlc_tick_t t
= ParseTime(cfg
->psz_value
);
278 AppendPhase(&pp
, offset
, chain
);
286 msg_Err(stream
, "unknown option \"%s\"", cfg
->psz_name
);
290 if (sys
->start
== NULL
|| offset
== 0)
293 msg_Err(stream
, "unknown or invalid cycle specification");
297 sys
->next
= sys
->start
;
298 sys
->period
= offset
;
300 stream
->pf_add
= Add
;
301 stream
->pf_del
= Del
;
302 stream
->pf_send
= Send
;
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
)
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")