• T31开发笔记:librtmp编译测试


    若该文为原创文章,转载请注明原文出处

    编译librtmp库,及代码详解测试。

    一、硬件和开发环境

    1、硬件:T31X+SC5235 

    2、开发环境: ubuntu16.04-64bit

    3、编译器:mips-gcc540-glibc222-32bit-r3.3.0.tar.gz

    注:板子和和WIFI模块是某淘上淘的,使用的是RTL8188,使用的是USB接口,uboot和内核是自己裁剪移植的,内核默认自带WIFI驱动,所以不用移植可以直接使用。

    二、交叉编译

    在交叉编译之前,要确保交叉编译链安装正常。

    交叉编译librtmp需要编译zlib,openssl .

    1、编译zlib库

    1. 1、获取源码
    2. wget http://zlib.net/zlib-1.2.11
    3. 2、解压
    4. tar -vxf zlib-1.2.11
    5. 3、进入目录
    6. cd zlib
    7. 4、设置环境,输入以下命令
    8. CC=mips-linux-gnu-gcc ./configure --prefix=/usr/local
    9. 5、编译
    10. make
    11. 6、安装
    12. make install
    13. 执行成功后会在/usr/local下生成库.

    2、编译openssl

    1. 1、下载源码
    2. get http://www.openssl.org/source/openssl-1.0.1u
    3. 2、解压
    4. tar -vxf openssl-1.0.1u
    5. 3、进入openssl目录
    6. cd openssl-1.0.1.u
    7. 4、设置环境,输入以下命令
    8. CC=mips-linux-gnu-gcc ./config no-asm shared --prefix=/usr/local
    9. 5、编译
    10. make
    11. 6、安装
    12. make install

    3、编译librtmp

    1. 1、下载源码
    2. git clone git://git.ffmpeg.org/rtmpdump
    3. 2、修改Makefile
    4. 1)、主要修改:
    5. CC=$(CROSS_COMPILE)gcc
    6. LD=$(CROSS_COMPILE)ld
    7. AR=$(CROSS_COMPILE)ar
    8. 修改成:
    9. CC=mips-linux-gnu-gcc
    10. LD=mips-linux-gnu-ld
    11. AR=mips-linux-gnu-ar
    12. 2)、修改CRYPTO=OPENSSL
    13. 修改为:
    14. CRYPTO=/usr/local/bin
    15. 3、编译
    16. make
    17. 4、安装
    18. make install

    三、代码解析

    编译代码需要用到的库,本人在T31上使用的是静态库,可以自行改成动态库,以减少编译文件的大小 。

    编译所需的库有:librtmp.a、libssl.a、libcrypto.a、libz.a

    代码:

    1. /*!
    2. *****************************************************************************
    3. *
    4. * Copyright ? 2017-2018 yifeng. All Rights Reserved.
    5. *
    6. * \file main.c
    7. * \author yifeng
    8. * \version 1.0
    9. * \date 2022年3月3日
    10. * \brief rtmp测试代码
    11. *
    12. *----------------------------------------------------------------------------
    13. * \attention
    14. *
    15. *
    16. *****************************************************************************
    17. */
    18. /*****************************************************************************
    19. change history:
    20. 1.date : 202233
    21. author: yifeng
    22. change: create file
    23. *****************************************************************************/
    24. #include <stdio.h>
    25. #include <stdlib.h>
    26. #include <string.h>
    27. #include <fcntl.h>
    28. #include <limits.h>
    29. #include <sys/types.h>
    30. #include <sys/stat.h>
    31. #include <arpa/inet.h>
    32. #include <sys/select.h>
    33. #include <sys/time.h>
    34. #include <time.h>
    35. #include <unistd.h>
    36. #include <signal.h>
    37. #include <sys/ioctl.h>
    38. #include <net/if.h>
    39. #include <netinet/in.h>
    40. #include <pthread.h>
    41. #include <stdbool.h>
    42. /* 环形队列头文件 */
    43. #include "ringfifo.h"
    44. #include "faac/faac.h"
    45. #include "xiecc_rtmp.h"
    46. #include <imp/imp_audio.h>
    47. #include <imp/imp_log.h>
    48. #define AAC_ADTS_HEADER_SIZE 7
    49. static uint32_t find_start_code(uint8_t *buf, uint32_t zeros_in_startcode)
    50. {
    51. uint32_t info;
    52. uint32_t i;
    53. info = 1;
    54. if ((info = (buf[zeros_in_startcode] != 1)? 0: 1) == 0)
    55. return 0;
    56. for (i = 0; i < zeros_in_startcode; i++)
    57. if (buf[i] != 0)
    58. {
    59. info = 0;
    60. break;
    61. };
    62. return info;
    63. }
    64. uint8_t * get_nal(uint32_t *len, uint8_t **offset, uint8_t *start, uint32_t total)
    65. {
    66. uint32_t info;
    67. uint8_t *q ;
    68. uint8_t *p = *offset;
    69. *len = 0;
    70. while(1) {
    71. info = find_start_code(p, 3);
    72. if (info == 1)
    73. break;
    74. p++;
    75. if ((p - start) >= total)
    76. return NULL;
    77. }
    78. q = p + 4;
    79. p = q;
    80. while(1) {
    81. info = find_start_code(p, 3);
    82. if (info == 1)
    83. break;
    84. p++;
    85. if ((p - start) >= total)
    86. return NULL;
    87. }
    88. *len = (p - q);
    89. *offset = p;
    90. return q;
    91. }
    92. uint8_t *get_adts(uint32_t *len, uint8_t **offset, uint8_t *start, uint32_t total)
    93. {
    94. uint8_t *p = *offset;
    95. uint32_t frame_len_1;
    96. uint32_t frame_len_2;
    97. uint32_t frame_len_3;
    98. uint32_t frame_length;
    99. if (total < AAC_ADTS_HEADER_SIZE) {
    100. return NULL;
    101. }
    102. if ((p - start) >= total) {
    103. return NULL;
    104. }
    105. if (p[0] != 0xff) {
    106. return NULL;
    107. }
    108. if ((p[1] & 0xf0) != 0xf0) {
    109. return NULL;
    110. }
    111. frame_len_1 = p[3] & 0x03;
    112. frame_len_2 = p[4];
    113. frame_len_3 = (p[5] & 0xe0) >> 5;
    114. frame_length = (frame_len_1 << 11) | (frame_len_2 << 3) | frame_len_3;
    115. *offset = p + frame_length;
    116. *len = frame_length;
    117. return p;
    118. }
    119. /*!
    120. * \fn main
    121. * \brief 主函数
    122. *
    123. * \param [in] int argc #
    124. * \param [in] char *argv[] #
    125. *
    126. * \retval int
    127. */
    128. int main(int argc, char *argv[])
    129. {
    130. pthread_t id;
    131. pthread_t audio_id;
    132. char serverStrBuf[100];
    133. if(argc != 2)
    134. {
    135. printf("Usage: rtmp serverip -eg << rtmp 192.168.1.100 >>");
    136. return -1;
    137. }
    138. sprintf(serverStrBuf, "rtmp://%s/live/stream", argv[1]);
    139. printf("Server=%s\n", serverStrBuf);
    140. /* 初始化内存 */
    141. ringmalloc(384*1024);
    142. void*p = rtmp_sender_alloc(serverStrBuf);
    143. if(rtmp_sender_start_publish(p, 0, 0) != 0)
    144. {
    145. printf("connect %s failed\n", serverStrBuf);
    146. return -1;
    147. }
    148. int fd = open("cms.264", O_RDONLY);
    149. uint8_t * buf = malloc(3 *1024 * 1024);
    150. uint32_t total;
    151. total = read(fd, buf, (1024*1024 *3));
    152. close(fd);
    153. int aacfd = open("audiotest.aac", O_RDONLY);
    154. uint8_t * audio_buf = malloc(1 *1024 * 1024);
    155. uint32_t audio_total;
    156. audio_total = read(aacfd, audio_buf, (1024*1024 *3));
    157. close(aacfd);
    158. uint8_t *buf_offset = buf;
    159. uint8_t *audio_buf_offset = audio_buf;
    160. uint32_t len;
    161. uint32_t audio_len;
    162. uint8_t *p_video ;
    163. uint8_t *pp;
    164. uint8_t *p_audio;
    165. uint32_t audio_ts = 0;
    166. uint32_t ts = 0;
    167. uint32_t len_1;
    168. uint32_t len_2;
    169. while (1) {
    170. p_audio = get_adts(&audio_len, &audio_buf_offset, audio_buf, audio_total);
    171. if (p_audio == NULL){
    172. audio_buf_offset = audio_buf;
    173. continue;
    174. }
    175. rtmp_sender_write_audio_frame(p, p_audio, audio_len, audio_ts);
    176. p_video = get_nal(&len, &buf_offset, buf, total);
    177. if (p_video == NULL) {
    178. buf_offset = buf;
    179. continue;
    180. }
    181. printf("%x %d\n", p_video[0], len);
    182. if (p_video[0] == 0x67) {
    183. pp = get_nal(&len_1, &buf_offset, buf, total);
    184. printf("%x %d\n", pp[0], len_1);
    185. pp = get_nal(&len_2, &buf_offset, buf, total);
    186. printf("%x %d\n", pp[0], len_2);
    187. uint8_t temp = len + len_1 + len_2 + 12;
    188. printf("temp %d\n", temp);
    189. rtmp_sender_write_video_frame(p, p_video - 4, temp, ts, 0);
    190. }
    191. else
    192. rtmp_sender_write_video_frame(p, p_video - 4, len + 4, ts, 0);
    193. ts += 50;
    194. audio_ts += 50;
    195. usleep(50 * 1000);
    196. }
    197. return 0;
    198. }

    代码功能主要是读取h264和AAC文件,封装后,通过rtmp传到服务器,服务器可以用SRS,nginx等,具体服务器搭建不在演示。

    把代码编译成可执行文件,运行测试。

    四、总结

    1、主要是测试和了解下rtmp的推流方式,由于硬件显示,不测试拉流。

    如有侵权,请及时联系博主删除,VX:18750903063

  • 相关阅读:
    WslRegisterDistribution failed with error: 0x800701bc
    npm install node-sass失败解决办法
    《计算机体系结构量化研究方法第六版》1.2 计算机的分类
    微信小程序封装请求API-promise格式
    UI设计工具都哪些常用的,推荐这5款
    多线程&并发篇---第七篇
    基于51单片机八路电压表采集系统波形发生器
    it监控系统可以电脑吗?有什么效果
    【操作系统】读写锁实现&&读写锁原理(亲测可用)
    【每日刷题】Day63
  • 原文地址:https://blog.csdn.net/weixin_38807927/article/details/127817667