contrib: cargo: use the 0.6.13 cargo-c version
[vlc.git] / modules / stream_filter / cache_block.c
blob4d6cb363bbd2faa52c89903997f2e11aad720b4f
1 /*****************************************************************************
2 * cache_block.c
3 *****************************************************************************
4 * Copyright (C) 1999-2004 VLC authors and VideoLAN
6 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <assert.h>
28 #include <stdlib.h>
29 #include <string.h>
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_stream.h>
34 #include <vlc_interrupt.h>
35 #include <vlc_block_helper.h>
37 /* TODO:
38 * - tune the 2 methods (block/stream)
39 * - compute cost for seek
40 * - improve stream mode seeking with closest segments
41 * - ...
44 /*
45 * One linked list of data read
48 /* How many tracks we have, currently only used for stream mode */
49 #ifdef OPTIMIZE_MEMORY
50 /* Max size of our cache 128KiB per stream */
51 # define STREAM_CACHE_SIZE (1024*128)
52 #else
53 /* Max size of our cache 48MiB per stream */
54 # define STREAM_CACHE_SIZE (4*12*1024*1024)
55 #endif
57 /* How many data we try to prebuffer
58 * XXX it should be small to avoid useless latency but big enough for
59 * efficient demux probing */
60 #define STREAM_CACHE_PREBUFFER_SIZE (128)
62 /* Method: Simple, for pf_block.
63 * We get blocks and put them in the linked list.
64 * We release blocks once the total size is bigger than STREAM_CACHE_SIZE
67 typedef struct
69 block_bytestream_t cache; /* bytestream chain for storing cache */
71 struct
73 /* Stats for calculating speed */
74 uint64_t read_bytes;
75 vlc_tick_t read_time;
76 } stat;
77 } stream_sys_t;
79 static int AStreamRefillBlock(stream_t *s)
81 stream_sys_t *sys = s->p_sys;
82 size_t cache_size = sys->cache.i_total;
84 /* Release data */
85 if (cache_size >= STREAM_CACHE_SIZE)
87 block_BytestreamFlush( &sys->cache );
88 cache_size = sys->cache.i_total;
90 if (cache_size >= STREAM_CACHE_SIZE &&
91 sys->cache.p_chain != *sys->cache.pp_last)
93 /* Enough data, don't read more */
94 return VLC_SUCCESS;
97 /* Now read a new block */
98 const vlc_tick_t start = vlc_tick_now();
99 block_t *b;
101 for (;;)
103 if (vlc_killed())
104 return VLC_EGENERIC;
106 /* Fetch a block */
107 if ((b = vlc_stream_ReadBlock(s->s)))
108 break;
109 if (vlc_stream_Eof(s->s))
110 return VLC_EGENERIC;
112 sys->stat.read_time += vlc_tick_now() - start;
113 size_t added_bytes;
114 block_ChainProperties( b, NULL, &added_bytes, NULL );
115 sys->stat.read_bytes += added_bytes;
117 block_BytestreamPush( &sys->cache, b );
118 return VLC_SUCCESS;
121 static void AStreamPrebufferBlock(stream_t *s)
123 stream_sys_t *sys = s->p_sys;
124 vlc_tick_t start = vlc_tick_now();
125 bool first = true;
127 msg_Dbg(s, "starting pre-buffering");
128 for (;;)
130 const vlc_tick_t now = vlc_tick_now();
131 size_t cache_size = block_BytestreamRemaining( &sys->cache );
133 if (vlc_killed() || cache_size > STREAM_CACHE_PREBUFFER_SIZE)
135 int64_t byterate;
137 /* Update stat */
138 sys->stat.read_bytes = cache_size;
139 sys->stat.read_time = now - start;
140 byterate = (CLOCK_FREQ * sys->stat.read_bytes ) /
141 (sys->stat.read_time -1);
143 msg_Dbg(s, "prebuffering done %zu bytes "
144 "in %"PRIu64"s - %"PRIu64"u KiB/s", cache_size,
145 SEC_FROM_VLC_TICK(sys->stat.read_time), byterate / 1024 );
146 break;
149 /* Fetch a block */
150 block_t *b = vlc_stream_ReadBlock(s->s);
151 if (b == NULL)
153 if (vlc_stream_Eof(s->s))
154 break;
155 continue;
158 block_BytestreamPush( &sys->cache, b);
160 if (first)
162 msg_Dbg(s, "received first data after %"PRId64" ms",
163 MS_FROM_VLC_TICK(vlc_tick_now() - start));
164 first = false;
169 /****************************************************************************
170 * AStreamControlReset:
171 ****************************************************************************/
172 static void AStreamControlReset(stream_t *s)
174 stream_sys_t *sys = s->p_sys;
176 block_BytestreamEmpty( &sys->cache );
178 /* Do the prebuffering */
179 AStreamPrebufferBlock(s);
182 static int AStreamSeekBlock(stream_t *s, uint64_t i_pos)
184 stream_sys_t *sys = s->p_sys;
186 if( block_SkipBytes( &sys->cache, i_pos) == VLC_SUCCESS )
187 return VLC_SUCCESS;
189 /* Not enought bytes, empty and seek */
190 /* Do the access seek */
191 if (vlc_stream_Seek(s->s, i_pos)) return VLC_EGENERIC;
193 block_BytestreamEmpty( &sys->cache );
195 /* Refill a block */
196 if (AStreamRefillBlock(s))
197 return VLC_EGENERIC;
199 return VLC_SUCCESS;
202 static ssize_t AStreamReadBlock(stream_t *s, void *buf, size_t len)
204 stream_sys_t *sys = s->p_sys;
206 ssize_t i_current = block_BytestreamRemaining( &sys->cache );
207 size_t i_copy = VLC_CLIP((size_t)i_current, 0, len);
210 * we should not signal end-of-file if we have not exhausted
211 * the cache. i_copy == 0 just means that the cache currently does
212 * not contain data at the offset that we want, not EOF.
214 if( i_copy == 0 )
216 /* Return EOF if we are unable to refill cache, most likely
217 * really EOF */
218 if( AStreamRefillBlock(s) == VLC_EGENERIC )
219 return 0;
222 /* Copy data */
223 if( block_GetBytes( &sys->cache, buf, i_copy ) )
224 return -1;
227 /* If we ended up on refill, try to read refilled cache */
228 if( i_copy == 0 && sys->cache.p_chain )
229 return AStreamReadBlock( s, buf, len );
231 return i_copy;
234 /****************************************************************************
235 * AStreamControl:
236 ****************************************************************************/
237 static int AStreamControl(stream_t *s, int i_query, va_list args)
239 switch(i_query)
241 case STREAM_CAN_SEEK:
242 case STREAM_CAN_FASTSEEK:
243 case STREAM_CAN_PAUSE:
244 case STREAM_CAN_CONTROL_PACE:
245 case STREAM_GET_SIZE:
246 case STREAM_GET_PTS_DELAY:
247 case STREAM_GET_TITLE_INFO:
248 case STREAM_GET_TITLE:
249 case STREAM_GET_SEEKPOINT:
250 case STREAM_GET_META:
251 case STREAM_GET_CONTENT_TYPE:
252 case STREAM_GET_SIGNAL:
253 case STREAM_GET_TAGS:
254 case STREAM_SET_PAUSE_STATE:
255 case STREAM_SET_PRIVATE_ID_STATE:
256 case STREAM_SET_PRIVATE_ID_CA:
257 case STREAM_GET_PRIVATE_ID_STATE:
258 return vlc_stream_vaControl(s->s, i_query, args);
260 case STREAM_SET_TITLE:
261 case STREAM_SET_SEEKPOINT:
263 int ret = vlc_stream_vaControl(s->s, i_query, args);
264 if (ret == VLC_SUCCESS)
265 AStreamControlReset(s);
266 return ret;
269 case STREAM_SET_RECORD_STATE:
270 default:
271 msg_Err(s, "invalid vlc_stream_vaControl query=0x%x", i_query);
272 return VLC_EGENERIC;
274 return VLC_SUCCESS;
277 static int Open(vlc_object_t *obj)
279 stream_t *s = (stream_t *)obj;
281 if (s->s->pf_block == NULL)
282 return VLC_EGENERIC;
284 stream_sys_t *sys = malloc(sizeof (*sys));
285 if (unlikely(sys == NULL))
286 return VLC_ENOMEM;
288 msg_Dbg(s, "Using block method for AStream*");
290 /* Init all fields of sys->block */
291 block_BytestreamInit( &sys->cache );
293 s->p_sys = sys;
294 /* Do the prebuffering */
295 AStreamPrebufferBlock(s);
297 if (block_BytestreamRemaining( &sys->cache ) <= 0)
299 msg_Err(s, "cannot pre fill buffer");
300 free(sys);
301 return VLC_EGENERIC;
304 s->pf_read = AStreamReadBlock;
305 s->pf_seek = AStreamSeekBlock;
306 s->pf_control = AStreamControl;
307 return VLC_SUCCESS;
310 /****************************************************************************
311 * AStreamDestroy:
312 ****************************************************************************/
313 static void Close(vlc_object_t *obj)
315 stream_t *s = (stream_t *)obj;
316 stream_sys_t *sys = s->p_sys;
318 block_BytestreamEmpty( &sys->cache );
319 free(sys);
322 vlc_module_begin()
323 set_category(CAT_INPUT)
324 set_subcategory(SUBCAT_INPUT_STREAM_FILTER)
325 set_capability("stream_filter", 0)
326 add_shortcut("cache")
328 set_description(N_("Block stream cache"))
329 set_callbacks(Open, Close)
330 vlc_module_end()