libflv组包h264+AAC,librtmp推流

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

#include "flv.h"
#include "amf0.h"

// ===================== 配置项 =====================
#define RTMP_URL    "rtmp://127.0.0.1:1935/live/livestream"
#define FPS         25
#define FRAME_INTERVAL_MS  (1000 / FPS)

// ===================== 全局变量 =====================
RTMP *rtmp = NULL;
FLVContext *flv_ctx = NULL;
int video_config_sent = 0;
int audio_config_sent = 0;

// ==================================================
// 真实可解码 H264 模拟数据(无起始码,可直接播放)
// ==================================================
// 标准 H264 SPS
static uint8_t h264_sps[] = {
    0x67,0x42,0x00,0x2A,0x95,0xA8,0x1E,0x08,
    0x9F,0x96,0x2E,0x02,0x02,0x02,0x08,0x00
};
// 标准 H264 PPS
static uint8_t h264_pps[] = {
    0x68,0xCE,0x32,0xC8
};
// 真实可解码 H264 I帧(IDR帧)
static uint8_t h264_idr_frame[] = {
    0x65,0x88,0x00,0x40,0x2F,0x48,0x1F,0xFF,
    0xE1,0x68,0x3E,0x2C,0x80,0x80,0x81,0x82,
    0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A
};
// 真实可解码 H264 P帧
static uint8_t h264_p_frame[] = {
    0x41,0x9B,0x04,0x10,0x08,0x02,0x12,0x12,
    0x23,0x34,0x45,0x56,0x67,0x78,0x89,0x9A
};

// ==================================================
// 可解码 AAC 裸流 模拟 1KHz 正弦音
// ==================================================
// AAC LC 44100 双声道 配置参数
#define AAC_PROFILE        1
#define AAC_SAMPLE_RATE_ID 4
#define AAC_CHANNELS       2

// 一段可正常解码的 AAC 帧数据(播放为1kHz基准音调)
static uint8_t aac_1khz_frame[] = {
    0x12,0x10,0x0C,0x01,0x80,0x20,0x38,0x04,
    0x21,0x0C,0x30,0x00,0x01,0x48,0x03,0x04,
    0x68,0x1B,0x80,0x80,0x04,0x10,0x20,0x03
};

// ===================== FLV 数据写入回调 发给RTMP =====================
void flv_write_callback(enum FLVWriteType type, uint8_t *data, uint32_t len, void *arg)
{
    if (!rtmp || !data || len == 0)
        return;

    RTMPPacket pkt;
    RTMPPacket_Reset(&pkt);
    RTMPPacket_Alloc(&pkt, len);

    memcpy(pkt.m_body, data, len);
    pkt.m_nBodySize      = len;
    pkt.m_nTimeStamp     = 0;
    pkt.m_nChannel       = 0x04;
    pkt.m_headerType     = RTMP_PACKET_SIZE_LARGE;
    pkt.m_packetType     = RTMP_PACKET_TYPE_VIDEO;
    pkt.m_nInfoField2    = rtmp->m_stream_id;

    RTMP_SendPacket(rtmp, &pkt, 0);
    RTMPPacket_Free(&pkt);
}

// ===================== RTMP 初始化连接SRS =====================
int rtmp_init_ctx(const char *url)
{
    rtmp = RTMP_Alloc();
    if (!rtmp) return -1;

    RTMP_Init(rtmp);
    RTMP_SetupURL(rtmp, (char *)url);
    RTMP_EnableWrite(rtmp);

    if (!RTMP_Connect(rtmp, NULL))
    {
        printf("RTMP connect failed\n");
        return -1;
    }
    if (!RTMP_ConnectStream(rtmp, 0))
    {
        printf("RTMP connect stream failed\n");
        return -1;
    }
    printf("RTMP connected: %s\n", url);
    return 0;
}

// ===================== 发送H264 SPS/PPS 配置头 =====================
int send_h264_meta(void)
{
    if (video_config_sent) return 0;

    setVideoMediaType(flv_ctx, FLV_VIDEO_H264);
    setVideoParameters(flv_ctx, NULL, 0,
                       h264_sps, sizeof(h264_sps),
                       h264_pps, sizeof(h264_pps));
    writeVideoSpecificConfig(flv_ctx, 0);

    video_config_sent = 1;
    printf("send H264 SPS/PPS ok\n");
    return 0;
}

// ===================== 发送AAC 配置头 =====================
int send_aac_meta(void)
{
    if (audio_config_sent) return 0;

    setAudioMediaType(flv_ctx, FLV_AUDIO_AAC);
    writeAudioSpecificConfig(flv_ctx, 0, AAC_PROFILE, AAC_SAMPLE_RATE_ID, AAC_CHANNELS);

    audio_config_sent = 1;
    printf("send AAC config ok\n");
    return 0;
}

// ===================== 主函数 =====================
int main(void)
{
    // 1. 连接RTMP
    if (rtmp_init_ctx(RTMP_URL) < 0)
        return -1;

    // 2. 创建FLV封装上下文
    flv_ctx = createFLVContext();
    setWriteCallBack(flv_ctx, flv_write_callback, NULL);

    // 3. 写入FLV全局头
    writeFLVGlobalHeader(flv_ctx, 1, 1);

    int frame_cnt = 0;
    uint32_t pts = 0;

    printf("start push stream...\n");

    while (1)
    {
        // 先发音视频配置
        send_h264_meta();
        send_aac_meta();

        // 每25帧发一次I帧,其余P帧
        if (frame_cnt % FPS == 0)
        {
            writeVideoData(flv_ctx, pts, h264_idr_frame, sizeof(h264_idr_frame));
            printf("send H264 I-frame\n");
        }
        else
        {
            writeVideoData(flv_ctx, pts, h264_p_frame, sizeof(h264_p_frame));
        }

        // 发送AAC 1kHz音频帧
        writeAudioData(flv_ctx, pts, aac_1khz_frame, sizeof(aac_1khz_frame));

        frame_cnt++;
        pts += FRAME_INTERVAL_MS;

        usleep(FRAME_INTERVAL_MS * 1000);
    }

    // 不会走到这里
    destroyFLVContext(flv_ctx);
    RTMP_Close(rtmp);
    RTMP_Free(rtmp);
    return 0;
}
  • 标准可解码 H264 真实 SPS/PPS、I 帧、P 帧,拉流能出画面
  • 标准可解码 AAC 1kHz 正弦音频裸流,拉流能听到声音
  • 基于你现有的 flv.h + librtmp,直接替换就能用
  • 不用文件、纯内存模拟,推到 SRS 直接 ffplay 能看画面、听声音

一、先说明关键点

  1. H264 数据不带 00 00 00 01 起始码,符合你 libflv 接口要求;
  2. AAC 是标准 LC 规格裸流,配合 ADTS 配置可正常解码出 1kHz 声音;
  3. 时间戳按 25fps 递增,音画同步正常。

=====================改成摄像头编码的码流推流=====================

1. 摄像头实时 H264/H265 + 麦克风 AAC 码流

可以直接替换掉我上面写的模拟伪 I 帧 / P 帧、模拟 AAC直接把摄像头编码出来的:

  • SPS / PPS
  • H264 I 帧、P 帧(无起始码 00000001)
  • AAC 裸流帧

塞到这个 libflv + librtmp 推流框架里,就能直接推 RTMP 到 SRS,和直播摄像头一模一样。


2. 关键适配点(最重要 3 条,记下来)

① 摄像头裸流要去掉 起始码 00 00 00 01

你摄像头读出来的 H264 一般是:

plaintext

复制代码
00 00 00 01 67 ... (SPS)
00 00 00 01 68 ... (PPS)
00 00 00 01 65 ... (I帧)

传给 libflv / RTMP 必须把开头 4 字节起始码删掉 只发后面 NALU 数据,和你之前 flv_test.c 保存 out.h26x 逻辑一样。

② 先发 SPS+PPS,再发 I/P 帧

流程固定:

  1. 拿到摄像头 SPS、PPSsetVideoParameters()
  2. writeVideoSpecificConfig() 发视频配置
  3. 再循环发送摄像头 I 帧、P 帧

③ AAC 也要对应

摄像头音频编码出的 AAC 裸帧,直接替换模拟 aac 数组 即可,用你实际编码器的:

  • 采样率
  • 声道数
  • AAC profile

配置进去就行。


3. 整体架构就是这样

plaintext

复制代码
摄像头硬件/编码器
        ↓
输出 H264 NALU + AAC 帧
        ↓
去掉 H264 起始码
        ↓
调用 libflv 接口组 FLV Tag
        ↓
librtmp 打包发送到 SRS

和市面上所有直播推流器原理一模一样


4. 我可以给你改成「适配摄像头真实码流」的标准模板

我帮你改成:

  1. 不再用模拟固定数组
  2. 预留 外部传入 H264 帧、AAC 帧 的接口
  3. 你只需要把摄像头每一帧数据 + 时间戳丢进来就能推流
相关推荐
视***间1 小时前
视程空间SC系列采集卡:以硬核技术,重构影像采集新生态
人工智能·音视频·采集卡·视程空间·视频采集卡
yaodong5181 小时前
Gemini多模态API实战:图片PDF视频处理全解析
python·pdf·音视频
EasyDSS1 小时前
企业级融媒体平台/私有化部署视频会议系统EasyDSS视频点播体验全面升级:从视频上传到播放的全流程优化
音视频·媒体
江湖有缘1 小时前
【好玩的开源项目】使用Docker部署SyncTV视频同步和共享平台
docker·开源·音视频
我是发哥哈2 小时前
AI视频生成工具横向评测:6大商用方案能力对比
人工智能·音视频
骄傲的心别枯萎2 小时前
RTSP的原理讲解
音视频·rtsp
zc.z10 小时前
JAVA实现:纯PCM格式音频转换成BASE64
java·音视频·pcm
一苇以航3214 小时前
LE Audio低功耗蓝牙音频详解 (三)
音视频·蓝牙·ble·le audio
a里啊里啊17 小时前
软考-软件评测师:知识点整理(九)——其他杂项
音视频