1 /*****************************************************************************
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 *****************************************************************************/
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>
38 * - tune the 2 methods (block/stream)
39 * - compute cost for seek
40 * - improve stream mode seeking with closest segments
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)
53 /* Max size of our cache 48MiB per stream */
54 # define STREAM_CACHE_SIZE (4*12*1024*1024)
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
69 block_bytestream_t cache
; /* bytestream chain for storing cache */
73 /* Stats for calculating speed */
79 static int AStreamRefillBlock(stream_t
*s
)
81 stream_sys_t
*sys
= s
->p_sys
;
82 size_t cache_size
= sys
->cache
.i_total
;
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 */
97 /* Now read a new block */
98 const vlc_tick_t start
= vlc_tick_now();
107 if ((b
= vlc_stream_ReadBlock(s
->s
)))
109 if (vlc_stream_Eof(s
->s
))
112 sys
->stat
.read_time
+= vlc_tick_now() - start
;
114 block_ChainProperties( b
, NULL
, &added_bytes
, NULL
);
115 sys
->stat
.read_bytes
+= added_bytes
;
117 block_BytestreamPush( &sys
->cache
, b
);
121 static void AStreamPrebufferBlock(stream_t
*s
)
123 stream_sys_t
*sys
= s
->p_sys
;
124 vlc_tick_t start
= vlc_tick_now();
127 msg_Dbg(s
, "starting pre-buffering");
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
)
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 );
150 block_t
*b
= vlc_stream_ReadBlock(s
->s
);
153 if (vlc_stream_Eof(s
->s
))
158 block_BytestreamPush( &sys
->cache
, b
);
162 msg_Dbg(s
, "received first data after %"PRId64
" ms",
163 MS_FROM_VLC_TICK(vlc_tick_now() - start
));
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
)
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
);
196 if (AStreamRefillBlock(s
))
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.
216 /* Return EOF if we are unable to refill cache, most likely
218 if( AStreamRefillBlock(s
) == VLC_EGENERIC
)
223 if( block_GetBytes( &sys
->cache
, buf
, i_copy
) )
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
);
234 /****************************************************************************
236 ****************************************************************************/
237 static int AStreamControl(stream_t
*s
, int i_query
, va_list args
)
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
);
269 case STREAM_SET_RECORD_STATE
:
271 msg_Err(s
, "invalid vlc_stream_vaControl query=0x%x", i_query
);
277 static int Open(vlc_object_t
*obj
)
279 stream_t
*s
= (stream_t
*)obj
;
281 if (s
->s
->pf_block
== NULL
)
284 stream_sys_t
*sys
= malloc(sizeof (*sys
));
285 if (unlikely(sys
== NULL
))
288 msg_Dbg(s
, "Using block method for AStream*");
290 /* Init all fields of sys->block */
291 block_BytestreamInit( &sys
->cache
);
294 /* Do the prebuffering */
295 AStreamPrebufferBlock(s
);
297 if (block_BytestreamRemaining( &sys
->cache
) <= 0)
299 msg_Err(s
, "cannot pre fill buffer");
304 s
->pf_read
= AStreamReadBlock
;
305 s
->pf_seek
= AStreamSeekBlock
;
306 s
->pf_control
= AStreamControl
;
310 /****************************************************************************
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
);
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
)