音频流转发服务器源码_流媒体转发服务器原理

hacker|
134

文章目录:

求一份c语言的RTP音频传输源码

1.项目前期工作(配置好环境)

2.发送端文件编写(见下面的send.cpp)

3.接收端文件编写(见下面的receive.cpp)

4.编译文件

(1)发送端

                      g++ -o send send.cpp -I /usr/local/include/jrtplib3/ -ljrtp

(2)接收端

                      g++ -o receive  receive.cpp -I /usr/local/include/jrtplib3/ -ljrtp

附录:

(1)send.cpp

[cpp]

#include "rtpsession.h" 

#include "rtppacket.h" 

#include "rtpudpv4transmitter.h" 

#include "rtpipv4address.h" 

#include "rtpsessionparams.h" 

#include "rtperrors.h" 

#include "rtpmemorymanager.h" 

#ifndef WIN32 

    #include netinet/in.h 

    #include arpa/inet.h 

#else 

    #include winsock2.h 

#endif // WIN32 

#include stdlib.h 

#include stdio.h 

#include iostream 

#include string 

 

// 

// This function checks if there was a RTP error. If so, it displays an error 

// message and exists. 

// 

 

void checkerror(int rtperr) 

    if (rtperr  0) 

    { 

        std::cout  "ERROR: "  RTPGetErrorString(rtperr)  std::endl; 

        exit(-1); 

    } 

 

// 

// The main routine 

// 

 

#ifdef RTP_SUPPORT_THREAD 

 

class MyMemoryManager : public RTPMemoryManager 

public: 

    MyMemoryManager()  

    {  

        mutex.Init(); 

        alloccount = 0;  

        freecount = 0;  

    } 

    ~MyMemoryManager()  

    {  

        std::cout  "alloc: "  alloccount  " free: "  freecount  std::endl;  

    } 

    void *AllocateBuffer(size_t numbytes, int memtype) 

    { 

        mutex.Lock(); 

        void *buf = malloc(numbytes); 

        std::cout  "Allocated "  numbytes  " bytes at location "  buf  " (memtype = "  memtype  ")"  std::endl; 

        alloccount++; 

        mutex.Unlock(); 

        return buf; 

    } 

 

    void FreeBuffer(void *p) 

    { 

        mutex.Lock(); 

        std::cout  "Freeing block "  p  std::endl; 

        freecount++; 

        free(p); 

        mutex.Unlock(); 

    } 

private: 

    int alloccount,freecount; 

    JMutex mutex; 

}; 

 

#else 

 

class MyMemoryManager : public RTPMemoryManager 

public: 

    MyMemoryManager()  

    {  

        alloccount = 0;  

        freecount = 0;  

    } 

    ~MyMemoryManager()  

    {  

        std::cout  "alloc: "  alloccount  " free: "  freecount  std::endl;  

    } 

    void *AllocateBuffer(size_t numbytes, int memtype) 

    { 

        void *buf = malloc(numbytes); 

        std::cout  "Allocated "  numbytes  " bytes at location "  buf  " (memtype = "  memtype  ")"  std::endl; 

        alloccount++; 

        return buf; 

    } 

 

    void FreeBuffer(void *p) 

    { 

        std::cout  "Freeing block "  p  std::endl; 

        freecount++; 

        free(p); 

    } 

private: 

    int alloccount,freecount; 

}; 

 

#endif // RTP_SUPPORT_THREAD 

 

int main(void) 

#ifdef WIN32 

    WSADATA dat; 

    WSAStartup(MAKEWORD(2,2),dat); 

#endif // WIN32 

     

    MyMemoryManager mgr; 

    RTPSession sess(mgr); 

    uint16_t portbase,destport; 

    uint32_t destip; 

    std::string ipstr; 

    int status,i,num; 

 

        // First, we'll ask for the necessary information 

         

    std::cout  "Enter local portbase:"  std::endl; 

    std::cin  portbase; 

    std::cout  std::endl; 

     

    std::cout  "Enter the destination IP address"  std::endl; 

    std::cin  ipstr; 

    destip = inet_addr(ipstr.c_str()); 

    if (destip == INADDR_NONE) 

    { 

        std::cerr  "Bad IP address specified"  std::endl; 

        return -1; 

    } 

     

    // The inet_addr function returns a value in network byte order, but 

    // we need the IP address in host byte order, so we use a call to 

    // ntohl 

    destip = ntohl(destip); 

     

    std::cout  "Enter the destination port"  std::endl; 

    std::cin  destport; 

     

    std::cout  std::endl; 

    std::cout  "Number of packets you wish to be sent:"  std::endl; 

    std::cin  num; 

     

    // Now, we'll create a RTP session, set the destination, send some 

    // packets and poll for incoming data. 

     

    RTPUDPv4TransmissionParams transparams; 

    RTPSessionParams sessparams; 

     

    // IMPORTANT: The local timestamp unit MUST be set, otherwise 

    //            RTCP Sender Report info will be calculated wrong 

    // In this case, we'll be sending 10 samples each second, so we'll 

    // put the timestamp unit to (1.0/10.0) 

    sessparams.SetOwnTimestampUnit(1.0/10.0);        

     

    sessparams.SetAcceptOwnPackets(true); 

    transparams.SetPortbase(portbase); 

    status = sess.Create(sessparams,transparams);   

    checkerror(status); 

     

    RTPIPv4Address addr(destip,destport); 

     

    status = sess.AddDestination(addr); 

    checkerror(status); 

     

    for (i = 1 ; i = num ; i++) 

    { 

        printf("\nSending packet %d/%d\n",i,num); 

         

        // send the packet 

        status = sess.SendPacket((void *)"1234567890",10,0,false,10); 

        checkerror(status); 

         

        sess.BeginDataAccess(); 

         

        // check incoming packets 

        if (sess.GotoFirstSourceWithData()) 

        { 

            do 

            { 

                RTPPacket *pack; 

                 

                while ((pack = sess.GetNextPacket()) != NULL) 

                { 

                    // You can examine the data here 

                    printf("Got packet !\n"); 

                     

                    // we don't longer need the packet, so 

                    // we'll delete it 

                    sess.DeletePacket(pack); 

                } 

            } while (sess.GotoNextSourceWithData()); 

        } 

         

        sess.EndDataAccess(); 

 

#ifndef RTP_SUPPORT_THREAD 

        status = sess.Poll(); 

        checkerror(status); 

#endif // RTP_SUPPORT_THREAD 

         

        RTPTime::Wait(RTPTime(1,0)); 

    } 

     

    sess.BYEDestroy(RTPTime(10,0),0,0); 

 

#ifdef WIN32 

    WSACleanup(); 

#endif // WIN32 

    return 0; 

(2) receive.cpp

[cpp] view plaincopy

#include "rtpsession.h" 

#include "rtppacket.h" 

#include "rtpudpv4transmitter.h" 

#include "rtpipv4address.h" 

#include "rtpsessionparams.h" 

#include "rtperrors.h" 

#ifndef WIN32 

    #include netinet/in.h 

    #include arpa/inet.h 

#else 

    #include winsock2.h 

#endif // WIN32 

#include "rtpsourcedata.h" 

#include stdlib.h 

#include stdio.h 

#include iostream 

#include string 

 

// 

// This function checks if there was a RTP error. If so, it displays an error 

// message and exists. 

// 

 

void checkerror(int rtperr) 

    if (rtperr  0) 

    { 

        std::cout  "ERROR: "  RTPGetErrorString(rtperr)  std::endl; 

        exit(-1); 

    } 

 

// 

// The new class routine 

// 

 

class MyRTPSession : public RTPSession 

protected: 

    void OnNewSource(RTPSourceData *dat) 

    { 

        if (dat-IsOwnSSRC()) 

            return; 

 

        uint32_t ip; 

        uint16_t port; 

         

        if (dat-GetRTPDataAddress() != 0) 

        { 

            const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat-GetRTPDataAddress()); 

            ip = addr-GetIP(); 

            port = addr-GetPort(); 

        } 

        else if (dat-GetRTCPDataAddress() != 0) 

        { 

            const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat-GetRTCPDataAddress()); 

            ip = addr-GetIP(); 

            port = addr-GetPort()-1; 

        } 

        else 

            return; 

         

        RTPIPv4Address dest(ip,port); 

        AddDestination(dest); 

 

        struct in_addr inaddr; 

        inaddr.s_addr = htonl(ip); 

        std::cout  "Adding destination "  std::string(inet_ntoa(inaddr))  ":"  port  std::endl; 

    } 

 

    void OnBYEPacket(RTPSourceData *dat) 

    { 

        if (dat-IsOwnSSRC()) 

            return; 

         

        uint32_t ip; 

        uint16_t port; 

         

        if (dat-GetRTPDataAddress() != 0) 

        { 

            const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat-GetRTPDataAddress()); 

            ip = addr-GetIP(); 

            port = addr-GetPort(); 

        } 

        else if (dat-GetRTCPDataAddress() != 0) 

        { 

            const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat-GetRTCPDataAddress()); 

            ip = addr-GetIP(); 

            port = addr-GetPort()-1; 

        } 

        else 

            return; 

         

        RTPIPv4Address dest(ip,port); 

        DeleteDestination(dest); 

         

        struct in_addr inaddr; 

        inaddr.s_addr = htonl(ip); 

        std::cout  "Deleting destination "  std::string(inet_ntoa(inaddr))  ":"  port  std::endl; 

    } 

 

    void OnRemoveSource(RTPSourceData *dat) 

    { 

        if (dat-IsOwnSSRC()) 

            return; 

        if (dat-ReceivedBYE()) 

            return; 

         

        uint32_t ip; 

        uint16_t port; 

         

        if (dat-GetRTPDataAddress() != 0) 

        { 

            const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat-GetRTPDataAddress()); 

            ip = addr-GetIP(); 

            port = addr-GetPort(); 

        } 

        else if (dat-GetRTCPDataAddress() != 0) 

        { 

            const RTPIPv4Address *addr = (const RTPIPv4Address *)(dat-GetRTCPDataAddress()); 

            ip = addr-GetIP(); 

            port = addr-GetPort()-1; 

        } 

        else 

            return; 

         

        RTPIPv4Address dest(ip,port); 

        DeleteDestination(dest); 

         

        struct in_addr inaddr; 

        inaddr.s_addr = htonl(ip); 

        std::cout  "Deleting destination "  std::string(inet_ntoa(inaddr))  ":"  port  std::endl; 

    } 

}; 

 

// 

// The main routine 

//  

 

int main(void) 

#ifdef WIN32 

    WSADATA dat; 

    WSAStartup(MAKEWORD(2,2),dat); 

#endif // WIN32 

     

    MyRTPSession sess; 

    uint16_t portbase; 

    std::string ipstr; 

    int status,i,num; 

 

        // First, we'll ask for the necessary information 

         

    std::cout  "Enter local portbase:"  std::endl; 

    std::cin  portbase; 

    std::cout  std::endl; 

     

    std::cout  std::endl; 

    std::cout  "Number of seconds you wish to wait:"  std::endl; 

    std::cin  num; 

     

    // Now, we'll create a RTP session, set the destination 

    // and poll for incoming data. 

     

    RTPUDPv4TransmissionParams transparams; 

    RTPSessionParams sessparams; 

     

    // IMPORTANT: The local timestamp unit MUST be set, otherwise 

    //            RTCP Sender Report info will be calculated wrong 

    // In this case, we'll be just use 8000 samples per second. 

    sessparams.SetOwnTimestampUnit(1.0/8000.0);      

     

    sessparams.SetAcceptOwnPackets(true); 

    transparams.SetPortbase(portbase); 

    status = sess.Create(sessparams,transparams);   

    checkerror(status); 

     

    for (i = 1 ; i = num ; i++) 

    { 

        sess.BeginDataAccess(); 

         

        // check incoming packets 

        if (sess.GotoFirstSourceWithData()) 

        { 

            do 

            { 

                RTPPacket *pack; 

                 

                while ((pack = sess.GetNextPacket()) != NULL) 

                { 

                    // You can examine the data here 

                    printf("Got packet !\n"); 

                     

                    // we don't longer need the packet, so 

                    // we'll delete it 

                    sess.DeletePacket(pack); 

                } 

            } while (sess.GotoNextSourceWithData()); 

        } 

         

        sess.EndDataAccess(); 

 

#ifndef RTP_SUPPORT_THREAD 

        status = sess.Poll(); 

        checkerror(status); 

#endif // RTP_SUPPORT_THREAD 

         

        RTPTime::Wait(RTPTime(1,0)); 

    } 

     

    sess.BYEDestroy(RTPTime(10,0),0,0); 

 

#ifdef WIN32 

    WSACleanup(); 

#endif // WIN32 

    return 0; 

}

直播平台软件开发,搭建直播平台系统源码时,音视频编解码技术是如何实现的?

这个让我来帮你解答一下。其实视频的编码和解码都是按照一定的算法来实现的,这也是对音视频信息的分析而推出的编解码算法。但音频的算法多样、复杂程度比视频更高。而且不同的场景需要选择不同的音频解码器。

音频编解码常用的实现方案有三种:第一种就是采用专用的音频芯片对语音信号进行采集和处理,音频编解码算法集成在硬件内部。第二种方案就是利用A/D采集卡加上计算机组成硬件平台,音频编解码算法由计算机软件来实现;第三种方案是使用高精度、高速度的A/D采集芯片来完成语音信号的采集。

直播平台软件开发,音视频流内容分发和转码方面的内容

1.前端设备,手机或者摄像机等设备将直播的音视频内容进行采集处理,才推动到平台源站服务器(采用多机集群热备份机制)。

2. 源站服务器一般会连接有专业的磁盘阵列存储设备,当源站服务器接收到数据之后,会先复制多份转发给下面的各个CDN节点,然后再复制其中一份发送给转码服务器。转码服务器会将收到的每一个音视频流进行实时转码。转码服务器会将实时的直播码流录制保存到磁盘阵列中,以方便用户进行回放使用。

3.由于音视频内容需要由高性能的服务器完成,在实时转码的过程中,常常会因为考虑不当,出现无法满足需求的问题。毕竟目前的直播应用属于高并发的大规模直播运营,在每个直播间不同的时间段都会遇上百个甚至成千上万个直播流,进行实时转码。这样一来就需要配置更多高配置的服务器,成本相对来说也会加大。

4.直播流的转码必须是实时性,而且必须要求转码延迟在1s内,对于先前的2-3s的延迟还是存在一定的差距的。所以,为了保证直播软件开发完成之后,音视频的转码能够顺利的进行,不仅需要在服务器的配置上多下功夫,也要注意是否具备高度实时性,转码延迟是否可以控制在一定的时间内。望采纳,谢谢

用易语言做一个音频与视频转换的转换器,源码,谢谢!!!

$request = curl_init('');

curl_setopt($request, CURLOPT_POST, true);

curl_setopt(

$request,

CURLOPT_POSTFIELDS,

array(

'file' = '@' . realpath('/home/test.mp3')

));

curl_setopt($request, CURLOPT_RETURNTRANSFER, true);

echo curl_exec($request);

// close the session

curl_close($request);

使用c++6.0,基于Socket开发网络音频点播程序。求源码!

“对图中的那些函数,我这里稍加解释一下。” int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData); 功能是初始化Windows Socket Dll,在Windows下必须使用它。参数:“wVersionRequested”表示版本,可以是1.1、2.2等;“lpWSAData”指向WSADATA数据结构的指针。int socket(int family, int type, int protocol); 功能是建立Socket,返回以后会用到的Socket值。如果错误,返回-1。参数:“int family”参数指定所要使用的通信协议,取以下几个值:AF_UNIX(Unix内部协议)、AF_INET(Internet协议)、AF_NS Xerox(NS协议)、AF_IMPLINK(IMP连接层),在Windows下只能把“AF”设为“AF_INET”;“int type”参数指定套接字的类型,取以下几个值:SOCK_STREAM(流套接字)、SOCK_DGRAM (数据报套接字)、SOCK_RAW(未加工套接字)、SOCK_SEQPACKET(顺序包套接字);“int protocol”参数通常设置为0。int bind(int sockfd, struct sockaddr *my_addr, int addrlen); 功能是把套接字和机器上一定的端口关联起来。参数:“sockfd”是调用socket()返回的套接字值;“my_addr”是指向数据结构struct sockaddr的指针,它保存你的地址,即端口和IP地址信息;“addrlen”设置为sizeof(struct sockaddr)。 int listen(int sockfd, int backlog); 功能是服务端监听一个端口,直到accept()。在发生错误时返回-1。参数:“sockfd”是调用socket()返回的套接字值;“backlog”是允许的连接数目。大多数系统的允许数目是20,也可以设置为5到10。 int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); 功能是客户端连接服务端监听的端口。参数:“sockfd”是调用socket()返回的套接字值;“serv_addr”保存着目的地端口和IP 地址的数据结构struct sockaddr;“addrlen”设置为sizeof(struct sockaddr)。 int accept(int sockfd, void *addr, int *addrlen); 功能是服务端接受客户端的连接请求,并返回一个新的套接字,以后服务端的数据传输就使用这个新的套接字。如果有错误,返回-1。参数:“sockfd”是和listen()中一样的套接字值;“addr”是个指向局部的数据结构sockaddr_in的指针;“addrlen”设置为sizeof(struct sockaddr_in)。int send(int sockfd, const void *msg, int len, int flags);int recv(int sockfd, void *buf, int len, unsigned int flags);功能是用于流式套接字或数据报套接字的通讯,我们数据的真正传输就由它们完成。参数:“sockfd”是发/收数据的套接字值;“msg”指向你想发送的数据的指针;“buf”是指向接收数据存放的地址;“len”是数据的长度;“flags”设置为 0。int sendto(int sockfd, const void *msg, int len, unsigned int flags,const struct sockaddr *to, int tolen);int recvfrom(int sockfd, void *buf, int len, unsigned int flags,  struct sockaddr *from, int *fromlen);功能和send、recv类似,不过是用于无连接数据报套接字的传输。 int closesocket(int sockfd) 功能是关闭套接字。参数“sockfd”为要关闭的套接字值。程序:“这里的目的是让大家对Socket编程有个整体了解。不用怕,程序我会详细解释的,首先是服务端的程序。其流程是: socket()→bind()→listen→accept()→recv()/send()→closesocket() 具体代码如下:”★#include #include #pragma comment(lib,"Ws2_32")#define MYPORT 830 /*定义用户连接端口*/ #define BACKLOG 10 /*多少等待连接控制*/ int main() { int sockfd, new_fd; /*定义套接字*/ struct sockaddr_in my_addr; /*本地地址信息 */ struct sockaddr_in their_addr; /*连接者地址信息*/ int sin_size; WSADATA ws; WSAStartup(MAKEWORD(2,2),ws); //初始化Windows Socket Dll //建立socket if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { //如果建立socket失败,退出程序 printf("socket error\n"); exit(1); } //bind本机的MYPORT端口 my_addr.sin_family = AF_INET; /* 协议类型是INET */ my_addr.sin_port = htons(MYPORT); /* 绑定MYPORT端口*/ my_addr.sin_addr.s_addr = INADDR_ANY; /* 本机IP*/ if (bind(sockfd, (struct sockaddr *)my_addr, sizeof(struct sockaddr))== -1) { //bind失败,退出程序 printf("bind error\n"); closesocket(sockfd); exit(1); } //listen,监听端口 if (listen(sockfd, BACKLOG) == -1) { //listen失败,退出程序 printf("listen error\n"); closesocket(sockfd); exit(1); } printf("listen"); //等待客户端连接 sin_size = sizeof(struct sockaddr_in); if ((new_fd = accept(sockfd, (struct sockaddr *)their_addr, sin_size)) == -1) { printf("accept error\n"); closesocket(sockfd); exit(1); } printf("\naccept!\n"); //有连接,发送ww0830字符串过去 if (send(new_fd, "ww0830\n", 14, 0) == -1) { printf("send error"); closesocket(sockfd); closesocket(new_fd); exit(1); } printf("send ok!\n"); //成功,关闭套接字 closesocket(sockfd); closesocket(new_fd); return 0;}对服务端程序的流程概括:先是初始化Windows Socket Dll: WSAStartup(MAKEWORD(2,2),ws); 然后建立Socket: sockfd = socket(AF_INET, SOCK_STREAM, 0) 再bind本机的MYPORT端口:my_addr.sin_family = AF_INET; /* 协议类型是INET */ my_addr.sin_port = htons(MYPORT); /* 绑定MYPORT端口 */ my_addr.sin_addr.s_addr = INADDR_ANY; /* 本机IP */ bind(sockfd, (struct sockaddr *)my_addr, sizeof(struct sockaddr)) 接下来监听端口: listen(sockfd, BACKLOG) 如果有客户端的连接请求,接收它: new_fd = accept(sockfd, (struct sockaddr *)their_addr, sin_size) 最后发送ww0830字符串过去: send(new_fd, "ww0830\n", 14, 0) 收尾工作,关闭socket: closesocket(sockfd); closesocket(new_fd); ”编译、执行,就会一直监听830端口客户端程序了。其流程是: socket()→connect()→send()/recv()→closesocket() 比服务端更简单吧!其实现代码如下:”★#include #include #include #pragma comment(lib,"Ws2_32") #define PORT 830 /* 客户机连接远程主机的端口 */ #define MAXDATASIZE 100 /* 每次可以接收的最大字节 */ int main(int argc, char *argv[]) { int sockfd, numbytes; char buf[MAXDATASIZE]; struct sockaddr_in their_addr; /* 对方的地址端口信息 */ if (argc != 2) { //需要有服务端ip参数 fprintf(stderr,"usage: client hostname\n"); exit(1); }  WSADATA ws;WSAStartup(MAKEWORD(2,2),ws); //初始化Windows Socket Dll if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ //如果建立socket失败,退出程序 printf("socket error\n"); exit(1); } //连接对方their_addr.sin_family = AF_INET; /* 协议类型是INET */ their_addr.sin_port = htons(PORT); /* 连接对方PORT端口 */ their_addr.sin_addr.s_addr = inet_addr(argv[1]); /* 连接对方的IP */ if (connect(sockfd, (struct sockaddr *)their_addr,sizeof(struct sockaddr)) == -1){ //如果连接失败,退出程序 printf("connet error\n"); closesocket(sockfd); exit(1); } //接收数据,并打印出来if ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1) { //接收数据失败,退出程序 printf("recv error\n"); closesocket(sockfd); exit(1); } buf[numbytes] = '\0'; printf("Received: %s",buf); closesocket(sockfd); return 0; } 对客户端程序的流程概括:首先是初始化Windows Socket Dll: WSAStartup(MAKEWORD(2,2),ws); 然后建立Socket: sockfd = socket(AF_INET, SOCK_STREAM, 0) 接着连接服务器方:their_addr.sin_family = AF_INET; /* 协议类型是INET */ their_addr.sin_port = htons(PORT); /* 连接对方PORT端口 */ their_addr.sin_addr.s_addr = inet_addr(argv[1]); /* 连接对方的IP */ connect(sockfd, (struct sockaddr *)their_addr,sizeof(struct sockaddr)) 连接成功就接收数据: recv(sockfd, buf, MAXDATASIZE, 0) 最后把收到的数据打印出来并关闭套接字: printf("Received: %s",buf); closesocket(sockfd); 编译结束后,运行服务端,然后。客户端 服务端IP 回车你会看到服务端发来得数据。那么基本的点对点通信就没问题了。只要两台机器同时包含服务端和客户端,就可以互相通信了。当然,你也可以将服务端和客户端分开做,专门一个服务器负责用户登录和转发消息。流程如下:A客户端发登录消息-----》服务器服务器验证发送用户消息----》客户端A客户端想发消息给B客户端----》先发给服务端服务器得到消息查询B客户端IP并转发消息。(或者B客户端循环发消息询问服务器有无消息)通信结束。

音频输出的源码和解码有什么区别?哪个好呢

源码输出,大体是指播放器播放的音频以数字形式输出给功放或者解码器进行音频的解码,然后输出到音箱;

解码输出,大体是指播放器本身先将音频进行解码,然后将解码后的音频输出给功放或者其他设备然后输出到音箱。

没有功放或者解码设备的,一般都是播放器自己解码后输出;

有功放或者解码设备的,建议播放器设置源码输出,然后解码工作交给功放或者解码器来进行解码。

相对来说,源码输出更好一些,因为功放的解码硬件要好于播放设备的解码。

1条大神的评论

  • avatar
    访客 2022-07-15 上午 05:36:49

    } printf("listen"); //等待客户端连接 sin_size = sizeof(struct sockaddr_in); if ((new_fd =

发表评论