• 嵌入式 vlc从接收到数据流到播放视频的过程分析(经典)


    个人整理:

    Vlc流播放流程

     vlc源码目录树:

    目录名称

    说明

    bindings

    Java, CIL 和Python绑定

    doc

    帮助文档 (不是更新的)

    extras

    另叙。

    include

    VLC 头文件

    libs

    SRTP库和装载库

    lxdialog

    制作 menuconfig的文件

    m4

    Automake和autoconf的宏文件

    modules

    除了src目录外最重要的目录。参考“功能模块目录树”一节

    po

    i18n (语言翻译)文件

    projects

    建立在 libvlc的项目,如Mozilla插件,ActiveX 插件和MacOS X Framework

    share

    图标,脚本等等

    src

    除了功能模块以外最重要的目录。

    test

    一些脚本或测试代码

    extras 的内容

    extras/analyser

    一些代码风格编辑器 (vim,emacs)的宏和一些valgrindsuppressions

    extras/buildsystem

    可选的编译系统

    extras/contrib

    需要的库文件 (包括Makefiles自动下载和编译(或交叉编译),补丁)。

    extras/deprecated

    deprecated 文件

    extras/misc

    未分类文件

    extras/package

    用于软件发布的文件如ipkg,不同的 rpm 规范文件,win32和Mac OS X安装文件。

     

     

     

    功能模块目录树


    目录名称

    子目录

    说明

    access


    通过网络获取视频流的协议(http,ftp,fake,tcp,udp等),获取物理媒体介质的媒体内容如cd,dvd。


    cdda

    读取CD音频的输入模块


    dshow

    DirectShow获取插件,用于WINDOWS平台下的编码卡。


    dvb

    使用V4L2API的输入模块,用于DVB-S/C/T媒体流。


    mms

    基于TCP,UDP的MMS和HTTP获取模块


    rtsp



    screen

    获取屏幕图像的输入模块。


    vcd

    获取VCD数据的输入模块。


    vcdx

    获取VCD输入模块,可以导航,静止




    access-filter


    包含下面的滤波器:timeshift, record, dump




    access-output






    audio-filter


    各种音频滤波器如解码,均衡,转换。


    channel-mixer

    各种混合器,解码器如 Dolby解码器


    converter

    定点或浮点音频格式转换如 AC/3,MPEG I-II 音频层1,2, 3 解码


    resampler

    各种音频重采样模块




    audio-mixer


    混合器插件




    audio-output


    音频输出插件如ALSA,OSS和 DirectX音频




    codec


    各种编解码,特别是ffmpeg


    cmml

    持续媒体标记语言,脚本/超链接解释器


    dmo

    一个DirectMediaObject解码器,利用DirectMedia对WMV3视频解码


    ffmpeg

    ffmpeg 库的视频解码器


    spudec

    RLE DVD 小标题解码


    xvmc

    XVMC视频输出和解码




    control


    控制播放器的各种接口:手势, 热键,lirc,远程控制和telnet


    http

    HTTP远程控制




    demux


    不同的解复用程序


    asf

    ASF 解复器


    avi

    AVI文件流解复器


    mp4

    MP4文件输入模块


    mpeg



    playlist

    播放清单导入模块




    gui


    不同平台的用户界面和 ncurses接口


    beos

    用于BeOS的音频输出,视频输出和用户界面输出。


    macosx

    Mac OS X 视频输出和用户界面模块


    pda

    iPaq用户接口,使用Gtk2+widget集.


    qnx

    QNX RTOS 插件


    qt4

    使用Qt4库交叉编译的用户界面模块。该模块是默认的界面库


    skins2

    换夫模块。


    wince

    Pocket PC 接口


    wxwidgets

    使用wxWindows库跨平台的接口。作为默认的接口的VLC版本是0.86a.




    meta-engine






    misc




    dummy

    哑 (没有GUI)音频输出,视频输出,用户接口和输入模块。


    memcpy

    内存快拷贝模块


    notify

    通知,使用libnotify


    playlist



    probe



    testsuite



    xml

    LibXML 和 xtagxml 解析




    mux

    Various Muxers



    mpeg



    rtp


    packetizer


    打包模块,用于H264/AVC和MPEG 4音视频流。




    services-discovery






    stream-out




    transrate





    video-chroma


    图像格式转换,如 YUV到 RGB




    video-filter


    各种视频滤波模块如Deinterlace,Transform, Wall, Crop, Panoramix 等等。




    video-output




    directx

    WINDOWS视频输出模块,使用Direct3D和Direct X API,OpenGL


    qte

    QT嵌入式视频输出模块


    x11

    X11 API视频输出模块




    visualization


    多种可视化模块,包括goom


    galaktos

    输出到 OpenGL的可视化模块


    visual

    可视化系统

    vlc核心的是libvlc,它提供界面,应用处理功能,所有的libvlc的源代码都放在src目录及其子目录

       ./config/:  从命令行和配置文件中加载配置

      ./control/: 提供动作控制功能,如播放等操作

     ./extras/:   大多是平台的特殊代码

     ./modules/: 模块管理

    ./network/:  提供网络接口(socket管理,网络接口)

     ./osd/:        显示屏幕上的操作

     ./test/:        libvlc测试模块

     ./text/:        字符集

     ./interface/: 提供代码中可以调用的接口,如按键后的硬件作出反应

     ./playlist/:   管理播放功能

     ./input/:     建立并读取一个输入流,并且分离其中的音频和视频,然后把分离好的音频和视频流发给解码器

     ./audio_output/: 初始化音频混合器,即设置正确的同步频率,并对从解码器传来的音频流重新取样

     ./video_output/: 初始化视频播放器,把从解码器得到视频画面转化格式从yuv到rgb,然后播放

     ./stream_output/ 输出音频流和视频流到网络

     ./misc/:            libvlc使用的其他部分功能,如线程系统,消息队列等.

     

    一、首先介绍一下vlc启动动态加载模块的过程

     

    1. 最先程序段入口是文件Vlc.c(./bin/)中的main()函数完成的Functions(parse command line, start interface and spawn threads),在main中程序会调用libvlc_new函数(./lib/Core.c)接口,实现创建一个VLC运行实例libvlc_instance_t,该实例在程序运行过程中唯一。

    2. 在libvlc_new函数接口中,调用了libvlc_InternalInit()函数实现具体的初始化工作。

    3. libvlc_InternalInit(./src/Libvlc.c) 函数中,首先通过system_Init()函数完成传入参数对系统的相关初始化,接着通过module_InitBank ()(./src/modules/Bank.c)函数初始化module_bank结构体,并创建了main模块,然后(不支持动态载入的时候则通过 module_LoadBuiltins载入静态模块)通过module_LoadPlugins(./src/modules/Bank.c)函数载入 动态模块,通过 module_need(./src/modules/Modules.c)函数载入并激活memcpy模块,通过playlist_Create(. /src/playlist/playlist.c)函数,创建了一个playlist播放管理的线程,其线程处理函数为RunThread(./src /stream_out/sap.c),通过intf_Create(./src/interface/Interface.c)函数添加并激活 hotkeys模块,最后根据系统设置定义了宏HAVE_X11_XLIB_H,因此还需要添加screensaver模块。

    4. 此时加载的模块有main,hotkeys,screensaver,memcpy;多创建了一个线程,用于管理playlist,该线程无限循环,直到p_playlist->b_die状态为止。

    5. 其次程序中创建VLM对象,该接口调用的是vlm_New(./src/input/Vlm.c)函数,实现VLM对象的创建,函数返回值是指向vlm_t的指针。

    6. vlm_New 函数中,创建了一个vlm管理线程,线程处理函数为Manage(./modueles/video_output/msw/Glwin32.c)。该函 数循环处理当前各种媒体(vod、 broadcast、schedule)的播放实例,控制其每个播放细节(如:从一个input切换到下一个input;schedule周期循环调度 等)。与playlist线程不同的是,Manage主要针对播放实例的操作,而RunThread主要针对播放列表的管理,也就是说VLC管理是分级 的,播放列表级和播放列表中媒体播放实例级。

    7. 其次程序载入播放节目单,该接口调用的是ExecuteLoad(./src/input/Vlmshell.c)函数,在该函数中,依次调用如下函数:stream_UrlNew、stream_Seek、stream_Read、Load。

    8. 接着程序调用libvlc_vlm_play_media(./lib/Vlm.c)将节目流发布出去,实质是调用 ExecuteCommand(./src/input/Vlmshell.c),完成对命令的执行,根据命令类型,由 ExecuteControl(./src/input/Vlmshell.c)函数处理。

    9. 然后由vlm_ControlMediaInstanceStart(./src/input/Vlm.c)函数完成播放实例的初始化,并调用input_CreateAndStart(./src/input/input.c)函数,input_CreateAndStart实际调用的是input_Create和input_Start(./src/input/input.c),在input_Start函数中实际调用vlc_clone最终完成播放线程的,线程的处理函数为 Run(./src/input/input.c)。

    10. Run线程是整个VLC作为流媒体服务器的核心。其主要分为如下几个步骤:Init、MainLoop和End。其中MainLoop是一个无限循环,是完成流媒体的整个发布过程。

    二、分别介绍获取、转化、播放

     

    Rtsp协议获取rtp数据包:

    1.      调用用函数rtsp_connect(./modules/access/rtsp/Rtsp.c)向服务器发出rtsp请求,然后函数rtsp_get_answers将会处理rtsp服务器反馈回来的信息,如果建立成功,则进入下一步。

    2.      然后进行建立rtsp交互,依次调用的函数 是:rtsp_request_optionsàrtsp_request_describeàrtsp_request_setupàrtsp_request_setparameteràrtsp_request_playàrtsp_request_tearoff, 完成建立交互和关闭交互。

    3.      详细的是在成功建立之后然后调用的是rtsp_read_data(./modules/access/rtsp/Rtsp.c)函数进行获取不透明的rtp数据实际填充的rtsp_client_t结构体最终实现完成数据的获取。

    Rtp数据包的转换:

    1.      获取rtp数据之后进行的转换就是yuv格式到rgb格式,使用的文件是    i420_rgb.c(./modules/video_chroma/i420_rgb.c)来是完成视频格式的转换。

    2.      首先要对rtp数据流进行解码,调用的函数是Rtp.c(./modules/access/rtp/Rtp.c)对rtp数据流进行demux,实际首 先调用rtp_autodetect(./modules/access/rtp/Rtp.c)去探测rtp数据包,然后调用函数 codec_decode(./modules/access/rtp/Rtp.c)把rtp数据包发送到decoder线程进行解码。

    3.      在codec_decode函数中实际调用的接 口是es_out_Control(./include/Vlc_es_out.h)和es_out_Send(./include /Vlc_es_out.h)来完成传送数据包到解码器,然后进入Decode.c(./src/input /Decodec.c)DecodeCreate等函数接口进行流解码。

    rgb数据的播放:

    1.      在进行图像格式的转换成rgb格式之后由vout_new_buffer(./src/input/Decodec.c)接口实现由解码器送到显示器模 块,在显示器通过vout_Request(./src/video_output/video_output.c)接口去获取解码之后的rgb格式的图 片或者子图片。

    2.      在vout_Request(./src/video_output/video_output.c)接口中如果vout原来存在的话就会进行尝试重使 用,通过spu_Attach(./src/video_output/vout_subpictures.c)函数接口进行流单元的附属操作,完成再使 用vout。

    3.      如果vout不存在的,则转向VoutCreate(./src/video_output/video_output.c)函数接口进行创建vout, 在该函数接口调用spu_Create(./include/Vlc_spu.h)进行流单元的创建,最终完成vout的创建,并创建处理线程 Thread。

    4.      处理线程Thread(./src/video_output/video_output.c)来实际调用ThreadDisplaySubpicture以及结合其他控制函数接口来完成流的控制和播放。

     

     

    参考资料:vlc官网:http://wiki.videolan.org/Developers_Corner

    从接收到数据流到播放视频的过程分析

    从网络接收到流->对数据流进行视频和音频分离->对视频用解码器解码->显示解码后的视频流

    视频显示部分走势线:分离->解码->新的VOUT缓冲区->VOUT线程

    Demux(modulesdemuxmpegps.c)->DemuxPs(modulesdemuxmpegsystem.c)-> ParsePS->input_SelectES(srcinputinput_programs.c)->input_RunDecoder(srcinputinput_dec.c)->CreateDecoder->

    vout_new_buffer->vout_Request(srcvideo_outputvideo_output.c)->vout_Create->RunThread->vout_RenderPicture(srcvideo_outputvout_pictures.c)->pf_display

    注意:p_dec->pf_vout_buffer_new = vout_new_buffer的pf_vout_buffer_new在ffmpeg_NewPictBuf(modulescodecffmpegvideo.c)函数中激活

    解码部分走势线:

    Demux(modulesdemuxmpegps.c)->DemuxPs(modulesdemuxmpegsystem.c)-> ParsePS->input_SelectES(srcinputinput_programs.c)->input_RunDecoder(srcinputinput_dec.c)->CreateDecoder->DecoderThread

    注意:在解码线程中对数据流(AUDIO 或者VIDEO)进行解码

    详细资料 http://developers.videolan.org/vlc/    VLC API documentation  或者VLC developer documentation

    Chapter 5.  The video output layer Data structures and main loop

    Important data structures are defined in include/video.h and include/video_output.h. The main data structure is picture_t, which describes everything a video decoder thread needs. Please refer to this file for more information. Typically, p_data will be a pointer to YUV planar picture.

    Note also the subpicture_t structure. In fact the VLC SPU decoder only parses the SPU header, and converts the SPU graphical data to an internal format which can be rendered much faster. So a part of the "real" SPU decoder lies in src/video_output/video_spu.c.

    The vout_thread_t structure is much more complex, but you needn't understand everything. Basically the video output thread manages a heap of pictures and subpictures (5 by default). Every picture has a status (displayed, destroyed, empty...) and eventually a presentation time. The main job of the video output is an infinite loop to : [this is subject to change in the near future]

    • Find the next picture to display in the heap.

    • Find the current subpicture to display.

    • Render the picture (if the video output plug-in doesn't support YUV overlay). Rendering will call an optimized YUV plug-in, which will also do the scaling, add subtitles and an optional picture information field.

    • Sleep until the specified date.

    • Display the picture (plug-in function). For outputs which display RGB data, it is often accomplished with a buffer switching. p_vout->p_buffer is an array of two buffers where the YUV transform takes place, and p_vout->i_buffer_index indicates the currently displayed buffer.

    • Manage events.

    Methods used by video decoders

    The video output exports a bunch of functions so that decoders can send their decoded data. The most important function is vout_CreatePicture which allocates the picture buffer to the size indicated by the video decoder. It then just needs to feed (void *) p_picture->p_data with the decoded data, and call vout_DisplayPicture and vout_DatePicture upon necessary.

    • picture_t * vout_CreatePicture ( vout_thread_t *p_vout, int i_type, int i_width, int i_height ) : Returns an allocated picture buffer. i_type will be for instance YUV_420_PICTURE, and i_width and i_height are in pixels.

      Warning

      If no picture is available in the heap, vout_CreatePicture will return NULL.

    • vout_LinkPicture ( vout_thread_t *p_vout, picture_t *p_pic ) : Increases the refcount of the picture, so that it doesn't get accidently freed while the decoder still needs it. For instance, an I or P picture can still be needed after displaying to decode interleaved B pictures.

    • vout_UnlinkPicture ( vout_thread_t *p_vout, picture_t *p_pic ) : Decreases the refcount of the picture. An unlink must be done for every link previously made.

    • vout_DatePicture ( vout_thread_t *p_vout, picture_t *p_pic ) : Gives the picture a presentation date. You can start working on a picture before knowing precisely at what time it will be displayed. For instance to date an I or P picture, you must wait until you have decoded all previous B pictures (which are indeed placed after - decoding order != presentation order).

    • vout_DisplayPicture ( vout_thread_t *p_vout, picture_t *p_pic ) : Tells the video output that a picture has been completely decoded and is ready to be rendered. It can be called before or after vout_DatePicture.

    • vout_DestroyPicture ( vout_thread_t *p_vout, picture_t *p_pic ) : Marks the picture as empty (useful in case of a stream parsing error).

    • subpicture_t * vout_CreateSubPicture ( vout_thread_t *p_vout, int i_channel, int i_type ) : Returns an allocated subpicture buffer. i_channel is the ID of the subpicture channel, i_type is DVD_SUBPICTURE or TEXT_SUBPICTURE, i_size is the length in bytes of the packet.

    • vout_DisplaySubPicture ( vout_thread_t *p_vout, subpicture_t *p_subpic ) : Tells the video output that a subpicture has been completely decoded. It obsoletes the previous subpicture.

    • vout_DestroySubPicture ( vout_thread_t *p_vout, subpicture_t *p_subpic ) : Marks the subpicture as empty.

    • 来源:http://blog.sina.com.cn/s/blog_8795b0970101ew4n.html
  • 相关阅读:
    安卓开发之ListAdapter(二)
    两listview联动
    不要天真了,这些简历HR一看就知道你是培训的,质量不佳的那种
    天真!这简历一看就是包装过的
    一线城市为何难逃离,职场饭局正在“失宠”?
    腾讯架构师分享的Java程序员需要突破的技术要点
    百度最穷程序员现身,工作4年晒出存款后,网友:你是真穷!
    震惊微软!招程序员的流程居然...
    python基础认识(一)
    input修改placeholder文字颜色
  • 原文地址:https://www.cnblogs.com/sunminmin/p/4479893.html
Copyright © 2020-2023  润新知