利用librtmp实现h264和AAC音频的推流

1. 基本流程

复制代码
#include <librtmp/rtmp.h>
#include <librtmp/log.h>

// 基本推流流程
RTMP* rtmp = NULL;

// 初始化RTMP连接
rtmp = RTMP_Alloc();
RTMP_Init(rtmp);

// 设置服务器地址和流密钥
RTMP_SetupURL(rtmp, (char*)"rtmp://server:1935/live/stream");
RTMP_EnableWrite(rtmp);

// 连接服务器
if (!RTMP_Connect(rtmp, NULL)) {
    // 处理错误
}

// 连接流
if (!RTMP_ConnectStream(rtmp, 0)) {
    // 处理错误
}

// 发送音视频数据
// ...

// 清理
RTMP_Close(rtmp);
RTMP_Free(rtmp);

2. H.264视频流推送

复制代码
// H.264相关参数
typedef struct {
    uint8_t* sps;      // SPS数据
    int sps_len;       // SPS长度
    uint8_t* pps;      // PPS数据
    int pps_len;       // PPS长度
    uint32_t timestamp; // 时间戳
} H264Context;

// 发送H.264帧
int send_h264_frame(RTMP* rtmp, uint8_t* data, int size, 
                    uint32_t timestamp, int is_keyframe) {
    RTMPPacket packet;
    RTMPPacket_Reset(&packet);
    RTMPPacket_Alloc(&packet, size + 16);
    
    packet.m_packetType = RTMP_PACKET_TYPE_VIDEO;
    packet.m_nChannel = 0x04;  // 视频通道
    packet.m_nTimeStamp = timestamp;
    packet.m_nInfoField2 = rtmp->m_stream_id;
    
    uint8_t* body = packet.m_body;
    int i = 0;
    
    // 视频标签头
    if (is_keyframe) {
        body[i++] = 0x17; // FrameType: KeyFrame, CodecID: AVC
    } else {
        body[i++] = 0x27; // FrameType: InterFrame, CodecID: AVC
    }
    
    // AVC包类型: NALU
    body[i++] = 0x01;
    
    // Composition time
    body[i++] = 0x00;
    body[i++] = 0x00;
    body[i++] = 0x00;
    
    // NALU长度
    body[i++] = (size >> 24) & 0xff;
    body[i++] = (size >> 16) & 0xff;
    body[i++] = (size >> 8) & 0xff;
    body[i++] = size & 0xff;
    
    // 复制NALU数据
    memcpy(&body[i], data, size);
    packet.m_nBodySize = size + i;
    
    // 发送包
    int ret = RTMP_SendPacket(rtmp, &packet, 0);
    RTMPPacket_Free(&packet);
    
    return ret;
}

// 发送SPS/PPS信息
int send_sps_pps(RTMP* rtmp, H264Context* ctx) {
    RTMPPacket packet;
    int sps_pps_size = ctx->sps_len + ctx->pps_len + 16;
    
    RTMPPacket_Reset(&packet);
    RTMPPacket_Alloc(&packet, sps_pps_size);
    
    packet.m_packetType = RTMP_PACKET_TYPE_VIDEO;
    packet.m_nChannel = 0x04;
    packet.m_nTimeStamp = 0;
    packet.m_nInfoField2 = rtmp->m_stream_id;
    
    uint8_t* body = packet.m_body;
    int i = 0;
    
    // 关键帧 + AVC序列头
    body[i++] = 0x17; // FrameType: KeyFrame, CodecID: AVC
    
    // AVC包类型: Sequence Header
    body[i++] = 0x00;
    
    // Composition time
    body[i++] = 0x00;
    body[i++] = 0x00;
    body[i++] = 0x00;
    
    // AVC序列头
    body[i++] = 0x01; // version
    body[i++] = ctx->sps[1]; // profile
    body[i++] = ctx->sps[2]; // profile_compat
    body[i++] = ctx->sps[3]; // level
    body[i++] = 0xff; // 6 bits reserved + 2 bits nal size length - 1
    
    // sps数量
    body[i++] = 0xe1; // 3 bits reserved + 5 bits num of sps
    
    // sps长度
    body[i++] = (ctx->sps_len >> 8) & 0xff;
    body[i++] = ctx->sps_len & 0xff;
    
    // sps数据
    memcpy(&body[i], ctx->sps, ctx->sps_len);
    i += ctx->sps_len;
    
    // pps数量
    body[i++] = 0x01; // num of pps
    
    // pps长度
    body[i++] = (ctx->pps_len >> 8) & 0xff;
    body[i++] = ctx->pps_len & 0xff;
    
    // pps数据
    memcpy(&body[i], ctx->pps, ctx->pps_len);
    i += ctx->pps_len;
    
    packet.m_nBodySize = i;
    
    int ret = RTMP_SendPacket(rtmp, &packet, 0);
    RTMPPacket_Free(&packet);
    
    return ret;
}

3. AAC音频流推送

复制代码
// AAC相关参数
typedef struct {
    uint8_t* asc;      // AudioSpecificConfig
    int asc_len;       // ASC长度
    uint32_t timestamp; // 时间戳
} AACContext;

// 发送AAC序列头
int send_aac_sequence_header(RTMP* rtmp, AACContext* ctx) {
    RTMPPacket packet;
    int size = ctx->asc_len + 2;
    
    RTMPPacket_Reset(&packet);
    RTMPPacket_Alloc(&packet, size);
    
    packet.m_packetType = RTMP_PACKET_TYPE_AUDIO;
    packet.m_nChannel = 0x05;  // 音频通道
    packet.m_nTimeStamp = 0;
    packet.m_nInfoField2 = rtmp->m_stream_id;
    
    uint8_t* body = packet.m_body;
    
    // 音频标签头
    body[0] = 0xAF; // SoundFormat: AAC (10), SoundRate: 44kHz (3)
                     // SoundSize: 16-bit samples (1), SoundType: Stereo (1)
    
    // AAC包类型: Sequence Header
    body[1] = 0x00;
    
    // AudioSpecificConfig
    memcpy(&body[2], ctx->asc, ctx->asc_len);
    
    packet.m_nBodySize = size;
    
    int ret = RTMP_SendPacket(rtmp, &packet, 0);
    RTMPPacket_Free(&packet);
    
    return ret;
}

// 发送AAC音频帧
int send_aac_frame(RTMP* rtmp, uint8_t* data, int size, 
                   uint32_t timestamp) {
    RTMPPacket packet;
    RTMPPacket_Reset(&packet);
    RTMPPacket_Alloc(&packet, size + 2);
    
    packet.m_packetType = RTMP_PACKET_TYPE_AUDIO;
    packet.m_nChannel = 0x05;
    packet.m_nTimeStamp = timestamp;
    packet.m_nInfoField2 = rtmp->m_stream_id;
    
    uint8_t* body = packet.m_body;
    
    // 音频标签头
    body[0] = 0xAF; // SoundFormat: AAC, 44kHz, 16-bit, Stereo
    
    // AAC包类型: Raw data
    body[1] = 0x01;
    
    // 音频数据
    memcpy(&body[2], data, size);
    packet.m_nBodySize = size + 2;
    
    int ret = RTMP_SendPacket(rtmp, &packet, 0);
    RTMPPacket_Free(&packet);
    
    return ret;
}

4. 完整的主程序示例

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <librtmp/rtmp.h>
#include <librtmp/log.h>

// 解析H.264 SPS/PPS (简化示例)
int parse_h264_sps_pps(uint8_t* data, int size, H264Context* ctx) {
    // 实际实现需要解析NALU找到SPS和PPS
    // 这里假设data包含SPS和PPS
    // ...
    return 0;
}

int main() {
    RTMP* rtmp = NULL;
    H264Context h264_ctx;
    AACContext aac_ctx;
    
    // 初始化RTMP
    rtmp = RTMP_Alloc();
    RTMP_Init(rtmp);
    
    // 设置URL
    char url[] = "rtmp://your-server:1935/live/stream";
    RTMP_SetupURL(rtmp, url);
    RTMP_EnableWrite(rtmp);
    
    // 连接
    if (!RTMP_Connect(rtmp, NULL)) {
        printf("RTMP连接失败\n");
        goto cleanup;
    }
    
    if (!RTMP_ConnectStream(rtmp, 0)) {
        printf("RTMP连接流失败\n");
        goto cleanup;
    }
    
    printf("RTMP连接成功\n");
    
    // 初始化音视频参数
    // 这里需要从你的音视频流中获取SPS/PPS和ASC
    // h264_ctx.sps = ...; h264_ctx.sps_len = ...;
    // h264_ctx.pps = ...; h264_ctx.pps_len = ...;
    // aac_ctx.asc = ...; aac_ctx.asc_len = ...;
    
    // 发送序列头
    send_sps_pps(rtmp, &h264_ctx);
    send_aac_sequence_header(rtmp, &aac_ctx);
    
    // 模拟音视频推送循环
    uint32_t video_timestamp = 0;
    uint32_t audio_timestamp = 0;
    int video_interval = 40; // 假设25fps
    int audio_interval = 23; // 假设44.1kHz, 1024 samples/frame
    
    for (int i = 0; i < 1000; i++) { // 推送1000帧
        // 发送视频帧
        uint8_t* video_data = NULL;
        int video_size = 0;
        int is_keyframe = (i % 100 == 0); // 每100帧一个关键帧
        
        // 这里获取实际的H.264 NALU数据
        // get_h264_frame(&video_data, &video_size, &is_keyframe);
        
        if (video_size > 0) {
            send_h264_frame(rtmp, video_data, video_size, 
                           video_timestamp, is_keyframe);
            video_timestamp += video_interval;
        }
        
        // 发送音频帧
        uint8_t* audio_data = NULL;
        int audio_size = 0;
        
        // 这里获取实际的AAC帧数据
        // get_aac_frame(&audio_data, &audio_size);
        
        if (audio_size > 0) {
            send_aac_frame(rtmp, audio_data, audio_size, audio_timestamp);
            audio_timestamp += audio_interval;
        }
        
        // 简单同步,实际应用中需要更精确的时钟控制
        usleep(10000); // 10ms
    }
    
cleanup:
    // 清理
    if (rtmp) {
        RTMP_Close(rtmp);
        RTMP_Free(rtmp);
    }
    
    return 0;
}

5. 编译命令

复制代码
gcc -o rtmp_pusher rtmp_pusher.c -lrtmp -lz -lpthread

6. 注意事项

  1. 时间戳同步:音视频时间戳需要同步,通常使用同一个时钟基准
  2. NALU处理:H.264流需要按NALU单位发送,注意起始码(0x00000001)的处理
  3. 关键帧:需要定期发送关键帧,并在开头发送SPS/PPS
  4. 错误处理:需要处理网络断开、服务器错误等情况
  5. 线程安全:如果使用多线程推送音视频,需要做好同步
相关推荐
byte轻骑兵2 小时前
蓝牙CAP规范解析:构建多设备协同的通用音频新生态
人工智能·音视频·le audio·低功耗音频·蓝牙通话
大象AI共学2 小时前
我让AI写了个网页,它自动变成了视频
人工智能·音视频
Prannt2 小时前
星朗智能语音——视频音色替换
ai·音视频·语音识别
时空自由民.1 天前
音视频图片压缩
音视频
日取其半万世不竭1 天前
PeerTube 部署指南:自建视频托管平台
云原生·eureka·音视频
luoqice1 天前
FLV文件解析
音视频
byte轻骑兵1 天前
【AVRCP】规范精讲[10]:链路管理器LM互操作规则与场景落地
人工智能·音视频·蓝牙·avrcp·音视频控制
JK Chen1 天前
faster_whisper,视频转文字,并生成字幕文件
python·whisper·音视频
Prannt2 天前
星朗智能语音——语音合成——上传文件配音
ai·音视频·语音识别