mux:ts: convert vlc_tick_t to seconds explicitly using SEC_FROM_VLC_TICK()
[vlc.git] / modules / access / concat.c
blobd8a94c465d3b1b1e36d9962bd04391ef588f0a08
1 /*****************************************************************************
2 * concat.c: Concatenated inputs
3 *****************************************************************************
4 * Copyright (C) 2015 RĂ©mi Denis-Courmont
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include <assert.h>
26 #include <stdint.h>
28 #include <vlc_common.h>
29 #include <vlc_plugin.h>
30 #include <vlc_access.h>
32 struct access_entry
34 struct access_entry *next;
35 char mrl[1];
38 typedef struct
40 stream_t *access;
41 struct access_entry *next;
42 struct access_entry *first;
43 bool can_seek;
44 bool can_seek_fast;
45 bool can_pause;
46 bool can_control_pace;
47 uint64_t size;
48 int64_t caching;
49 } access_sys_t;
51 static stream_t *GetAccess(stream_t *access)
53 access_sys_t *sys = access->p_sys;
54 stream_t *a = sys->access;
56 if (a != NULL)
58 if (!vlc_stream_Eof(a))
59 return a;
61 vlc_stream_Delete(a);
62 sys->access = NULL;
65 if (sys->next == NULL)
66 return NULL;
68 a = vlc_access_NewMRL(VLC_OBJECT(access), sys->next->mrl);
69 if (a == NULL)
70 return NULL;
72 sys->access = a;
73 sys->next = sys->next->next;
74 return a;
77 static ssize_t Read(stream_t *access, void *buf, size_t len)
79 stream_t *a = GetAccess(access);
80 if (a == NULL)
81 return 0;
83 /* NOTE: Since we recreate the underlying access, the access method can
84 * change. We need to check it. For instance, a path could point to a
85 * regular file during Open() yet point to a directory here and now. */
86 if (unlikely(a->pf_read == NULL))
87 return 0;
89 return vlc_stream_ReadPartial(a, buf, len);
92 static block_t *Block(stream_t *access, bool *restrict eof)
94 stream_t *a = GetAccess(access);
95 if (a == NULL)
97 *eof = true;
98 return NULL;
101 return vlc_stream_ReadBlock(a);
104 static int Seek(stream_t *access, uint64_t position)
106 access_sys_t *sys = access->p_sys;
108 if (sys->access != NULL)
110 vlc_stream_Delete(sys->access);
111 sys->access = NULL;
114 sys->next = sys->first;
116 for (uint64_t offset = 0;;)
118 stream_t *a = GetAccess(access);
119 if (a == NULL)
120 break;
122 bool can_seek;
123 vlc_stream_Control(a, STREAM_CAN_SEEK, &can_seek);
124 if (!can_seek)
125 break;
127 uint64_t size;
129 if (vlc_stream_GetSize(a, &size))
130 break;
131 if (position - offset < size)
133 if (vlc_stream_Seek(a, position - offset))
134 break;
135 return VLC_SUCCESS;
138 offset += size;
139 vlc_stream_Delete(a);
140 sys->access = NULL;
143 return VLC_EGENERIC;
146 static int Control(stream_t *access, int query, va_list args)
148 access_sys_t *sys = access->p_sys;
150 switch (query)
152 case STREAM_CAN_SEEK:
153 *va_arg(args, bool *) = sys->can_seek;
154 break;
155 case STREAM_CAN_FASTSEEK:
156 *va_arg(args, bool *) = sys->can_seek_fast;
157 break;
158 case STREAM_CAN_PAUSE:
159 *va_arg(args, bool *) = sys->can_pause;
160 break;
161 case STREAM_CAN_CONTROL_PACE:
162 *va_arg(args, bool *) = sys->can_control_pace;
163 break;
164 case STREAM_GET_SIZE:
165 if (sys->size == UINT64_MAX)
166 return VLC_EGENERIC;
167 *va_arg(args, uint64_t *) = sys->size;
168 break;
169 case STREAM_GET_PTS_DELAY:
170 *va_arg(args, int64_t *) = sys->caching;
171 break;
173 case STREAM_GET_SIGNAL:
174 case STREAM_SET_PAUSE_STATE:
175 return vlc_stream_vaControl(sys->access, query, args);
177 default:
178 return VLC_EGENERIC;
180 return VLC_SUCCESS;
183 static int Open(vlc_object_t *obj)
185 stream_t *access = (stream_t *)obj;
187 char *list = var_CreateGetNonEmptyString(access, "concat-list");
188 if (list == NULL)
189 return VLC_EGENERIC;
191 access_sys_t *sys = vlc_obj_malloc(obj, sizeof (*sys));
192 if (unlikely(sys == NULL))
194 free(list);
195 return VLC_ENOMEM;
198 var_SetString(access, "concat-list", ""); /* prevent recursion */
200 bool read_cb = true;
202 sys->access = NULL;
203 sys->can_seek = true;
204 sys->can_seek_fast = true;
205 sys->can_pause = true;
206 sys->can_control_pace = true;
207 sys->size = 0;
208 sys->caching = 0;
210 struct access_entry **pp = &sys->first;
212 for (char *buf, *mrl = strtok_r(list, ",", &buf);
213 mrl != NULL;
214 mrl = strtok_r(NULL, ",", &buf))
216 size_t mlen = strlen(mrl);
217 struct access_entry *e = malloc(sizeof (*e) + mlen);
218 if (unlikely(e == NULL))
219 break;
221 stream_t *a = vlc_access_NewMRL(obj, mrl);
222 if (a == NULL)
224 msg_Err(access, "cannot concatenate location %s", mrl);
225 free(e);
226 continue;
229 if (a->pf_read == NULL)
231 if (a->pf_block == NULL)
233 msg_Err(access, "cannot concatenate directory %s", mrl);
234 vlc_stream_Delete(a);
235 free(e);
236 continue;
238 read_cb = false;
241 *pp = e;
242 e->next = NULL;
243 memcpy(e->mrl, mrl, mlen + 1);
245 if (sys->can_seek)
246 vlc_stream_Control(a, STREAM_CAN_SEEK, &sys->can_seek);
247 if (sys->can_seek_fast)
248 vlc_stream_Control(a, STREAM_CAN_FASTSEEK, &sys->can_seek_fast);
249 if (sys->can_pause)
250 vlc_stream_Control(a, STREAM_CAN_PAUSE, &sys->can_pause);
251 if (sys->can_control_pace)
252 vlc_stream_Control(a, STREAM_CAN_CONTROL_PACE,
253 &sys->can_control_pace);
254 if (sys->size != UINT64_MAX)
256 uint64_t size;
258 if (vlc_stream_GetSize(a, &size))
259 sys->size = UINT64_MAX;
260 else
261 sys->size += size;
264 int64_t caching;
265 vlc_stream_Control(a, STREAM_GET_PTS_DELAY, &caching);
266 if (caching > sys->caching)
267 sys->caching = caching;
269 vlc_stream_Delete(a);
270 pp = &e->next;
273 free(list);
274 *pp = NULL;
275 sys->next = sys->first;
277 access->pf_read = read_cb ? Read : NULL;
278 access->pf_block = read_cb ? NULL : Block;
279 access->pf_seek = Seek;
280 access->pf_control = Control;
281 access->p_sys = sys;
283 return VLC_SUCCESS;
286 static void Close(vlc_object_t *obj)
288 stream_t *access = (stream_t *)obj;
289 access_sys_t *sys = access->p_sys;
291 if (sys->access != NULL)
292 vlc_stream_Delete(sys->access);
294 for (struct access_entry *e = sys->first, *next; e != NULL; e = next)
296 next = e->next;
297 free(e);
300 var_Destroy(access, "concat-list");
303 #define INPUT_LIST_TEXT N_("Inputs list")
304 #define INPUT_LIST_LONGTEXT N_( \
305 "Comma-separated list of input URLs to concatenate.")
307 vlc_module_begin()
308 set_shortname(N_("Concatenation"))
309 set_description(N_("Concatenated inputs"))
310 set_category(CAT_INPUT)
311 set_subcategory(SUBCAT_INPUT_ACCESS)
312 add_string("concat-list", NULL, INPUT_LIST_TEXT, INPUT_LIST_LONGTEXT, true)
313 set_capability("access", 0)
314 set_callbacks(Open, Close)
315 add_shortcut("concast", "list")
316 vlc_module_end()