• 【无标题】


    工作流程:

    1)读取ADTS头(7字节),解析得到aac帧的信息(频率,声道,帧长度)

    2)读取aac原始数据块,使用RTP打包aac原始数据

      RTP打包h264码流时,由于h264数据长度不稳定,少则几字节,多则几千字节,所以RTP打包形式较多,需要根据大小决定是否进行分片。

      而AAC数据块长度不会像h264那样变化,一般稳定在几百字节,所以它的打包方式比较单一。

    打包方式如下

    RTP包 = rtpheader(12字节) + 载荷标识(4字节)+ AAC数据块

    载荷标识(4字节):

    1. // 前两个字节值固定,第三个字节和第四个字节保存AAC Data的大小
    2. // frameSize = adts.length - 7
    3. rtpPacket->payload[0] = 0x00;
    4. rtpPacket->payload[1] = 0x10;
    5. rtpPacket->payload[2] = (frameSize & 0x1FE0) >> 5;
    6. rtpPacket->payload[3] = (frameSize & 0x1F) << 3;

    3)传输一个rtp包,并对序列号和时间戳操作

    对于rtpheader有一个要注意的点: 传输h264时marker位为0,传输aac时marker位置1

    4)回到步骤1,传输下一帧AAC

    代码表达:

    0)protocol.h

    1. #ifndef __PROTOCOL_H
    2. #define __PROTOCOL_H
    3. // 相关协议的约定
    4. typedef struct {
    5. char *ip;
    6. int tcp_port;
    7. int rtp_port;
    8. int rtcp_port;
    9. } client_t;
    10. // 在rtsp+rtp传输时,客户端的RTP端口不能指定,需要从SETUP请求中获取
    11. // 单独用于RTP_H264/AAC测试
    12. #define RTP_CLIENT_IP "192.168.102.215"
    13. #define RTP_CLIENT_PORT 2018
    14. // 测试文件的路径
    15. #define AAC_FILE "/home/zhou/ffmpeg/testvideo/001.aac"
    16. #endif

    本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

    1)rtp_aac.h

    1. #ifndef __RTP_AAC_H
    2. #define __RTP_AAC_H
    3. #include "protocol.h"
    4. /*
    5. * @func : RTP打包传输AAC码流
    6. * @param:
    7. * sockfd --- UDP socket
    8. * client --- client->ip, client->rtp_port
    9. * path --- AAC_FILE
    10. */
    11. int rtp_play_aac(int sockfd, client_t *client, const char *path);
    12. /*
    13. * 例程模块测试:
    14. * Linux下直接调用rtp_aac_test(AAC_FILE);
    15. * Windows下创建rtp_test.sdp文件,用VLC打开。
    16. */
    17. /* rtp_test.sdp文件:
    18. *
    19. * m=audio 2018 RTP/AVP 97
    20. * a=rtpmap:97 mpeg4-generic/44100/2
    21. * a=fmtp:97 SizeLength=13;
    22. * c=IN IP4 127.0.0.1
    23. */
    24. int rtp_aac_test(const char *file);
    25. #endif

     2)rtp_aac.c

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. #include <unistd.h>
    5. #include "sock.h"
    6. #include "rtp.h"
    7. #include "rtp_aac.h"
    8. struct adts_header {
    9. char profile[8];
    10. int channel;
    11. int freq;
    12. int length; // 一帧aac长度,包括adts头和原始流
    13. };
    14. static int parser_adts(struct adts_header *adts, uint8_t header[]) {
    15. if ((header[0] != 0xFF) && ((header[1] & 0xF0) != 0xF0)) {
    16. return -1; // syncword(12bits)不是0XFFF
    17. }
    18. memset(adts, 0, sizeof(struct adts_header));
    19. // profile 17:18位, 取第3字节高2
    20. int pro = ((unsigned int)header[2] & 0xC0) >> 6;
    21. switch (pro) {
    22. case 0: strcpy(adts->profile, "Main");break;
    23. case 1: strcpy(adts->profile, "LC");break;
    24. case 2: strcpy(adts->profile, "SSR");break;
    25. default: strcpy(adts->profile, "Unknown");break;
    26. };
    27. // frequency_idx 19:23位,取第3字节中间4
    28. int freq_index = ((unsigned int)header[2] & 0x3C) >> 2;
    29. switch (freq_index) {
    30. //...
    31. case 3: adts->freq = 48000; break;
    32. case 4: adts->freq = 44100; break;
    33. default: adts->freq = 0; break;
    34. }
    35. adts->channel = ((unsigned int)header[2] & 0x01) << 2;
    36. adts->channel += ((unsigned int)header[3] & 0xC0) >> 6;
    37. // aac_frame_length 30:4213位) header[3]后2+header[4]+header[5]前3
    38. int size = ((unsigned int)header[5] & 0XE0) >> 5; // low 3bits
    39. size += header[4] << 3; // mid 8bits
    40. size += (header[3] & 0x03) << 11; // high 2bits
    41. adts->length = size;
    42. return 0;
    43. }
    44. static int rtp_send_acc_frame(int sockfd, client_t *client, uint8_t *data, int datalen, struct rtp_packet *packet) {
    45. packet->payload[0] = 0x00;
    46. packet->payload[1] = 0x10;
    47. packet->payload[2] = (datalen & 0x1fe0) >> 5;
    48. packet->payload[3] = (datalen & 0x1f) << 3;
    49. memcpy(packet->payload+4, data, datalen);
    50. int ret = rtp_send_packet(sockfd, client->ip, client->rtp_port, \
    51. packet, RTP_HEADER_SIZE+4+datalen);
    52. if (ret < 0) return -1;
    53. packet->header.seq++;
    54. packet->header.timestamp += 1024;
    55. return 0;
    56. }
    57. int rtp_play_aac(int sockfd, client_t *client, const char *path) {
    58. struct rtp_packet *packet = (struct rtp_packet *)malloc(RTP_PACKET_SIZE);
    59. rtp_header_init(&packet->header, RTP_PAYLOAD_TYPE_AAC, 1, 0, 0, 0x32411);
    60. FILE *fp = fopen(path, "r");
    61. if (fp == NULL) {
    62. return -1;
    63. }
    64. uint8_t header[7];
    65. struct adts_header adts;
    66. uint8_t *data = malloc(8*1024);
    67. int ret = 0;
    68. while (1) {
    69. ret = fread(header, 1, 7, fp);
    70. if (ret <= 0) {
    71. break;
    72. }
    73. if (parser_adts(&adts, header) < 0) {
    74. printf("failed parser_adts\n");
    75. break;
    76. }
    77. fread(data, 1, adts.length-7, fp);
    78. rtp_send_acc_frame(sockfd, client, data, adts.length-7, packet);
    79. //printf("packet seq:%d adts freq:%d length: %d\n",\
    80. packet->header.seq, adts.freq, adts.length);
    81. float fps = adts.freq / 1024.0;
    82. usleep(1000*1000 / (int)fps);
    83. }
    84. free(packet);
    85. free(data);
    86. fclose(fp);
    87. return 0;
    88. }
    89. int rtp_aac_test(const char *file)
    90. {
    91. int sockfd = create_udp_socket();
    92. if (sockfd < 0) {
    93. printf("failed to init socket\n");
    94. return -1;
    95. }
    96. client_t client;
    97. client.ip = strdup(RTP_CLIENT_IP);
    98. client.rtp_port = RTP_CLIENT_PORT;
    99. rtp_play_aac(sockfd, &client, file);
    100. close_socket(sockfd);
    101. return 0;
    102. }

     如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!

    本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

  • 相关阅读:
    2023_Spark_实验十七:导入招聘大数据(项目)
    SpringMVC入门宝典(四)SpringMVC注解(上)
    PMP 80个输入输出总结
    opencv基础-印度小哥
    Java 面试 知识清单
    基于Springboot的校园技能帮帮站的设计与实现
    Mysql 数据恢复逻辑 基于binlog redolog undolog
    噪声系数分析仪---TFN ZF9000A
    一次 Java log4j2 漏洞导致的生产问题
    超声检测技术(一)
  • 原文地址:https://blog.csdn.net/m0_60259116/article/details/127450554