VLC学习-3
来源:互联网 发布:炒股软件源码 编辑:程序博客网 时间:2024/05/22 01:42
这章主要想写写数据初始化的问题
--工作中主要是PS流,裸码流,音频的编码也是G711, 所以自己的说法有很大的片面性,请谅解
小吐怡情: 本来是由较充裕的时间完成这些工作的,但是因为小万同学的突然辞职,前面段时间就一直在接手他手上关于流媒体服务器的工作。不过这次却让我对整个live555的架构有了更深的认识,非常感谢小万同学的耐心指导,也感谢我老大赵大哥也指导了我非常多的东西。这次学习我进步很多了,在这里祝万同学在新的环境里,一切顺利、步步高升。
下面继续说说vlc中数据初始化的问题。数据初始化分为几个部分(可能说的也不是很对,仅供参考):
1. libvlc_instance_t : vlc实例
2. libvlc_media_player: 播放器
3. libvlc_media_t: 媒体路径
4. 视频播放相关变量如何初始化
5. 音频播放相关变量如何初始化
可能自己更关心的是这3个东西怎么组合起来,完成这个播放的功能。另外播放器的事件是如何驱动的。
--------------------------------------------------------------------------------------------------------------------------
1. libvlc_instance_t : 顾名思义,是整个vlc的实例。我们跟着代码:
vlc_argv[vlc_argc++] = "--ignore-config"; //其他的怎么配置我也不太清楚,在我所接触到的的Demo中就是这么调用的 p_instance = libvlc_new(vlc_argc, vlc_argv);
这里面到底初始化些什么乱七八糟的东西?
a. 初始化TLS (线程局部存储): 初始看来是没什么用的
b. libvlc_InternalInit(). 这又进入到了VLC学习-2中的内容。
2. libvlc_media_t: 媒体路径,这个东东是用来标记媒体的么?
下面看两个接口:
libvlc_media_t *libvlc_media_new_location(libvlc_instance_t *p_instance, const char * psz_mrl );//MRL libvlc_media_t *libvlc_media_new_path( libvlc_instance_t *p_instance,const char *path );//本地文件实际上在 libvlc_media_new_path() 最终也是调用libvlc_media_new_location() 那我们下来还是仔细的看看这个接口就可以了。
input_item_t * p_input_item; //输入项目libvlc_media_t * p_md; //mediap_input_item = input_item_New( p_instance->p_libvlc_int, psz_mrl, NULL ); //初始化input_item ,设置psz_uri//最主要的地方在于初始化eventManager,及注册相关事件p_md = libvlc_media_new_from_input_item( p_instance, p_input_item );
3.libvlc_media_player_t 真正的播放器
直接上代码:libvlc_media_player_new_from_media(libvlc_media_t* p_md)
libvlc_media_player_t * p_mi; //a.创建属性:例如var_Create (mp, "fullscreen", VLC_VAR_BOOL); 为播放器添加"fullscreen"的属性,属性类型为BOOL //b.添加事件 register_event(mp, Stopped); 为播放器添加Stopped事件 //c.另外用户自己可以在libvlc_media_player_t的struct中添加自己的属性,在这里将其初始化 p_mi = libvlc_media_player_new( p_md->p_libvlc_instance ); libvlc_media_retain( p_md ); //增加引用计数,在后面释放时候只有引用计数最终减为0的时候才会真正释放资源 p_mi->p_md = p_md;
-------------------------------------------------------------------------------------------------------------------
4.对于音视频主要有几个步骤:
视频 Input >Demux >(h264:packetizer) > Decoder >Show
音频 Input >Demux >Decoder >resampler >mix >play
首先需要了解VLC的是基于插件实现功能的,这样方便VLC的功能扩展,在VLC-学习1中提到的plugin中就是这些插件存放的地方。
那么这些Input, Demux, Decoder ,Show模块无一例外的都是插件形式提供的。
那么我们分别来看其中的几个大模块的大致作用
a> Input 实际上就是位于module/access模块下具体有几种 tcp, udp, file, rtsp等等,其实这个模块无外乎就是获取数据的地方。
无论是何种输入的模式,都需要根据选择实现:pf_read,pf_control,pf_seek, pf_block几个模块。
插件的调用方式:查看VLC学习-2中的内容
b> Demux(解复用功能):对不同格式的数据分离音视频,因为公司用到的就暂时只有PS,es, 所以自己也只是对这两种比较熟悉。
PS相对于ES(h264)实际上就是多了PS相关的头。在解复用的时候需要将流中的PTS,DTS,SCR抽取出来,做音视频播放,同步等。
另外因为有PS的头信息,可以根据这些信息判定PS包是否完整。PS流的音视频格式等。
ES(h264)在Demux的时候,是通过packize_h264的功能将h264流中的帧率获取到I-Slice,P-Slice,B-Slice,SPS,PPS信息,从中获取到帧率,具体的计算帧率的方式
可以参照live555中的h264Framer中的实现。 获取过程太长,截取一小段代码:
unsigned num_units_in_tick = bs_read( &s, 32 );unsigned time_scale = bs_read( &s, 32 );unsigned fixed_frame_rate_flag = bs_read( &s, 1 );fps = time_scale/(2.0*num_units_in_tick);那么在执行es_out_send前将pts加入到block_t的实例中就OK。直接上代码:
iNow = time(NULL); int64_t m_gap = (int64_t)((double)1000000.0 / fps);if (iNow > p_sys->m_last + m_gap){ p_block_out->i_dts = p_block_out->i_pts = p_sys->m_last = i_now;}else{ p_sys->m_last +=m_gap; p_block_out->i_dts = p_block_out->i_pts = p_sys->m_last;}es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block_out->i_dts ); es_out_Send( p_demux->out, p_sys->tk->p_es, p_block_out );
c > Decoder 解码: 好像要绕好多弯弯,留待后面详解
视频: video.c 主要是调用ffmpeg库,将传入的数据解码为图片YUV420格式 输出,那么渲染的时候可以有2种方式,直接渲染YV12,或者是转为RGB
音频: araw.c 主要是重采样,量化,混音
d >show 音频播放,视频渲染。这两个自己也不是太清楚,看dx的demo吧
视频渲染: DirectX 或者D3D 这个就不说了吧
音频: DirectSound
下面接着看上面所提到的 都是在从哪儿进入去调用 module_need()接口而完成插件的加载呢。VLC采取的是动态的加载插件的方式,实际上在项目使用中,可以将
这些动态库在程序初始化时一次性全部载入,然后在程序运行中,只需要找到入口即可。我们这边就是这样去使用的。有兴趣的可以去试试。
>> vlc 是怎么事件驱动的呢: MainLoop()在core模块的Input分支下?
在第一部分提到的instance, media, player的初始化中,好像都没有看到哪里创建了线程......
初始化完成后,我们需要做的一个动作是调用libvlc_media_player_play(libvlc_media_player_t* player);
那我们进入到接口中:
在这个接口中有这么一句:这个input_Create调用了libvlccore库中,这个库就是整个vlc的逻辑控制 的核心库了,所有的控制都是在这里完成的。p_input_thread = input_Create( p_mi, p_mi->p_md->p_input_item, NULL, p_mi->input.p_resource );
这个接口真的是做了好多事情啊:几乎所有的东西在这个里面初始化的,可以说自己完全没看懂么,自己能够看懂的就只有
创建了input_thread对象,并且通过 input_ConfigVarInit( p_input )及 input_ControlVarInit( p_input ) 两个接口初始化了很多东西
另外里面的一个函数调用: p_input->p->p_es_out_display = input_EsOutNew( p_input, p_input->p->i_rate ); 这个也是自己没能理解到底是什么,
匆匆进入到input_start()接口: 里面很简单,只是创建了线程:线程的调用为Run() 在core库的input.c中
首先:创建es out, 在前面提到 的流程:ps >(demux) > es p_input->p->p_es_out = input_EsOutTimeshiftNew( p_input, p_input->p->p_es_out_display, p_input->p->i_rate );其次:初始化动作 InputSourceInit( p_input, &p_input->p->input,p_input->p->p_item->psz_uri, NULL ) 这里就主要Open了3个东西Demux, access 及stream ,可以理解为stream 就是在access上面封装的一层的。
哎:囫囵吞枣... 找到了2个模块的初始化的地方。
该死的初始化总算是完了吧,进入了MainLoop()中,这可是VLC的发动机啊!
-------------------------------------------------------------------------------
- VLC学习-3
- vlc学习
- VLC学习
- VLC学习
- 准备学习VLC-Android
- VLC学习笔记
- VLC学习-1
- VLC学习-2
- VLC部分API学习
- VLC学习相关
- VLC源代码学习zz
- vlc开发学习
- VLC-SDK调用学习
- VLC学习文档(载)
- vlc学习总结(一)
- VLC学习(2) VLC架构及流程分析
- VLC学习(1) Linux 下编译 VLC for Android
- VLC学习(2) VLC架构及流程分析
- 模拟小练
- sdut2074区间覆盖
- ptr[-1]的作用和用法
- ZOJ 1484 HDU 1394 Minimum Inversion Number / 线段树单点更新
- const char*, char const*, char*const区别
- VLC学习-3
- 计算机视觉领域资料
- LCD控制器
- 贴图的合并
- 《STL剖析》——空间配置器(一)
- c语言内存分配
- C++ CSV解析
- 基于S3C6410&WINCE6.0的LCD驱动详解
- 好莱坞名导:魔兽世界教会我们的7个人生哲理