一、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();
08-10 09:03