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

📄 stream.c

📁 video linux conference
💻 C
📖 第 1 页 / 共 3 页
字号:
                break;            }            *pi_64 = p_access->info.i_size;            break;        case STREAM_CAN_SEEK:            p_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );            access2_Control( p_access, ACCESS_CAN_SEEK, p_bool );            break;        case STREAM_CAN_FASTSEEK:            p_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );            access2_Control( p_access, ACCESS_CAN_FASTSEEK, p_bool );            break;        case STREAM_GET_POSITION:            pi_64 = (int64_t*)va_arg( args, int64_t * );            *pi_64 = p_sys->i_pos;            break;        case STREAM_SET_POSITION:            i_64 = (int64_t)va_arg( args, int64_t );            if( p_sys->b_block )                return AStreamSeekBlock( s, i_64 );            else                return AStreamSeekStream( s, i_64 );        case STREAM_GET_MTU:            return VLC_EGENERIC;        case STREAM_CONTROL_ACCESS:            i_int = (int) va_arg( args, int );            if( i_int != ACCESS_SET_PRIVATE_ID_STATE &&                i_int != ACCESS_SET_PRIVATE_ID_CA &&                i_int != ACCESS_GET_PRIVATE_ID_STATE )            {                msg_Err( s, "Hey, what are you thinking ?"                            "DON'T USE STREAM_CONTROL_ACCESS !!!" );                return VLC_EGENERIC;            }            return access2_vaControl( p_access, i_int, args );        default:            msg_Err( s, "invalid stream_vaControl query=0x%x", i_query );            return VLC_EGENERIC;    }    return VLC_SUCCESS;}/**************************************************************************** * Method 1: ****************************************************************************/static void AStreamPrebufferBlock( stream_t *s ){    stream_sys_t *p_sys = s->p_sys;    int64_t i_first = 0;    int64_t i_start;    msg_Dbg( s, "pre buffering" );    i_start = mdate();    for( ;; )    {        int64_t i_date = mdate();        vlc_bool_t b_eof;        block_t *b;        if( s->b_die || p_sys->block.i_size > STREAM_CACHE_PREBUFFER_SIZE ||            ( i_first > 0 && i_first + STREAM_CACHE_PREBUFFER_LENGTH < i_date ) )        {            int64_t i_byterate;            /* Update stat */            p_sys->stat.i_bytes = p_sys->block.i_size;            p_sys->stat.i_read_time = i_date - i_start;            i_byterate = ( I64C(1000000) * p_sys->stat.i_bytes ) /                         (p_sys->stat.i_read_time + 1);            msg_Dbg( s, "prebuffering done "I64Fd" bytes in "I64Fd"s - "                     I64Fd" kbytes/s",                     p_sys->stat.i_bytes,                     p_sys->stat.i_read_time / I64C(1000000),                     i_byterate / 1024 );            break;        }        /* Fetch a block */        if( ( b = AReadBlock( s, &b_eof ) ) == NULL )        {            if( b_eof ) break;            msleep( STREAM_DATA_WAIT );            continue;        }        if( i_first == 0 )        {            i_first = mdate();            msg_Dbg( s, "received first data for our buffer");        }        /* Append the block */        p_sys->block.i_size += b->i_buffer;        *p_sys->block.pp_last = b;        p_sys->block.pp_last = &b->p_next;        p_sys->stat.i_read_count++;    }    p_sys->block.p_current = p_sys->block.p_first;}static int AStreamRefillBlock( stream_t *s );static int AStreamReadBlock( stream_t *s, void *p_read, int i_read ){    stream_sys_t *p_sys = s->p_sys;    uint8_t *p_data= (uint8_t*)p_read;    int     i_data = 0;    /* It means EOF */    if( p_sys->block.p_current == NULL )        return 0;    if( p_read == NULL )    {        /* seek within this stream if possible, else use plain old read and discard */        stream_sys_t *p_sys = s->p_sys;        access_t     *p_access = p_sys->p_access;        vlc_bool_t   b_aseek;        access2_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );        if( b_aseek )            return AStreamSeekBlock( s, p_sys->i_pos + i_read ) ? 0 : i_read;    }    while( i_data < i_read )    {        int i_current =            p_sys->block.p_current->i_buffer - p_sys->block.i_offset;        int i_copy = __MIN( i_current, i_read - i_data);        /* Copy data */        if( p_data )        {            memcpy( p_data,                    &p_sys->block.p_current->p_buffer[p_sys->block.i_offset],                    i_copy );            p_data += i_copy;        }        i_data += i_copy;        p_sys->block.i_offset += i_copy;        if( p_sys->block.i_offset >= p_sys->block.p_current->i_buffer )        {            /* Current block is now empty, switch to next */            if( p_sys->block.p_current )            {                p_sys->block.i_offset = 0;                p_sys->block.p_current = p_sys->block.p_current->p_next;            }            /*Get a new block */            if( AStreamRefillBlock( s ) )            {                break;            }        }    }    p_sys->i_pos += i_data;    return i_data;}static int AStreamPeekBlock( stream_t *s, uint8_t **pp_peek, int i_read ){    stream_sys_t *p_sys = s->p_sys;    uint8_t *p_data;    int      i_data = 0;    block_t *b;    int      i_offset;    if( p_sys->block.p_current == NULL ) return 0; /* EOF */    /* We can directly give a pointer over our buffer */    if( i_read <= p_sys->block.p_current->i_buffer - p_sys->block.i_offset )    {        *pp_peek = &p_sys->block.p_current->p_buffer[p_sys->block.i_offset];        return i_read;    }    /* We need to create a local copy */    if( p_sys->i_peek < i_read )    {        p_sys->p_peek = realloc( p_sys->p_peek, i_read );        if( !p_sys->p_peek )        {            p_sys->i_peek = 0;            return 0;        }        p_sys->i_peek = i_read;    }    /* Fill enough data */    while( p_sys->block.i_size - (p_sys->i_pos - p_sys->block.i_start)           < i_read )    {        block_t **pp_last = p_sys->block.pp_last;        if( AStreamRefillBlock( s ) ) break;        /* Our buffer are probably filled enough, don't try anymore */        if( pp_last == p_sys->block.pp_last ) break;    }    /* Copy what we have */    b = p_sys->block.p_current;    i_offset = p_sys->block.i_offset;    p_data = p_sys->p_peek;    while( b && i_data < i_read )    {        int i_current = b->i_buffer - i_offset;        int i_copy = __MIN( i_current, i_read - i_data );        memcpy( p_data, &b->p_buffer[i_offset], i_copy );        i_data += i_copy;        p_data += i_copy;        i_offset += i_copy;        if( i_offset >= b->i_buffer )        {            i_offset = 0;            b = b->p_next;        }    }    *pp_peek = p_sys->p_peek;    return i_data;}static int AStreamSeekBlock( stream_t *s, int64_t i_pos ){    stream_sys_t *p_sys = s->p_sys;    access_t   *p_access = p_sys->p_access;    int64_t    i_offset = i_pos - p_sys->block.i_start;    vlc_bool_t b_seek;    /* We already have thoses data, just update p_current/i_offset */    if( i_offset >= 0 && i_offset < p_sys->block.i_size )    {        block_t *b = p_sys->block.p_first;        int i_current = 0;        while( i_current + b->i_buffer < i_offset )        {            i_current += b->i_buffer;            b = b->p_next;        }        p_sys->block.p_current = b;        p_sys->block.i_offset = i_offset - i_current;        p_sys->i_pos = i_pos;        return VLC_SUCCESS;    }    /* We may need to seek or to read data */    if( i_offset < 0 )    {        vlc_bool_t b_aseek;        access2_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );        if( !b_aseek )        {            msg_Err( s, "backward seek impossible (access non seekable)" );            return VLC_EGENERIC;        }        b_seek = VLC_TRUE;    }    else    {        vlc_bool_t b_aseek, b_aseekfast;        access2_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );        access2_Control( p_access, ACCESS_CAN_FASTSEEK, &b_aseekfast );        if( !b_aseek )        {            b_seek = VLC_FALSE;            msg_Warn( s, I64Fd" bytes need to be skipped "                      "(access non seekable)",                      i_offset - p_sys->block.i_size );        }        else        {            int64_t i_skip = i_offset - p_sys->block.i_size;            /* Avg bytes per packets */            int i_avg = p_sys->stat.i_bytes / p_sys->stat.i_read_count;            /* TODO compute a seek cost instead of fixed threshold */            int i_th = b_aseekfast ? 1 : 5;            if( i_skip <= i_th * i_avg &&                i_skip < STREAM_CACHE_SIZE )                b_seek = VLC_FALSE;            else                b_seek = VLC_TRUE;            msg_Dbg( s, "b_seek=%d th*avg=%d skip="I64Fd,                     b_seek, i_th*i_avg, i_skip );        }    }    if( b_seek )    {        int64_t i_start, i_end;        /* Do the access seek */        i_start = mdate();        if( ASeek( s, i_pos ) ) return VLC_EGENERIC;        i_end = mdate();        /* Release data */        block_ChainRelease( p_sys->block.p_first );        /* Reinit */        p_sys->block.i_start = p_sys->i_pos = 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;        /* Refill a block */        if( AStreamRefillBlock( s ) )        {            msg_Err( s, "cannot re fill buffer" );            return VLC_EGENERIC;        }        /* Update stat */        p_sys->stat.i_seek_time += i_end - i_start;        p_sys->stat.i_seek_count++;        return VLC_SUCCESS;    }    else    {        /* Read enought data */        while( p_sys->block.i_start + p_sys->block.i_size < i_pos )        {            if( AStreamRefillBlock( s ) )            {                msg_Err( s, "can't read enough data in seek" );                return VLC_EGENERIC;            }            while( p_sys->block.p_current &&                   p_sys->i_pos + p_sys->block.p_current->i_buffer < i_pos )            {                p_sys->i_pos += p_sys->block.p_current->i_buffer;                p_sys->block.p_current = p_sys->block.p_current->p_next;            }        }        p_sys->block.i_offset = i_pos - p_sys->i_pos;        p_sys->i_pos = i_pos;        /* TODO read data */        return VLC_SUCCESS;    }    return VLC_EGENERIC;}static int AStreamRefillBlock( stream_t *s ){    stream_sys_t *p_sys = s->p_sys;    int64_t      i_start, i_stop;    block_t      *b;    /* Release data */    while( p_sys->block.i_size >= STREAM_CACHE_SIZE &&           p_sys->block.p_first != p_sys->block.p_current )    {        block_t *b = p_sys->block.p_first;        p_sys->block.i_start += b->i_buffer;        p_sys->block.i_size  -= b->i_buffer;        p_sys->block.p_first  = b->p_next;        block_Release( b );    }    if( p_sys->block.i_size >= STREAM_CACHE_SIZE &&        p_sys->block.p_current == p_sys->block.p_first &&        p_sys->block.p_current->p_next )    /* At least 2 packets */    {        /* Enough data, don't read more */        return VLC_SUCCESS;    }    /* Now read a new block */    i_start = mdate();    for( ;; )    {        vlc_bool_t b_eof;        if( s->b_die ) return VLC_EGENERIC;        /* Fetch a block */        if( ( b = AReadBlock( s, &b_eof ) ) ) break;        if( b_eof ) return VLC_EGENERIC;        msleep( STREAM_DATA_WAIT );    }    i_stop = mdate();    /* Append the block */    p_sys->block.i_size += b->i_buffer;    *p_sys->block.pp_last = b;    p_sys->block.pp_last = &b->p_next;    /* Fix p_current */    if( p_sys->block.p_current == NULL )        p_sys->block.p_current = b;    /* Update stat */    p_sys->stat.i_bytes += b->i_buffer;    p_sys->stat.i_read_time += i_stop - i_start;    p_sys->stat.i_read_count++;    return VLC_SUCCESS;}/**************************************************************************** * Method 2: ****************************************************************************/static int AStreamRefillStream( stream_t *s );static int AStreamReadStream( stream_t *s, void *p_read, int i_read ){    stream_sys_t *p_sys = s->p_sys;    stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];    uint8_t *p_data = (uint8_t *)p_read;    int      i_data = 0;    if( tk->i_start >= tk->i_end ) return 0; /* EOF */    if( p_read == NULL )    {        /* seek within this stream if possible, else use plain old read and discard */        stream_sys_t *p_sys = s->p_sys;        access_t     *p_access = p_sys->p_access;        vlc_bool_t   b_aseek;        access2_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );        if( b_aseek )            return AStreamSeekStream( s, p_sys->i_pos + i_read ) ? 0 : i_read;    }#if 0    msg_Dbg( s, "AStreamReadStream: %d pos="I64Fd" tk=%d start="I64Fd             " offset=%d end="I64Fd,             i_read, p_sys->i_pos, p_sys->stream.i_tk,             tk->i_start, p_sys->stream.i_offset, tk->i_end );#endif    while( i_data < i_read )    {        int i_off = (tk->i_start + p_sys->stream.i_offset) %                    STREAM_CACHE_TRACK_SIZE;        int i_current =            __MIN( tk->i_end - tk->i_start - p_sys->stream.i_offset,                   STREAM_CACHE_TRACK_SIZE - i_off );        int i_copy = __MIN( i_current, i_read - i_data );        if( i_copy <= 0 ) break; /* EOF */        /* Copy data */        /* msg_Dbg( s, "AStreamReadStream: copy %d", i_copy ); */        if( p_data )        {            memcpy( p_data, &tk->p_buffer[i_off], i_copy );            p_data += i_copy;        }        i_data += i_copy;        p_sys->stream.i_offset += i_copy;        /* Update pos now */        p_sys->i_pos += i_copy;        /* */        p_sys->stream.i_used += i_copy;        if( tk->i_start + p_sys->stream.i_offset >= tk->i_end ||            p_sys->stream.i_used >= p_sys->stream.i_read_size )        {            if( AStreamRefillStream( s ) )            {                /* EOF */                if( tk->i_start >= tk->i_end ) break;            }        }    }    return i_data;}static int AStreamPeekStream( stream_t *s, uint8_t **pp_peek, int i_read )

⌨️ 快捷键说明

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