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

📄 stream.c

📁 video linux conference
💻 C
📖 第 1 页 / 共 3 页
字号:
/***************************************************************************** * stream.c ***************************************************************************** * Copyright (C) 1999-2004 VideoLAN * $Id: stream.c 10660 2005-04-12 18:15:33Z gbazin $ * * 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., 59 Temple Place - Suite 330, Boston, MA  02111, USA. *****************************************************************************/#include <stdlib.h>#include <vlc/vlc.h>#include <vlc/input.h>#include "input_internal.h"/* TODO: *  - tune the 2 methods *  - compute cost for seek *  - improve stream mode seeking with closest segments *  - ... *//* Two methods: *  - using pf_block *      One linked list of data read *  - using pf_read *      More complex scheme using mutliple track to avoid seeking *//* 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;struct stream_sys_t{    access_t    *p_access;    vlc_bool_t  b_block;    /* Block method (1) or stream */    int64_t     i_pos;      /* Current reading offset */    /* Method 1: pf_block */    struct    {        int64_t i_start;        /* Offset of block for p_first */        int     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;    /* Peek temporary buffer */    int     i_peek;    uint8_t *p_peek;    /* Stat for both method */    struct    {        vlc_bool_t 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 ? */    vlc_bool_t b_quick;};/* Method 1: */static int  AStreamReadBlock( stream_t *s, void *p_read, int i_read );static int  AStreamPeekBlock( stream_t *s, uint8_t **p_peek, 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, vlc_bool_t *pb_eof );/* Method 2 */static int  AStreamReadStream( stream_t *s, void *p_read, int i_read );static int  AStreamPeekStream( stream_t *s, uint8_t **pp_peek, 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, int i_read );/* 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 );/**************************************************************************** * stream_UrlNew: create a stream from a access ****************************************************************************/stream_t *__stream_UrlNew( vlc_object_t *p_parent, const char *psz_url ){    char *psz_access, *psz_demux, *psz_path, *psz_dup;    access_t *p_access;    stream_t *p_res;    if( !psz_url ) return 0;    psz_dup = strdup( psz_url );    MRLSplit( p_parent, psz_dup, &psz_access, &psz_demux, &psz_path );        /* Now try a real access */    p_access = access2_New( p_parent, psz_access, psz_demux, psz_path, 0 );    free( psz_dup );    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, VLC_TRUE ) ) )    {        access2_Delete( p_access );        return NULL;    }    p_res->pf_destroy = UStreamDestroy;    return p_res;}stream_t *stream_AccessNew( access_t *p_access, vlc_bool_t b_quick ){    stream_t *s = vlc_object_create( p_access, VLC_OBJECT_STREAM );    stream_sys_t *p_sys;    char *psz_list;    if( !s ) return NULL;    /* Attach it now, needed for b_die */    vlc_object_attach( s, p_access );    s->pf_block  = NULL;    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 ) );    /* Common field */    p_sys->p_access = p_access;    p_sys->b_block = p_access->pf_block ? VLC_TRUE : VLC_FALSE;    p_sys->i_pos = p_access->info.i_pos;    /* Stats */    access2_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) );        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 );        TAB_APPEND( p_sys->i_list, p_sys->list, p_entry );        msg_Dbg( p_access, "adding file `%s', ("I64Fd" 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 = access2_New( p_access, p_access->psz_access,                                               0, psz_name, 0 );                if( !p_tmp )                {                    psz_name = psz_parser;                    if( psz_name ) psz_name++;                    continue;                }                msg_Dbg( p_access, "adding file `%s', ("I64Fd" bytes)",                         psz_name, p_tmp->info.i_size );                p_entry = malloc( sizeof(access_entry_t) );                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 );                access2_Delete( p_tmp );            }            psz_name = psz_parser;            if( psz_name ) psz_name++;        }    }    if( psz_list ) free( psz_list );    /* Peek */    p_sys->i_peek = 0;    p_sys->p_peek = NULL;    if( p_sys->b_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    {        int i;        s->pf_read = AStreamReadStream;        s->pf_peek = AStreamPeekStream;        /* Allocate/Setup our tracks */        p_sys->stream.i_offset = 0;        p_sys->stream.i_tk     = 0;        p_sys->stream.p_buffer = malloc( STREAM_CACHE_SIZE );        p_sys->stream.i_used   = 0;        access2_Control( p_access, ACCESS_GET_MTU,                         &p_sys->stream.i_read_size );        if( p_sys->stream.i_read_size <= 0 )            p_sys->stream.i_read_size = STREAM_READ_ATONCE;        else if( p_sys->stream.i_read_size <= 256 )            p_sys->stream.i_read_size = 256;        for( i = 0; i < STREAM_CACHE_TRACK; i++ )        {            p_sys->stream.tk[i].i_date  = 0;            p_sys->stream.tk[i].i_start = p_sys->i_pos;            p_sys->stream.tk[i].i_end   = p_sys->i_pos;            p_sys->stream.tk[i].p_buffer=                &p_sys->stream.p_buffer[i * STREAM_CACHE_TRACK_SIZE];        }        /* Do the prebuffering */        AStreamPrebufferStream( s );        if( p_sys->stream.tk[p_sys->stream.i_tk].i_end <= 0 )        {            msg_Err( s, "cannot pre fill buffer" );            goto error;        }    }    return s;error:    if( p_sys->b_block )    {        /* Nothing yet */    }    else    {        free( p_sys->stream.p_buffer );    }    free( s->p_sys );    vlc_object_detach( s );    vlc_object_destroy( s );    return NULL;}/**************************************************************************** * AStreamDestroy: ****************************************************************************/static void AStreamDestroy( stream_t *s ){    stream_sys_t *p_sys = s->p_sys;    vlc_object_detach( s );    if( p_sys->b_block ) block_ChainRelease( p_sys->block.p_first );    else free( p_sys->stream.p_buffer );    if( p_sys->p_peek ) free( p_sys->p_peek );    if( p_sys->p_list_access && p_sys->p_list_access != p_sys->p_access )        access2_Delete( p_sys->p_list_access );    while( p_sys->i_list-- )    {        free( p_sys->list[p_sys->i_list]->psz_path );        free( p_sys->list[p_sys->i_list] );        if( !p_sys->i_list ) free( p_sys->list );    }    free( s->p_sys );    vlc_object_destroy( s );}static void UStreamDestroy( stream_t *s ){    access_t *p_access = (access_t*)vlc_object_find( s, VLC_OBJECT_ACCESS, FIND_PARENT );    AStreamDestroy( s );    vlc_object_release( p_access );    access2_Delete( p_access );}/**************************************************************************** * stream_AccessReset: ****************************************************************************/void stream_AccessReset( stream_t *s ){    stream_sys_t *p_sys = s->p_sys;    p_sys->i_pos = p_sys->p_access->info.i_pos;    if( p_sys->b_block )    {        block_ChainRelease( p_sys->block.p_first );        /* 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 );    }    else    {        int i;        /* Setup our tracks */        p_sys->stream.i_offset = 0;        p_sys->stream.i_tk     = 0;        p_sys->stream.i_used   = 0;        for( i = 0; i < STREAM_CACHE_TRACK; i++ )        {            p_sys->stream.tk[i].i_date  = 0;            p_sys->stream.tk[i].i_start = p_sys->i_pos;            p_sys->stream.tk[i].i_end   = p_sys->i_pos;        }        /* Do the prebuffering */        AStreamPrebufferStream( s );    }}/**************************************************************************** * stream_AccessUpdate: ****************************************************************************/void stream_AccessUpdate( stream_t *s ){    stream_sys_t *p_sys = s->p_sys;    p_sys->i_pos = p_sys->p_access->info.i_pos;    if( p_sys->i_list )    {        int i;        for( i = 0; i < p_sys->i_list_index; i++ )        {            p_sys->i_pos += p_sys->list[i]->i_size;        }    }}/**************************************************************************** * AStreamControl: ****************************************************************************/static int AStreamControl( stream_t *s, int i_query, va_list args ){    stream_sys_t *p_sys = s->p_sys;    access_t     *p_access = p_sys->p_access;    vlc_bool_t *p_bool;    int64_t    *pi_64, i_64;    int        i_int;    switch( i_query )    {        case STREAM_GET_SIZE:            pi_64 = (int64_t*)va_arg( args, int64_t * );            if( s->p_sys->i_list )            {                int i;                *pi_64 = 0;                for( i = 0; i < s->p_sys->i_list; i++ )                    *pi_64 += s->p_sys->list[i]->i_size;

⌨️ 快捷键说明

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