一、FFmpeg參數初始化:
//在打開碼流前指定各種參數比如:探測時間/超時時間/最大延時等//設置緩存大小,1080p可將值調大av_dict_set(&options, "buffer_size", "8192000", 0);//以tcp方式打開,如果以udp方式打開將tcp替換為udpav_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();