VLC主要流程
Posted 白嫩豆腐
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VLC主要流程相关的知识,希望对你有一定的参考价值。
VLC
vlc工作主要分为三个部分,
- input 线程读取帧数据
- DecoderThread 解压缩input读取的数据
- video_output、audio_ouput 线程把数据输出
读取数据
读取数据主要包括三部分,核心是两部分,一个是access,主要是直接把输入比如http服务器或者ftp或者本地文件,主要把输入源抽象成如下的结构体:
struct stream_t
VLC_COMMON_MEMBERS
/* Module properties for stream filter */
module_t *p_module;
char *psz_name;
char *psz_url; /**< Full URL or MRL (can be NULL) */
const char *psz_location; /**< Location (URL with the scheme stripped) */
char *psz_filepath; /**< Local file path (if applicable) */
bool b_preparsing; /**< True if this access is used to preparse */
/* Stream source for stream filter */
stream_t *p_source;
/**
* Read data.
*
* Callback to read data from the stream into a caller-supplied buffer.
*
* This may be NULL if the stream is actually a directory rather than a
* byte stream, or if \\ref stream_t.pf_block is non-NULL.
*
* \\param buf buffer to read data into
* \\param len buffer length (in bytes)
*
* \\retval -1 no data available yet
* \\retval 0 end of stream (incl. fatal error)
* \\retval positive number of bytes read (no more than len)
*/
ssize_t (*pf_read)(stream_t *, void *buf, size_t len);
/**
* Read data block.
*
* Callback to read a block of data. The data is read into a block of
* memory allocated by the stream. For some streams, data can be read more
* efficiently in block of a certain size, and/or using a custom allocator
* for buffers. In such case, this callback should be provided instead of
* \\ref stream_t.pf_read; otherwise, this should be NULL.
*
* \\param eof storage space for end-of-stream flag [OUT]
* (*eof is always false when invoking pf_block(); pf_block() should set
* *eof to true if it detects the end of the stream)
*
* \\return a data block,
* NULL if no data available yet, on error and at end-of-stream
*/
block_t *(*pf_block)(stream_t *, bool *eof);
/**
* Read directory.
*
* Callback to fill an item node from a directory
* (see doc/browsing.txt for details).
*
* NULL if the stream is not a directory.
*/
int (*pf_readdir)(stream_t *, input_item_node_t *);
/**
* Seek.
*
* Callback to set the stream pointer (in bytes from start).
*
* May be NULL if seeking is not supported.
*/
int (*pf_seek)(stream_t *, uint64_t);
/**
* Stream control.
*
* Cannot be NULL.
*
* \\see stream_query_e
*/
int (*pf_control)(stream_t *, int i_query, va_list);
/**
* Private data pointer
*/
void *p_sys;
/* Weak link to parent input */
input_thread_t *p_input;
;
主要保存文件源的地址以及处理方法,比如本地文件,就保存fd.读取以及跳转的就保存fd的函数指针。p_sys保存fd
第二部分主要FIllter,非必要,这里不在介绍
第三部分主要是对封装文件的解析
多媒体文件的打包过程一般包括两部分内容,分别是压缩和封装,比如mp4就是一种封装方式,把不同编码(压缩)方式的音视频文件打包成一个文件(ie: h264\\h265).
mp4类似于html的树状文件,在不同的标签下保存不同的信息,比如track保存音轨或视频帧信息(每一帧的位置),
所有的解封装最终会抽象出一个结构体
struct demux_t
VLC_COMMON_MEMBERS
/* Module properties */
module_t *p_module;
/* eg informative but needed (we can have access+demux) */
char *psz_access;
char *psz_demux;
char *psz_location;
char *psz_file;
union
/**
* Input stream
*
* Depending on the module capability:
* - "demux": input byte stream (not NULL)
* - "access_demux": a NULL pointer
* - "demux_filter": undefined
*/
stream_t *s;
/**
* Input demuxer
*
* If the module capability is "demux_filter", this is the upstream
* demuxer or demux filter. Otherwise, this is undefined.
*/
demux_t *p_next;
;
/* es output */
es_out_t *out; /* our p_es_out */
bool b_preparsing; /* True if the demux is used to preparse */
/* set by demuxer */
int (*pf_demux) ( demux_t * ); /* demux one frame only */
int (*pf_control)( demux_t *, int i_query, va_list args);
/* Demux has to maintain them uptodate
* when it is responsible of seekpoint/title */
struct
unsigned int i_update; /* Demux sets them on change,
Input removes them once take into account*/
/* Seekpoint/Title at demux level */
int i_title; /* idem, start from 0 (could be menu) */
int i_seekpoint; /* idem, start from 0 */
info;
demux_sys_t *p_sys;
/* Weak link to parent input */
input_thread_t *p_input;
;
pf_demux这个方法指针对于不同的解封装器,提供不同的方法,主要是通过stream进行解封装,得到视频帧信息,或者音频采样信息,通过es_out_t传给DecoderThread的队列中。
解码
解码是在解码线程初始化后得到一个解码器的抽象结构体
truct decoder_t
VLC_COMMON_MEMBERS
/* Module properties */
module_t * p_module;
decoder_sys_t * p_sys;
/* Input format ie from demuxer (XXX: a lot of field could be invalid) */
es_format_t fmt_in;
/* Output format of decoder/packetizer */
es_format_t fmt_out;
/* Tell the decoder if it is allowed to drop frames */
bool b_frame_drop_allowed;
# define VLCDEC_SUCCESS VLC_SUCCESS
# define VLCDEC_ECRITICAL VLC_EGENERIC
# define VLCDEC_RELOAD (-100)
/* This function is called to decode one packetized block.
*
* The module implementation will own the input block (p_block) and should
* process and release it. Depending of the decoder type, the module should
* send output frames/blocks via decoder_QueueVideo(), decoder_QueueAudio()
* or decoder_QueueSub().
*
* If p_block is NULL, the decoder asks the module to drain itself. The
* module should return all available output frames/block via the queue
* functions.
*
* Return values can be:
* VLCDEC_SUCCESS: pf_decode will be called again
* VLCDEC_ECRITICAL: in case of critical error, pf_decode won't be called
* again.
* VLCDEC_RELOAD: Request that the decoder should be reloaded. The current
* module will be unloaded. Reloading a module may cause a loss of frames.
* When returning this status, the implementation shouldn't release or
* modify the p_block in argument (The same p_block will be feed to the
* next decoder module).
*/
int ( * pf_decode ) ( decoder_t *, block_t *p_block );
/* This function is called in a loop with the same pp_block argument until
* it returns NULL. This allows a module implementation to return more than
* one output blocks for one input block.
*
* pp_block or *pp_block can be NULL.
*
* If pp_block and *pp_block are not NULL, the module implementation will
* own the input block (*pp_block) and should process and release it. The
* module can also process a part of the block. In that case, it should
* modify (*pp_block)->p_buffer/i_buffer accordingly and return a valid
* output block. The module can also set *pp_block to NULL when the input
* block is consumed.
*
* If pp_block is not NULL but *pp_block is NULL, a previous call of the pf
* function has set the *pp_block to NULL. Here, the module can return new
* output block for the same, already processed, input block (the
* pf_packetize function will be called as long as the module return an
* output block).
*
* When the pf function returns NULL, the next call to this function will
* have a new a valid pp_block (if the packetizer is not drained).
*
* If pp_block is NULL, the packetizer asks the module to drain itself. In
* that case, the module has to return all output frames available (the
* pf_packetize function will be called as long as the module return an
* output block).
*/
block_t * ( * pf_packetize )( decoder_t *, block_t **pp_block );
/* */
void ( * pf_flush ) ( decoder_t * );
/* Closed Caption (CEA 608/708) extraction.
* If set, it *may* be called after pf_packetize returned data. It should
* return CC for the pictures returned by the last pf_packetize call only,
* channel bitmaps will be used to known which cc channel are present (but
* globaly, not necessary for the current packet. Video decoders should use
* the decoder_QueueCc() function to pass closed captions. */
block_t * ( * pf_get_cc ) ( decoder_t *, decoder_cc_desc_t * );
/* Meta data at codec level
* The decoder owner set it back to NULL once it has retreived what it needs.
* The decoder owner is responsible of its release except when you overwrite it.
*/
vlc_meta_t *p_description;
/*
* Owner fields
* XXX You MUST not use them directly.
*/
/* Video output callbacks
* XXX use decoder_NewPicture */
int (*pf_vout_format_update)( decoder_t * );
picture_t *(*pf_vout_buffer_new)( decoder_t * );
/**
* Number of extra (ie in addition to the DPB) picture buffers
* needed for decoding.
*/
int i_extra_picture_buffers;
/* Audio output callbacks */
int (*pf_aout_format_update)( decoder_t * );
/* SPU output callbacks
* XXX use decoder_NewSubpicture */
subpicture_t *(*pf_spu_buffer_new)( decoder_t *, const subpicture_updater_t * );
/* Input attachments
* XXX use decoder_GetInputAttachments */
int (*pf_get_attachments)( decoder_t *p_dec, input_attachment_t ***ppp_attachment, int *pi_attachment );
/* Display date
* XXX use decoder_GetDisplayDate */
mtime_t (*pf_get_display_date)( decoder_t *, mtime_t );
/* Display rate
* XXX use decoder_GetDisplayRate */
int (*pf_get_display_rate)( decoder_t * );
/* XXX use decoder_QueueVideo or decoder_QueueVideoWithCc */
int (*pf_queue_video)( decoder_t *, picture_t * );
/* XXX use decoder_QueueAudio */
int (*pf_queue_audio)( decoder_t *, block_t * );
/* XXX use decoder_QueueCC */
int (*pf_queue_cc)( decoder_t *, block_t *, const decoder_cc_desc_t * );
/* XXX use decoder_QueueSub */
int (*pf_queue_sub)( decoder_t *, subpicture_t *);
void *p_queue_ctx;
/* Private structure for the owner of the decoder */
decoder_owner_sys_t *p_owner;
;
pf_decode保存不同编码格式的解码方法,我们大部分视频格式都通过mediacodec_ndk这个module来处理的,核心是通过mediacodec实现解码工作的,具体流程这里不在详细介绍。
在写出数据时候,回开启一个线程,通过vout_PutPicture把解析后的帧数据写入到队列中,最终通过video_output线程吧数据渲染到屏幕上
渲染
syms.AMediaCodec.releaseOutputBuffer
syms.AMediaCodec.configure(
以上是关于VLC主要流程的主要内容,如果未能解决你的问题,请参考以下文章