luat_rtmp_push.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /**
  2. * @file luat_rtmp_push.h
  3. * @brief RTMP推流组件 - 基于lwip raw API实现
  4. * @author LuatOS Team
  5. *
  6. * 该组件实现了RTMP(Real Time Messaging Protocol)推流功能,
  7. * 支持将H.264视频流推送到RTMP服务器。
  8. *
  9. * 主要特性:
  10. * - 基于lwip raw socket API,适应嵌入式环境
  11. * - 支持自定义H.264帧来源,灵活的NALU帧注入
  12. * - 完整的RTMP握手和连接管理
  13. * - 支持FLV格式视频打包和发送
  14. * - C99语法,内存使用优化
  15. *
  16. * 调试说明:
  17. * - 在 luat_rtmp_push.c 中修改 RTMP_DEBUG_VERBOSE 宏来控制详细日志输出
  18. * - 设置为 1 开启详细调试信息,设置为 0 关闭(仅保留关键日志)
  19. */
  20. #ifndef __LUAT_RTMP_PUSH_H__
  21. #define __LUAT_RTMP_PUSH_H__
  22. #include "luat_base.h"
  23. #include "lwip/tcp.h"
  24. #include <stdint.h>
  25. #include <stddef.h>
  26. #include <stdbool.h>
  27. #ifdef __cplusplus
  28. extern "C" {
  29. #endif
  30. /* ======================== RTMP常量定义 ======================== */
  31. /** RTMP默认块大小(字节) - RTMP规范规定的默认值为128 */
  32. #define RTMP_DEFAULT_CHUNK_SIZE 128
  33. /** RTMP缓冲区大小(字节) - 需要足够大以容纳I帧 */
  34. #define RTMP_BUFFER_SIZE (512 * 1024)
  35. /** 发送帧队列最大字节数上限,超出将丢弃未发送帧(优先丢弃非关键帧) */
  36. #define RTMP_MAX_QUEUE_BYTES (1024 * 1024)
  37. /** RTMP握手数据大小(字节) */
  38. #define RTMP_HANDSHAKE_SIZE 1536
  39. /** RTMP命令超时时间(毫秒) */
  40. #define RTMP_CMD_TIMEOUT 5000
  41. /* ======================== 返回值定义 ======================== */
  42. /** 操作成功 */
  43. #define RTMP_OK 0
  44. /** 通用错误 */
  45. #define RTMP_ERR_FAILED (-1)
  46. /** 参数无效 */
  47. #define RTMP_ERR_INVALID_PARAM (-2)
  48. /** 内存不足 */
  49. #define RTMP_ERR_NO_MEMORY (-3)
  50. /** 连接错误 */
  51. #define RTMP_ERR_CONNECT_FAILED (-4)
  52. /** 握手失败 */
  53. #define RTMP_ERR_HANDSHAKE_FAILED (-5)
  54. /** 网络错误 */
  55. #define RTMP_ERR_NETWORK (-6)
  56. /** 超时 */
  57. #define RTMP_ERR_TIMEOUT (-7)
  58. /** 缓冲区溢出 */
  59. #define RTMP_ERR_BUFFER_OVERFLOW (-8)
  60. /* ======================== 数据类型定义 ======================== */
  61. /**
  62. * RTMP连接状态枚举
  63. */
  64. typedef enum {
  65. RTMP_STATE_IDLE = 0, /**< 空闲状态 */
  66. RTMP_STATE_CONNECTING = 1, /**< 正在连接 */
  67. RTMP_STATE_HANDSHAKING = 2, /**< 握手中 */
  68. RTMP_STATE_CONNECTED = 3, /**< 已连接 */
  69. RTMP_STATE_PUBLISHING = 4, /**< 正在推流 */
  70. RTMP_STATE_DISCONNECTING = 5, /**< 正在断开连接 */
  71. RTMP_STATE_ERROR = 6 /**< 错误状态 */
  72. } rtmp_state_t;
  73. /**
  74. * RTMP消息类型枚举
  75. */
  76. typedef enum {
  77. RTMP_MSG_SET_CHUNK_SIZE = 1, /**< 设置块大小 */
  78. RTMP_MSG_ABORT = 2, /**< 中止消息 */
  79. RTMP_MSG_BYTES_READ = 3, /**< 字节已读 */
  80. RTMP_MSG_CONTROL = 4, /**< 用户控制消息 */
  81. RTMP_MSG_SERVER_BW = 5, /**< 服务器带宽 */
  82. RTMP_MSG_CLIENT_BW = 6, /**< 客户端带宽 */
  83. RTMP_MSG_AUDIO = 8, /**< 音频数据 */
  84. RTMP_MSG_VIDEO = 9, /**< 视频数据 */
  85. RTMP_MSG_AMFDATAFILE = 15, /**< AMF数据 */
  86. RTMP_MSG_COMMAND = 20, /**< 命令(AMF0) */
  87. RTMP_MSG_EXTENDED_COMMAND = 17 /**< 扩展命令 */
  88. } rtmp_msg_type_t;
  89. /**
  90. * H.264 NALU类型枚举
  91. */
  92. typedef enum {
  93. NALU_TYPE_NON_IDR = 1, /**< 非IDR帧 */
  94. NALU_TYPE_IDR = 5, /**< IDR帧(关键帧) */
  95. NALU_TYPE_SEI = 6, /**< SEI(补充增强信息) */
  96. NALU_TYPE_SPS = 7, /**< SPS(序列参数集) */
  97. NALU_TYPE_PPS = 8, /**< PPS(图像参数集) */
  98. NALU_TYPE_AUD = 9 /**< AUD(访问单元分隔符) */
  99. } nalu_type_t;
  100. /**
  101. * H.264视频帧标签结构体
  102. * 用于描述FLV格式中的视频数据帧
  103. */
  104. typedef struct {
  105. uint8_t frame_type; /**< 帧类型: 1=关键帧, 2=普通帧 */
  106. uint8_t codec_id; /**< 编码器ID: 7=H.264 */
  107. uint32_t cts; /**< 时间戳偏移(ms) */
  108. uint8_t *data; /**< 视频数据指针 */
  109. uint32_t len; /**< 视频数据长度 */
  110. } video_tag_t;
  111. /**
  112. * RTMP推流统计信息结构体
  113. * 用于查询RTMP连接的实时统计数据
  114. */
  115. typedef struct {
  116. uint32_t bytes_sent; /**< 已发送的字节数 */
  117. uint32_t video_frames_sent; /**< 已发送的视频帧数 */
  118. uint32_t audio_frames_sent; /**< 已发送的音频帧数 */
  119. uint32_t connection_time; /**< 连接持续时间(毫秒) */
  120. uint32_t packets_sent; /**< 已发送的包数 */
  121. uint32_t last_video_timestamp; /**< 最后视频时间戳(毫秒) */
  122. uint32_t last_audio_timestamp; /**< 最后音频时间戳(毫秒) */
  123. } rtmp_stats_t;
  124. /**
  125. * RTMP推流上下文结构体
  126. * 管理单个RTMP连接的所有状态和缓冲区
  127. */
  128. typedef struct {
  129. /** ============ 连接信息 ============ */
  130. char *url; /**< RTMP服务器URL */
  131. char *host; /**< RTMP服务器主机名/IP地址 */
  132. char *app; /**< RTMP应用名 */
  133. char *stream; /**< 推流名 */
  134. char *auth; /**< 认证信息 */
  135. uint16_t port; /**< 连接端口 */
  136. /** ============ TCP连接状态 ============ */
  137. struct tcp_pcb *pcb; /**< lwip TCP控制块 */
  138. rtmp_state_t state; /**< 当前连接状态 */
  139. uint32_t last_activity_time; /**< 最后活动时间戳 */
  140. int handshake_state; /**< 握手状态: 0=发送C0C1, 1=等待S0S1, 2=发送C2, 3=完成 */
  141. /** ============ RTMP协议状态 ============ */
  142. uint32_t in_chunk_size; /**< 输入块大小 */
  143. uint32_t out_chunk_size; /**< 输出块大小 */
  144. uint32_t chunk_size; /**< 当前chunk大小(用于分块发送)*/
  145. uint32_t video_stream_id; /**< 视频流ID */
  146. uint32_t audio_stream_id; /**< 音频流ID */
  147. /** ============ 缓冲区管理 ============ */
  148. uint8_t *recv_buf; /**< 接收缓冲区 */
  149. uint32_t recv_buf_size; /**< 接收缓冲区大小 */
  150. uint32_t recv_pos; /**< 接收缓冲区写位置 */
  151. uint8_t *send_buf; /**< 发送缓冲区 */
  152. uint32_t send_buf_size; /**< 发送缓冲区大小 */
  153. uint32_t send_pos; /**< 发送缓冲区写位置 */
  154. /** ============ 帧发送队列 ============ */
  155. struct rtmp_frame_node *frame_head; /**< 待发送帧队列头 */
  156. struct rtmp_frame_node *frame_tail; /**< 待发送帧队列尾 */
  157. uint32_t frame_queue_bytes; /**< 队列占用的总字节数 */
  158. /** ============ 时间戳管理 ============ */
  159. uint32_t video_timestamp; /**< 当前视频时间戳(ms) */
  160. uint32_t audio_timestamp; /**< 当前音频时间戳(ms) */
  161. uint32_t base_timestamp; /**< 基准时间戳 */
  162. /** ============ 统计信息 ============ */
  163. uint32_t packets_sent; /**< 已发送的包数 */
  164. uint32_t bytes_sent; /**< 已发送的字节数 */
  165. uint32_t command_id; /**< 当前命令ID */
  166. /** ============ 用户数据 ============ */
  167. void *user_data; /**< 用户自定义数据指针 */
  168. } rtmp_ctx_t;
  169. /* ======================== 核心接口函数 ======================== */
  170. /**
  171. * 创建RTMP推流上下文
  172. *
  173. * 分配并初始化RTMP上下文结构体,为后续的RTMP连接做准备。
  174. *
  175. * @return 返回RTMP上下文指针,失败返回NULL
  176. */
  177. rtmp_ctx_t* rtmp_create(void);
  178. /**
  179. * 销毁RTMP推流上下文
  180. *
  181. * 释放所有由RTMP上下文占用的资源,包括内存缓冲区和TCP连接。
  182. *
  183. * @param ctx RTMP上下文指针
  184. * @return 返回RTMP_OK表示成功
  185. */
  186. int rtmp_destroy(rtmp_ctx_t *ctx);
  187. /**
  188. * 设置RTMP服务器URL
  189. *
  190. * 解析并设置RTMP服务器地址,支持的格式为:
  191. * - rtmp://hostname:port/app/stream
  192. * - rtmp://hostname/app/stream (使用默认端口1935)
  193. *
  194. * 如果设置过URL,新的设置会覆盖旧的设置。
  195. *
  196. * @param ctx RTMP上下文指针
  197. * @param url RTMP服务器URL字符串
  198. * @return RTMP_OK表示成功,其他值表示失败
  199. */
  200. int rtmp_set_url(rtmp_ctx_t *ctx, const char *url);
  201. /**
  202. * 连接到RTMP服务器
  203. *
  204. * 建立与RTMP服务器的TCP连接,然后执行RTMP握手流程。
  205. * 该函数是非阻塞的,实际的连接过程通过回调函数进行。
  206. *
  207. * @param ctx RTMP上下文指针
  208. * @return RTMP_OK表示连接已启动,其他值表示参数错误或资源不足
  209. */
  210. int rtmp_connect(rtmp_ctx_t *ctx);
  211. /**
  212. * 断开RTMP连接
  213. *
  214. * 主动关闭与RTMP服务器的连接,释放TCP资源。
  215. *
  216. * @param ctx RTMP上下文指针
  217. * @return RTMP_OK表示断开已启动
  218. */
  219. int rtmp_disconnect(rtmp_ctx_t *ctx);
  220. /**
  221. * 发送H.264 NALU帧
  222. *
  223. * 将一个H.264 NALU帧打包为FLV视频标签并发送。
  224. * 支持自动检测关键帧(IDR)和普通帧。
  225. *
  226. * 使用示例:
  227. * @code
  228. * uint8_t nalu_data[1024];
  229. * uint32_t nalu_len = 1024;
  230. * rtmp_send_nalu(ctx, nalu_data, nalu_len, 0); // 时间戳0ms
  231. * @endcode
  232. *
  233. * @param ctx RTMP上下文指针
  234. * @param nalu_data NALU数据指针,包含完整的NALU单元
  235. * @param nalu_len NALU数据长度
  236. * @param timestamp 视频时间戳(毫秒),从0开始递增
  237. * @return RTMP_OK表示发送成功,其他值表示错误
  238. * - RTMP_ERR_INVALID_PARAM: 参数无效
  239. * - RTMP_ERR_BUFFER_OVERFLOW: 缓冲区不足
  240. * - RTMP_ERR_FAILED: 发送失败
  241. */
  242. int rtmp_send_nalu(rtmp_ctx_t *ctx, const uint8_t *nalu_data,
  243. uint32_t nalu_len, uint32_t timestamp);
  244. /**
  245. * 发送多个NALU帧(聚合发送)
  246. *
  247. * 将多个NALU帧聚合打包为单个FLV视频数据包发送,
  248. * 可以提高网络传输效率。
  249. *
  250. * @param ctx RTMP上下文指针
  251. * @param nalus NALU数据指针数组
  252. * @param lengths 对应NALU的长度数组
  253. * @param count NALU帧的个数
  254. * @param timestamp 视频时间戳(毫秒)
  255. * @return RTMP_OK表示发送成功
  256. */
  257. int rtmp_send_nalu_multi(rtmp_ctx_t *ctx, const uint8_t **nalus,
  258. const uint32_t *lengths, uint32_t count,
  259. uint32_t timestamp);
  260. /**
  261. * 获取当前连接状态
  262. *
  263. * @param ctx RTMP上下文指针
  264. * @return 返回当前的rtmp_state_t状态值
  265. */
  266. rtmp_state_t rtmp_get_state(rtmp_ctx_t *ctx);
  267. /**
  268. * 处理RTMP事件(需要定期调用)
  269. *
  270. * 处理TCP连接事件、接收数据、超时检测等。
  271. * 该函数应该在主循环或定时器中定期调用,建议间隔为10-50毫秒。
  272. *
  273. * @param ctx RTMP上下文指针
  274. * @return RTMP_OK表示正常,其他值表示发生错误
  275. */
  276. int rtmp_poll(rtmp_ctx_t *ctx);
  277. /**
  278. * 设置用户自定义数据
  279. *
  280. * 可用于关联用户的上下文信息,在回调函数中可以通过
  281. * rtmp_get_user_data获取。
  282. *
  283. * @param ctx RTMP上下文指针
  284. * @param user_data 用户数据指针
  285. * @return RTMP_OK表示成功
  286. */
  287. int rtmp_set_user_data(rtmp_ctx_t *ctx, void *user_data);
  288. /**
  289. * 获取用户自定义数据
  290. *
  291. * @param ctx RTMP上下文指针
  292. * @return 返回用户设置的数据指针,未设置则返回NULL
  293. */
  294. void* rtmp_get_user_data(rtmp_ctx_t *ctx);
  295. /**
  296. * 获取统计信息
  297. *
  298. * 获取RTMP连接的实时统计数据,包括字节数、帧数、连接时长等。
  299. * 该函数可以在任何时刻调用以查询当前的推流统计信息。
  300. *
  301. * @param ctx RTMP上下文指针
  302. * @param stats 指向rtmp_stats_t结构体的指针,用于返回统计信息
  303. * @return RTMP_OK表示成功,其他值表示失败
  304. * - RTMP_ERR_INVALID_PARAM: ctx或stats参数为NULL
  305. *
  306. * 使用示例:
  307. * @code
  308. * rtmp_stats_t stats;
  309. * if (rtmp_get_stats(ctx, &stats) == RTMP_OK) {
  310. * printf("已发送: %u 字节, %u 视频帧\n",
  311. * stats.bytes_sent, stats.video_frames_sent);
  312. * }
  313. * @endcode
  314. */
  315. int rtmp_get_stats(rtmp_ctx_t *ctx, rtmp_stats_t *stats);
  316. /* ======================== 回调函数定义 ======================== */
  317. /**
  318. * RTMP连接状态变化回调函数类型
  319. *
  320. * @param ctx RTMP上下文指针
  321. * @param old_state 旧状态
  322. * @param new_state 新状态
  323. * @param error_code 如果是ERROR状态,此参数表示错误码
  324. */
  325. typedef void (*rtmp_state_callback)(rtmp_ctx_t *ctx, rtmp_state_t old_state,
  326. rtmp_state_t new_state, int error_code);
  327. /**
  328. * 设置状态变化回调函数
  329. *
  330. * 当RTMP连接状态发生变化时会调用此回调函数。
  331. *
  332. * @param ctx RTMP上下文指针
  333. * @param callback 回调函数指针,传NULL则禁用回调
  334. * @return RTMP_OK表示成功
  335. */
  336. int rtmp_set_state_callback(rtmp_ctx_t *ctx, rtmp_state_callback callback);
  337. #ifdef __cplusplus
  338. }
  339. #endif
  340. #endif /* __LUAT_RTMP_PUSH_H__ */