stream: merge stream_CommonDelete() and stream_Delete()
[vlc.git] / src / input / stream_access.c
1 /*****************************************************************************
2  * stream_access.c
3  *****************************************************************************
4  * Copyright (C) 1999-2004 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include <vlc_common.h>
33 #include <vlc_interrupt.h>
34
35 #include <libvlc.h>
36 #include "access.h"
37 #include "stream.h"
38 #include "input_internal.h"
39
40 struct stream_sys_t
41 {
42     access_t *access;
43     block_t  *block;
44 };
45
46 /* Block access */
47 static ssize_t AStreamReadBlock(stream_t *s, void *buf, size_t len)
48 {
49     stream_sys_t *sys = s->p_sys;
50     input_thread_t *input = s->p_input;
51     block_t *block = sys->block;
52
53     while (block == NULL)
54     {
55         if (vlc_access_Eof(sys->access))
56             return 0;
57         if (vlc_killed())
58             return -1;
59
60         block = vlc_access_Block(sys->access);
61     }
62
63     if (input != NULL)
64     {
65         uint64_t total;
66
67         vlc_mutex_lock(&input->p->counters.counters_lock);
68         stats_Update(input->p->counters.p_read_bytes, block->i_buffer, &total);
69         stats_Update(input->p->counters.p_input_bitrate, total, NULL);
70         stats_Update(input->p->counters.p_read_packets, 1, NULL);
71         vlc_mutex_unlock(&input->p->counters.counters_lock);
72     }
73
74     size_t copy = block->i_buffer < len ? block->i_buffer : len;
75
76     if (likely(copy > 0) && buf != NULL /* skipping data? */)
77         memcpy(buf, block->p_buffer, copy);
78
79     block->p_buffer += copy;
80     block->i_buffer -= copy;
81
82     if (block->i_buffer == 0)
83         block_Release(block);
84     else
85         sys->block = block;
86
87     return copy;
88 }
89
90 /* Read access */
91 static ssize_t AStreamReadStream(stream_t *s, void *buf, size_t len)
92 {
93     stream_sys_t *sys = s->p_sys;
94     input_thread_t *input = s->p_input;
95     ssize_t val = 0;
96
97     do
98     {
99         if (vlc_access_Eof(sys->access))
100             return 0;
101         if (vlc_killed())
102             return -1;
103
104         val = vlc_access_Read(sys->access, buf, len);
105         if (val == 0)
106             return 0; /* EOF */
107     }
108     while (val < 0);
109
110     if (input != NULL)
111     {
112         uint64_t total;
113
114         vlc_mutex_lock(&input->p->counters.counters_lock);
115         stats_Update(input->p->counters.p_read_bytes, val, &total);
116         stats_Update(input->p->counters.p_input_bitrate, total, NULL);
117         stats_Update(input->p->counters.p_read_packets, 1, NULL);
118         vlc_mutex_unlock(&input->p->counters.counters_lock);
119     }
120
121     return val;
122 }
123
124 /* Directory */
125 static input_item_t *AStreamReadDir(stream_t *s)
126 {
127     stream_sys_t *sys = s->p_sys;
128
129     if (sys->access->pf_readdir == NULL)
130         return NULL;
131     return sys->access->pf_readdir(sys->access);
132 }
133
134 /* Common */
135 #define static_control_match(foo) \
136     static_assert((unsigned) STREAM_##foo == ACCESS_##foo, "Mismatch")
137
138 static int AStreamControl(stream_t *s, int cmd, va_list args)
139 {
140     stream_sys_t *sys = s->p_sys;
141     access_t *access = sys->access;
142
143     static_control_match(CAN_SEEK);
144     static_control_match(CAN_FASTSEEK);
145     static_control_match(CAN_PAUSE);
146     static_control_match(CAN_CONTROL_PACE);
147     static_control_match(GET_SIZE);
148     static_control_match(GET_PTS_DELAY);
149     static_control_match(GET_TITLE_INFO);
150     static_control_match(GET_TITLE);
151     static_control_match(GET_SEEKPOINT);
152     static_control_match(GET_META);
153     static_control_match(GET_CONTENT_TYPE);
154     static_control_match(GET_SIGNAL);
155     static_control_match(SET_PAUSE_STATE);
156     static_control_match(SET_TITLE);
157     static_control_match(SET_SEEKPOINT);
158     static_control_match(SET_PRIVATE_ID_STATE);
159     static_control_match(SET_PRIVATE_ID_CA);
160     static_control_match(GET_PRIVATE_ID_STATE);
161
162     switch (cmd)
163     {
164         case STREAM_CAN_SEEK:
165         case STREAM_CAN_FASTSEEK:
166         case STREAM_CAN_PAUSE:
167         case STREAM_CAN_CONTROL_PACE:
168         case STREAM_GET_SIZE:
169         case STREAM_GET_PTS_DELAY:
170         case STREAM_GET_TITLE_INFO:
171         case STREAM_GET_TITLE:
172         case STREAM_GET_SEEKPOINT:
173         case STREAM_GET_META:
174         case STREAM_GET_CONTENT_TYPE:
175         case STREAM_GET_SIGNAL:
176         case STREAM_SET_PAUSE_STATE:
177         case STREAM_SET_TITLE:
178         case STREAM_SET_SEEKPOINT:
179         case STREAM_SET_PRIVATE_ID_STATE:
180         case STREAM_SET_PRIVATE_ID_CA:
181         case STREAM_GET_PRIVATE_ID_STATE:
182             return access_vaControl(access, cmd, args);
183
184         case STREAM_IS_DIRECTORY:
185         {
186             bool *b;
187
188             *va_arg(args, bool *) = access->pf_readdir != NULL;
189             b = va_arg(args, bool *);
190             if (b != NULL)
191                 *b = access->info.b_dir_sorted;
192             b = va_arg(args, bool *);
193             if (b != NULL)
194                 *b = access->info.b_dir_can_loop;
195             break;
196         }
197
198         case STREAM_GET_POSITION:
199         {
200             uint64_t *ppos =va_arg(args, uint64_t *);
201
202             *ppos = access->info.i_pos;
203             if (sys->block != NULL)
204             {
205                 assert(sys->block->i_buffer <= *ppos);
206                 *ppos -= sys->block->i_buffer;
207             }
208             break;
209         }
210
211         case STREAM_SET_POSITION:
212         {
213             uint64_t pos = va_arg(args, uint64_t);
214
215             if (sys->block != NULL)
216             {
217                 block_Release(sys->block);
218                 sys->block = NULL;
219             }
220             return vlc_access_Seek(sys->access, pos);
221         }
222
223         default:
224             return VLC_EGENERIC;
225     }
226     return VLC_SUCCESS;
227 }
228
229 static void AStreamDestroy(stream_t *s)
230 {
231     stream_sys_t *sys = s->p_sys;
232
233     if (sys->block != NULL)
234         block_Release(sys->block);
235     vlc_access_Delete(sys->access);
236     free(sys);
237 }
238
239 stream_t *stream_AccessNew(vlc_object_t *parent, input_thread_t *input,
240                            const char *url)
241 {
242     stream_t *s = stream_CommonNew(parent);
243     if (unlikely(s == NULL))
244         return NULL;
245
246     s->p_input = input;
247     s->psz_url = strdup(url);
248
249     stream_sys_t *sys = malloc(sizeof (*sys));
250     if (unlikely(s->psz_url == NULL || sys == NULL))
251         goto error;
252
253     sys->access = access_New(VLC_OBJECT(s), input, url);
254     if (sys->access == NULL)
255         goto error;
256
257     sys->block = NULL;
258
259     s->p_sys      = sys;
260     if (sys->access->pf_block != NULL)
261         s->pf_read = AStreamReadBlock;
262     else
263         s->pf_read = AStreamReadStream;
264     s->pf_readdir = AStreamReadDir;
265     s->pf_control = AStreamControl;
266     s->pf_destroy = AStreamDestroy;
267
268     return s;
269 error:
270     free(sys);
271     stream_Delete(s);
272     return NULL;
273 }