VLC主要流程

Posted 白嫩豆腐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VLC主要流程相关的知识,希望对你有一定的参考价值。

VLC

vlc工作主要分为三个部分,

  1. input 线程读取帧数据
  2. DecoderThread 解压缩input读取的数据
  3. 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主要流程的主要内容,如果未能解决你的问题,请参考以下文章

VLC输出流程简介

VLC输出流程简介

来自两个视频的FFMPEG mux视频和音频

vlc播放流程分析

vlc源码分析 播放流程

Monster Audio 使用教程 发送音轨的设置