⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stream.c

📁 VLC Player Source Code
💻 C
📖 第 1 页 / 共 5 页
字号:
/***************************************************************************** * stream.c ***************************************************************************** * Copyright (C) 1999-2004 the VideoLAN team * $Id: 1e442b407cc2630e7012b49cf672806a52054be9 $ * * Authors: Laurent Aimar <fenrir@via.ecp.fr> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <assert.h>#include "input_internal.h"#undef STREAM_DEBUG/* TODO: *  - tune the 2 methods (block/stream) *  - compute cost for seek *  - improve stream mode seeking with closest segments *  - ... *  - Maybe remove (block/stream) in favour of immediate *//* Two methods: *  - using pf_block *      One linked list of data read *  - using pf_read *      More complex scheme using mutliple track to avoid seeking *  - using directly the access (only indirection for peeking). *      This method is known to introduce much less latency. *      It should probably defaulted (instead of the stream method (2)). *//* How many tracks we have, currently only used for stream mode */#ifdef OPTIMIZE_MEMORY#   define STREAM_CACHE_TRACK 1    /* Max size of our cache 128Ko per track */#   define STREAM_CACHE_SIZE  (STREAM_CACHE_TRACK*1024*128)#else#   define STREAM_CACHE_TRACK 3    /* Max size of our cache 4Mo per track */#   define STREAM_CACHE_SIZE  (4*STREAM_CACHE_TRACK*1024*1024)#endif/* How many data we try to prebuffer */#define STREAM_CACHE_PREBUFFER_SIZE (32767)/* Maximum time we take to pre-buffer */#define STREAM_CACHE_PREBUFFER_LENGTH (100*1000)/* Method1: Simple, for pf_block. *  We get blocks and put them in the linked list. *  We release blocks once the total size is bigger than CACHE_BLOCK_SIZE */#define STREAM_DATA_WAIT 40000       /* Time between before a pf_block retry *//* Method2: A bit more complex, for pf_read *  - We use ring buffers, only one if unseekable, all if seekable *  - Upon seek date current ring, then search if one ring match the pos, *      yes: switch to it, seek the access to match the end of the ring *      no: search the ring with i_end the closer to i_pos, *          if close enough, read data and use this ring *          else use the oldest ring, seek and use it. * *  TODO: - with access non seekable: use all space available for only one ring, but *          we have to support seekable/non-seekable switch on the fly. *        - compute a good value for i_read_size *        - ? */#define STREAM_READ_ATONCE 32767#define STREAM_CACHE_TRACK_SIZE (STREAM_CACHE_SIZE/STREAM_CACHE_TRACK)typedef struct{    int64_t i_date;    int64_t i_start;    int64_t i_end;    uint8_t *p_buffer;} stream_track_t;typedef struct{    char     *psz_path;    int64_t  i_size;} access_entry_t;typedef enum stream_read_method_t{    Immediate,    Block,    Stream} stream_read_method_t;struct stream_sys_t{    access_t    *p_access;    stream_read_method_t   method;    /* method to use */    int64_t     i_pos;      /* Current reading offset */    /* Method 1: pf_block */    struct    {        int64_t i_start;        /* Offset of block for p_first */        int64_t i_offset;       /* Offset for data in p_current */        block_t *p_current;     /* Current block */        int     i_size;         /* Total amount of data in the list */        block_t *p_first;        block_t **pp_last;    } block;    /* Method 2: for pf_read */    struct    {        int i_offset;   /* Buffer offset in the current track */        int i_tk;       /* Current track */        stream_track_t tk[STREAM_CACHE_TRACK];        /* Global buffer */        uint8_t *p_buffer;        /* */        int i_used; /* Used since last read */        int i_read_size;    } stream;    /* Method 3: for pf_read */    struct    {        int64_t i_end;        uint8_t *p_buffer;    } immediate;    /* Peek temporary buffer */    unsigned int i_peek;    uint8_t *p_peek;    /* Stat for both method */    struct    {        bool b_fastseek;  /* From access */        /* Stat about reading data */        int64_t i_read_count;        int64_t i_bytes;        int64_t i_read_time;        /* Stat about seek */        int     i_seek_count;        int64_t i_seek_time;    } stat;    /* Streams list */    int            i_list;    access_entry_t **list;    int            i_list_index;    access_t       *p_list_access;    /* Preparse mode ? */    bool      b_quick;};/* Method 1: */static int  AStreamReadBlock( stream_t *s, void *p_read, unsigned int i_read );static int  AStreamPeekBlock( stream_t *s, const uint8_t **p_peek, unsigned int i_read );static int  AStreamSeekBlock( stream_t *s, int64_t i_pos );static void AStreamPrebufferBlock( stream_t *s );static block_t *AReadBlock( stream_t *s, bool *pb_eof );/* Method 2 */static int  AStreamReadStream( stream_t *s, void *p_read, unsigned int i_read );static int  AStreamPeekStream( stream_t *s, const uint8_t **pp_peek, unsigned int i_read );static int  AStreamSeekStream( stream_t *s, int64_t i_pos );static void AStreamPrebufferStream( stream_t *s );static int  AReadStream( stream_t *s, void *p_read, unsigned int i_read );/* Method 3 */static int  AStreamReadImmediate( stream_t *s, void *p_read, unsigned int i_read );static int  AStreamPeekImmediate( stream_t *s, const uint8_t **pp_peek, unsigned int i_read );static int  AStreamSeekImmediate( stream_t *s, int64_t i_pos );/* Common */static int AStreamControl( stream_t *s, int i_query, va_list );static void AStreamDestroy( stream_t *s );static void UStreamDestroy( stream_t *s );static int  ASeek( stream_t *s, int64_t i_pos );/**************************************************************************** * Method 3 helpers: ****************************************************************************/static inline int64_t stream_buffered_size( stream_t *s ){    return s->p_sys->immediate.i_end;}static inline void stream_buffer_empty( stream_t *s, int length ){    length = __MAX( stream_buffered_size( s ), length );    if( length )    {        memmove( s->p_sys->immediate.p_buffer,                 s->p_sys->immediate.p_buffer + length,                 stream_buffered_size( s ) - length );    }    s->p_sys->immediate.i_end -= length;}static inline void stream_buffer_fill( stream_t *s, int length ){    s->p_sys->immediate.i_end += length;}static inline uint8_t * stream_buffer( stream_t *s ){    return s->p_sys->immediate.p_buffer;}/**************************************************************************** * stream_UrlNew: create a stream from a access ****************************************************************************/stream_t *__stream_UrlNew( vlc_object_t *p_parent, const char *psz_url ){    const char *psz_access, *psz_demux;    char *psz_path;    access_t *p_access;    stream_t *p_res;    if( !psz_url )        return NULL;    char psz_dup[strlen( psz_url ) + 1];    strcpy( psz_dup, psz_url );    input_SplitMRL( &psz_access, &psz_demux, &psz_path, psz_dup );    /* Now try a real access */    p_access = access_New( p_parent, psz_access, psz_demux, psz_path );    if( p_access == NULL )    {        msg_Err( p_parent, "no suitable access module for `%s'", psz_url );        return NULL;    }    if( !( p_res = stream_AccessNew( p_access, true ) ) )    {        access_Delete( p_access );        return NULL;    }    p_res->pf_destroy = UStreamDestroy;    return p_res;}stream_t *stream_AccessNew( access_t *p_access, bool b_quick ){    stream_t *s = vlc_stream_create( VLC_OBJECT(p_access) );    stream_sys_t *p_sys;    char *psz_list = NULL;    if( !s ) return NULL;    /* Attach it now, needed for b_die */    vlc_object_attach( s, p_access );    s->pf_read   = NULL;    /* Set up later */    s->pf_peek   = NULL;    s->pf_control = AStreamControl;    s->pf_destroy = AStreamDestroy;    s->p_sys = p_sys = malloc( sizeof( stream_sys_t ) );    if( p_sys == NULL )        goto error;    /* UTF16 and UTF32 text file conversion */    s->i_char_width = 1;    s->b_little_endian = false;    s->conv = (vlc_iconv_t)(-1);    /* Common field */    p_sys->p_access = p_access;    if( p_access->pf_block )        p_sys->method = Block;    else if (var_CreateGetBool( s, "use-stream-immediate"))        p_sys->method = Immediate;    else        p_sys->method = Stream;    p_sys->i_pos = p_access->info.i_pos;    /* Stats */    access_Control( p_access, ACCESS_CAN_FASTSEEK, &p_sys->stat.b_fastseek );    p_sys->stat.i_bytes = 0;    p_sys->stat.i_read_time = 0;    p_sys->stat.i_read_count = 0;    p_sys->stat.i_seek_count = 0;    p_sys->stat.i_seek_time = 0;    p_sys->i_list = 0;    p_sys->list = 0;    p_sys->i_list_index = 0;    p_sys->p_list_access = 0;    p_sys->b_quick = b_quick;    /* Get the additional list of inputs if any (for concatenation) */    if( (psz_list = var_CreateGetString( s, "input-list" )) && *psz_list )    {        access_entry_t *p_entry = malloc( sizeof(access_entry_t) );        if( p_entry == NULL )            goto error;        char *psz_name, *psz_parser = psz_name = psz_list;        p_sys->p_list_access = p_access;        p_entry->i_size = p_access->info.i_size;        p_entry->psz_path = strdup( p_access->psz_path );        if( p_entry->psz_path == NULL )        {            free( p_entry );            goto error;        }        TAB_APPEND( p_sys->i_list, p_sys->list, p_entry );        msg_Dbg( p_access, "adding file `%s', (%"PRId64" bytes)",                 p_entry->psz_path, p_access->info.i_size );        while( psz_name && *psz_name )        {            psz_parser = strchr( psz_name, ',' );            if( psz_parser ) *psz_parser = 0;            psz_name = strdup( psz_name );            if( psz_name )            {                access_t *p_tmp = access_New( p_access, p_access->psz_access,                                               "", psz_name );                if( !p_tmp )                {                    psz_name = psz_parser;                    if( psz_name ) psz_name++;                    continue;                }                msg_Dbg( p_access, "adding file `%s', (%"PRId64" bytes)",                         psz_name, p_tmp->info.i_size );                p_entry = malloc( sizeof(access_entry_t) );                if( p_entry == NULL )                    goto error;                p_entry->i_size = p_tmp->info.i_size;                p_entry->psz_path = psz_name;                TAB_APPEND( p_sys->i_list, p_sys->list, p_entry );                access_Delete( p_tmp );            }            psz_name = psz_parser;            if( psz_name ) psz_name++;        }    }    FREENULL( psz_list );    /* Peek */    p_sys->i_peek = 0;    p_sys->p_peek = NULL;    if( p_sys->method == Block )    {        msg_Dbg( s, "Using AStream*Block" );        s->pf_read = AStreamReadBlock;        s->pf_peek = AStreamPeekBlock;        /* Init all fields of p_sys->block */        p_sys->block.i_start = p_sys->i_pos;        p_sys->block.i_offset = 0;        p_sys->block.p_current = NULL;        p_sys->block.i_size = 0;        p_sys->block.p_first = NULL;        p_sys->block.pp_last = &p_sys->block.p_first;        /* Do the prebuffering */        AStreamPrebufferBlock( s );        if( p_sys->block.i_size <= 0 )        {            msg_Err( s, "cannot pre fill buffer" );            goto error;        }    }    else if (p_sys->method == Immediate)    {        msg_Dbg( s, "Using AStream*Immediate" );        s->pf_read = AStreamReadImmediate;        s->pf_peek = AStreamPeekImmediate;        /* Allocate/Setup our tracks (useful to peek)*/        p_sys->immediate.i_end = 0;        p_sys->immediate.p_buffer = malloc( STREAM_CACHE_SIZE );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -