今天终于实现了live555+DM365 dvsdk encode例程的直播
主要参看前两篇博客--live555直播准备,在融合到DVSDK的时候主要做了如下几点改动
0.修改的writer线程,以前write线程作用是将视频数据保存为文件,这里修改成将视频数据赋给live555RTSP服务器
1.关于线程函数总定义参数部分改为全局变量,因为是要在C代码中掺杂上C++的类,为了C++中也可以使用这些参数,所以改为了全局变量
2.将线程中的envp参数通过构造函数传递给类函数
3.在H264FramedLiveSource类中添加void cleanup1()方法用于在类中运行关于encode部分的代码出错时清零线程用的,跟线程函数中的cleanup标号相同的作用
4.主要修改了doGetNextFrame()方法,将以前write线程函数中while循环中的代码放到此函数中,也就能够得到视频数据了,关于live555获取此数据的程序这样写
if( fFrameSize > fMaxSize) { fNumTruncatedBytes = fFrameSize - fMaxSize; fFrameSize = fMaxSize; } else { fNumTruncatedBytes = 0; } memmove(fTo, Buffer_getUserPtr(hOutBuf), fFrameSize); nextTask() = envir().taskScheduler().scheduleDelayedTask( 0, (TaskFunc*)FramedSource::afterGetting, this);
需要把DVSDK和live555融合在一起,编译出一个可执行文件
此处记录下出现的问题和解决方法:
问题一:C++代码(live555)和C代码(DVSDK)编译时怎样修改?
解决:参考当初DVSDK+JRTPLIB实现音视频同步时候的修改,还是遇到了下面当初没有遇到的问题
编译的时候没有问题,就是在连接的时候,出现undefined等,就是live555的静态连接库没有找到
理论上按照jrtplib时的方法,在Makefile中添加live555的四个动态链接库,但是问题并未解决,困扰一天
解决:最后终于找到原因,是因为Makefile中连接时候的命令如下所示:
arm_v5t_le-g++ -lpthread -lpng -ljpeg -lfreetype -lasound -lliveMedia -lgroupsock -lBasicUsageEnvironment -lUsageEnvironment -o encode capture.o codecs.o main.o speech.o video.o writer.o ../ctrl.o ../uibuttons.o ../ui.o encode_config/linker.cmd
从连接命令可以看到,先写的调用库和输出,再写的.o输入,只需改为先输入再调用库再输出就好了如下所示:
arm_v5t_le-g++ capture.o codecs.o main.o speech.o video.o writer.o ../ctrl.o ../uibuttons.o ../ui.o encode_config/linker.cmd -lpthread -lpng -ljpeg -lfreetype -lasound -lliveMedia -lgroupsock -lBasicUsageEnvironment -lUsageEnvironment -o encode
为什么C连接的时候和jrtplib的时候这种位置可以连接通过,live555就连接不到库呢?
待解决?
对应的Makefile修改如下:
0.显示编译连接命令
VERBOSE = @ 改为 VERBOSE =
1.添加live555的库
#change by zjk
LD_FLAGS += -lpthread -lpng -ljpeg -lfreetype -lasound -lliveMedia -lgroupsock -lBasicUsageEnvironment -lUsageEnvironment
2.修改编译器
#change by zjk
COMPILE.c = $(VERBOSE) $(MVTOOL_PREFIX)g++ $(C_FLAGS) $(CPP_FLAGS) -c
3.修改连接器和连接输入输出文件交换位置
#change by zjk for live555
LINK.c = $(VERBOSE) $(MVTOOL_PREFIX)g++
#change by zjk
$(LINK.c) $^ $(LD_FLAGS) -o $@
问题二:刚开始把线程中申请bufer的函数放到类H264FramedLiveSource 的构造函数里面去了,当初想着,当初始化的时候顺便将这些buffer申请了,正好doGetNextFrame()函数中也需要这些参数,直接把变量的申请放到类里面了,这样正好不用在线程函数中定义变量并将变量传给类,参数太多也太麻烦
出现问题:第一次打开的时候是可以看到直播画面的,如果想再打开一个或者再打开一次就会程序停止并报错: CMEMK Error: Failed to find a pool which fits 622080
CMEM Error: getPool: Failed to get a pool fitting a size 622080
Failed to allocate memory.
Error: Failed to allocate contiguous buffers
encode_live555: BufTab.c:430: BufTab_getBuf: Assertion `hBufTab' failed.
Aborted
解决:这是因为每次再打开一次或者打开多个客户端的时候会重新建一个H264FramedLiveSource 类的对象,而此时正好创建buffer的语句在构造函数中,相当于没打开一次就多创建一次buffer,又没有释放掉,导致内存泄露,进行代码更改:将在类中的变量定义变成全局变量,在构造函数创建buffer语句重新放到线程函数中,这样不管打开几次客户端,创建buffer代码只是创建了一次,就不会内存溢出了。
365内存不够可以使用其他方法,祥看CSDN博客:
但是不适合这个问题,因为那样治标不治本,而且标也没法治,将系统减小到64M,运行encode的时候提示capture创建失败
问题三:有2秒左右的延时
解决:将VLC播放器打开网络的地方,下面有个显示更多选项,选中后,将缓存更改为300ms,这样延时在1s左右
实现良好,心情大好
张纪宽
2014/08/05
2014/08/12:删掉了关于文件存储部分的代码,更改了关于内存申请部分的代码,删掉了关于264打包部分的代码(live中不需要进行打包),其余测试良好。
这个程序是live555直播,用的单播的形式,稳定性非常好。
测试:
运行./encode_live555 -v /home/test.264 -y 2
VLC :rtsp://172.18.168.62:8554/H264-live-unicast-zjk
如下图所示
PC端;
手机端:
缺点:
1.用的是单播的形式,这样的缺点是占用资源,当有两个客户端同时打开的时候会非常卡,甚至没有图像了,下次应该修改成广播的形式
2.只能在同一局域网使用,关于pc上运行可以用airJ无线点播,365运行不能的原因还未搞定