VLC学习文档(载)

一 videolan-howto-en-html

该文档完全描述了VideoLAN "流"的解决方法.

VideoLAN 项目包括两个软件.

1) VLC:以前是视频流接收的客户端,但是现在也可以作为服务端工作.

2) VLS:视频服务端,能发送 MPEG-1, MPEG-2 and MPEG-4 files, DVDs, digital satellite channels, digital terrestial television channels and live videos on the network in unicast or multicast.

1.VLC 在REDHAT 下的安装

从下面的链接中下载 vlc的包和包所需要的库,把他们都放在同一个目录.

http://www.videolan.org/vlc/download-redhat.html

源代码安装:

源代码安装需要的库如下:

libdvbpsi (compulsory) ,

mpeg2dec (compulsory) ,

libdvdcss if you want to be able to read encrypted DVDs ,

libdvdplay if you want to have DVD menu navigation ,

a52dec if you want to be able to decode the AC3 (i.e. A52) sound format often used in DVDs ,

ffmpeg, libmad, faad2 if you want to read MPEG 4 / DivX files ,

libogg & libvorbis if you want to read Ogg Vorbis files .

2.VLC在命令行下接收流

Receive an unicast stream

% vlc -vvv udp:

Receive a multicast stream

% vlc -vvv udp:@239.255.12.42

where 239.255.12.42 is the multicast IP address you want to join.

Receive an HTTP/FTP/MMS stream

Use one of the following command lines:

% vlc -vvv http://example/stream.xyz

where http://example/stream.xyz is the HTTP address of the stream;

% vlc -vvv ftp://example/stream.xyz

where ftp://example/stream.xyz is the FTP address of the stream;

% vlc -vvv ms://viptvr.yacast.fr/encoderfranceinfo

where mms://viptvr.yacast.fr/encoderfranceinfo is the MMS address of the stream.

Receive a RTP stream available through RTSP

% vlc -vvv rtsp://www.hardradio.com/tonbeme.mov

where rtsp://www.hardradio.com/tonbeme.mov is the address of the stream.

Receive a stream described by an SDP file

% vlc -vvv http://server.example.org/stream.sdp

3.VLC在命令行下发送流

% vlc -vvv video1.xyz --sout udp:192.168.0.42 --ttl 12

where:

*video1.xyz is the file you want to stream,

*192.168.0.42 is either:

o the IP address of the machine you want to unicast to;

o or the DNS name the machine you want to unicast to;

o or a multicast IP address.

*12 is the value of the TTL (Time To Live) of your IP packets (which means that the stream will be able to cross 11 routers).

If you want to stream the file continuously, add the --loop option.

4.VLC 高级应用(VLC's stream output (transcoding, multiple streaming, etc...))

语法: Please refer to the" command line interface" chapter of the "VLC user guide "to learn the syntax of VLC's stream output.

例子:

----编码方面的例子

Transcode the input stream and send it to a multicast IP address with the associated SAP announce:

% vlc -vvv input_stream --sout '#transcode{vcodec=mp4v,acodec=mpga,vb=800,ab=128,deinterlace}:

standard{access=udp,mux=ts,url=239.255.12.42,sap,name="TestStream"}'

Display the input stream, transcode it and send it to a multicast IP address with the associated SAP announce:

% vlc -vvv input_stream --sout '#duplicate{dst=display,dst=

"transcode{vcodec=mp4v,acodec=mpga,vb=800,ab=128,deinterlace}:

standard{access=udp,mux=ts,url=239.255.12.42,sap,name="TestStream"}"}'

Transcode the input stream, display the transcoded stream and send it to a multicast IP address with the associated SAP announce:

% vlc -vvv input_stream --sout '#transcode{vcodec=mp4v,acodec=mpga,vb=800,ab=128,deinterlace}:

duplicate{dst=display,dst=standard{access=udp,mux=ts,url=239.255.12.42,sap,name="TestStream"}}'

--多种流的例子

Send a stream to a multicast IP address and a unicast IP address:

% vlc -vvv input_stream --sout '#duplicate{dst=

standard{access=udp,mux=ts,url=239.255.12.42,sap,name="TestStream"},

dst=standard{access=udp,mux=ts,url=192.168.1.2}}'

Display the stream and send it to two unicast IP addresses:

% vlc -vvv input_stream --sout '#duplicate{dst=display,dst=

standard{access=udp,mux=ts,url=192.168.1.12},

dst=standard{access=udp,mux=ts,url=192.168.1.42}}'

Send parts of a multiple program input stream:

% vlc -vvv multiple_program_input_stream

--sout '#duplicate{dst=standard{access=udp,mux=ts,url=239.255.12.42},select="program=12345",

dst=standard{access=udp,mux=ts,url=239.255.12.43}, select="video,program=1234-2345"}'

This command sends the program of the input stream which id is 12345 to 239.255.12.42 and all video programs with id between 1234 and 2345 to 239.255.12.43.

Transcoding and multiple streaming

Transcode the input stream, display the transcoded stream and send it to a multicast IP address with the associated SAP announce and an unicast IP address:

% vlc -vvv input_stream --sout '#transcode{vcodec=mp4v,acodec=mpga,vb=800,ab=128,deinterlace}:

duplicate{dst=display,dst=standard{access=udp,mux=ts,url=239.255.12.42,sap,name="TestStream"},

dst=standard{access=udp,mux=ts,url=192.168.1.2}}'

Display the input stream, transcode it and send it to two unicast IP addresses:

% vlc -vvv input_stream --sout '#duplicate{dst=display,

dst="transcode{vcodec=mp4v,acodec=mpga,vb=800,ab=128}:

duplicate{dst=standard{access=udp,mux=ts,url=192.168.1.2},

dst=standard{access=udp,mux=ts,url=192.168.1.12}"}'

Send the input stream to a multicast IP address and the transcoded stream to another multicast IP address with the associated SAP announces:

% vlc -vvv input_stream --sout '#duplicate{dst=

standard{access=udp,mux=ts,url=239.255.1.2,sap,name="OriginalStream"},

dst="transcode{vcodec=mp4v,acodec=mpga,vb=800,ab=128}:

standard{access=udp,mux=ts,url=239.255.1.3,sap,name="TranscodedStream"}"}'

 二、二进制包安装及使用

1.在RH9上的安装需要

     1).RH9的升级包.

     2).FC2的RPM包

    详细说明清参见:http://www.videolan.org/vlc/download-redhat.html

    以上VLC 版本为:0.7.2

2.下载RH9的升级包

    http://download.videolan.org/pub/videolan/vlc/0.7.2/rpm/redhat/rh9/

3.下载FC2的RPM包

  http://download.videolan.org/pub/videolan/vlc/0.7.2/rpm/fedora/fc2/

   二进制包为:  vlc-binary.tar.gz

4.将RH9的升级包和 vlc-binary.tar.gz放在同一个目录.

   ~#tar -zxvf   vlc-binary.tar.gz

   ~#tar -zxvf   redhat9-updates.tar.gz

 5.安装

   ~#rpm -Uv  vlc/* --force --nodeps

6.使用

    1) 在REDHAT->AUDIO AND VIDEO->VLAN MEDIA PLAYER 可以打开

     2)或者在BASH 中打开vlc,使用命令行选项直接启动,参见videolan-how-to-en.

7.未测试出的功能

      在局域网内的同一网段内的两台PC上不能用MULTICAST 进行VIDEO

      传输.

三、 VLC及其他播放器

一.rm格式的播放器:

  下载地址:http://www.real.com/linux/?src=020923home_cn_cn

  安装方式:~#./realplayer.bin

        打开方式:

     命令行:~#realplay

                    GUI:redhat->audio and video->other app->realplayer  

二.mp3 播放器:xmms-1.2.8.tar.gz

      安装方式:./configure & make &make install

三. 经验:从源码编译安装Mplayer 1.0pre5

 来自:http://yangchengkai.blogchina.com/blog/refer.177855.html

  

  Mplayer/gmplayer是目前Linux下广范使用的媒体播放器,一个字--强!但由于它一般以Tarball的格式发布,安装比较BT,许多朋友都在找rpm的版本,但来源不同的rpm版本往往无法自己定制许多特性,比如中文支持等,而且容易造成rpm包的依赖问题,所以有不少朋友最终对 Mplayer又爱又恨...-_-!!

其实自己编译mplayer并不是什么太难的事,只是过程比较麻烦,但基本还是遵循tarball的安装步骤,有关这个的文章Sir里已经有了不少,自己这篇就不打算往Sir里贴了,且留在这里和大家分享...:)

首先是下载最新的mplayer的tarball,即1.0pre5:

http://www4.mplayerhq.hu/homepage/design7/dload.html

接下来是下载解码器包,一般只要下载Essential Codes就足够了,要放rmvb需要reallib的解码器,我一般用xine放rmvb:

http://www4.mplayerhq.hu/homepage/design7/codecs.html

还有mplayer的字体文件:

http://www4.mplayerhq.hu/homepage/design7/dload.html

这里大家不用到"其他字体"里下载中文字体,待会可以用simsun.ttf替代.

当然,还要下载Skin文件给gmplayer用:

http://ftp5.mplayerhq.hu/mplayer/Skin/

建议用default blue或者neutron,当然,你也可以下载其他的Skin.

我们先把下载的所有文件cp到/opt/目录下,然后开始具体安装步骤.

1.首先安装解码器:

tar -jxvf essential-20040916.tar.bz2

tar -jxvf rp9codecs-20040626.tar.bz2

cp -rf rp9codecs-20040626/* essential-20040916/

mv essential-20040916 /usr/lib/codes

以上命令把解码器包安装到了/usr/lib/codes,其实就是把解压后的目录ren&mv了过去.

2.编译安装mplayer:

tar -jxvf MPlayer-1.0pre5.tar.bz2

cd MPlayer-1.0pre5

./configure --enable-gui --with-codecsdir=/usr/lib/codecs --with-win32libdir=/usr/lib/codecs --with-reallibdir=/usr/lib/codecs --language=zh_CN

以上几个参数解释一下:

--enable-gui:打开图形界面支持,就是gmplayer

--with-codecsdir=/usr/lib/codecs:指明解码器的目录

--with-win32libdir=/usr/lib/codecs:指明windows的媒体文件解码器目录位置

--with-reallibdir=/usr/lib/codecs:指明real媒体文件的解码器目录位置,要用gmplayer放rmvb必须指定这条.

--language=zh_CN:设定系统界面语言为中文

在configure之前可以运行./configure --help查看支持的特性设定,可以根据自己需求选择,以上只是最基本的啦.

make

make install

3.安装字体文件:

tar -jxvf font-arial-iso-8859-1.tar.bz2

mv font-arial-iso-8859-1/ /usr/local/share/mplayer/font/

cd /usr/local/share/mplayer/font/

如果你的系统用simsun美化过,则直接

ln -s ***/simsun.ttf subfont.ttf

注意,这里的***是指simsun的具体位置,为了保险起见,建议在~/.mplayer/里也做同样的链接.

要是系统没有美化过,试试

ln -s /usr/share/fonts/zh_CN/TrueType/gbsn001p.ttf subfont.ttf

这样中文字幕就搞定了.

4.安装Skin:

超级简单,把skin包解压后mv到/usr/local/share/mplayer/Skin就可以了,注意一定要有一个skin叫做default,不然gmplayer无法运行.

OK,目前为止所有工作结束,运行gmplayer/mplayer看看,Enjoy it!:)

PS:要是你用xine,在setup里可以把codes的目录指定同mplayer一样,这样可以节省点空间^_^

5.nvidia driver 驱动安装:

   下载:http://www.nvidia.com/object/linux_display_ia32_1.0-4363.html

    安装:

              进入LEVEL 2  ,init 2

   配置: 在/etc/X11/XF86config

           load 'nv'  改成 load 'nvidia'

           load 'dri' 改成 load 'GLcore'

 在文字模式下:

#vim /etc/X11/XF86Config

找到Driver "nv",改为“nvidia”

去除 Load "dri"

Load "GLcore"

保存后退出,再进入X桌面

看到NVIDIA画面就OK了

  四、在EMACS中使用GDB调试

一 .EMACS 中调试

  1、using the clipboard

                M-x  menu-bar-enable-clipboard

        (make cut,copy,pasty menu items,use the clipboard)

  2、using “wheel”mice

              M-x   mouse-wheel-mode

         (激活中间的滚动键)

  3、退出出任何命令状态

         C-g

 

  4、进入编译模式

       M-x  compile 或者从菜单-》TOOLS-》COMPILE

  5、用COMPILE 模式

       C-x  `       (搜索出错的源代码行)

       <RET>    (光标定位在compile buffer 的出错提示行上,按〈RET〉键,会跳到出错的源代码行)

      C-u C-x ` 在compile buffer 列出同样的错误。

   6、用GREP 搜索

       一、M-x grep    进入搜索

              参数为 a grep-style regexp(using in single-quotes to quote the shell's special characters)follows bye file names;

       二、 C-x  `       (搜索出错的源代码行 --grep  搜索出来的同种错误)

         <RET>    (光标定位在grep  buffer 的出错提示行上,按〈RET〉键,会跳到出错的源代码行)

二、GUD 调试

   1、进入

        M-x gdb

   2、命令

        C-x <SPC>     在指针所在源代码行上设置断点

    说明 C-c 在GUD BUFFER,而C-x C-a 在gud buffer and source buffer 都行

    3、  C-c    C-l

            C-x C-a   C-l   到达最后一行

    4、C-c   C-s

          C-x C-a  C-s      gud-step

    5、C-c   C-n

          C-x C-a  C-n      gud-next

     6、C-c C-r

            C-x C-a  C-r  gud-cont  执行到下一个断点

      7、C-c  C-d

            C-x C-a  C-d   gud-remove 删除当前断点

三、GDB 命令

    1、调试命令

          step         next          continue          untile

     2、设置断点

           break file.c:foo

           break  file.c:11

           break +12

           break -12        如果执行到某一行,+表示往前,-表示向后

          断点信息

             info breakpoint

             enable <breakpoint number>

             disable  <breakpoint number>

            断点条件

              break <args> if <cond>

              condition <break number> <cond>

              delete  breakpoints <break number> 

             clear

    3、显示源代码

           list 使用同断点

    4、查看变量

          print /fmt  <expr>

     5、查看内存

          x /<fmt>  <addr>

     6、切换目录

             cd

     7、添加源文件路径

           dir <path>

     8、显示

           如果有    char msg[25];

                           int *arr=(int *)mollac(len*sizeof(int));

  

            则    display msg

                    display *arr@len

             或者  p msg

                       p  *arr@len

         9、跳转执行

             jump linespec

             jump  <addr>

四、Makefile 文件

//mt.h

#ifdef _cplusplus

extern "c" {

#endif

int add(int a,int b);

int substract(int num,int n,int *ret);

#ifdef _cplusplus

}

#endif

-----------------------------------------------

//math.c

#include"mt.h"

int add(int a,int b)

 {  return (a+b);}

int subtract(int num,int n,int *ret)

{*ret=num-n;

return *ret;

}

-----------------------------------------------

//msg.h

#ifdef _cplusplus

extern "c" {

#endif

void prnmsg(char *msg);

#ifdef _cplusplus

}

#endif

-----------------------------------------------

//msg.c

#include<stdio.h>

#include"msg.h"

void prnmsg(char * msg)

{  printf("%s\n",msg);}

-----------------------------------------------

//comm.h

#include"mt.h"

#include"msg.h"

-----------------------------------------------

//vlc.c

#include<stdlib.h>

#include<stdio.h>

#include"comm.h"

int main(int argc,char *argv[])

{

   int i,j,sum;

   int *p_iret;

 

  char  msg[256];

    printf("hellow,this is a test program\n");

   

    i=15;

    j=10;

    sum=add(i,j);

  

   sprintf(msg,"number=%d",sum);

    prnmsg(msg);

 

   subtract(i,j,p_iret);

   sprintf(msg,"substract=%d",*p_iret);

   prnmsg(msg);

   

   sprintf(msg,"this has modify=%d",*p_iret);

   prnmsg(msg);

   return 0;

}

-----------------------------------------------

//Makefile

vlc:vlc.o math.o msg.o

    gcc -g -o $@ vlc.o  math.o msg.o

math.o:math.c mt.h

    gcc -g -c -o $@ math.c

msg.o:msg.c msg.h

    gcc -g -c msg.c

vlc.o:vlc.c comm.h

    gcc -g -c  vlc.c

clean:

    rm -rvf msg.o math.o vlc.o vlc

 

vlc学习计划(5)--VLC程序宏及线程分析

第一部分             变量及宏定义

1.消息映射宏

                       vlc_module_begin();

                           …………………..

vlc_module_end();

2.结构中包含函数

       struct input_thread_t

{

    VLC_COMMON_MEMBERS

 

    /* Thread properties */

    vlc_bool_t              b_eof;

    vlc_bool_t              b_out_pace_control;

 

    /* Access module */

    module_t *       p_access;

    ssize_t       (* pf_read ) ( input_thread_t *, byte_t *, size_t );

    int           (* pf_set_program )( input_thread_t *, pgrm_descriptor_t * );

    int           (* pf_set_area )( input_thread_t *, input_area_t * );

    void          (* pf_seek ) ( input_thread_t *, off_t );

}

3.宏与换行符妙用

#define VLC_COMMON_MEMBERS                                                  \

/** \name VLC_COMMON_MEMBERS                                                \

 * these members are common for all vlc objects                             \

 */                                                                         \

/**@{*/                                                                     \

    int   i_object_id;                                                      \

    int   i_object_type;                                                    \

    char *psz_object_type;                                                  \

    char *psz_object_name;                                                  \

                                                                                               \

 /** Just a reminder so that people don't cast garbage */                \

    int be_sure_to_add_VLC_COMMON_MEMBERS_to_struct;                        \

/**@}*/                   

 

#define VLC_OBJECT( x ) \

((vlc_object_t *)(x))+

0*(x)->be_sure_to_add_VLC_COMMON_MEMBERS_to_struct

 

struct vlc_object_t

{

    VLC_COMMON_MEMBERS

};//定义一个结构来使用宏定义的公共成员

 

4.定义导出函数

#ifndef __PLUGIN__

#   define VLC_EXPORT( type, name, args ) type name args

#else

#   define VLC_EXPORT( type, name, args ) struct _u_n_u_s_e_d_

    extern module_symbols_t* p_symbols;

#endif

5.定义回调函数

 

typedef int ( * vlc_callback_t ) ( vlc_object_t *,      /* variable's object */

                                   char const *,            /* variable name */

                                   vlc_value_t,                 /* old value */

                                   vlc_value_t,                 /* new value */

 

                                   void * );                /* callback data */                                                

 

6.函数作为参数的定义方式

     Int Fun(int n,int (*pf)(int ,int),char *pstr)

{   int j =10;

pf(n,j);

}

 

7.回调函数的声明

必须声明为global,或者static

 

Int   vlc_callback_t (int ,int)

{。。。。。。。。。。。}

      

8.回调函数的使用

       Fun(0, vlc_callback_t,"test");

 

9.函数表达式

#define input_BuffersInit(a) __input_BuffersInit(VLC_OBJECT(a))

void * __input_BuffersInit( vlc_object_t * );

 

#define module_Need(a,b,c,d) __module_Need(VLC_OBJECT(a),b,c,d)

VLC_EXPORT( module_t *, __module_Need, ( vlc_object_t *, const char *, const char *, vlc_bool_t ) );

 

10.定义函数

   /* Dynamic array handling: realloc array, move data, increment position */

#define INSERT_ELEM( p_ar, i_oldsize, i_pos, elem )                           \

    do                                                                        \

    {                                                                         \

        if( i_oldsize )                                                       \

        {                                                                     \

            (p_ar) = realloc( p_ar, ((i_oldsize) + 1) * sizeof( *(p_ar) ) );  \

        }                                                                     \

        else                                                                  \

        {                                                                     \

            (p_ar) = malloc( ((i_oldsize) + 1) * sizeof( *(p_ar) ) );         \

        }                                                                     \

        if( (i_oldsize) - (i_pos) )                                           \

        {                                                                     \

            memmove( (p_ar) + (i_pos) + 1,                                    \

                     (p_ar) + (i_pos),                                        \

                     ((i_oldsize) - (i_pos)) * sizeof( *(p_ar) ) );           \

        }                                                                     \

        (p_ar)[i_pos] = elem;                                                 \

        (i_oldsize)++;                                                        \

    }                                                                         \

    while( 0 )

 

 

应用为:

     INSERT_ELEM( p_new->p_libvlc->pp_objects,

                     p_new->p_libvlc->i_objects,

                     p_new->p_libvlc->i_objects,

                     p_new );

 

 

11.改变地址的方式传递其值

stream_t *input_StreamNew( input_thread_t *p_input )

{    stream_t *s = vlc_object_create( p_input, sizeof( stream_t ) );

    input_stream_sys_t *p_sys;

    if( s )

    {

        s->p_sys = malloc( sizeof( input_stream_sys_t ) );

        p_sys = (input_stream_sys_t*)s->p_sys;

        p_sys->p_input = p_input;

    }

return s;//注解:s->p_sys改变了

}

 

                            第二部分  程序框架实现

1. 播放列表文件src/playlist/playlist.c的线程

playlist_t * __playlist_Create ( vlc_object_t *p_parent )函数中创建的线程,线程函数为

static void RunThread ( playlist_t *p_playlist )

   线程思路分析:

     在RunThread里面执行循环,如果没有任务执行,则适当的延迟,如果接到p_playlist->i_status != PLAYLIST_STOPPED的条件,则调用PlayItem( p_playlist )函数,在PlayItem( p_playlist )函数中从新创建输入线程。

 

通过void playlist_Command( playlist_t * p_playlist, playlist_command_t i_command,int i_arg )接收来自GUI界面的各种命令,然后设置p_playlist->i_status的状态,由该状态改变该播放列表文件主循环线程的执行。

 

2. 输入文件SRC/INPUT/INPUT.C的输入线程

    input_thread_t *__input_CreateThread( vlc_object_t *p_parent,

                                      input_item_t *p_item )函数中创建的线程,线程函数为

static int RunThread( input_thread_t *p_input )

   线程思路分析:

由 input_thread_t结构的成员分析是接收文件流还是网络流,如果是文件流,则调用file module 的读函数(pf_read)和打开函数(--).如果是network 则打开network   module 的打开函数和读函数(pf_read)。

    在 RunThread线程函数中接收数据和调用demux 或者decode etc处理。

一旦产生新的输入,则在播放列表线程中会首先结束该输入线程,然后从新创建新的输入线程。

 

3. 视频输出文件src/video_output/ video_output.c的线程

vout_thread_t * __vout_Create( vlc_object_t *p_parent,

                               unsigned int i_width, unsigned int i_height,

                               vlc_fourcc_t i_chroma, unsigned int i_aspect )函数中创建的线程,线程函数为

static void RunThread( vout_thread_t *p_vout)

线程思路分析:

     在RunThread里面执行循环,任务是显示视频。

 

4. 在modules\gui\wxwindows\wxwindows.cpp中的GUI线程

 static void Run( intf_thread_t *p_intf ) 函数中创建的线程,线程函数为

             static void Init( intf_thread_t *p_intf )

 

线程思路分析:

     在Init( intf_thread_t *p_intf )里面执行循环,创建新的GUI实例。Instance-》OnInit()(CreateDialogsProvider)-》DialogsProvider为运行的对话框。

 

     接收网络文件的步骤

OnOpenNet( wxCommandEvent& event )打开网络文件的步骤。打开OpenDialog对话框,点击Ok后调用OpenDialog::OnOk( wxCommandEvent& WXUNUSED(event) )函数,调用playlist_Command函数改变播放列表线程的状态。

 

  激活线程分析:

         在wxwindow.cpp中的消息映射中 set_callbacks( OpenDialogs, Close ); 则设置了module_t->pf_activate= OpenDialogs函数,

        在module.c 的__module_Need( vlc_object_t *p_this, const char *psz_capability,

                          const char *psz_name, vlc_bool_t b_strict )

函数中用到了pf_activate激活GUI对话框;

    在video_output.c 的static void RunThread( vout_thread_t *p_vout)线程中,也用到了pf_activate激活GUI对话框;

 

 

5. 开始所有module 的精髓

         消息映射宏

                       vlc_module_begin();

                          set_callbacks( NetOpen, NULL );

vlc_module_end();

然后设置模块结构的成员函数为:

#define set_callbacks( activate, deactivate )                                 \

               p_submodule->pf_activate = activate;                                      \

                 p_submodule->pf_deactivate = deactivate

 

在__module_Need函数中启动pf_activate  激活相应的module。

 

 

1. 我的理解:

macro of message map

 

2./*********

*定义一个公共的结构

*并把激活本模块的函数传给该结构的函数成员

************************/

vlc_module_begin();

set_callbacks( NetOpen, NULL );

vlc_module_end();

 

设置模块结构的pf_activate成员函数为NetOpen:

#define set_callbacks( activate, deactivate ) \

p_submodule->pf_activate = activate; \

p_submodule->pf_deactivate = deactivate

 

所以当通过函数module_need激活模块的时候,就是通过pf_activate来启动模块的!

vlc_module_begin()起到了一个消息传递的作用!

 

vlc学习计划(6)--网络数据流接收处理过程分析

网络数据流接收处理分析

 

1、在input.c(src\input)文件中的主线程循环

 

      Thread in charge of processing the network packets and demultiplexing

 

RunThread( input_thread_t *p_input )

 

{

 

          InitThread( p_input ) ;

 

…………………………………………………….

 

     input_SelectES( p_input, p_input->stream.p_newly_selected_es );

 

              …………………………………………………….

 

      /* Read and demultiplex some data. */

 

     i_count = p_input->pf_demux( p_input );

 

 

 

}

 

2、在下列函数中:

 

分离出access  , demux  , name字符串 ;

根据分离出的access  字符串通过module_Need函数找到acess 指针模块;

根据分离出的demux  字符串通过module_Need函数找到demux  指针模块;

 static int InitThread( input_thread_t * p_input )

 

{

 

     msg_Dbg( p_input, "access `%s', demux `%s', name `%s'",

 

             p_input->psz_access, p_input->psz_demux, p_input->psz_name );

 

 

 

    /* Find and open appropriate access module */

 

    p_input->p_access = module_Need( p_input, "access",

 

                                     p_input->psz_access, VLC_TRUE );

 

 …………………………………………………….

 

  while( !input_FillBuffer( p_input ) )

 

  …………………………………………………….

 

    /* Find and open appropriate demux module */

 

    p_input->p_demux =

 

        module_Need( p_input, "demux",

 

                     (p_input->psz_demux && *p_input->psz_demux) ?

 

                     p_input->psz_demux : "$demux",

 

                     (p_input->psz_demux && *p_input->psz_demux) ?

 

                     VLC_TRUE : VLC_FALSE );

 

…………………………………………………….

 

}

 

3、在ps.c (module\demux\mpeg)文件中

 

a.通过消息映射宏赋值启动函数Activate;

 

b.通过函数Activate赋值p_input->pf_demux = Demux;

 

c. 通过函数module_Need( p_input, "mpeg-system", NULL, 0 ) 激活p_input->p_demux_data->mpeg.pf_read_ps( p_input, &p_data )函数(pf_read_ps);

 

d.在InitThread函数中激活;

 

 

 

        static int Activate( vlc_object_t * p_this )

 

{

 

      /* Set the demux function */

 

p_input->pf_demux = Demux;

 

p_input->p_private = (void*)&p_demux->mpeg;

 

    p_demux->p_module = module_Need( p_input, "mpeg-system", NULL, 0 );

 

}

 

4、在system.c (module\demux\mpeg)文件中

 

         赋值解码模块mpeg_demux_t的成员函数;

 

     static int Activate ( vlc_object_t *p_this )

 

{

 

    static mpeg_demux_t mpeg_demux =

 

                    { NULL, ReadPS, ParsePS, DemuxPS, ReadTS, DemuxTS };

 

    mpeg_demux.cur_scr_time = -1;

 

    memcpy( p_this->p_private, &mpeg_demux, sizeof( mpeg_demux ) );

 

 

 

    return VLC_SUCCESS;

 

}

 

并且申明函数static ssize_t ReadPS( input_thread_t * p_input, data_packet_t ** pp_data );

 

 

 

5、在ps.c (module\demux\mpeg)文件中

 

Demux( input_thread_t * p_input )

 

{

 

i_result = p_input->p_demux_data->mpeg.pf_read_ps( p_input, &p_data );

 

      p_input->p_demux_data->mpeg.pf_demux_ps( p_input, p_data );

 

}

 

进行读取数据和分离工作;

 

6、在system.c (module\demux\mpeg)文件中

 

数据走向图如下

 

ReadPS-> PEEK-> input_Peek(src\input\input_ext-plugins.c)-> input_FillBuffert 通过 i_ret = p_input->pf_read( p_input,

 

                              (byte_t *)p_buf + sizeof(data_buffer_t)

 

                               + i_remains,

 

                              p_input->i_bufsize );

 

input_thread_t结构的pf_read函数成员如果是为udp.c(modules\access)的RTPChoose函数

 

则在开启access(UDP 模块)时通过module_need 激活;

 

 激活网络读数据模块 RTPChoose(modules\access\ udp.c)->Read->net_Read(src\misc\net.c);

 

 

 

7、在input_programs.c(src\input)文件中

 

         运行解码器对ES流解码

 

   int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )

 

{

 

      p_es->p_dec = input_RunDecoder( p_input, p_es );

 

  

 

}

 

 input_SelectES(src\input\input_programs.c)->input_RunDecoder(src\input\input_dec.c)->DecoderThread->DecoderDecode ->vout_DisplayPicture

vlc学习计划(7)--从接收到数据流到播放视频的过程分析

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

 

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

 

 

 

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

 

Demux(modules\demux\mpeg\ps.c)->DemuxPs(modules\demux\mpeg\system.c)-> ParsePS->input_SelectES(src\input\input_programs.c)->input_RunDecoder(src\input\input_dec.c)->CreateDecoder->

 

vout_new_buffer->vout_Request(src\video_output\video_output.c)->vout_Create->RunThread->vout_RenderPicture(src\video_output\vout_pictures.c)->pf_display

 

 

 

注意:p_dec->pf_vout_buffer_new = vout_new_buffer的pf_vout_buffer_new在ffmpeg_NewPictBuf(modules\codec\ffmpeg\video.c)函数中激活

 

 

 

   解码部分走势线:

 

Demux(modules\demux\mpeg\ps.c)->DemuxPs(modules\demux\mpeg\system.c)-> ParsePS->input_SelectES(src\input\input_programs.c)->input_RunDecoder(src\input\input_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.

你可能感兴趣的:(VLC学习文档(载))