定制网站哪家好,wordpress列表页怎么加关键词,办公室设计效果图大全,品牌注册查询官网一、前言
这篇文章讲解#xff1a; 采用华为云最新推出的Flexus云服务器X实例搭建RTSP服务器#xff0c;完成视频直播需求。
随着实时视频流传输需求的增长#xff0c;RTSP#xff08;实时流协议#xff09;服务器成为了许多视频监控、直播和多媒体应用的核心组件。在当…一、前言
这篇文章讲解 采用华为云最新推出的Flexus云服务器X实例搭建RTSP服务器完成视频直播需求。
随着实时视频流传输需求的增长RTSP实时流协议服务器成为了许多视频监控、直播和多媒体应用的核心组件。在当今高度互联的世界中能够快速部署且稳定运行的RTSP服务器对于确保高质量的视频流体验至关重要。本文将指导如何在华为云Flexus X实例上部署一款轻量级的RTSP服务器——采用simple-rtsp-server。
通过本教程将详细介绍如何在华为云Flexus X实例上安装和配置simple-rtsp-server。simple-rtsp-server以其简单易用的特点而闻名非常适合那些希望快速搭建起基本RTSP服务的开发者。将涵盖从环境准备到软件安装再到基本配置的所有步骤帮助顺利搭建一个可靠的RTSP服务器为视频流应用提供坚实的基础。
华为云Flexus云服务器X实例是由国家科技进步奖获得者、华为公司Fellow及华为云首席架构师顾炯炯牵头研发的一款创新性云服务器。该实例基于华为的擎天QingTian架构、瑶光云脑和盘古大模型等核心技术是业界首款应用驱动的柔性算力云服务器适用于高科技、零售、金融、游戏等多个行业的通用工作负载场景如网络应用、数据库、虚拟桌面、分析索引、微服务及持续集成/持续部署CI/CD等。
传统的云服务器通常只提供固定的CPU和内存规格无法精准匹配用户的实际资源需求导致资源利用效率低下。相比之下华为云Flexus X实例提供了更为灵活的算力配置支持超过100种不同的CPU与内存配比最高可达到3:1的比例从而更好地适应各种业务应用的需求。
Flexus X实例不仅在性能方面表现出色还内置了智能应用调优算法结合华为技术专家多年积累的经验在基础模式下其GeekBench单核及多核跑分可达业界同规格独享型实例的1.6倍。在性能模式下Flexus X实例的性能超过了同类C系/G系/R系及S系旗舰型云主机的标准。
此外Flexus X实例还配备了X-Turbo加速技术和大模型底层智能调度技术为关键业务应用提供加速功能。例如在Flexus X实例上部署的MySQL、Redis和Nginx等应用其性能最高可达业界同规格独享型实例的6倍MySQL性能长期运行时也能保持2倍的性能优势。
Flexus X实例在定价策略上定位于经济型级别但其性能表现却超越了旗舰级云主机。通过动态业务画像规格优化等技术用户在将业务从本地服务器或其他云服务提供商迁移到Flexus X实例时可以节省高达30%的算力成本从而实现业务的全面提速和效能提升享受到云基础设施的显著改进体验。
二、服务器选购
2.1 登录官网
链接https://www.huaweicloud.com/ 在官网首页的轮播图里可以看到有Flexus云服务器的宣传。这是华为云匠心打造的下一代跃级产品面向中低负载场景性能倍增、体验跃级的服务器。
2.2 选购服务器
在产品页面也可以看到Flexus云服务的选项点击进去选购服务器。 链接https://www.huaweicloud.com/product/flexus.html 在选购页面可以看到服务器推广器件1年36块钱。 每个月的流量是100G对于一些访问量不高的服务器或者测试用是非常合适的。 当前我要选择的服务器是Flexus云服务器X实例 点击Flexus系列产品选择X实例。Flexus云服务器X实例符合柔性算力六倍性能旗舰体验覆盖高科技、零售、金融、游戏等行业大多数通用工作负载场景。 2.3 选择服务器区域
针对时延敏感型业务请选择靠近您业务的区域以降低网络时延提高访问速度针对和存量云产品有内网互通需求的业务请选择和存量产品相同的区域。 2.4 选择服务器规格 2.5 选择系统镜像
我这选择ubuntu系统用来搭建服务器。这个根据自己的情况选择自己适合那一种就选择哪一种。 2.6 选择存储盘
我选择150G大小。 2.7 配置密码
设置好服务器的名字如果你有多个服务器为了自己好区别和系统的登录密码。 2.8 配置云备份
云备份这个不买。有需要自己可以购买。 2.9 确认配置 2.10 立即购买 购买成功。 创建成功之后邮箱会收到提示的。 2.10 后台控制台
链接https://console.huaweicloud.com/ecm
在控制台可以看到服务器的详情。 三、服务器登录
3.1 查看服务器的详情
点击服务器的名称可以进去到详情页面。 3.2 远程登录 填入设置好的密码。 登录成功。 3.9 采用FinalShell登录
自带的在浏览器里运行每次需要打开浏览器文件也不方便上传下载。
所以这里开发阶段我采用的 FinalShell登录到服务器。
新建SSH连接输入连接信息。 登录成功。 接下来就可以进行开发了。
四、搭建RTSP流媒体服务器
4.1 simple-rtsp-server库
simple-rtsp-server依赖ffmpeg版本要求4.x。
GitHub仓库地址https://github.com/BreakingY/simple-rtsp-server 4.2 安装基础依赖
在命令行运行。
sudo apt-get -y install autoconf automake build-essential libass-dev libfreetype6-dev libsdl2-dev libtheora-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev pkg-config texinfo zlib1g-dev安装过程中: 安装完成。 4.3 安装依赖库
在系统命令行分别运行以下命令安装依赖库。
汇编库
sudo apt-get install yasm
sudo apt-get install nasm视频库
sudo apt-get install libx264-dev
sudo apt-get install libx265-dev音频库
sudo apt-get install libfdk-aac-dev
sudo apt-get install libmp3lame-dev
sudo apt-get install libopus-dev4.4 安装ffmpeg
下载ffmpeg的库源码。
wget https://ffmpeg.org//releases/ffmpeg-4.0.5.tar.bz2tar xjvf ffmpeg-4.0.5.tar.bz2cd ffmpeg-4.0.5编译ffmpeg库源码。
./configure --prefix/usr/local --enable-libx264 --disable-x86asm --enable-nonfree --enable-libfdk-aac --enable-shared --enable-gpl --enable-libmp3lame --enable-libopus --extra-cflags-I/usr/local/include --extra-ldflags-L/usr/local/libmakemake install4.5 simple-rtsp-server下载编译
git clone https://github.com/BreakingY/simple-rtsp-server.gitcd simple-rtsp-servermkdir buildcd buildcmake ..make -j44.6 运行服务器
cp -r ../mp4path .
./rtsp_server loop 0运行效果 4.7 开放规则
要记得把服务器的 端口开放出来 不然无法访问。 4.8 播放测试RTSP协议播放云端视频文件
自带了4个测试文件。 可以直接播放。
这是自带的4个测试文件的路径
rootflexusx-1a58:~/work/simple-rtsp-server# ls mp4path/
test_1280x720_h264_aac.mp4 test_h264_aac.mp4 test_h264_pcma.mkv test_h265_aac.mp4下面是播放格式
rtsp://116.205.107.156:8554/test_1280x720_h264_aac.mp4其中
rtsp://自己的公网IP:8554/mp4path目录下的视频文件名称下面是potplayer播放器播放的效果: 播放过程中在服务器上会打印出每个过程的详情。 4.9 rtsp_server.c代码
#include common.h
#include session.h
#include arpa/inet.h
#include errno.h
#include stdio.h
#include stdlib.h
#include string.h
#include sys/socket.h
#include unistd.h
#define BUF_MAX_SIZE (1024 * 1024)
char *mp4Dir mp4path/\0; // MP4文件存放位置
int auth 1;
#define USER admin
#define PASSWORD 123456
/*doClientThd线程参数*/
struct thd_arg_st
{int client_sock_fd;char client_ip[30];int client_port;
};int create_rtp_sockets(int *fd1, int *fd2, int *port1, int *port2)
{struct sockaddr_in addr;int port 0;*fd1 socket(AF_INET, SOCK_DGRAM, 0);if (*fd1 0){perror(socket);return -1;}*fd2 socket(AF_INET, SOCK_DGRAM, 0);if (*fd2 0){perror(socket);close(*fd1);return -1;}memset(addr, 0, sizeof(addr));addr.sin_family AF_INET;addr.sin_addr.s_addr htonl(INADDR_ANY);for (port 1024; port 65535; port 2){addr.sin_port htons(port);if (bind(*fd1, (struct sockaddr *)addr, sizeof(addr)) 0){addr.sin_port htons(port 1);if (bind(*fd2, (struct sockaddr *)addr, sizeof(addr)) 0){*port1 port;*port2 port 1;return 0;}close(*fd1);}}close(*fd1);close(*fd2);return -1;
}
static void generate_session_id(char *session_id, size_t size) {if (size 9) {return;}time_t timestamp time(NULL);srand((unsigned int)timestamp);int random_part rand() % 1000000;snprintf(session_id, size, %02ld%06d, timestamp % 100, random_part);return;
}
/*处理客户端rtsp请求*/
void *doClientThd(void *arg)
{signal(SIGINT, sig_handler);signal(SIGQUIT, sig_handler);signal(SIGKILL, sig_handler);struct thd_arg_st *arg_thd (struct thd_arg_st *)arg;int client_sock_fd arg_thd-client_sock_fd;char *client_ip arg_thd-client_ip;int client_port arg_thd-client_port;char method[40];char url[100];char url_tmp[100];char filename[100];char url_setup[100];char track[1024];char url_play[1024];char local_ip[40];char version[40];int cseq;char *buf_ptr;char *buf_tmp;char *recv_buf malloc(BUF_MAX_SIZE);char *send_buf malloc(BUF_MAX_SIZE);char line[400];// rtp_over_tcpint sig_0 -1;int sig_1 -1;int sig_2 -1;int sig_3 -1;int ture_of_rtp_tcp 0;// rtp_over_udpint client_rtp_port -1;int client_rtcp_port -1;int client_rtp_port_1 -1;int client_rtcp_port_1 -1;int server_rtp_port -1;int server_rtcp_port -1;int server_rtp_port_1 -1;int server_rtcp_port_1 -1;int server_udp_socket_rtp_fd -1;int server_udp_socket_rtcp_fd -1;int server_udp_socket_rtp_1_fd -1;int server_udp_socket_rtcp_1_fd -1;char ch /;int findflag 0;char path[100];memcpy(path, mp4Dir, strlen(mp4Dir));path[strlen(mp4Dir)] \0;char path_tmp[100];memcpy(path_tmp, mp4Dir, strlen(mp4Dir));path_tmp[strlen(mp4Dir)] \0;int fd;char *realm simple-rtsp-server;char nonce[33] {0};generate_nonce(nonce, sizeof(nonce));char session_id[512];generate_session_id(session_id, sizeof(session_id));while (1){int recv_len;recv_len recv(client_sock_fd, recv_buf, BUF_MAX_SIZE, 0);if (recv_len 0)goto out;recv_buf[recv_len] \0;printf(---------------C-S--------------\n);printf(%s, recv_buf);buf_ptr getLineFromBuf(recv_buf, line);buf_tmp buf_ptr;if (sscanf(line, %s %s %s\r\n, method, url, version) ! 3){printf(parse err\n);goto out;}/*解析序列号*/while (1){buf_ptr getLineFromBuf(buf_ptr, line);if (!strncmp(line, CSeq:, strlen(CSeq:))){if (sscanf(line, CSeq: %d\r\n, cseq) ! 1){printf(parse err\n);goto out;}break;}}if(auth 1){// authorizationif(!strcmp(method, SETUP) || !strcmp(method, DESCRIBE) || !strcmp(method, PLAY)){AuthorizationInfo *auth_info find_authorization(recv_buf);if(auth_info NULL){handleCmd_Unauthorized(send_buf, cseq, realm, nonce);printf(---------------S-C--------------\n);printf(%s, send_buf);send(client_sock_fd, send_buf, strlen(send_buf), 0);continue;}else{// printf(nonce:%s\n, auth_info-nonce);// printf(realm:%s\n, auth_info-realm);// printf(response:%s\n, auth_info-response);// printf(uri:%s\n, auth_info-uri);// printf(username:%s\n, auth_info-username);// 鉴权校验int ret authorization_verify(USER, PASSWORD, realm, nonce, auth_info-uri, method, auth_info-response);free_authorization_info(auth_info);if(ret 0){ // 鉴权失败goto out;}}}}/* 如果是SETUP,需要解析是RTP_OVER_TCP还是RTP_OVER_UDP模式 */if (!strcmp(method, SETUP)){memset(url_setup, 0, sizeof(url_setup));memset(track, 0, sizeof(track));strcpy(url_setup, url);char *p strrchr(url_setup, ch);memcpy(track, p 1, strlen(p)); // video-track0 audio -track1while (1){buf_tmp getLineFromBuf(buf_tmp, line);if (!buf_tmp){break;}if (!strncmp(line, Transport: RTP/AVP/TCP, strlen(Transport: RTP/AVP/TCP))){if (memcmp(track, track0, 6) 0){sscanf(line, Transport: RTP/AVP/TCP;unicast;interleaved%d-%d\r\n, sig_0, sig_1);}else{sscanf(line, Transport: RTP/AVP/TCP;unicast;interleaved%d-%d\r\n, sig_2, sig_3);}ture_of_rtp_tcp 1;break;}if (!strncmp(line, Transport: RTP/AVP/UDP, strlen(Transport: RTP/AVP/UDP))){if (memcmp(track, track0, 6) 0){sscanf(line, Transport: RTP/AVP/UDP;unicast;client_port%d-%d\r\n, client_rtp_port, client_rtcp_port);}else{sscanf(line, Transport: RTP/AVP/UDP;unicast;client_port%d-%d\r\n, client_rtp_port_1, client_rtcp_port_1);}break;}if (!strncmp(line, Transport: RTP/AVP, strlen(Transport: RTP/AVP))){if (memcmp(track, track0, 6) 0){sscanf(line, Transport: RTP/AVP;unicast;client_port%d-%d\r\n, client_rtp_port, client_rtcp_port);}else{sscanf(line, Transport: RTP/AVP;unicast;client_port%d-%d\r\n, client_rtp_port_1, client_rtcp_port_1);}break;}}}if (!strcmp(method, OPTIONS)){char *p strrchr(url, ch);memcpy(filename, p 1, strlen(p));char *tmp strcat(path_tmp, filename);findflag 1;fd open(tmp, O_RDONLY);if (fd 0) // 请求的资源不存在返回404并关闭客户端文件描述符{perror(failed);handleCmd_404(send_buf, cseq);send(client_sock_fd, send_buf, strlen(send_buf), 0);goto out;}else{close(fd);if (handleCmd_OPTIONS(send_buf, cseq)){printf(failed to handle options\n);goto out;}}}else if (!strcmp(method, DESCRIBE)){if (findflag 0){char *p strrchr(url, ch);memcpy(filename, p 1, strlen(p));char *tmp strcat(path_tmp, filename);fd open(tmp, O_RDONLY);if (fd 0) // 请求的资源不存在返回404并关闭客户端文件描述符{perror(failed);handleCmd_404(send_buf, cseq);send(client_sock_fd, send_buf, strlen(send_buf), 0);goto out;}close(fd);findflag 1;}char sdp[1024];char localIp[100];sscanf(url, rtsp://%[^:]:, localIp);int ret generateSDP(path_tmp, localIp, sdp, sizeof(sdp));if (ret 0){ // mp4文件有问题或者视频不是H264/H265,音频不是AAC/PCMAhandleCmd_500(send_buf, cseq);send(client_sock_fd, send_buf, strlen(send_buf), 0);goto out;}if (handleCmd_DESCRIBE(send_buf, cseq, url, sdp)){printf(failed to handle describe\n);goto out;}}else if (!strcmp(method, SETUP) ture_of_rtp_tcp 0) // RTP_OVER_UDP{sscanf(url, rtsp://%[^:]:, local_ip);if (memcmp(track, track0, 6) 0){create_rtp_sockets(server_udp_socket_rtp_fd, server_udp_socket_rtcp_fd, server_rtp_port, server_rtp_port);handleCmd_SETUP_UDP(send_buf, cseq, client_rtp_port, server_rtp_port, session_id);}else{create_rtp_sockets(server_udp_socket_rtp_1_fd, server_udp_socket_rtcp_1_fd, server_rtp_port_1, server_rtp_port_1);handleCmd_SETUP_UDP(send_buf, cseq, client_rtp_port_1, server_rtp_port_1, session_id);}}else if (!strcmp(method, SETUP) ture_of_rtp_tcp 1) // RTP_OVER_TCP{sscanf(url, rtsp://%[^:]:, local_ip);if (memcmp(track, track0, 6) 0){handleCmd_SETUP_TCP(send_buf, cseq, local_ip, client_ip, sig_0, session_id);}else{handleCmd_SETUP_TCP(send_buf, cseq, local_ip, client_ip, sig_2, session_id);}}else if (!strcmp(method, PLAY)){memset(url_play, 0, sizeof(url_play));memset(track, 0, sizeof(track));strcpy(url_play, url);if (handleCmd_PLAY(send_buf, cseq, url_play, session_id)){printf(failed to handle play\n);goto out;}}else{goto out;}printf(---------------S-C--------------\n);printf(%s, send_buf);send(client_sock_fd, send_buf, strlen(send_buf), 0);if (!strcmp(method, PLAY)){struct timeval time_pre, time_now;gettimeofday(time_pre, NULL);char *tmp strcat(path, filename);int ret addClient(tmp, client_sock_fd, sig_0, sig_2, ture_of_rtp_tcp, client_ip, client_rtp_port, client_rtp_port_1,server_udp_socket_rtp_fd, server_udp_socket_rtcp_fd, server_udp_socket_rtp_1_fd, server_udp_socket_rtcp_1_fd);if (ret 0)goto out;int sum getClientNum();gettimeofday(time_now, NULL);int time_handle 1000 * (time_now.tv_sec - time_pre.tv_sec) (time_now.tv_usec - time_pre.tv_usec) / 1000;printf(timeuse:%dms sum_client:%d\n\n, time_handle, sum);goto over;}}
out:close(client_sock_fd);free(recv_buf);free(send_buf);free(arg);return NULL;
over:free(recv_buf);free(send_buf);free(arg);return NULL;
}int main(int argc, char *argv[])
{if(argc 3){printf(./rtsp_server auth(0-not authentication; 1-authentication) loop(0-not loop 1-loop)\n);return -1;}auth atoi(argv[1]);reloop_flag atoi(argv[2]);int server_sock_fd;int ret;signal(SIGINT, sig_handler);signal(SIGQUIT, sig_handler);signal(SIGKILL, sig_handler);signal(SIGPIPE, SIG_IGN);signal(SIGFPE, SIG_IGN);server_sock_fd createTcpSocket();if (server_sock_fd 0){printf(failed to create tcp socket\n);return -1;}ret bindSocketAddr(server_sock_fd, SERVER_IP, SERVER_PORT);if (ret 0){printf(failed to bind addr\n);return -1;}ret listen(server_sock_fd, 100);if (ret 0){printf(failed to listen\n);return -1;}moduleInit();printf(rtsp://%s:%d/filename\n, SERVER_IP, SERVER_PORT);while (1){int client_sock_fd;char client_ip[40];int client_port;pthread_t tid;client_sock_fd acceptClient(server_sock_fd, client_ip, client_port);if (client_sock_fd 0){printf(failed to accept client\n);return -1;}printf(###########accept client -- client_sock_fd:%d client ip:%s,client port:%d###########\n, client_sock_fd, client_ip, client_port);struct thd_arg_st *arg;arg malloc(sizeof(struct thd_arg_st));memcpy(arg-client_ip, client_ip, strlen(client_ip));arg-client_port client_port;arg-client_sock_fd client_sock_fd;ret pthread_create(tid, NULL, doClientThd, (void *)arg);if (ret 0){perror(doClientThd pthread_create());}pthread_detach(tid);}moduleDel();close(server_sock_fd);return 0;
}4.10 common.c 代码
#include common.h
#include md5.h
#include arpa/inet.h
#include assert.h
#include errno.h
#include fcntl.h
#include libavcodec/avcodec.h
#include libavformat/avformat.h
#include libavutil/log.h
#include libavutil/time.h
#include netinet/in.h
#include stdio.h
#include stdlib.h
#include string.h
#include sys/socket.h
#include sys/stat.h
#include sys/types.h
#include unistd.h
int createTcpSocket()
{int sockfd;int on 1;sockfd socket(AF_INET, SOCK_STREAM, 0);if (sockfd 0)return -1;setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)on, sizeof(on));return sockfd;
}
int createUdpSocket()
{int sockfd;int on 1;sockfd socket(AF_INET, SOCK_DGRAM, 0);if (sockfd 0)return -1;setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)on, sizeof(on));return sockfd;
}int bindSocketAddr(int sockfd, const char *ip, int port)
{struct sockaddr_in addr;addr.sin_family AF_INET;addr.sin_port htons(port);addr.sin_addr.s_addr inet_addr(ip);if (bind(sockfd, (struct sockaddr *)addr, sizeof(struct sockaddr)) 0)return -1;return 0;
}
int acceptClient(int sockfd, char *ip, int *port)
{int clientfd;socklen_t len 0;struct sockaddr_in addr;memset(addr, 0, sizeof(addr));len sizeof(addr);clientfd accept(sockfd, (struct sockaddr *)addr, len);if (clientfd 0){printf(accept err:%s\n, strerror(errno));return -1;}strcpy(ip, inet_ntoa(addr.sin_addr));*port ntohs(addr.sin_port);return clientfd;
}
void rtpHeaderInit(struct RtpPacket *rtpPacket, uint8_t csrcLen, uint8_t extension,uint8_t padding, uint8_t version, uint8_t payloadType, uint8_t marker,uint16_t seq, uint32_t timestamp, uint32_t ssrc)
{rtpPacket-rtpHeader.csrcLen csrcLen;rtpPacket-rtpHeader.extension extension;rtpPacket-rtpHeader.padding padding;rtpPacket-rtpHeader.version version;rtpPacket-rtpHeader.payloadType payloadType;rtpPacket-rtpHeader.marker marker;rtpPacket-rtpHeader.seq seq;rtpPacket-rtpHeader.timestamp timestamp;rtpPacket-rtpHeader.ssrc ssrc;return;
}char *getLineFromBuf(char *buf, char *line)
{while (*buf ! \n){*line *buf;line;buf;}*line \n;line;*line \0;buf;return buf;
}
static char *extract_value(const char *source, const char *key) {const char *start strstr(source, key);if (!start) {return NULL;}start strlen(key) 2; // 跳过 keyconst char *end strchr(start, );if (!end) {return NULL;}size_t len end - start;char *value (char *)malloc(len 1);if (!value) {return NULL;}strncpy(value, start, len);value[len] \0;return value;
}AuthorizationInfo *find_authorization(const char *request) {const char *auth_start strstr(request, Authorization: );if (!auth_start) {return NULL; // Authorization字段未找到}auth_start strlen(Authorization: );const char *auth_end strchr(auth_start, \r);if (!auth_end) {auth_end strchr(auth_start, \n);}if (!auth_end) {return NULL; // 无法找到行尾}char *auth_value (char *)malloc(auth_end - auth_start 1);if (!auth_value) {return NULL; // 内存分配失败}strncpy(auth_value, auth_start, auth_end - auth_start);auth_value[auth_end - auth_start] \0;AuthorizationInfo *auth_info (AuthorizationInfo *)malloc(sizeof(AuthorizationInfo));if (!auth_info) {free(auth_value);return NULL; // 内存分配失败}auth_info-username extract_value(auth_value, username);auth_info-realm extract_value(auth_value, realm);auth_info-nonce extract_value(auth_value, nonce);auth_info-uri extract_value(auth_value, uri);auth_info-response extract_value(auth_value, response);free(auth_value);return auth_info;
}void free_authorization_info(AuthorizationInfo *auth_info) {if (auth_info) {free(auth_info-username);free(auth_info-realm);free(auth_info-nonce);free(auth_info-uri);free(auth_info-response);free(auth_info);}return;
}
// 生成随机字符串
static void generate_random_string(char *buf, int length) {static const char charset[] abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;for (size_t i 0; i length; i) {buf[i] charset[rand() % (sizeof(charset) - 1)];}return;
}// 生成nonce
void generate_nonce(char *nonce, int length) {if (length 1) {nonce[0] \0;return;}memset(nonce, 0, length);srand((unsigned int)time(NULL));char random_string[128] {0};generate_random_string(random_string, sizeof(random_string));char timestamp[32];snprintf(timestamp, sizeof(timestamp), %ld, (long)time(NULL));char combined[256] {0};snprintf(combined, sizeof(combined), %s%s, random_string, timestamp);MD5_CTX md5;unsigned char decrypt[16];MD5Init(md5);MD5Update(md5, combined, strlen(combined));MD5Final(md5, decrypt);for(int i 0; i 16; i) {snprintf((nonce[i * 2]), 3, %02x, decrypt[i]);}return;
}int authorization_verify(char *username, char *password, char *realm, char *nonce, char *uri, char * method, char *response){// md5(username:realm:password)unsigned char res1[16];char res1_hex[33] {0};char buffer1[256] {0};sprintf(buffer1,%s:%s:%s, username, realm, password);MD5_CTX md5_1;MD5Init(md5_1);MD5Update(md5_1, buffer1, strlen(buffer1));MD5Final(md5_1, res1);for(int i 0; i 16; i) {snprintf((res1_hex[i * 2]), 3, %02x, res1[i]);}// md5(public_method:url)unsigned char res2[16];char res2_hex[33] {0};char buffer2[256] {0};sprintf(buffer2,%s:%s, method, uri);MD5_CTX md5_2;MD5Init(md5_2);MD5Update(md5_2, buffer2, strlen(buffer2));MD5Final(md5_2, res2);for(int i 0; i 16; i) {snprintf((res2_hex[i * 2]), 3, %02x, res2[i]);}// md5( md5(username:realm:password):nonce:md5(public_method:url) )unsigned char res[16];char res_hex[33] {0};char buffer[512] {0};sprintf(buffer,%s:%s:%s, res1_hex, nonce, res2_hex);MD5_CTX md5;MD5Init(md5);MD5Update(md5, buffer, strlen(buffer));MD5Final(md5, res);for(int i 0; i 16; i) {snprintf((res_hex[i * 2]), 3, %02x, res[i]);}// printf(res:%s response:%s\n, res_hex, response);if(strcmp(res_hex, response) 0){return 0;}return -1;
}int handleCmd_Unauthorized(char *result, int cseq, char *realm, char *nonce){sprintf(result, RTSP/1.0 401 Unauthorized\r\nCSeq: %d\r\nWWW-Authenticate: Digest realm\%s\, nonce\%s\\r\n\r\n,cseq,realm,nonce);return 0;
}
int handleCmd_OPTIONS(char *result, int cseq)
{sprintf(result, RTSP/1.0 200 OK\r\nCSeq: %d\r\nPublic: OPTIONS, DESCRIBE, SETUP, PLAY\r\n\r\n,cseq);return 0;
}
int handleCmd_DESCRIBE(char *result, int cseq, char *url, char *sdp)
{sprintf(result, RTSP/1.0 200 OK\r\nCSeq: %d\r\nContent-Base: %s\r\nContent-type: application/sdp\r\nContent-length: %d\r\n\r\n%s,cseq,url,strlen(sdp),sdp);return 0;
}
int handleCmd_SETUP_TCP(char *result, int cseq, char *localIp, char *clientIp, int sig_0, char *session)
{sprintf(result, RTSP/1.0 200 OK\r\nCSeq: %d\r\nTransport: RTP/AVP/TCP;unicast;destination%s;source%s;interleaved%d-%d\r\nSession: %s\r\n\r\n,cseq,clientIp,localIp,sig_0,sig_0 1,session);return 0;
}
int handleCmd_SETUP_UDP(char *result, int cseq, int clientRtpPort, int serverRtpPort, char *session)
{sprintf(result, RTSP/1.0 200 OK\r\nCSeq: %d\r\nTransport: RTP/AVP;unicast;client_port%d-%d;server_port%d-%d\r\nSession: %s\r\n\r\n,cseq,clientRtpPort,clientRtpPort 1,serverRtpPort,serverRtpPort 1,session);return 0;
}
int handleCmd_PLAY(char *result, int cseq, char *url_setup, char *session)
{sprintf(result, RTSP/1.0 200 OK\r\nCSeq: %d\r\nRange: npt0.000-\r\nSession: %s; timeout60\r\n\r\n,cseq,session);return 0;
}
int handleCmd_404(char *result, int cseq)
{sprintf(result, RTSP/1.0 404 NOT FOUND\r\nCSeq: %d\r\n\r\n,cseq);return 0;
}
int handleCmd_500(char *result, int cseq)
{sprintf(result, RTSP/1.0 500 SERVER ERROR\r\nCSeq: %d\r\n\r\n,cseq);return 0;
}
int check_media_info(const char *filename, MediaInfo *info)
{AVFormatContext *format_ctx NULL;int ret;if ((ret avformat_open_input(format_ctx, filename, NULL, NULL)) 0){fprintf(stderr, Could not open source file %s\n, filename);return ret;}if ((ret avformat_find_stream_info(format_ctx, NULL)) 0){fprintf(stderr, Could not find stream information\n);avformat_close_input(format_ctx);return ret;}info-has_audio 0;info-has_video 0;info-is_video_h26x 0;info-is_audio_aac_pcma 0;info-audio_sample_rate 0;info-audio_channels 0;// info-vps NULL;// info-sps NULL;// info-pps NULL;// info-vps_size 0;// info-sps_size 0;// info-pps_size 0;for (unsigned int i 0; i format_ctx-nb_streams; i){AVStream *stream format_ctx-streams[i];AVCodecParameters *codecpar stream-codecpar;if (codecpar-codec_type AVMEDIA_TYPE_VIDEO){info-has_video 1;if (codecpar-codec_id AV_CODEC_ID_H264 || codecpar-codec_id AV_CODEC_ID_H265 || codecpar-codec_id AV_CODEC_ID_HEVC){info-is_video_h26x 1;if (codecpar-codec_id AV_CODEC_ID_H264)info-video_type H264;elseinfo-video_type H265;}}else if (codecpar-codec_type AVMEDIA_TYPE_AUDIO){info-has_audio 1;if (codecpar-codec_id AV_CODEC_ID_AAC || codecpar-codec_id AV_CODEC_ID_PCM_ALAW){info-is_audio_aac_pcma 1;info-audio_sample_rate codecpar-sample_rate;info-audio_channels codecpar-channels;info-profile codecpar-profile;if(codecpar-codec_id AV_CODEC_ID_AAC)info-audio_type AAC;elseinfo-audio_type PCMA;}}}avformat_close_input(format_ctx);return 0;
}
void free_media_info(MediaInfo *info)
{// if (info-vps)// {// free(info-vps);// }// if (info-sps)// {// free(info-sps);// }// if (info-pps)// {// free(info-pps);// }return;
}
/*
#define FF_PROFILE_AAC_MAIN 0
#define FF_PROFILE_AAC_LOW 1
#define FF_PROFILE_AAC_SSR 2
#define FF_PROFILE_AAC_LTP 3
#define FF_PROFILE_AAC_HE 4
#define FF_PROFILE_AAC_HE_V2 28
#define FF_PROFILE_AAC_LD 22
#define FF_PROFILE_AAC_ELD 38
#define FF_PROFILE_MPEG2_AAC_LOW 128
#define FF_PROFILE_MPEG2_AAC_HE 131
*/
static int get_audio_obj_type(int aactype){//AAC HE V2 AAC LC SBR PS//AAV HE AAC LC SBR//所以无论是 AAC_HEv2 还是 AAC_HE 都是 AAC_LCswitch(aactype){case 0:case 2:case 3:return aactype 1;case 1:case 4:case 28:return 2;default:return 2;}return 2;
}static int get_sample_rate_index(int freq, int aactype){int i 0;int freq_arr[13] {96000, 88200, 64000, 48000, 44100, 32000,24000, 22050, 16000, 12000, 11025, 8000, 7350};//如果是 AAC HEv2 或 AAC HE, 则频率减半if(aactype 28 || aactype 4){freq / 2;}for(i 0; i 13; i){if(freq freq_arr[i]){return i;}}return 4;//默认是44100
}static int get_channel_config(int channels, int aactype){//如果是 AAC HEv2 通道数减半if(aactype 28){return (channels / 2);}return channels;
}
int generateSDP(char *file, char *localIp, char *buffer, int buffer_len)
{memset(buffer, 0, buffer_len);MediaInfo info;if (check_media_info(file, info) ! 0){printf(server error\n);free_media_info(info);return -1;}if (info.has_video !info.is_video_h26x){printf(only support h264 h265\n);free_media_info(info);return -1;}if (info.has_audio !info.is_audio_aac_pcma){printf(only support aac pcma\n);free_media_info(info);return -1;}sprintf(buffer, v0\r\no- 9%ld 1 IN IP4 %s\r\ncIN IP4 %s\r\nt0 0\r\nacontrol:*\r\n,time(NULL), localIp, localIp);if (info.has_video){sprintf(buffer strlen(buffer), mvideo 0 RTP/AVP %d\r\nartpmap:%d %s/90000\r\n//afmtp:%d profile-level-id42A01E; packetization-mode1; sprop-parameter-setsZ0IACpZTBYmI,aMljiA\r\nafmtp:%d packetization-mode1\r\nacontrol:track0\r\n,RTP_PAYLOAD_TYPE_H26X, RTP_PAYLOAD_TYPE_H26X, info.video_type H264 ? H264 : H265, RTP_PAYLOAD_TYPE_H26X);}if (info.has_audio){if (info.audio_type AAC){char config[10] {0};int index get_sample_rate_index(info.audio_sample_rate, info.profile);sprintf(config, %02x%02x, (uint8_t)((get_audio_obj_type(info.profile)) 3)|(index 1), (uint8_t)((index 7)|(info.audio_channels 3)));sprintf(buffer strlen(buffer), maudio 0 RTP/AVP %d\r\nartpmap:%d MPEG4-GENERIC/%u/%u\r\nafmtp:%d streamtype5;profile-level-id1;modeAAC-hbr;config%04u;sizelength13;indexlength3;indexdeltalength3\r\nacontrol:track1\r\n,RTP_PAYLOAD_TYPE_AAC, RTP_PAYLOAD_TYPE_AAC, info.audio_sample_rate, info.audio_channels, RTP_PAYLOAD_TYPE_AAC, atoi(config));}else{sprintf(buffer strlen(buffer), maudio 0 RTP/AVP %d\r\nartpmap:%d PCMA/%u/%u\r\nacontrol:track1\r\n,RTP_PAYLOAD_TYPE_PCMA, RTP_PAYLOAD_TYPE_PCMA, info.audio_sample_rate, info.audio_channels);}}free_media_info(info);return 0;
}
// aactype ffmpeg -- AVCodecParameters *codecpar-profile
void adts_header(char *adts_header_buffer, int data_len, int aactype, int frequency, int channels){int audio_object_type get_audio_obj_type(aactype);int sampling_frequency_index get_sample_rate_index(frequency, aactype);int channel_config get_channel_config(channels, aactype);int adts_len data_len 7;adts_header_buffer[0] 0xff; //syncword:0xfff 高8bitsadts_header_buffer[1] 0xf0; //syncword:0xfff 低4bitsadts_header_buffer[1] | (0 3); //MPEG Version:0 for MPEG-4,1 for MPEG-2 1bitadts_header_buffer[1] | (0 1); //Layer:0 2bitsadts_header_buffer[1] | 1; //protection absent:1 1bitadts_header_buffer[2] (audio_object_type - 1)6; //profile:audio_object_type - 1 2bitsadts_header_buffer[2] | (sampling_frequency_index 0x0f)2; //sampling frequency index:sampling_frequency_index 4bitsadts_header_buffer[2] | (0 1); //private bit:0 1bitadts_header_buffer[2] | (channel_config 0x04)2; //channel configuration:channel_config 高1bitadts_header_buffer[3] (channel_config 0x03)6; //channel configuration:channel_config 低2bitsadts_header_buffer[3] | (0 5); //original0 1bitadts_header_buffer[3] | (0 4); //home0 1bitadts_header_buffer[3] | (0 3); //copyright id bit0 1bitadts_header_buffer[3] | (0 2); //copyright id start0 1bitadts_header_buffer[3] | ((adts_len 0x1800) 11); //frame lengthvalue 高2bitsadts_header_buffer[4] (uint8_t)((adts_len 0x7f8) 3); //frame length:value 中间8bitsadts_header_buffer[5] (uint8_t)((adts_len 0x7) 5); //frame length:value 低3bitsadts_header_buffer[5] | 0x1f; //buffer fullness:0x7ff 高5bitsadts_header_buffer[6] 0xfc;return;
}五、总结
华为云正在举行其年度828 B2B企业节活动期间提供了包括Flexus X实例在内的多种产品的优惠。对于那些对计算性能有较高要求并且需要自行部署MySQL、Redis、Nginx等服务的用户来说这次促销是一个很好的机会建议有兴趣的朋友可以前往查看相关的优惠信息。
官网直达https://activity.huaweicloud.com/828_promotion/index.html