从零开始写一个RTSP服务器(五)RTP传输AAC

从零开始写一个RTSP服务器系列

★我的开源项目-RtspServer

从零开始写一个RTSP服务器(一)RTSP协议讲解

从零开始写一个RTSP服务器(二)RTSP协议的实现

从零开始写一个RTSP服务器(三)RTP传输H.264

从零开始写一个RTSP服务器(四)一个传输H.264的RTSP服务器

从零开始写一个RTSP服务器(五)RTP传输AAC

从零开始写一个RTSP服务器(六)一个传输AAC的RTSP服务器

从零开始写一个RTSP服务器(七)多播传输RTP包

从零开始写一个RTSP服务器(八)一个多播的RTSP服务器

从零开始写一个RTSP服务器(九)一个RTP OVER RTSP/TCP的RTSP服务器

从零开始写一个RTSP服务器(五)RTP传输AAC

文章目录

  • 从零开始写一个RTSP服务器(五)RTP传输AAC
    • 一、RTP封装
      • 1.1 RTP数据结构
      • 1.2 源码
        • rtp.h
        • rtp.c
    • 二、AAC的RTP打包
      • 2.1 AAC格式
      • 2.2 AAC的RTP打包方式
      • 2.3 AAC RTP包的时间戳计算
      • 2.4 源码
        • rtp_aac.c
    • 三、AAC的sdp媒体描述
    • 四、测试

本文实现目标:使用vlc打开sdp文件可以听到音频

一、RTP封装

这一部分在前面的文章已经介绍过,放到这里只是怕你没有看前面的文章

1.1 RTP数据结构

RTP包格式前面已经比较详细的介绍过,参考从零开始写一个RTSP服务器(一)不一样的RTSP协议讲解

看一张RTP头的格式图回忆一下

从零开始写一个RTSP服务器(五)RTP传输AAC_第1张图片

每个RTP包都包含这样一个RTP头部和RTP载荷,为了方便,我将这个头部封装成一个结构体,还有发送包封装成一个函数,下面来看一看

  • RTP头结构体
/*
 * 作者:_JT_
 * 博客:https://blog.csdn.net/weixin_42462202
 */

  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;
  };

其中的:n是一种位表示法,这个结构体跟RTP的头部一一对应

  • RTP的发包函数

    RTP包

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

    这是我封装的一个RTP包,包含一个RTP头部和RTP载荷,uint8_t payload[0]并不占用空间,它表示rtp头部接下来紧跟着的地址

    RTP的发包函数

  /*
   * 函数功能:发送RTP包
   * 参数 socket:表示本机的udp套接字
   * 参数 ip:表示目的ip地址
   * 参数 port:表示目的的端口号
   * 参数 rtpPacket:表示rtp包
   * 参数 dataSize:表示rtp包中载荷的大小
   * 放回值:发送字节数
   */
  int rtpSendPacket(int socket, char* ip, int16_t port, struct RtpPacket* rtpPacket, uint32_t dataSize)
  {
   
      struct sockaddr_in addr;
      int ret;
  
      addr.sin_family = AF_INET;
      addr.sin_port = htons(port);
      addr.sin_addr.s_addr = inet_addr(ip);
  
      rtpPacket->rtpHeader.seq = htons(rtpPacket->rtpHeader.seq);
      rtpPacket->rtpHeader.timestamp = htonl(rtpPacket->rtpHeader.timestamp);
      rtpPacket->rtpHeader.ssrc = htonl(rtpPacket->rtpHeader.ssrc);
  
      ret = sendto(socket, (void*)rtpPacket, dataSize+RTP_HEADER_SIZE, 0,
                      (struct sockaddr*)&addr, sizeof(addr));
  
      rtpPacket->rtpHeader.seq = ntohs(rtpPacket->rtpHeader.seq);
      rtpPacket->rtpHeader.timestamp = ntohl(rtpPacket->rtpHeader.timestamp);
      rtpPacket->rtpHeader.ssrc = ntohl(rtpPacket->rtpHeader.ssrc);
  
      return ret;
  }

仔细看这个函数你应该可以看懂

我们设置好一个包之后,就会调用这个函数发送指定目标

这个函数中多处使用htons等函数,是因为RTP是采用网络字节序(大端模式),所以要将主机字节字节序转换为网络字节序

下面给出源码,rtp.hrtp.c,这两个文件在后面讲经常使用

1.2 源码

rtp.h
/*
 * 作者:_JT_
 * 博客:https://blog.csdn.net/weixin_42462202
 */

#ifndef _RTP_H_
#define _RTP_H_
#include 

#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
{

你可能感兴趣的:(从零开始写一个RTSP服务器(五)RTP传输AAC)