8

如何使用 librtmp 库发布流?我阅读了 librtmp 手册页并使用了 RTMP_Write() 进行发布。

我正在这样做。

//Code
//Init RTMP code
RTMP *r;
char uri[]="rtmp://localhost:1935/live/desktop";
r= RTMP_Alloc();
RTMP_Init(r);
RTMP_SetupURL(r, (char*)uri);
RTMP_EnableWrite(r);
RTMP_Connect(r, NULL);
RTMP_ConnectStream(r,0);

然后响应来自服务器的 ping/其他消息,我使用一个线程来响应如下:

//Thread
While (ThreadIsRunning && RTMP_IsConnected(r) && RTMP_ReadPacket(r, &packet))
{
   if (RTMPPacket_IsReady(&packet))
   {
 if (!packet.m_nBodySize)
         continue;
    RTMP_ClientPacket(r, &packet); //This takes care of handling ping/other messages
    RTMPPacket_Free(&packet);
   }
}

在此之后,我被困在如何使用 RTMP_Write() 将文件发布到 Wowza 媒体服务器?

4

2 回答 2

9

以我自己的经验,将视频数据流式传输到 RTMP 服务器实际上在 librtmp 端非常简单。棘手的部分是正确打包视频/音频数据并以正确的速率读取它。

假设您使用的是 FLV 视频文件,只要您可以正确隔离文件中的每个标签并使用一次RTMP_Write调用发送每个标签,您甚至不需要处理传入的数据包。

棘手的部分是了解 FLV 文件是如何制作的。官方规范可在此处获得:http: //www.adobe.com/devnet/f4v.html

首先,有一个标题,它由 9 个字节组成。此标头不得发送到服务器,而只能通读以确保文件确实是 FLV。

然后是标签流。每个标签都有一个 11 字节的标头,其中包含标签类型(视频/音频/元数据)、正文长度和标签的时间戳等。

标签头可以用这个结构来描述:

typedef struct __flv_tag {
  uint8       type;
  uint24_be   body_length; /* in bytes, total tag size minus 11 */
  uint24_be   timestamp; /* milli-seconds */
  uint8       timestamp_extended; /* timestamp extension */
  uint24_be   stream_id; /* reserved, must be "\0\0\0" */
  /* body comes next */
} flv_tag;

正文长度和时间戳显示为 24 位大端整数,如有必要,带有一个补充字节以将时间戳扩展到 32 位(大约在 4 小时左右)。

一旦您阅读了标签标题,您就可以阅读正文本身,因为您现在知道它的长度 ( body_length)。

之后有一个 32 位大端整数值,其中包含标签的完整长度(11 字节 + body_length)。

您必须在一次 调用中写入标签标题 + 正文 + 之前的标签大小RTMP_Write(否则它不会播放)。

另外,请注意以视频的标称帧速率发送数据包,否则播放会受到很大影响。

我已经编写了一个完整的 FLV 文件解复用器,作为我的 GPL 项目FLVmeta的一部分,您可以将其用作参考。

于 2012-12-10T14:41:24.083 回答
0

事实上,RTMP_Write() 似乎要求你已经在 buf 中形成了 RTMP 数据包。

RTMPPacket *pkt = &r->m_write;
...
pkt->m_packetType = *buf++;

所以,你不能只把 flv 数据推送到那里——你需要先把它分成数据包。

有一个不错的函数 RTMP_ReadPacket(),但它从网络套接字读取。

我和你有同样的问题,希望尽快解决。

编辑:

RTMP_Write() 中存在某些错误。我做了一个补丁,现在它可以工作了。我要发布那个。

于 2011-03-15T14:57:09.720 回答