LIVE555 利用FIFO实现直播

发布时间 2023-07-26 09:54:26作者: 阿风小子
1.LIVE555 直播
 
直播方案采取的是  直播流  -> FIFO -> 输出  的技术路线。
 
2.搭建:
 
a. 在LIVE555 编译之后,在BIN文件下,有很多可执行程序生成,这些程序有些是LIVE555服务器(live555MediaServer),有些是客户端(testRTSPClient),还有大量的流推送服务(testMPEG2TransportStreamer)
 
b.我们选取testOnDemandRTSPServer(客户响应服务) 和  testMPEG2TransportStreamer(推流) 就可以搭建一个live555直播。
 
3.服务端代码修改:
 
在 testOnDemandRTSPServer.cpp 中我们可以看到以下代码内容:
 
// A MPEG-2 Transport Stream, coming from a live UDP (raw-UDP or RTP/UDP) source:
  {
    char const* streamName = "mpeg2TransportStreamFromUDPSourceTest";
    char const* inputAddressStr = "239.255.42.42";
        // This causes the server to take its input from the stream sent by the "testMPEG2TransportStreamer" demo application.
        // (Note: If the input UDP source is unicast rather than multicast, then change this to NULL.)
    portNumBits const inputPortNum = 1234;
        // This causes the server to take its input from the stream sent by the "testMPEG2TransportStreamer" demo application.
    Boolean const inputStreamIsRawUDP = False; 
    ServerMediaSession* sms
      = ServerMediaSession::createNew(*env, streamName, streamName,
          descriptionString);
    sms->addSubsession(MPEG2TransportUDPServerMediaSubsession
         ::createNew(*env, inputAddressStr, inputPortNum, inputStreamIsRawUDP));
    rtspServer->addServerMediaSession(sms);
    char* url = rtspServer->rtspURL(sms);
    *env << "\n\"" << streamName << "\" stream, from a UDP Transport Stream input source \n\t(";
    if (inputAddressStr != NULL) {
      *env << "IP multicast address " << inputAddressStr << ",";
    } else {
      *env << "unicast;";
    }
    *env << " port " << inputPortNum << ")\n";
    *env << "Play this stream using the URL \"" << url << "\"\n";
    delete[] url;
  }
 
我们需要修改的地方有以下几处:
 
a. 把输入流的地址,从 "239.255.42.42" 改为回环地址 “127.0.0.1”(因为推流程序和服务程序都在本机)
 
b. 把输出的流名streamName  从 "mpeg2TransportStreamFromUDPSourceTest" 改为自己设定的 “live”
 
4.推流端服务代码修改:
 
推流代码 testMPEG2TransportStreamer.cpp 有以下几个地方需要修改:
 
a. 对应服务端,把发送地址改为 “127.0.0.1"
 
   char const* destinationAddressStr = "127.0.0.1";
 
b. 原先的推流代码不支持FIFO,他是把一个本地文件不停的循环播放,因此我们需要把本地文件改为FIFO:
 
  char const* inputFileName = "test.ts"; 改为 char const* inputFileName = "/var/ibuf_fifo";
 
c. 因为FIFO文件有一点特殊(后边会提及),我们需要修改播放的类 ByteStreamFileSource ,如果不想修改,我们可以直接抄袭 ByteStreamFileSource类自己生成一个新类,然后修改代码。
 
   FIFO文件的特殊性: 前端的编码器修改参数,必然会中断编码器流输出,此时FIFO会被testMPEG2TransportStreamer这个发送端读空。
 
                      当编码器重新送流后,FIFO也会处于一种临界读空的状态,导致播放时十分卡顿。
 
                      因此需要处理FIFO的上溢和下溢。
 
   具体的修改: 在类的 fileReadableHandler函数中添加以下内容(此处的修改以FIFO的大小为2M为例):
 
void newByteStreamFileSource::fileReadableHandler(newByteStreamFileSource* source, int /*mask*/) 
{
// 新增代码,防止FIFO上溢或者下溢,如果上溢则取出一部分数据,下溢则等待
int count = 0;
ioctl(fileno(source->fFid), FIONREAD, &count);
if((count < 0x40000) || (count >= 0x1FF000))
{
if(count >= 0x1FF000)
{
int dropNum = 0;
char buffer[0x200000] = {0};
dropNum = fread(buffer, 1,  1000  * 188 , source->fFid);
printf("[%s]%d Drop data  (%d) ...\n", __func__, __LINE__, dropNum);
}
source->handleClosure();
}
// 新增代码结束
 
if (!source->isCurrentlyAwaitingData())
{
source->doStopGettingFrames(); // we're not ready for the data yet
return;
}
 
source->doReadFromFile();
}