librtmp示例c编程?

时间:2014-07-15 02:35:48

标签: c rtmp flv wowza

大家好我是c编程的新手,想知道是否有人有一个非常简单的例子来打开.flv文件并使用librtmp发送到wowza服务器。

我发现很多代码能够使用库连接,但在发布flv时却没有太多。

基本上:

init librtmp - > enable write - >连接 - > packetize flv - >发送数据包直到完成

编辑:

好的,所以我必须先打开我的flv文件并隔离flv文件中的每个数据包,然后将其发送到librtmp。到目前为止,我发现了这段代码:

https://github.com/noirotm/flvmeta/blob/master/src/flv.c

2 个答案:

答案 0 :(得分:7)

这是FLVMeta的作者。

您可能想查看我对this questionhttps://stackoverflow.com/a/13803143/393701

的回答

除了这些信息之外,我还可以解释一下我编写的C ++软件的一些部分(遗憾的是暂时不是开源的),这些部分用于将FLV文件流式传输到RTMP服务器。

这已经过测试,可以与Wowza,nginx-rtmp以及Dailymotion直播服务器一起使用。

初始化

std::string rtmp_url = "rtmp://server/app/stream";
// add this if doing live streaming:
rtmp_url.append(" live=1");

RTMP * rtmp = RTMP_Alloc();
if (!rtmp) {
    std::cerr << "Unable to create rtmp object\n";
    return;
}

RTMP_Init(rtmp);
RTMP_LogSetLevel(RTMP_LOGINFO);
RTMP_LogSetOutput(stderr);
RTMP_SetupURL(rtmp, const_cast<char*>(rtmp_url.c_str())); // librtmp is a mess
RTMP_EnableWrite(rtmp);

奇怪的const_cast是因为librtmp设计奇怪,并且使用非const char *作为URL,即使它实际上可能没有被库修改。登记/> 此外,只要RTMP对象存在,缓冲区就会被使用,因此在删除RTMP对象之前不能释放该字符串。

连接

// connect to server
if (!RTMP_Connect(rtmp, NULL)) {
    std::cerr << "Unable to connect to server\n";
    RTMP_Free(rtmp);
    return;
}

RTMP_Connect的第二个参数是一个可选指针,指向要作为参数发送的RTMP数据包而不是librtmp发送的默认连接数据包。通常在连接到正常情况时不应使用此功能。 RTMP服务器。

// connect to stream (this will be the stream specified in the RTMP URL)
if (!RTMP_ConnectStream(rtmp, 0)) {
    cerr << "Unable to connect to stream\n";
    RTMP_Free(rtmp);
    return;
}

RTMP_ConnectStream的第二个参数是一个整数,表示播放视频时要寻找的时间戳。发布时,使用0是一个安全的选择。

发布数据包

本节假设使用FLVMeta项目中的FLV代码(参见https://github.com/noirotm/flvmeta/blob/master/src/flv.h#L175)。

flv_stream * flvin = flv_open(input_file.c_str());
if (!flvin) {
    std::cerr << "Unable to open " << input_file << '\n';
    return;
}

首先,确保我们打开一个真正的FLV文件是个好主意。

flv_header header;
int res = flv_read_header(flvin, &header);
if (res == FLV_ERROR_NO_FLV || res == FLV_ERROR_EOF) {
    std::cerr << "Input file is not an FLV video\n";
    flv_close(flvin);
    return;
}

现在读取文件中的每个标记,并将它们发送到RTMP服务器。

// 10 MB copy buffer should be enough
#define BUFFER_SIZE 10000000
char buffer[BUFFER_SIZE];

flv_tag tag;
while (flv_read_tag(flvin, &tag) != FLV_ERROR_EOF) {
    // copy tag header
    flv_copy_tag(buffer, &tag, FLVSTREAMER_BUFFER_SIZE);

    // copy tag body
    size_t data_size = flv_read_tag_body(flvin, buffer + FLV_TAG_SIZE, BUFFER_SIZE - FLV_TAG_SIZE);

    // copy previous tag size
    uint32 pts;
    flv_read_prev_tag_size(flvin, &pts);
    flv_copy_prev_tag_size(
        buffer + FLV_TAG_SIZE + flv_tag_get_body_length(tag),
        pts,
        BUFFER_SIZE - (FLV_TAG_SIZE + flv_tag_get_body_length(tag))
    );

    // write the packet
    int size = FLV_TAG_SIZE + data_size + sizeof(uint32);
    if (RTMP_Write(rtmp, buffer, size) <= 0) {
        std::cerr << "Unable to write to server" << endl;
        break;
    }
}

各种flv_*函数负责处理FLV格式的特殊性,例如字节序问题以及最终的数据格式错误,因此如果您的程序与GPL许可证兼容,我建议使用它们。
如果没有,只要很好地理解FLV格式,使用标准I / O迭代标记并不复杂。

请务必注意,不得发送FLV文件头。 librtmp将检测任何发送FLV标头并阻止它的尝试。

发布时不必读取传入的RTMP数据包,但如果要正确处理协议,建议使用@szatmary在其代码中使用的方法。

此处未解决的另一个重要方面是,在发布实时流时,必须实施某种形式的限制,以便以视频的标称比特率发送数据,否则RTMP服务器将跳过数据包和视频播放会受到很大影响 解决这个问题的常用方法可能是读取每个标记的时间戳,如果写得太快就会睡觉。

清理

flv_close(flvin);
RTMP_Free(rtmp);

RTMP_Free函数将负责关闭流,连接并释放任何已分配的内存。

答案 1 :(得分:0)

这是我用C ++ https://github.com/szatmary/RtmpBroadcaster/blob/master/rtmp.cpp

写的一个非常简单的例子