luat_rtmp_push.h 12 KB

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