1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 1999-2008 VLC authors and VideoLAN
7 * Author: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
32 #include <vlc_common.h>
34 #include <vlc_modules.h>
35 #include <vlc_interrupt.h>
39 #include "input_internal.h"
41 struct vlc_access_private
46 struct vlc_access_stream_private
48 input_thread_t
*input
;
51 /* Decode URL (which has had its scheme stripped earlier) to a file path. */
52 char *get_path(const char *location
)
56 /* Prepending "file://" is a bit hackish. But then again, we do not want
57 * to hard-code the list of schemes that use file paths in vlc_uri2path().
59 if (asprintf(&url
, "file://%s", location
) == -1)
62 path
= vlc_uri2path (url
);
67 static void vlc_access_Destroy(stream_t
*access
)
69 struct vlc_access_private
*priv
= vlc_stream_Private(access
);
71 module_unneed(access
, priv
->module
);
72 free(access
->psz_filepath
);
73 free(access
->psz_name
);
78 static stream_t
*accessNewAttachment(vlc_object_t
*parent
,
79 input_thread_t
*input
, const char *mrl
)
84 input_attachment_t
*attachment
= input_GetAttachment(input
, mrl
+ 13);
87 stream_t
*stream
= vlc_stream_AttachmentNew(parent
, attachment
);
90 vlc_input_attachment_Delete(attachment
);
93 stream
->psz_url
= strdup(mrl
);
96 vlc_stream_Delete(stream
);
99 stream
->psz_location
= stream
->psz_url
+ 13;
103 /*****************************************************************************
105 *****************************************************************************/
106 static stream_t
*access_New(vlc_object_t
*parent
, input_thread_t
*input
,
107 es_out_t
*out
, bool preparsing
, const char *mrl
)
109 struct vlc_access_private
*priv
;
110 char *redirv
[MAX_REDIR
];
113 if (strncmp(mrl
, "attachment://", 13) == 0)
114 return accessNewAttachment(parent
, input
, mrl
);
116 stream_t
*access
= vlc_stream_CustomNew(parent
, vlc_access_Destroy
,
117 sizeof (*priv
), "access");
118 if (unlikely(access
== NULL
))
121 access
->p_input_item
= input
? input_GetItem(input
) : NULL
;
123 access
->psz_name
= NULL
;
124 access
->psz_url
= strdup(mrl
);
125 access
->psz_filepath
= NULL
;
126 access
->b_preparsing
= preparsing
;
127 priv
= vlc_stream_Private(access
);
129 if (unlikely(access
->psz_url
== NULL
))
132 while (redirc
< MAX_REDIR
)
134 char *url
= access
->psz_url
;
135 msg_Dbg(access
, "creating access: %s", url
);
137 const char *p
= strstr(url
, "://");
141 access
->psz_name
= strndup(url
, p
- url
);
142 if (unlikely(access
->psz_name
== NULL
))
145 access
->psz_location
= p
+ 3;
146 access
->psz_filepath
= get_path(access
->psz_location
);
147 if (access
->psz_filepath
!= NULL
)
148 msg_Dbg(access
, " (path: %s)", access
->psz_filepath
);
150 priv
->module
= module_need(access
, "access", access
->psz_name
, true);
151 if (priv
->module
!= NULL
) /* success */
154 free(redirv
[--redirc
]);
156 assert(access
->pf_control
!= NULL
);
160 if (access
->psz_url
== url
) /* failure (no redirection) */
164 msg_Dbg(access
, "redirecting to: %s", access
->psz_url
);
165 redirv
[redirc
++] = url
;
167 for (unsigned j
= 0; j
< redirc
; j
++)
168 if (!strcmp(redirv
[j
], access
->psz_url
))
170 msg_Err(access
, "redirection loop");
174 free(access
->psz_filepath
);
175 free(access
->psz_name
);
176 access
->psz_filepath
= access
->psz_name
= NULL
;
179 msg_Err(access
, "too many redirections");
182 free(redirv
[--redirc
]);
183 free(access
->psz_filepath
);
184 free(access
->psz_name
);
185 stream_CommonDelete(access
);
189 stream_t
*vlc_access_NewMRL(vlc_object_t
*parent
, const char *mrl
)
191 return access_New(parent
, NULL
, NULL
, false, mrl
);
194 /*****************************************************************************
195 * access_vaDirectoryControlHelper:
196 *****************************************************************************/
197 int access_vaDirectoryControlHelper( stream_t
*p_access
, int i_query
, va_list args
)
199 VLC_UNUSED( p_access
);
203 case STREAM_CAN_SEEK
:
204 case STREAM_CAN_FASTSEEK
:
205 case STREAM_CAN_PAUSE
:
206 case STREAM_CAN_CONTROL_PACE
:
207 *va_arg( args
, bool* ) = false;
209 case STREAM_GET_PTS_DELAY
:
210 *va_arg( args
, vlc_tick_t
* ) = 0;
219 static block_t
*AStreamReadBlock(stream_t
*s
, bool *restrict eof
)
221 stream_t
*access
= s
->p_sys
;
224 if (vlc_stream_Eof(access
))
232 block
= vlc_stream_ReadBlock(access
);
236 struct vlc_access_stream_private
*priv
= vlc_stream_Private(s
);
237 struct input_stats
*stats
=
238 priv
->input
? input_priv(priv
->input
)->stats
: NULL
;
240 input_rate_Add(&stats
->input_bitrate
, block
->i_buffer
);
247 static ssize_t
AStreamReadStream(stream_t
*s
, void *buf
, size_t len
)
249 stream_t
*access
= s
->p_sys
;
251 if (vlc_stream_Eof(access
))
256 ssize_t val
= vlc_stream_ReadPartial(access
, buf
, len
);
260 struct vlc_access_stream_private
*priv
= vlc_stream_Private(s
);
261 struct input_stats
*stats
=
262 priv
->input
? input_priv(priv
->input
)->stats
: NULL
;
264 input_rate_Add(&stats
->input_bitrate
, val
);
271 static int AStreamSeek(stream_t
*s
, uint64_t offset
)
273 stream_t
*access
= s
->p_sys
;
275 return vlc_stream_Seek(access
, offset
);
278 static int AStreamControl(stream_t
*s
, int cmd
, va_list args
)
280 stream_t
*access
= s
->p_sys
;
282 return vlc_stream_vaControl(access
, cmd
, args
);
285 static void AStreamDestroy(stream_t
*s
)
287 stream_t
*access
= s
->p_sys
;
289 vlc_stream_Delete(access
);
292 stream_t
*stream_AccessNew(vlc_object_t
*parent
, input_thread_t
*input
,
293 es_out_t
*out
, bool preparsing
, const char *url
)
295 stream_t
*access
= access_New(parent
, input
, out
, preparsing
, url
);
301 if (access
->pf_block
!= NULL
|| access
->pf_read
!= NULL
)
303 struct vlc_access_stream_private
*priv
;
304 s
= vlc_stream_CustomNew(VLC_OBJECT(access
), AStreamDestroy
,
305 sizeof(*priv
), "stream");
307 if (unlikely(s
== NULL
))
309 vlc_stream_Delete(access
);
312 priv
= vlc_stream_Private(s
);
315 s
->p_input_item
= input
? input_GetItem(input
) : NULL
;
316 s
->psz_url
= strdup(access
->psz_url
);
318 if (access
->pf_block
!= NULL
)
319 s
->pf_block
= AStreamReadBlock
;
320 if (access
->pf_read
!= NULL
)
321 s
->pf_read
= AStreamReadStream
;
323 s
->pf_seek
= AStreamSeek
;
324 s
->pf_control
= AStreamControl
;
327 s
= stream_FilterChainNew(s
, "prefetch,cache");