在ti81xx系列芯片上,实现硬件h264编码的码流,I帧特别大,而P帧又特别小,这样编码虽说编码效率较高(信息和残差分离的比较好),但是通过网络传输的时候会增加网络的冲击,导致视频丢包,例如,在1080P 60帧的编码中,会出现30万byte的一帧,而普通的帧不过1万byte左右。
可以通过更改DVR RDK的encLink_h264.c的方法,解决这个问题。
文件路径为:
DVRRDK_04.00.00.03/dvr_rdk/mcfw/src_bios6/links_m3video/iva_enc/encLink_h264.c
更改的代码为:
dynamicParams->rateControlParams.maxPicSizeRatioI = 960;
改为300左右,如果出现大的P帧,也可以增加设置,例如
dynamicParams->rateControlParams.maxPicSizeRatioP = 250;
重新编译固件,在
~/DVR_RDK/dvr_rdk
下输入
make -s dvr_rdk_bios6
生成结果在
~/DVR_RDK/dvr_rdk/bin/ti816x/firmware
下面,替换相应的firmware,可以得到平缓的视频byte流,不过这样会增加编码器的性能消耗。
同事给出了通过网络来解决解决I帧过大的问题,如上文所说的,30万byte一帧,60帧每秒,其瞬时带宽占用为1800万byte每秒,即17.17Mbyte/s,即137.33Mbit/s,需要千兆网络作为RTP的发送服务端。
另外,udp的sendto函数,作为非阻塞的函数,不会因为发送丢包而返回失败,所以需要解决sendto丢包的问题,可以通过设置sendto的缓冲区及缓冲队列的长度来解决问题。
需要引入的头文件为:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
设置缓冲区大小的方法为:
int value = 102400*100;
socklen_t valSize = sizeof(value);
setsockopt(udpfd, SOL_SOCKET, SO_SNDBUFFORCE,(char *)&value, valSize);
value =0;
getsockopt(udpfd, SOL_SOCKET, SO_SNDBUF,(char *)&value, &valSize);
printf("socket size: %d\n",value);
设置队列长度的方法为
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name));
if (-1 == ioctl(udpfd, SIOCGIFTXQLEN, &ifr))
printf( "failed to get dev eth0 queue length\n");
printf( "Dev eth0 queue length:%d\n ", ifr.ifr_qlen);
ifr.ifr_qlen = 1000000;
if (-1 == ioctl(udpfd, SIOCSIFTXQLEN, &ifr))
printf( "failed to set dev eth0 queue length\n");
if (-1 == ioctl(udpfd, SIOCGIFTXQLEN, &ifr))
printf( "failed to get dev eth0 queue length\n");
printf( "Dev eth0 queue length:%d\n ", ifr.ifr_qlen);