Vlc部分功能

 

Vlc部分功能流程图

block_FifoGet

获取编码的block

DecoderProcess

Decoder thread

DecoderProcessVideo

packetizer_Packetize将接受到的block进行packet组装为一个完整的NAL

DecoderDecodeVideo

使用ffmpeg解码

DecodeVideo

判断当前packet是否过期需要丢弃,无需解码

填充AVPacket,解码avcodec_decode_video2

Compute the PTSStream pts转换为system pts,并加上缓冲延时时间。判断当前帧是否已经滞后,并记统计滞后数目。解码下一帧时根据滞后标记,决定解码还是直接丢弃。更新p_pic->date =i_pts

DecoderPlayVideo stream ptssystem pts的转换,加上缓冲时间延迟。display thread会用于判断显示

Display thread

ThreadDisplayPicture

ThreadDisplayPreparePicture

ThreadDisplayRenderPicture

picture_fifo_Pop获取解码过的picture

根据decoded->date与当前系统时间相减,若超过20ms直接丢弃,若不到则显示并打印提示滞后时间。

decodedpicture赋值vout->p->displayed.decoded       = picture_Hold(decoded);

current为空则直接赋值currentvout->p->displayed.current =picture;否则赋给next。vout->p->displayed.next=picture;

date_refresh = vout->p->displayed.date +VOUT_REDISPLAY_DELAY - render_delay计算刷新时间,与当前比较决定是否refresh =date_refresh <= date;

vout->p->displayed.current获取current显示的picture

vout_display_Prepare进行subpictodisplayblend

Direct3DImportPicturepicturesurface copy到系统texturesurface

Direct3DImportSubpicturesubpicture blend入到texture

vout_display_Display完成显示

1.  对于ts流和一些封装过的流在live555接收到数据未作处理直接调用block_FifoPut放入p_sys->block_fifo_t之中。

2.  需要Demux线程调用block_FifoGet(p_sys->p_fifo )分析数据去掉封装最后调用block_FifoPut(p_owner->p_fifo, p_block );放入到decoder_owner_sys_tp_fifo中。对于直接是h264的数据的block是直接放入decoder_owner_sys_tp_fifo中的。

解码线程

i_used = avcodec_decode_video2( p_context, p_sys->p_ff_pic,

                                       &b_gotpicture, &pkt );

利用ffmpeg decode解码得到AVFrame即p_sys->p_ff_pic,里面包含有解码的frame的pts,vlc将对这个pts进行修正,确保时间戳的合法性。

渲染线程

ThreadDisplayPicture在渲染线程中执行。

vout_display_Prepare主要讲subpictodisplay进行blend

 

解码线程与渲染线程的同步:

Decode threadrenderthrad通过picture_fifo_t对解码过的picture_t进行同步使用

 

sys->poolDirect3DCreatePool调用picture_pool_NewExtendedpicture_reservedfalse,会创建count1pool

sys->decoder_poolvout_InitWrapper会创建count33pool,前四个的picture_reserved设置为trueXXX3 for filter, 1 for SPU. 1 for last displayed picture,28 for decoder picture

sys->private_poolpicture_pool_Reserve(sys->decoder_pool,private_picture);同时将sys->decoder_pool的前四个的picture_reserved设置为true,并会创建count4pool

 

以下使用ts stream作为source进行debug调试:

call stack

decode thread:

 

Decode thread get display date

input_clock_ConvertTS

根据ffmpeg解码给出的ptspts转换为系统时间加上delay时间与当前系统时间比较判断当前frame是否过期。

判断当前帧是否滞后,并统计滞后的数目

更新picturepts,直接等于ffmpeg解码给出的时间戳。

丢弃过期的block

主要用于判断当前frame的时间戳是否已经过期,并统计过期的frame数目,当只有一帧数据时需要更新第一个过期时间,此时间可用于后面的frame是解码还是丢弃的时间参考。

一般由于网络延迟或者cpu解码性能不够导致。

 

 

Display thread:

prepare

Prepare render 时会将pts与当前的系统的时间进行比较,若有延迟则会log显示滞后时间。可以通过vlc的消息窗口显示当前的log信息。

消息窗口在vlc 的工具菜单选项下面,或者按快捷键Ctrl+M显示出来。图如下。

Buffering的过程:

i_buffering_duration的时常就是的预先设置好的缓冲时间,如1000ms,则i_buffering_duration = 1000*1000

call stack

typedef struct

{

    /* Program ID */

    int i_id;

    /* Number of es for this pgrm */

    int i_es;

    bool b_selected;

    bool b_scrambled;

    /* Clock for this program */

    input_clock_t *p_clock; //此处使用了这个clock

    char    *psz_name;

    char    *psz_now_playing;

    char    *psz_publisher;

}es_out_pgrm_t;

PCR: program clock reference

Ts stream block 更新pcr

根据streamclocksystem clock创建clock_point_t

 

Demux使用input_clock_Updateframestream时间和系统时间更新到clock->last中,而clock->ref参考时钟只有在cl->b_has_reference没有的情况下才会进行更新。

i_ck_stream的时间间隔一般为33.3ms

ClockStreamToSystem,将当前的stream clock减去stream ref,再加上system ref,得到期望的时间;滞后时间即为当前时间减去cache的缓冲时间,再减去期望时间。通过滞后时间可以判断当前frame是否已经滞后。

                           

具体streamsystemduration通过clreflast来计算。

int input_clock_GetState( input_clock_t *cl,

                          mtime_t *pi_stream_start,mtime_t *pi_system_start,

                          mtime_t *pi_stream_duration,mtime_t *pi_system_duration )

{

    vlc_mutex_lock( &cl->lock );

    if( !cl->b_has_reference )

    {

        vlc_mutex_unlock( &cl->lock );

        return VLC_EGENERIC;

    }

    *pi_stream_start = cl->ref.i_stream;

    *pi_system_start = cl->ref.i_system;

    *pi_stream_duration = cl->last.i_stream -cl->ref.i_stream;

    *pi_system_duration = cl->last.i_system -cl->ref.i_system;

    vlc_mutex_unlock( &cl->lock );

    return VLC_SUCCESS;

}

render

network-caching参数主要用于修改pts

/*PTS delay: request from demux first. This is required for

         * access_demux and some special caseslike SDP demux. Otherwise,

         * fallback to access */

        if( demux_Control( in->p_demux,DEMUX_GET_PTS_DELAY,

                           &in->i_pts_delay ) )

Ts流的pts一般是以90khz为单位,计算时间戳时使用i_pcr *100 / 9,得到单位是us。

cl->last = clock_point_Create( i_ck_stream, i_ck_system );

调用clock_point_Create用于更新参考时钟的cl->last.i_streamcl->last.i_system

Clock referenceaverage counter

i_cr_average = var_GetInteger(p_input, "cr-average" );一般等于40

#define CLOCK_FREQINT64_C(1000000)

#define DEFAULT_PTS_DELAY              (3*CLOCK_FREQ/10)

当设置network-caching=1000时,i_cr_average = 133

const inti_cr_average = var_GetInteger( p_input, "cr-average" ) * i_pts_delay / DEFAULT_PTS_DELAY;

es_out_SetJitter( p_input->p->p_es_out,i_pts_delay, 0, i_cr_average );

 

streamclock convert to system clock

ClockStreamToSystem ( cl, *pi_ts0 + AvgGet( &cl->drift ) );

然后加上delay时间得到最终的时间戳。

返回的时间单位为us

 

About packetizer_Packetize

 

 

猜你喜欢

转载自blog.csdn.net/cys861214/article/details/72654207