| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- /**
- * @file luat_rtmp_push.h
- * @brief RTMP推流组件 - 基于lwip raw API实现
- * @author LuatOS Team
- *
- * 该组件实现了RTMP(Real Time Messaging Protocol)推流功能,
- * 支持将H.264视频流推送到RTMP服务器。
- *
- * 主要特性:
- * - 基于lwip raw socket API,适应嵌入式环境
- * - 支持自定义H.264帧来源,灵活的NALU帧注入
- * - 完整的RTMP握手和连接管理
- * - 支持FLV格式视频打包和发送
- * - C99语法,内存使用优化
- */
- #ifndef __LUAT_RTMP_PUSH_H__
- #define __LUAT_RTMP_PUSH_H__
- #include "luat_base.h"
- #include "lwip/tcp.h"
- #include <stdint.h>
- #include <stddef.h>
- #include <stdbool.h>
- #ifdef __cplusplus
- extern "C" {
- #endif
- /* ======================== RTMP常量定义 ======================== */
- /** RTMP默认块大小(字节) - RTMP规范规定的默认值为128 */
- #define RTMP_DEFAULT_CHUNK_SIZE 128
- /** RTMP缓冲区大小(字节) - 需要足够大以容纳I帧 */
- #define RTMP_BUFFER_SIZE (512 * 1024)
- /** 发送帧队列最大字节数上限,超出将丢弃未发送帧(优先丢弃非关键帧) */
- #define RTMP_MAX_QUEUE_BYTES (1024 * 1024)
- /** RTMP握手数据大小(字节) */
- #define RTMP_HANDSHAKE_SIZE 1536
- /** RTMP命令超时时间(毫秒) */
- #define RTMP_CMD_TIMEOUT 5000
- /* ======================== 返回值定义 ======================== */
- /** 操作成功 */
- #define RTMP_OK 0
- /** 通用错误 */
- #define RTMP_ERR_FAILED (-1)
- /** 参数无效 */
- #define RTMP_ERR_INVALID_PARAM (-2)
- /** 内存不足 */
- #define RTMP_ERR_NO_MEMORY (-3)
- /** 连接错误 */
- #define RTMP_ERR_CONNECT_FAILED (-4)
- /** 握手失败 */
- #define RTMP_ERR_HANDSHAKE_FAILED (-5)
- /** 网络错误 */
- #define RTMP_ERR_NETWORK (-6)
- /** 超时 */
- #define RTMP_ERR_TIMEOUT (-7)
- /** 缓冲区溢出 */
- #define RTMP_ERR_BUFFER_OVERFLOW (-8)
- /* ======================== 数据类型定义 ======================== */
- /**
- * RTMP连接状态枚举
- */
- typedef enum {
- RTMP_STATE_IDLE = 0, /**< 空闲状态 */
- RTMP_STATE_CONNECTING = 1, /**< 正在连接 */
- RTMP_STATE_HANDSHAKING = 2, /**< 握手中 */
- RTMP_STATE_CONNECTED = 3, /**< 已连接 */
- RTMP_STATE_PUBLISHING = 4, /**< 正在推流 */
- RTMP_STATE_DISCONNECTING = 5, /**< 正在断开连接 */
- RTMP_STATE_ERROR = 6 /**< 错误状态 */
- } rtmp_state_t;
- /**
- * RTMP消息类型枚举
- */
- typedef enum {
- RTMP_MSG_SET_CHUNK_SIZE = 1, /**< 设置块大小 */
- RTMP_MSG_ABORT = 2, /**< 中止消息 */
- RTMP_MSG_BYTES_READ = 3, /**< 字节已读 */
- RTMP_MSG_CONTROL = 4, /**< 用户控制消息 */
- RTMP_MSG_SERVER_BW = 5, /**< 服务器带宽 */
- RTMP_MSG_CLIENT_BW = 6, /**< 客户端带宽 */
- RTMP_MSG_AUDIO = 8, /**< 音频数据 */
- RTMP_MSG_VIDEO = 9, /**< 视频数据 */
- RTMP_MSG_AMFDATAFILE = 15, /**< AMF数据 */
- RTMP_MSG_COMMAND = 20, /**< 命令(AMF0) */
- RTMP_MSG_EXTENDED_COMMAND = 17 /**< 扩展命令 */
- } rtmp_msg_type_t;
- /**
- * H.264 NALU类型枚举
- */
- typedef enum {
- NALU_TYPE_NON_IDR = 1, /**< 非IDR帧 */
- NALU_TYPE_IDR = 5, /**< IDR帧(关键帧) */
- NALU_TYPE_SEI = 6, /**< SEI(补充增强信息) */
- NALU_TYPE_SPS = 7, /**< SPS(序列参数集) */
- NALU_TYPE_PPS = 8, /**< PPS(图像参数集) */
- NALU_TYPE_AUD = 9 /**< AUD(访问单元分隔符) */
- } nalu_type_t;
- /**
- * H.264视频帧标签结构体
- * 用于描述FLV格式中的视频数据帧
- */
- typedef struct {
- uint8_t frame_type; /**< 帧类型: 1=关键帧, 2=普通帧 */
- uint8_t codec_id; /**< 编码器ID: 7=H.264 */
- uint32_t cts; /**< 时间戳偏移(ms) */
- uint8_t *data; /**< 视频数据指针 */
- uint32_t len; /**< 视频数据长度 */
- } video_tag_t;
- /**
- * RTMP推流统计信息结构体
- * 用于查询RTMP连接的实时统计数据
- */
- typedef struct {
- uint32_t bytes_sent; /**< 已发送的字节数 */
- uint32_t video_frames_sent; /**< 已发送的视频帧数 */
- uint32_t audio_frames_sent; /**< 已发送的音频帧数 */
- uint32_t connection_time; /**< 连接持续时间(毫秒) */
- uint32_t packets_sent; /**< 已发送的包数 */
- uint32_t last_video_timestamp; /**< 最后视频时间戳(毫秒) */
- uint32_t last_audio_timestamp; /**< 最后音频时间戳(毫秒) */
- } rtmp_stats_t;
- /**
- * RTMP推流上下文结构体
- * 管理单个RTMP连接的所有状态和缓冲区
- */
- typedef struct {
- /** ============ 连接信息 ============ */
- char *url; /**< RTMP服务器URL */
- char *host; /**< RTMP服务器主机名/IP地址 */
- char *app; /**< RTMP应用名 */
- char *stream; /**< 推流名 */
- char *auth; /**< 认证信息 */
- uint16_t port; /**< 连接端口 */
-
- /** ============ TCP连接状态 ============ */
- struct tcp_pcb *pcb; /**< lwip TCP控制块 */
- rtmp_state_t state; /**< 当前连接状态 */
- uint32_t last_activity_time; /**< 最后活动时间戳 */
- int handshake_state; /**< 握手状态: 0=发送C0C1, 1=等待S0S1, 2=发送C2, 3=完成 */
-
- /** ============ RTMP协议状态 ============ */
- uint32_t in_chunk_size; /**< 输入块大小 */
- uint32_t out_chunk_size; /**< 输出块大小 */
- uint32_t chunk_size; /**< 当前chunk大小(用于分块发送)*/
- uint32_t video_stream_id; /**< 视频流ID */
- uint32_t audio_stream_id; /**< 音频流ID */
-
- /** ============ 缓冲区管理 ============ */
- uint8_t *recv_buf; /**< 接收缓冲区 */
- uint32_t recv_buf_size; /**< 接收缓冲区大小 */
- uint32_t recv_pos; /**< 接收缓冲区写位置 */
-
- uint8_t *send_buf; /**< 发送缓冲区 */
- uint32_t send_buf_size; /**< 发送缓冲区大小 */
- uint32_t send_pos; /**< 发送缓冲区写位置 */
- /** ============ 帧发送队列 ============ */
- struct rtmp_frame_node *frame_head; /**< 待发送帧队列头 */
- struct rtmp_frame_node *frame_tail; /**< 待发送帧队列尾 */
- uint32_t frame_queue_bytes; /**< 队列占用的总字节数 */
-
- /** ============ 时间戳管理 ============ */
- uint32_t video_timestamp; /**< 当前视频时间戳(ms) */
- uint32_t audio_timestamp; /**< 当前音频时间戳(ms) */
- uint32_t base_timestamp; /**< 基准时间戳 */
-
- /** ============ 统计信息 ============ */
- uint32_t packets_sent; /**< 已发送的包数 */
- uint32_t bytes_sent; /**< 已发送的字节数 */
- uint32_t command_id; /**< 当前命令ID */
-
- /** ============ 用户数据 ============ */
- void *user_data; /**< 用户自定义数据指针 */
- } rtmp_ctx_t;
- /* ======================== 核心接口函数 ======================== */
- /**
- * 创建RTMP推流上下文
- *
- * 分配并初始化RTMP上下文结构体,为后续的RTMP连接做准备。
- *
- * @return 返回RTMP上下文指针,失败返回NULL
- */
- rtmp_ctx_t* rtmp_create(void);
- /**
- * 销毁RTMP推流上下文
- *
- * 释放所有由RTMP上下文占用的资源,包括内存缓冲区和TCP连接。
- *
- * @param ctx RTMP上下文指针
- * @return 返回RTMP_OK表示成功
- */
- int rtmp_destroy(rtmp_ctx_t *ctx);
- /**
- * 设置RTMP服务器URL
- *
- * 解析并设置RTMP服务器地址,支持的格式为:
- * - rtmp://hostname:port/app/stream
- * - rtmp://hostname/app/stream (使用默认端口1935)
- *
- * 如果设置过URL,新的设置会覆盖旧的设置。
- *
- * @param ctx RTMP上下文指针
- * @param url RTMP服务器URL字符串
- * @return RTMP_OK表示成功,其他值表示失败
- */
- int rtmp_set_url(rtmp_ctx_t *ctx, const char *url);
- /**
- * 连接到RTMP服务器
- *
- * 建立与RTMP服务器的TCP连接,然后执行RTMP握手流程。
- * 该函数是非阻塞的,实际的连接过程通过回调函数进行。
- *
- * @param ctx RTMP上下文指针
- * @return RTMP_OK表示连接已启动,其他值表示参数错误或资源不足
- */
- int rtmp_connect(rtmp_ctx_t *ctx);
- /**
- * 断开RTMP连接
- *
- * 主动关闭与RTMP服务器的连接,释放TCP资源。
- *
- * @param ctx RTMP上下文指针
- * @return RTMP_OK表示断开已启动
- */
- int rtmp_disconnect(rtmp_ctx_t *ctx);
- /**
- * 发送H.264 NALU帧
- *
- * 将一个H.264 NALU帧打包为FLV视频标签并发送。
- * 支持自动检测关键帧(IDR)和普通帧。
- *
- * 使用示例:
- * @code
- * uint8_t nalu_data[1024];
- * uint32_t nalu_len = 1024;
- * rtmp_send_nalu(ctx, nalu_data, nalu_len, 0); // 时间戳0ms
- * @endcode
- *
- * @param ctx RTMP上下文指针
- * @param nalu_data NALU数据指针,包含完整的NALU单元
- * @param nalu_len NALU数据长度
- * @param timestamp 视频时间戳(毫秒),从0开始递增
- * @return RTMP_OK表示发送成功,其他值表示错误
- * - RTMP_ERR_INVALID_PARAM: 参数无效
- * - RTMP_ERR_BUFFER_OVERFLOW: 缓冲区不足
- * - RTMP_ERR_FAILED: 发送失败
- */
- int rtmp_send_nalu(rtmp_ctx_t *ctx, const uint8_t *nalu_data,
- uint32_t nalu_len, uint32_t timestamp);
- /**
- * 发送多个NALU帧(聚合发送)
- *
- * 将多个NALU帧聚合打包为单个FLV视频数据包发送,
- * 可以提高网络传输效率。
- *
- * @param ctx RTMP上下文指针
- * @param nalus NALU数据指针数组
- * @param lengths 对应NALU的长度数组
- * @param count NALU帧的个数
- * @param timestamp 视频时间戳(毫秒)
- * @return RTMP_OK表示发送成功
- */
- int rtmp_send_nalu_multi(rtmp_ctx_t *ctx, const uint8_t **nalus,
- const uint32_t *lengths, uint32_t count,
- uint32_t timestamp);
- /**
- * 获取当前连接状态
- *
- * @param ctx RTMP上下文指针
- * @return 返回当前的rtmp_state_t状态值
- */
- rtmp_state_t rtmp_get_state(rtmp_ctx_t *ctx);
- /**
- * 处理RTMP事件(需要定期调用)
- *
- * 处理TCP连接事件、接收数据、超时检测等。
- * 该函数应该在主循环或定时器中定期调用,建议间隔为10-50毫秒。
- *
- * @param ctx RTMP上下文指针
- * @return RTMP_OK表示正常,其他值表示发生错误
- */
- int rtmp_poll(rtmp_ctx_t *ctx);
- /**
- * 设置用户自定义数据
- *
- * 可用于关联用户的上下文信息,在回调函数中可以通过
- * rtmp_get_user_data获取。
- *
- * @param ctx RTMP上下文指针
- * @param user_data 用户数据指针
- * @return RTMP_OK表示成功
- */
- int rtmp_set_user_data(rtmp_ctx_t *ctx, void *user_data);
- /**
- * 获取用户自定义数据
- *
- * @param ctx RTMP上下文指针
- * @return 返回用户设置的数据指针,未设置则返回NULL
- */
- void* rtmp_get_user_data(rtmp_ctx_t *ctx);
- /**
- * 获取统计信息
- *
- * 获取RTMP连接的实时统计数据,包括字节数、帧数、连接时长等。
- * 该函数可以在任何时刻调用以查询当前的推流统计信息。
- *
- * @param ctx RTMP上下文指针
- * @param stats 指向rtmp_stats_t结构体的指针,用于返回统计信息
- * @return RTMP_OK表示成功,其他值表示失败
- * - RTMP_ERR_INVALID_PARAM: ctx或stats参数为NULL
- *
- * 使用示例:
- * @code
- * rtmp_stats_t stats;
- * if (rtmp_get_stats(ctx, &stats) == RTMP_OK) {
- * printf("已发送: %u 字节, %u 视频帧\n",
- * stats.bytes_sent, stats.video_frames_sent);
- * }
- * @endcode
- */
- int rtmp_get_stats(rtmp_ctx_t *ctx, rtmp_stats_t *stats);
- /* ======================== 回调函数定义 ======================== */
- /**
- * RTMP连接状态变化回调函数类型
- *
- * @param ctx RTMP上下文指针
- * @param old_state 旧状态
- * @param new_state 新状态
- * @param error_code 如果是ERROR状态,此参数表示错误码
- */
- typedef void (*rtmp_state_callback)(rtmp_ctx_t *ctx, rtmp_state_t old_state,
- rtmp_state_t new_state, int error_code);
- /**
- * 设置状态变化回调函数
- *
- * 当RTMP连接状态发生变化时会调用此回调函数。
- *
- * @param ctx RTMP上下文指针
- * @param callback 回调函数指针,传NULL则禁用回调
- * @return RTMP_OK表示成功
- */
- int rtmp_set_state_callback(rtmp_ctx_t *ctx, rtmp_state_callback callback);
- #ifdef __cplusplus
- }
- #endif
- #endif /* __LUAT_RTMP_PUSH_H__ */
|