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 *****************************************************************************/
28 #include <vlc_common.h>
29 #include <vlc_plugin.h>
30 #include <vlc_access.h>
34 struct access_entry
*next
;
41 struct access_entry
*next
;
42 struct access_entry
*first
;
46 bool can_control_pace
;
51 static stream_t
*GetAccess(stream_t
*access
)
53 access_sys_t
*sys
= access
->p_sys
;
54 stream_t
*a
= sys
->access
;
58 if (!vlc_stream_Eof(a
))
65 if (sys
->next
== NULL
)
68 a
= vlc_access_NewMRL(VLC_OBJECT(access
), sys
->next
->mrl
);
73 sys
->next
= sys
->next
->next
;
77 static ssize_t
Read(stream_t
*access
, void *buf
, size_t len
)
79 stream_t
*a
= GetAccess(access
);
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
))
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
);
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
);
114 sys
->next
= sys
->first
;
116 for (uint64_t offset
= 0;;)
118 stream_t
*a
= GetAccess(access
);
123 vlc_stream_Control(a
, STREAM_CAN_SEEK
, &can_seek
);
129 if (vlc_stream_GetSize(a
, &size
))
131 if (position
- offset
< size
)
133 if (vlc_stream_Seek(a
, position
- offset
))
139 vlc_stream_Delete(a
);
146 static int Control(stream_t
*access
, int query
, va_list args
)
148 access_sys_t
*sys
= access
->p_sys
;
152 case STREAM_CAN_SEEK
:
153 *va_arg(args
, bool *) = sys
->can_seek
;
155 case STREAM_CAN_FASTSEEK
:
156 *va_arg(args
, bool *) = sys
->can_seek_fast
;
158 case STREAM_CAN_PAUSE
:
159 *va_arg(args
, bool *) = sys
->can_pause
;
161 case STREAM_CAN_CONTROL_PACE
:
162 *va_arg(args
, bool *) = sys
->can_control_pace
;
164 case STREAM_GET_SIZE
:
165 if (sys
->size
== UINT64_MAX
)
167 *va_arg(args
, uint64_t *) = sys
->size
;
169 case STREAM_GET_PTS_DELAY
:
170 *va_arg(args
, int64_t *) = sys
->caching
;
173 case STREAM_GET_SIGNAL
:
174 case STREAM_SET_PAUSE_STATE
:
175 return vlc_stream_vaControl(sys
->access
, query
, args
);
183 static int Open(vlc_object_t
*obj
)
185 stream_t
*access
= (stream_t
*)obj
;
187 char *list
= var_CreateGetNonEmptyString(access
, "concat-list");
191 access_sys_t
*sys
= vlc_obj_malloc(obj
, sizeof (*sys
));
192 if (unlikely(sys
== NULL
))
198 var_SetString(access
, "concat-list", ""); /* prevent recursion */
203 sys
->can_seek
= true;
204 sys
->can_seek_fast
= true;
205 sys
->can_pause
= true;
206 sys
->can_control_pace
= true;
210 struct access_entry
**pp
= &sys
->first
;
212 for (char *buf
, *mrl
= strtok_r(list
, ",", &buf
);
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
))
221 stream_t
*a
= vlc_access_NewMRL(obj
, mrl
);
224 msg_Err(access
, "cannot concatenate location %s", mrl
);
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
);
243 memcpy(e
->mrl
, mrl
, mlen
+ 1);
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
);
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
)
258 if (vlc_stream_GetSize(a
, &size
))
259 sys
->size
= UINT64_MAX
;
265 vlc_stream_Control(a
, STREAM_GET_PTS_DELAY
, &caching
);
266 if (caching
> sys
->caching
)
267 sys
->caching
= caching
;
269 vlc_stream_Delete(a
);
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
;
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
)
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.")
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")