一、FFmpeg参数初始化:
//在打开码流前指定各种参数比如:探测时间/超时时间/最大延时等
//设置缓存大小,1080p可将值调大
av_dict_set(&options, "buffer_size", "8192000", 0);
//以tcp方式打开,如果以udp方式打开将tcp替换为udp
av_dict_set(&options, "rtsp_transport", transport.toUtf8().constData(), 0);
//设置超时断开连接时间,单位微秒,3000000表示3秒
av_dict_set(&options, "stimeout", "3000000", 0);
//设置最大时延,单位微秒,1000000表示1秒
av_dict_set(&options, "max_delay", "1000000", 0);
//自动开启线程数
av_dict_set(&options, "threads", "auto", 0);
//等待3秒超时
av_dict_set(&options, "listen_timeout", "3", 0);
二、初始化输入
AVFormatContext* formatCtx = avformat_alloc_context();
//关键函数,提供从udp进行码流读取
//read_udp_packet函数中将opaque转换为UdpReceiver指针(receiver_udp即该指针),从而获得socket信息
//通过调用recvfrom进行udp码流读取
formatCtx->pb = avio_alloc_context(buffer, bufsize,0,receiver_udp, read_udp_packet, NULL, NULL);
int result = avformat_open_input(&formatCtx, 0, ifmt, &options);
三、后续的一系列操作就按照普通解码顺序进行即可。
用UDP读取码流的相关代码:
//windows平台下初始化套接字
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
return;
}
SOCKET sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if ( sockfd == -1) {
printf("socket error!!!\n");
return ;
}
int reuse = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse, sizeof(reuse)) < 0) {
printf("Setting SO_REUSEADDR error");
closesocket(sockfd);
return ;
}
unsigned int recvBuf = 50*1024*1024;
int recvBufLen = sizeof(recvBuf);
auto nErrCode = setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,(char*)&recvBuf, recvBufLen);
sockaddr_in* localaddr = new struct sockaddr_in;
localaddr->sin_family = AF_INET;
localaddr->sin_port = htons(MULTICAST_GROUP_PORT);
localaddr->sin_addr.s_addr = inet_addr(LOCAL_IP.toStdString().c_str())/* htonl(INADDR_ANY)*/;
struct timeval tv_out;
tv_out.tv_sec=3000;
tv_out.tv_usec=0;
int ret =setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv_out, sizeof(tv_out));
if ( ret == -1 ) {
printf("setsockopt timeout error!!!\n");
closesocket(sockfd);
return ;
}
ret = bind(sockfd, (struct sockaddr*)localaddr, sizeof(struct sockaddr));
if ( ret == -1) {
printf("bind localaddr error!!!\n");
auto id = WSAGetLastError();
closesocket(sockfd);
return ;
}
//是否支持本地回环接收
int loopBack = 1;
ret = setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, (const char *)&loopBack, sizeof(loopBack));
if ( ret == -1) {
printf("setsockopt broadcaset error!!!\n");
closesocket(sockfd);
return ;
}
//是否接收广播消息
struct ip_mreq ipmr = { 0 };
ipmr.imr_interface.s_addr = inet_addr(LOCAL_IP.toStdString().c_str()) /*(INADDR_ANY)*/;
ipmr.imr_multiaddr.s_addr = inet_addr(MULTICAST_GROUP_ADDRESS.toStdString().c_str());
int len = sizeof(ipmr);
ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&ipmr, len);
if ( ret == -1) {
printf("set error IP_ADD_MEMBERSHIP %d\n", WSAGetLastError());
closesocket(sockfd);
return ;
}
//关闭套接字,释放资源
closesocket(sockfd);
WSACleanup();