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

📄 v4l.c

📁 VLC媒体播放程序
💻 C
📖 第 1 页 / 共 4 页
字号:
    access_sys_t *p_sys = p_input->p_access_data;    p_sys->vid_mmap.frame = ( p_sys->i_frame_pos + 1 ) %                            p_sys->vid_mbuf.frames;    for( ;; )    {        if( ioctl( p_sys->fd_video, VIDIOCMCAPTURE, &p_sys->vid_mmap ) >= 0 )        {            break;        }        if( errno != EAGAIN )        {            msg_Err( p_input, "failed while grabbing new frame" );            return( NULL );        }        msg_Dbg( p_input, "another try ?" );    }    //msg_Warn( p_input, "grab a new frame" );    while( ioctl(p_sys->fd_video, VIDIOCSYNC, &p_sys->i_frame_pos) < 0 &&           ( errno == EAGAIN || errno == EINTR ) );    p_sys->i_frame_pos = p_sys->vid_mmap.frame;    /* leave i_video_frame_size alone */    return p_sys->p_video_mmap + p_sys->vid_mbuf.offsets[p_sys->i_frame_pos];}static uint8_t *GrabMJPEG( input_thread_t *p_input ){    access_sys_t *p_sys = p_input->p_access_data;    struct mjpeg_sync sync;    uint8_t *p_frame, *p_field, *p;    uint16_t tag;    uint32_t i_size;    struct quicktime_mjpeg_app1 *p_app1 = NULL;    /* re-queue the last frame we sync'd */    if( p_sys->i_frame_pos != -1 )        while( ioctl( p_sys->fd_video, MJPIOC_QBUF_CAPT, &p_sys->i_frame_pos ) < 0 &&                ( errno == EAGAIN || errno == EINTR ) );    /* sync on the next frame */    while( ioctl( p_sys->fd_video, MJPIOC_SYNC, &sync ) < 0 &&            ( errno == EAGAIN || errno == EINTR ) );    p_sys->i_frame_pos = sync.frame;    p_frame = p_sys->p_video_mmap + p_sys->mjpeg_buffers.size * sync.frame;    /* p_frame now points to the data.  fix up the Quicktime APP1 marker */    tag = 0xffd9;    tag = hton16( tag );    p_field = p_frame;    /* look for EOI */    p = memmem( p_field, sync.length, &tag, 2 );    if( p )    {        p += 2; /* data immediately following EOI */        /* UNALIGNED! */        p_app1 = (struct quicktime_mjpeg_app1 *)(p_field + 6);        i_size = ((uint32_t)(p - p_field));        i_size = hton32( i_size );        memcpy( &p_app1->i_field_size, &i_size, 4 );        while( *p == 0xff && *(p+1) == 0xff )            p++;        i_size = ((uint32_t)(p - p_field));        i_size = hton32( i_size );        memcpy( &p_app1->i_padded_field_size, &i_size, 4 );    }    tag = 0xffd8;    tag = hton16( tag );    p_field = memmem( p, sync.length - (size_t)(p - p_frame), &tag, 2 );    if( p_field )    {        i_size = (uint32_t)(p_field - p_frame);        i_size = hton32( i_size );        memcpy( &p_app1->i_next_field, &i_size, 4 );        /* UNALIGNED! */        p_app1 = (struct quicktime_mjpeg_app1 *)(p_field + 6);        tag = 0xffd9;        tag = hton16( tag );        p = memmem( p_field, sync.length - (size_t)(p_field - p_frame),                &tag, 2 );        if( !p )        {            /* sometimes the second field doesn't have the EOI.  just put it             * there             */            p = p_frame + sync.length;            memcpy( p, &tag, 2 );            sync.length += 2;        }        p += 2;        i_size = (uint32_t)(p - p_field);        i_size = hton32( i_size );        memcpy( &p_app1->i_field_size, &i_size, 4 );        i_size = (uint32_t)(sync.length - (uint32_t)(p_field - p_frame));        i_size = hton32( i_size );        memcpy( &p_app1->i_padded_field_size, &i_size, 4 );    }    p_sys->i_video_frame_size = sync.length;    return p_frame;}static int GrabVideo( input_thread_t * p_input,                      uint8_t **pp_data,                      int *pi_data,                      mtime_t  *pi_pts ){    access_sys_t *p_sys   = p_input->p_access_data;    uint8_t      *p_frame;    if( p_sys->f_fps >= 0.1 && p_sys->i_video_pts > 0 )    {        mtime_t i_dur = (mtime_t)((double)1000000 / (double)p_sys->f_fps);        /* Did we wait long enougth ? */        if( p_sys->i_video_pts + i_dur > mdate() )        {            return VLC_ETIMEOUT;        }    }    if( p_sys->b_mjpeg )        p_frame = GrabMJPEG( p_input );    else        p_frame = GrabCapture( p_input );    if( !p_frame )        return VLC_EGENERIC;    p_sys->i_video_pts   = mdate();    p_sys->p_video_frame = p_frame;    *pp_data = p_sys->p_video_frame;    *pi_data = p_sys->i_video_frame_size;    *pi_pts  = p_sys->i_video_pts;    return VLC_SUCCESS;}/***************************************************************************** * Read: reads from the device into PES packets. ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, otherwise the number of * bytes. *****************************************************************************/static int Read( input_thread_t * p_input, byte_t * p_buffer, size_t i_len ){    access_sys_t *p_sys = p_input->p_access_data;    int          i_data = 0;    int          i_stream;    mtime_t      i_pts;    while( i_len > 0 )    {        /* First copy header if any */        if( p_sys->i_header_pos < p_sys->i_header_size )        {            int i_copy;            i_copy = __MIN( p_sys->i_header_size - p_sys->i_header_pos,                            (int)i_len );            memcpy( p_buffer, &p_sys->p_header[p_sys->i_header_pos], i_copy );            p_sys->i_header_pos += i_copy;            p_buffer += i_copy;            i_len -= i_copy;            i_data += i_copy;        }        /* then data */        if( i_len > 0 && p_sys->i_data_pos < p_sys->i_data_size )        {            int i_copy;            i_copy = __MIN( p_sys->i_data_size - p_sys->i_data_pos,                            (int)i_len );            memcpy( p_buffer, &p_sys->p_data[p_sys->i_data_pos], i_copy );            p_sys->i_data_pos += i_copy;            p_buffer += i_copy;            i_len -= i_copy;            i_data += i_copy;        }        /* The caller got what he wanted */        if( i_len == 0 )        {            return i_data;        }        /* Read no more than one frame at a time.         * That kills latency, especially for encoded v4l streams */        if( p_sys->i_data_size && p_sys->i_data_pos == p_sys->i_data_size )        {            p_sys->i_data_pos = 0; p_sys->i_data_size = 0;            return i_data;        }        /* Re-fill data by grabbing audio/video */        p_sys->i_data_pos = p_sys->i_data_size = 0;        /* Try grabbing audio frames first */        i_stream = p_sys->i_streams - 1;        if( p_sys->fd_audio < 0 ||            GrabAudio( p_input, &p_sys->p_data,                       &p_sys->i_data_size, &i_pts ) != VLC_SUCCESS )        {            int i_ret = VLC_ETIMEOUT;            /* Try grabbing video frame */            i_stream = 0;            if( p_sys->fd_video > 0 )            {                i_ret = GrabVideo( p_input, &p_sys->p_data,                                   &p_sys->i_data_size, &i_pts );            }            /* No video or timeout */            if( i_ret == VLC_ETIMEOUT )            {                /* Sleep so we do not consume all the cpu, 10ms seems                 * like a good value (100fps) */                msleep( 10000 );                continue;            }            else if( i_ret != VLC_SUCCESS )            {                msg_Err( p_input, "Error during capture!" );                return -1;            }        }        /* create pseudo header */        p_sys->i_header_size = 16;        p_sys->i_header_pos  = 0;        SetDWBE( &p_sys->p_header[0], i_stream );        SetDWBE( &p_sys->p_header[4], p_sys->i_data_size );        SetQWBE( &p_sys->p_header[8], i_pts );    }    return i_data;}/***************************************************************************** * Demux: local prototypes *****************************************************************************/struct demux_sys_t{    int         i_es;    es_out_id_t **es;};static int  Demux      ( input_thread_t * );/**************************************************************************** * DemuxOpen: ****************************************************************************/static int DemuxOpen( vlc_object_t *p_this ){    input_thread_t *p_input = (input_thread_t *)p_this;    demux_sys_t    *p_sys;    uint8_t        *p_peek;    int            i_es;    int            i;    /* a little test to see if it's a v4l stream */    if( stream_Peek( p_input->s, &p_peek, 8 ) < 8 )    {        msg_Warn( p_input, "v4l plugin discarded (cannot peek)" );        return VLC_EGENERIC;    }    if( strncmp( p_peek, ".v4l", 4 ) ||        ( i_es = GetDWBE( &p_peek[4] ) ) <= 0 )    {        msg_Warn( p_input, "v4l plugin discarded (not a valid stream)" );        return VLC_EGENERIC;    }    vlc_mutex_lock( &p_input->stream.stream_lock );    if( input_InitStream( p_input, 0 ) == -1)    {        vlc_mutex_unlock( &p_input->stream.stream_lock );        msg_Err( p_input, "cannot init stream" );        return( VLC_EGENERIC );    }    p_input->stream.i_mux_rate =  0 / 50;    vlc_mutex_unlock( &p_input->stream.stream_lock );    p_input->pf_demux = Demux;    p_input->pf_demux_control = demux_vaControlDefault;    p_input->p_demux_data = p_sys = malloc( sizeof( demux_sys_t ) );    p_sys->i_es = 0;    p_sys->es   = NULL;    if( stream_Peek( p_input->s, &p_peek, 8 + 20 * i_es ) < 8 + 20 * i_es )    {        msg_Err( p_input, "v4l plugin discarded (cannot peek)" );        return VLC_EGENERIC;    }    p_peek += 8;    for( i = 0; i < i_es; i++ )    {        es_format_t fmt;        if( !strncmp( p_peek, "auds", 4 ) )        {            es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( p_peek[4], p_peek[5],                                                        p_peek[6], p_peek[7] ) );            fmt.audio.i_channels = GetDWBE( &p_peek[8] );            fmt.audio.i_rate = GetDWBE( &p_peek[12] );            fmt.audio.i_bitspersample = GetDWBE( &p_peek[16] );            fmt.audio.i_blockalign = fmt.audio.i_channels *                                     fmt.audio.i_bitspersample / 8;            fmt.i_bitrate = fmt.audio.i_channels *                            fmt.audio.i_rate *                            fmt.audio.i_bitspersample;            msg_Dbg( p_input, "new audio es %d channels %dHz",                     fmt.audio.i_channels, fmt.audio.i_rate );            TAB_APPEND( p_sys->i_es, p_sys->es,                        es_out_Add( p_input->p_es_out, &fmt ) );        }        else if( !strncmp( p_peek, "vids", 4 ) )        {            es_format_Init( &fmt, VIDEO_ES, VLC_FOURCC( p_peek[4], p_peek[5],                            p_peek[6], p_peek[7] ) );            fmt.video.i_width  = GetDWBE( &p_peek[8] );            fmt.video.i_height = GetDWBE( &p_peek[12] );            msg_Dbg( p_input, "added new video es %4.4s %dx%d",                     (char*)&fmt.i_codec,                     fmt.video.i_width, fmt.video.i_height );            TAB_APPEND( p_sys->i_es, p_sys->es,                        es_out_Add( p_input->p_es_out, &fmt ) );        }        p_peek += 20;    }    /* Skip header */    stream_Read( p_input->s, NULL, 8 + 20 * i_es );    return VLC_SUCCESS;}/**************************************************************************** * DemuxClose: ****************************************************************************/static void DemuxClose( vlc_object_t *p_this ){    input_thread_t *p_input = (input_thread_t *)p_this;    demux_sys_t    *p_sys = p_input->p_demux_data;    if( p_sys->i_es > 0 )    {        free( p_sys->es );    }    free( p_sys );}/**************************************************************************** * Demux: ****************************************************************************/static int Demux( input_thread_t *p_input ){    demux_sys_t *p_sys = p_input->p_demux_data;    block_t     *p_block;    int i_es;    int i_size;    uint8_t *p_peek;    mtime_t i_pts;    if( stream_Peek( p_input->s, &p_peek, 16 ) < 16 )    {        msg_Warn( p_input, "cannot peek (EOF ?)" );        return 0;    }    i_es   = GetDWBE( &p_peek[0] );    if( i_es < 0 || i_es >= p_sys->i_es )    {        msg_Err( p_input, "cannot find ES" );        return -1;    }    i_size = GetDWBE( &p_peek[4] );    i_pts  = GetQWBE( &p_peek[8] );    if( ( p_block = stream_Block( p_input->s, 16 + i_size ) ) == NULL )    {        msg_Warn( p_input, "cannot read data" );        return 0;    }    p_block->p_buffer += 16;    p_block->i_buffer -= 16;    p_block->i_dts =    p_block->i_pts = i_pts + p_input->i_pts_delay;    es_out_Send( p_input->p_es_out, p_sys->es[i_es], p_block );    return 1;}

⌨️ 快捷键说明

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