当前位置: 首页 > news >正文

【RTSP从零实践】13、TCP传输AAC格式RTP包(RTP_over_TCP)的RTSP服务器(附带源码)

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭TCP传输H264格式RTP包(RTP_OVER_TCP)的RTSP服务器🍭
⏰发布时间⏰: 2025-07-16

本文未经允许,不得转发!!!

目录

  • 🎄一、概述
  • 🎄二、RTP over TCP(RTSP) 介绍
    • ✨2.1 RTP over TCP(RTSP) 相关概念
    • ✨2.2 怎么区分 RTSP包、RTP包、RTCP包
    • ✨2.3 RTP包封装代码
  • 🎄三、RTP_over_TCP的RTSP服务端源码
  • 🎄四、总结


在这里插入图片描述

前面系列文章回顾:
【音视频 | RTSP】RTSP协议详解 及 抓包例子解析(详细而不赘述)
【音视频 | RTSP】SDP(会话描述协议)详解 及 抓包例子分析
【音视频 | RTP】RTP协议详解(H.264的RTP封包格式、AAC的RTP封包格式)
【RTSP从零实践】01、根据RTSP协议实现一个RTSP服务
【RTSP从零实践】02、使用RTP协议封装并传输H264
【RTSP从零实践】03、实现最简单的传输H264的RTSP服务器
【RTSP从零实践】04、使用RTP协议封装并传输AAC
【RTSP从零实践】05、实现最简单的传输AAC的RTSP服务器
【RTSP从零实践】06、实现最简单的同时传输H264、AAC的RTSP服务器
【RTSP从零实践】07、多播传输H264格式的RTP包(附带源码)
【RTSP从零实践】08、多播传输H264码流的RTSP服务器——最简单的实现例子(附带源码)
【RTSP从零实践】09、多播传输AAC格式的RTP包(附带源码)
【RTSP从零实践】10、多播传输AAC码流的RTSP服务器——最简单的实现例子(附带源码)
【RTSP从零实践】11、多播同时传输H264、AAC码流的RTSP服务器——最简单的实现例子(附带源码)
【RTSP从零实践】12、TCP传输H264格式RTP包(RTP_over_TCP)的RTSP服务器(附带源码)

在这里插入图片描述

🎄一、概述

上篇文章介绍了使用TCP协议传输H264格式的RTP包,这篇介绍的是使用TCP协议传输AAC格式的RTP包,下面主要介绍 RTP over TCP(RTSP) 的相关概念,然后直接看代码。


在这里插入图片描述

🎄二、RTP over TCP(RTSP) 介绍

✨2.1 RTP over TCP(RTSP) 相关概念

我们前面系列文章介绍过的rtsp服务器都是创建了一个TCP服务来处理RTSP协议,创建另一个UDP套接字来发送RTP包,这种方式就是 RTP over UDP。而RTP over TCP不单独建立一个UDP套接字去发送RTP包,而是利用处理RTSP协议的TCP套接字来发送RTP包的,所有有些资料也把这种方式称为RTP over RTSP

  • RTP over UDP:一个TCP套接字处理RTSP协议,另一个UDP套接字发送RTP包、RTCP包;
  • RTP over TCP(RTSP):一个TCP套接字处理RTSP协议、RTP包、RTCP包。

✨2.2 怎么区分 RTSP包、RTP包、RTCP包

如上面所说,我们复用发送RTSP交互的socket来发送RTP包和RTCP信息,那么对于客户端来说,如何区分这三种数据呢?

我们将这三个分为两类,一类是RTSP,一类是RTP、RTCP

发送RTSP信息的情况没有变化,还是更以前一样的方式

发送RTP、RTCP包,在每个包前面都加上四个字节,这四个字节解释如下:

字节描述
第一个字节字符'$',表示这个包是RTP包 或 RTCP包
第二个字节通道号channel,用于区分RTP包 或 RTCP包
第三、四个字节表示RTP包的大小

使用TCP协议传输的RTP包和RTCP包,第一个字节固定为$字符,第二字节的channel是在RTSP服务器处理的SETUP过程中,客户端发送给服务端的。

所以,使用TCP协议传输的RTP包结构如下:
在这里插入图片描述


✨2.3 RTP包封装代码

在RTP包起始位置增加4个字节的数据:

struct RtpPacket
{char header[4];struct RtpHeader rtpHeader;uint8_t payload[0];
};

在发送RTP包前,是这样填写这4个字节:

rtpPacket->header[0] = '$';
rtpPacket->header[1] = rtpChannel;
rtpPacket->header[2] = ((dataSize+RTP_HEADER_SIZE) & 0xFF00 ) >> 8;
rtpPacket->header[3] = (dataSize+RTP_HEADER_SIZE) & 0xFF;

在这里插入图片描述

🎄三、RTP_over_TCP的RTSP服务端源码

1、aacReader.h

/*** @file aacReader.h* @author : https://blog.csdn.net/wkd_007* @brief * @version 0.1* @date 2025-06-30* * @copyright Copyright (c) 2025* */
#ifndef	__AAC_READER_H__
#define __AAC_READER_H__#include <stdio.h>#define ADTS_HEADER_LEN	(7)typedef struct
{int frame_len;                //! unsigned char *pFrameBuf;     //! 
} AACFrame_t;typedef struct AACReaderInfo_s
{FILE *pFileFd;
}AACReaderInfo_t;int AAC_FileOpen(char *fileName, AACReaderInfo_t *pAACInfo);
int AAC_FileClose(AACReaderInfo_t *pAACInfo);
int AAC_GetADTSFrame(AACFrame_t *pAACFrame, const AACReaderInfo_t *pAACInfo);
int AAC_IsEndOfFile(const AACReaderInfo_t *pAACInfo);
void AAC_SeekFile(const AACReaderInfo_t *pAACInfo);#endif 	// __AAC_READER_H__

2、aacReader.c

/*** @file aacReader.c* @author : https://blog.csdn.net/wkd_007* @brief * @version 0.1* @date 2025-06-30* * @copyright Copyright (c) 2025* */
#include <stdlib.h>
#include <string.h>
#include "aacReader.h"#define MAX_FRAME_LEN (1024*1024)	// Ò»Ö¡Êý¾Ý×î´ó×Ö½ÚÊý
#define MAX_SYNCCODE_LEN    (3)     // ͬ²½Âë×Ö½Ú¸öÊý 2025-05-21 17:45:06static int findSyncCode_0xFFF(unsigned char *Buf, int *size)
{if((Buf[0] == 0xff) && ((Buf[1] & 0xf0) == 0xf0) )//0xFF F£¬Ç°12bit¶¼Îª1 2025-05-21 17:46:57{*size |= ((Buf[3] & 0x03) <<11);     //high 2 bit*size |= Buf[4]<<3;                //middle 8 bit*size |= ((Buf[5] & 0xe0)>>5);        //low 3bitreturn 1;}return 0;
}int AAC_FileOpen(char *fileName, AACReaderInfo_t *pAACInfo)
{pAACInfo->pFileFd = fopen(fileName, "rb+");if (pAACInfo->pFileFd==NULL){printf("[%s %d]Open file error\n",__FILE__,__LINE__);return -1;}return 0;
}int AAC_FileClose(AACReaderInfo_t *pAACInfo)
{if (pAACInfo->pFileFd != NULL) {fclose(pAACInfo->pFileFd);pAACInfo->pFileFd = NULL;}return 0;
}int AAC_IsEndOfFile(const AACReaderInfo_t *pAACInfo)
{return feof(pAACInfo->pFileFd);
}void AAC_SeekFile(const AACReaderInfo_t *pAACInfo)
{fseek(pAACInfo->pFileFd,0,SEEK_SET);
}/*** @brief * * @param pAACFrame :Êä³ö²ÎÊý£¬Ê¹Óúó pAACInfo->pFrameBuf ÐèÒªfree* @param pAACInfo * @return int */
int AAC_GetADTSFrame(AACFrame_t *pAACFrame, const AACReaderInfo_t *pAACInfo)
{int rewind = 0;if (pAACInfo->pFileFd==NULL){printf("[%s %d]pFileFd error\n",__FILE__,__LINE__);return -1;}// 1.ÏȶÁÈ¡ADTSÖ¡Í·(7¸ö×Ö½Ú)unsigned char* pFrame = (unsigned char*)malloc(MAX_FRAME_LEN);int readLen = fread(pFrame, 1, ADTS_HEADER_LEN, pAACInfo->pFileFd);if(readLen <= 0){printf("[%s %d]fread error readLen=%d\n",__FILE__,__LINE__,readLen);free(pFrame);return -1;}// 2.²éÕÒµ±Ç°Ö¡Í¬²½Â룬»ñȡ֡³¤¶Èint i=0;int size = 0;for(; i<readLen-MAX_SYNCCODE_LEN; i++){if(!findSyncCode_0xFFF(&pFrame[i], &size)){continue;}else{break;}}if(i!=0)	// ²»ÊÇÖ¡¿ªÍ·£¬Æ«ÒƵ½Ö¡¿ªÍ·ÖØÐ¶Á{printf("[%s %d]synccode error, i=%d\n",__FILE__,__LINE__,i);free(pFrame);rewind = (-(readLen-i));fseek (pAACInfo->pFileFd, rewind, SEEK_CUR);return -1;}// 3.¶ÁÈ¡ADTSÖ¡Êý¾Ý 2025-05-22 21:44:39readLen = fread(pFrame+ADTS_HEADER_LEN, 1, size-ADTS_HEADER_LEN, pAACInfo->pFileFd);if(readLen <= 0){printf("[%s %d]fread error\n",__FILE__,__LINE__);free(pFrame);return -1;}// 4.ÌîÊý¾ÝpAACFrame->frame_len = size;pAACFrame->pFrameBuf = pFrame;return pAACFrame->frame_len;
}

3、tcp_rtp.h

#ifndef _RTP_H_
#define _RTP_H_
#include <stdint.h>#define RTP_VESION              2#define RTP_PAYLOAD_TYPE_H264   96
#define RTP_PAYLOAD_TYPE_AAC    97#define RTP_HEADER_SIZE         12
#define RTP_MAX_PKT_SIZE        1400/***    0                   1                   2                   3*    7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0*   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*   |V=2|P|X|  CC   |M|     PT      |       sequence number         |*   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*   |                           timestamp                           |*   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*   |           synchronization source (SSRC) identifier            |*   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+*   |            contributing source (CSRC) identifiers             |*   :                             ....                              :*   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+**/
struct RtpHeader
{/* byte 0 */uint8_t csrcLen:4;uint8_t extension:1;uint8_t padding:1;uint8_t version:2;/* byte 1 */uint8_t payloadType:7;uint8_t marker:1;/* bytes 2,3 */uint16_t seq;/* bytes 4-7 */uint32_t timestamp;/* bytes 8-11 */uint32_t ssrc;
};struct RtpPacket
{char header[4];struct RtpHeader rtpHeader;uint8_t payload[0];
};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);
int rtpSendPacket(int socket, uint8_t rtpChannel, struct RtpPacket* rtpPacket, uint32_t dataSize);#endif //_RTP_H_

4、tcp_rtp.c

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <arpa/inet.h>#include "tcp_rtp.h"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;
}int rtpSendPacket(int socket, uint8_t rtpChannel, struct RtpPacket* rtpPacket, uint32_t dataSize)
{int ret;rtpPacket->header[0] = '$';rtpPacket->header[1] = rtpChannel;rtpPacket->header[2] = ((dataSize+RTP_HEADER_SIZE) & 0xFF00 ) >> 8;rtpPacket->header[3] = (dataSize+RTP_HEADER_SIZE) & 0xFF;rtpPacket->rtpHeader.seq = htons(rtpPacket->rtpHeader.seq);rtpPacket->rtpHeader.timestamp = htonl(rtpPacket->rtpHeader.timestamp);rtpPacket->rtpHeader.ssrc = htonl(rtpPacket->rtpHeader.ssrc);ret = send(socket, (void*)rtpPacket, dataSize+RTP_HEADER_SIZE+4, 0);rtpPacket->rtpHeader.seq = ntohs(rtpPacket->rtpHeader.seq);rtpPacket->rtpHeader.timestamp = ntohl(rtpPacket->rtpHeader.timestamp);rtpPacket->rtpHeader.ssrc = ntohl(rtpPacket->rtpHeader.ssrc);return ret;
}

5、rtsp_aac_tcp_main.c

/*** @file rtsp_aac_tcp_main.c* @author : https://blog.csdn.net/wkd_007* @brief * @version 0.1* @date 2025-07-16* * @copyright Copyright (c) 2025* */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>#include "tcp_rtp.h"
#include "aacReader.h"#define AAC_FILE_NAME   "test.aac"#define RTSP_PORT       8554
#define MAX_CLIENTS     5
#define SESSION_ID      10086001
#define SESSION_TIMEOUT 60typedef struct
{int   rtpSendFd;int   rtpPort;int   rtpChannel;int   bPlayFlag; // 播放标志char *cliIp;
} RTP_Send_t;typedef enum
{RTP_NULL,RTP_PLAY,RTP_PLAYING,RTP_STOP,
} RTP_PLAY_STATE;static int createUdpSocket()
{int fd = socket(AF_INET, SOCK_DGRAM, 0);if (fd < 0)return -1;int on = 1;setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));return fd;
}static int rtpSendAACFrame(int socket, int rtpChannel,struct RtpPacket *rtpPacket, uint8_t *frame, uint32_t frameSize)
{int ret;rtpPacket->payload[0] = 0x00;rtpPacket->payload[1] = 0x10;rtpPacket->payload[2] = (frameSize & 0x1FE0) >> 5; // 高8位rtpPacket->payload[3] = (frameSize & 0x1F) << 3;   // 低5位memcpy(rtpPacket->payload + 4, frame, frameSize);ret = rtpSendPacket(socket, rtpChannel, rtpPacket, frameSize + 4);if (ret < 0){printf("failed to send rtp packet\n");return -1;}rtpPacket->rtpHeader.seq++;return 0;
}void *sendRtp(void *arg)
{RTP_Send_t *pRtpSend    = (RTP_Send_t *)arg;int         rtp_send_fd = pRtpSend->rtpSendFd;int         rtpChannel  = pRtpSend->rtpChannel;struct RtpPacket *rtpPacket = (struct RtpPacket *)malloc(sizeof(struct RtpPacket) + 1500);rtpHeaderInit(rtpPacket, 0, 0, 0, RTP_VESION, RTP_PAYLOAD_TYPE_AAC, 1, 0, 0, 0x32411);// aacAACReaderInfo_t aacInfo;if (AAC_FileOpen(AAC_FILE_NAME, &aacInfo) < 0){printf("failed to open %s\n", AAC_FILE_NAME);return NULL;}while (pRtpSend->bPlayFlag){if (!AAC_IsEndOfFile(&aacInfo)){AACFrame_t aacFrame;memset(&aacFrame, 0, sizeof(aacFrame));AAC_GetADTSFrame(&aacFrame, &aacInfo);if (aacFrame.pFrameBuf != NULL){// printf("rtpSendAACFrame\n");rtpSendAACFrame(rtp_send_fd, rtpChannel, rtpPacket,aacFrame.pFrameBuf + ADTS_HEADER_LEN, aacFrame.frame_len - ADTS_HEADER_LEN);free(aacFrame.pFrameBuf);/** 如果采样频率是48000* 一般AAC每个1024个采样为一帧* 所以一秒就有 48000 / 1024 = 46帧* 时间增量就是 48000 / 46 = 1043* 一帧的时间为 1000ms / 46 = 21ms*/rtpPacket->rtpHeader.timestamp += 1043;usleep(21 * 1000);}else{printf("warning SeekFile\n");AAC_SeekFile(&aacInfo);}}}free(rtpPacket);AAC_FileClose(&aacInfo);return NULL;
}// 解析RTSP请求
void rtsp_request_parse(char *buffer, char *method, char *url, int *cseq, int *pRtpChannel)
{char *line = strtok(buffer, "\r\n");sscanf(line, "%s %s RTSP/1.0", method, url);while ((line = strtok(NULL, "\r\n")) != NULL){if (strncmp(line, "CSeq:", 5) == 0){sscanf(line, "CSeq: %d", cseq);}char *pInterleaved = strstr(line, "interleaved=");if (pInterleaved != NULL){int rtcpChn = 0;sscanf(pInterleaved, "interleaved=%d-%d", pRtpChannel, &rtcpChn);// printf("rtpPort: %d-%d\n",*pRtpChannel, rtcpChn);}}
}// 生成SDP描述
const char *generate_sdp()
{return "v=0\r\n""o=- 0 0 IN IP4 0.0.0.0\r\n""s=Example Stream\r\n""t=0 0\r\n""m=audio 0 RTP/AVP 97\r\n""a=rtpmap:97 mpeg4-generic/48000/2\r\n""a=fmtp:97 SizeLength=13;\r\n""a=control:streamid=0\r\n";
}void rtsp_handle_OPTION(char *response, int cseq)
{sprintf(response,"RTSP/1.0 200 OK\r\n""CSeq: %d\r\n""Public: OPTIONS, DESCRIBE, SETUP, PLAY, TEARDOWN\r\n\r\n",cseq);
}static void rtsp_handle_DESCRIBE(char *response, int cseq)
{sprintf(response,"RTSP/1.0 200 OK\r\n""CSeq: %d\r\n""Content-Type: application/sdp\r\n""Content-Length: %zu\r\n\r\n%s",cseq, strlen(generate_sdp()), generate_sdp());
}static void rtsp_handle_SETUP(char *response, int cseq, int rtpChannel)
{sprintf(response,"RTSP/1.0 200 OK\r\n""CSeq: %d\r\n""Session: %u; timeout=%d\r\n""Transport: RTP/AVP/TCP;unicast;interleaved=%hhu-%hhu\r\n\r\n",cseq, SESSION_ID, SESSION_TIMEOUT, rtpChannel, rtpChannel + 1);
}static void rtsp_handle_PLAY(char *response, int cseq)
{sprintf(response,"RTSP/1.0 200 OK\r\n""CSeq: %d\r\n""Session: %u; timeout=%d\r\n""Range: npt=0.000-\r\n\r\n",cseq, SESSION_ID, SESSION_TIMEOUT);
}static void rtsp_handle_TEARDOWN(char *response, int cseq)
{sprintf(response,"RTSP/1.0 200 OK\r\n""CSeq: %d\r\n""Session: %d; timeout=%d\r\n\r\n",cseq, SESSION_ID, SESSION_TIMEOUT);
}// 处理客户端连接
int handle_client(int cli_fd, char *cli_ip)
{int           client_sock  = cli_fd;char          buffer[1024] = {0};int           cseq         = 0;int           rtpChn       = 0;unsigned char bSendFlag    = RTP_NULL;RTP_Send_t    rtpSend;pthread_t     thread_id;while (1){memset(buffer, 0, sizeof(buffer));int len = read(client_sock, buffer, sizeof(buffer) - 1);if (len <= 0)break;printf("C->S [%s]\n\n", buffer);char method[16] = {0};char url[128]   = {0};rtsp_request_parse(buffer, method, url, &cseq, &rtpChn);char response[1024] = {0}; // 构造响应if (strcmp(method, "OPTIONS") == 0){rtsp_handle_OPTION(response, cseq);}else if (strcmp(method, "DESCRIBE") == 0){rtsp_handle_DESCRIBE(response, cseq);}else if (strcmp(method, "SETUP") == 0){rtsp_handle_SETUP(response, cseq, rtpChn);}else if (strcmp(method, "PLAY") == 0){rtsp_handle_PLAY(response, cseq);bSendFlag = RTP_PLAY;}else if (strcmp(method, "TEARDOWN") == 0){rtsp_handle_TEARDOWN(response, cseq);bSendFlag = RTP_STOP;}else{snprintf(response, sizeof(response),"RTSP/1.0 501 Not Implemented\r\nCSeq: %d\r\n\r\n", cseq);}write(client_sock, response, strlen(response));printf("S->C [%s]\n\n", response);if (bSendFlag == RTP_PLAY) // PLAY{rtpSend.rtpSendFd  = cli_fd;rtpSend.rtpPort    = 0;rtpSend.rtpChannel = rtpChn;rtpSend.cliIp      = NULL;rtpSend.bPlayFlag  = 1;// 这里不使用线程的话,会一直无法处理 client_sock 发过来的 OPTION 消息,导致播放出问题if (pthread_create(&thread_id, NULL, (void *)sendRtp, (void *)&rtpSend) < 0){perror("pthread_create");}bSendFlag = RTP_PLAYING;}if (bSendFlag == RTP_STOP) // TEARDOWN{rtpSend.bPlayFlag = 0;pthread_join(thread_id); // 等待线程结束bSendFlag = RTP_NULL;break;}}printf("close ip=[%s] fd=[%d]\n", cli_ip, client_sock);close(client_sock);return 0;
}int main(int argc, char *argv[])
{int                server_fd, client_fd;struct sockaddr_in address;int                opt     = 1;socklen_t          addrlen = sizeof(address);// 创建套接字if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0){perror("socket failed");return -1;}// 设置套接字选项if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))){perror("setsockopt");return -1;}address.sin_family      = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port        = htons(RTSP_PORT);// 绑定端口if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0){perror("bind failed");return -1;}// 开始监听if (listen(server_fd, MAX_CLIENTS) < 0){perror("listen");return -1;}printf("RTSP Server listening on port %d\n", RTSP_PORT);// 主循环接受连接,目前处理一个客户端while (1){char cli_ip[40] = {0};if ((client_fd = accept(server_fd, (struct sockaddr *)&address, &addrlen)) < 0){perror("accept");return -1;}strncpy(cli_ip, inet_ntoa(address.sin_addr), sizeof(cli_ip));printf("handle cliend [%s]\n", cli_ip);handle_client(client_fd, cli_ip);}return 0;
}

首先设置一下VLC,工具->偏好设置->输入/编解码器,勾选如下图的RTP over RTSP(TCP)
在这里插入图片描述

将上面代码保存在同一个目录后,并且在同目录里放一个.aac文件,然后运行 gcc *.c -lpthread 编译,再执行./a.out运行程序,下面是我运行的过程:
在这里插入图片描述


在这里插入图片描述

🎄四、总结

👉本文介绍了RTP_over_TCP的一些概念,以及TCP传输AAC格式的RTP包的RTSP服务器实现的步骤和细节,最后提供了实现的源代码,帮助读者学习理解。

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

http://www.xdnf.cn/news/1131769.html

相关文章:

  • Node.js Process Events 深入全面讲解
  • 【AI智能体】Dify 基于知识库搭建智能客服问答应用详解
  • 壹脉销客AI电子名片源码核心架构
  • SSM框架学习——day3
  • 【JVM】内存分配与回收原则
  • RAG优化秘籍:基于Tablestore的知识库答疑系统架构设计
  • 【前端】HTML语义标签的作用与实践
  • 产品经理笔试考试回忆集(2025湖南某国企)
  • 智慧公厕系统打造洁净、安全的公共空间
  • 搭建云途YTM32B1MD1芯片VSCODE+GCC + Nijia + Cmake+Jlink开发环境
  • WebStorm vs VSCode:前端圈的「豆腐脑甜咸之争」
  • vscode连接不上云服务解决
  • 万字长文解析 OneCode3.0 AI创新设计
  • [Linux入门] Linux 账号和权限管理入门:从基础到实践
  • 【Java入门到精通】(五)初识MySql数据库
  • beautiful-react-hooks库——入门实践常用hook详解
  • [Matlab]使用系统辨识应用程序辨识线性模型
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 微博类别信息爬取
  • CoreNext主题源码 V1.7.1开心版 WordPress轻量高性能主题
  • 访问者设计模式
  • Ray集群部署与维护
  • pytorch | minist手写数据集
  • 基于Hadoop与LightFM的美妆推荐系统设计与实现
  • 前端网络性能优化
  • STM32 GPIO的八种工作模式
  • Fluent许可问题常见解答
  • 分布式弹性故障处理框架——Polly(1)
  • JobSet:Kubernetes 分布式任务编排的统一解决方案
  • 为什么要用erc165识别erc721或erc1155
  • LIN通信协议入门