分享

通过live555实现H264 RTSP直播

 waston 2021-10-19

      实现思路是将视频流发送给live555, 由live555来实现H264数据流直播。

      视频采集模块通过FIFO队列将H264数据帧发送给live555. live555 在收到客户端的RTSP播放请求后,开始从FIFO中读取H264视频数据并通过RTSP直播出去。整个流程如下图所示:


调整和修改Live555 MediaServer

        下载live555源码,在media目录下增加四个文件并修改文件live555MediaServer.cpp。增加的四个文件如下:

WW_H264VideoServerMediaSubsession.h

WW_H264VideoServerMediaSubsession.cpp

 WW_H264VideoSource.h

WW_H264VideoSource.cpp

        下面附上四个文件的源码:

WW_H264VideoServerMediaSubsession.h

  1. #pragma once  


  2. #include "liveMedia.hh"  

  3. #include "BasicUsageEnvironment.hh"  

  4. #include "GroupsockHelper.hh"  


  5. #include "OnDemandServerMediaSubsession.hh"  

  6. #include "WW_H264VideoSource.h"  


  7. class WW_H264VideoServerMediaSubsession : public OnDemandServerMediaSubsession  

  8. {  

  9. public:  

  10.     WW_H264VideoServerMediaSubsession(UsageEnvironment & env, FramedSource * source);  

  11.     ~WW_H264VideoServerMediaSubsession(void);  


  12. public:  

  13.     virtual char const * getAuxSDPLine(RTPSink * rtpSink, FramedSource * inputSource);  

  14.     virtual FramedSource * createNewStreamSource(unsigned clientSessionId, unsigned & estBitrate); // "estBitrate" is the stream's estimated bitrate, in kbps  

  15.     virtual RTPSink * createNewRTPSink(Groupsock * rtpGroupsock, unsigned char rtpPayloadTypeIfDynamic, FramedSource * inputSource);  


  16.     static WW_H264VideoServerMediaSubsession * createNew(UsageEnvironment & env, FramedSource * source);  


  17.     static void afterPlayingDummy(void * ptr);  


  18.     static void chkForAuxSDPLine(void * ptr);  

  19.     void chkForAuxSDPLine1();  


  20. private:  

  21.     FramedSource * m_pSource;  

  22.     char * m_pSDPLine;  

  23.     RTPSink * m_pDummyRTPSink;  

  24.     char m_done;  

  25. };  

WW_H264VideoServerMediaSubsession.cpp

  1. #include "WW_H264VideoServerMediaSubsession.h"  


  2. WW_H264VideoServerMediaSubsession::WW_H264VideoServerMediaSubsession(UsageEnvironment & env, FramedSource * source) : OnDemandServerMediaSubsession(env, True)  

  3. {  

  4.     m_pSource = source;  

  5.     m_pSDPLine = 0;  

  6. }  


  7. WW_H264VideoServerMediaSubsession::~WW_H264VideoServerMediaSubsession(void)  

  8. {  

  9.     if (m_pSDPLine)  

  10.     {  

  11.         free(m_pSDPLine);  

  12.     }  

  13. }  


  14. WW_H264VideoServerMediaSubsession * WW_H264VideoServerMediaSubsession::createNew(UsageEnvironment & env, FramedSource * source)  

  15. {  

  16.     return new WW_H264VideoServerMediaSubsession(env, source);  

  17. }  


  18. FramedSource * WW_H264VideoServerMediaSubsession::createNewStreamSource(unsigned clientSessionId, unsigned & estBitrate)  

  19. {  

  20.     return H264VideoStreamFramer::createNew(envir(), new WW_H264VideoSource(envir()));  

  21. }  


  22. RTPSink * WW_H264VideoServerMediaSubsession::createNewRTPSink(Groupsock * rtpGroupsock, unsigned char rtpPayloadTypeIfDynamic, FramedSource * inputSource)  

  23. {  

  24.     return H264VideoRTPSink::createNew(envir(), rtpGroupsock, rtpPayloadTypeIfDynamic);  

  25. }  


  26. char const * WW_H264VideoServerMediaSubsession::getAuxSDPLine(RTPSink * rtpSink, FramedSource * inputSource)  

  27. {  

  28.     if (m_pSDPLine)  

  29.     {  

  30.         return m_pSDPLine;  

  31.     }  


  32.     m_pDummyRTPSink = rtpSink;  


  33.     //mp_dummy_rtpsink->startPlaying(*source, afterPlayingDummy, this);  

  34.     m_pDummyRTPSink->startPlaying(*inputSource, 0, 0);  


  35.     chkForAuxSDPLine(this);  


  36.     m_done = 0;  


  37.     envir().taskScheduler().doEventLoop(&m_done);  


  38.     m_pSDPLine = strdup(m_pDummyRTPSink->auxSDPLine());  


  39.     m_pDummyRTPSink->stopPlaying();  


  40.     return m_pSDPLine;  

  41. }  


  42. void WW_H264VideoServerMediaSubsession::afterPlayingDummy(void * ptr)  

  43. {  

  44.     WW_H264VideoServerMediaSubsession * This = (WW_H264VideoServerMediaSubsession *)ptr;  


  45.     This->m_done = 0xff;  

  46. }  


  47. void WW_H264VideoServerMediaSubsession::chkForAuxSDPLine(void * ptr)  

  48. {  

  49.     WW_H264VideoServerMediaSubsession * This = (WW_H264VideoServerMediaSubsession *)ptr;  


  50.     This->chkForAuxSDPLine1();  

  51. }  


  52. void WW_H264VideoServerMediaSubsession::chkForAuxSDPLine1()  

  53. {  

  54.     if (m_pDummyRTPSink->auxSDPLine())  

  55.     {  

  56.         m_done = 0xff;  

  57.     }  

  58.     else  

  59.     {  

  60.         double delay = 1000.0 / (FRAME_PER_SEC);  // ms  

  61.         int to_delay = delay * 1000;  // us  


  62.         nextTask() = envir().taskScheduler().scheduleDelayedTask(to_delay, chkForAuxSDPLine, this);  

  63.     }  

  64. }  


WW_H264VideoSource.h
  1. #ifndef _WW_H264VideoSource_H  

  2. #define _WW_H264VideoSource_H  


  3. #include "liveMedia.hh"  

  4. #include "BasicUsageEnvironment.hh"  

  5. #include "GroupsockHelper.hh"  

  6. #include "FramedSource.hh"  


  7. #define FRAME_PER_SEC 25  


  8. class WW_H264VideoSource : public FramedSource  

  9. {  

  10. public:  

  11.     WW_H264VideoSource(UsageEnvironment & env);  

  12.     ~WW_H264VideoSource(void);  


  13. public:  

  14.     virtual void doGetNextFrame();  

  15.     virtual unsigned int maxFrameSize() const;  


  16.     static void getNextFrame(void * ptr);  

  17.     void GetFrameData();  


  18. private:  

  19.     void *m_pToken;  

  20.     char *m_pFrameBuffer;  

  21.     int  m_hFifo;  

  22. };  


  23. #endif  

WW_H264VideoSource.cpp
  1. #include "WW_H264VideoSource.h"  

  2. #include <stdio.h>  

  3. #ifdef WIN32  

  4. #include <windows.h>  

  5. #else  

  6. #include <sys/types.h>  

  7. #include <sys/stat.h>  

  8. #include <string.h>  

  9. #include <fcntl.h>  

  10. #include <unistd.h>  

  11. #include <limits.h>  

  12. #endif  


  13. #define FIFO_NAME     "/tmp/H264_fifo"  

  14. #define BUFFER_SIZE   PIPE_BUF  

  15. #define REV_BUF_SIZE  (1024*1024)  


  16. #ifdef WIN32  

  17. #define mSleep(ms)    Sleep(ms)  

  18. #else  

  19. #define mSleep(ms)    usleep(ms*1000)  

  20. #endif  



  21. WW_H264VideoSource::WW_H264VideoSource(UsageEnvironment & env) :   

  22. FramedSource(env),  

  23. m_pToken(0),  

  24. m_pFrameBuffer(0),  

  25. m_hFifo(0)  

  26. {  

  27.     m_hFifo = open(FIFO_NAME,O_RDONLY);  

  28.         printf("[MEDIA SERVER] open fifo result = [%d]\n",m_hFifo);  

  29.     if(m_hFifo == -1)  

  30.     {  

  31.         return;  

  32.     }  


  33.     m_pFrameBuffer = new char[REV_BUF_SIZE];  

  34.     if(m_pFrameBuffer == NULL)  

  35.     {  

  36.         printf("[MEDIA SERVER] error malloc data buffer failed\n");  

  37.         return;  

  38.     }  

  39.     memset(m_pFrameBuffer,0,REV_BUF_SIZE);  

  40. }  


  41. WW_H264VideoSource::~WW_H264VideoSource(void)  

  42. {  

  43.     if(m_hFifo)  

  44.     {  

  45.         ::close(m_hFifo);  

  46.     }  


  47.     envir().taskScheduler().unscheduleDelayedTask(m_pToken);  


  48.     if(m_pFrameBuffer)  

  49.     {  

  50.         delete[] m_pFrameBuffer;  

  51.         m_pFrameBuffer = NULL;  

  52.     }  


  53.     printf("[MEDIA SERVER] rtsp connection closed\n");  

  54. }  


  55. void WW_H264VideoSource::doGetNextFrame()  

  56. {  

  57.     // 根据 fps,计算等待时间  

  58.     double delay = 1000.0 / (FRAME_PER_SEC * 2);  // ms  

  59.     int to_delay = delay * 1000;  // us  


  60.     m_pToken = envir().taskScheduler().scheduleDelayedTask(to_delay, getNextFrame, this);  

  61. }  


  62. unsigned int WW_H264VideoSource::maxFrameSize() const  

  63. {  

  64.     return 1024*200;  

  65. }  


  66. void WW_H264VideoSource::getNextFrame(void * ptr)  

  67. {  

  68.     ((WW_H264VideoSource *)ptr)->GetFrameData();  

  69. }  


  70. void WW_H264VideoSource::GetFrameData()  

  71. {  

  72.     gettimeofday(&fPresentationTime, 0);  


  73.     fFrameSize = 0;  


  74.     int len = 0;  

  75.     unsigned char buffer[BUFFER_SIZE] = {0};  

  76.     while((len = read(m_hFifo,buffer,BUFFER_SIZE))>0)  

  77.     {  

  78.         memcpy(m_pFrameBuffer+fFrameSize,buffer,len);  

  79.         fFrameSize+=len;  

  80.     }  

  81.     //printf("[MEDIA SERVER] GetFrameData len = [%d],fMaxSize = [%d]\n",fFrameSize,fMaxSize);  


  82.     // fill frame data  

  83.     memcpy(fTo,m_pFrameBuffer,fFrameSize);  


  84.     if (fFrameSize > fMaxSize)  

  85.     {  

  86.         fNumTruncatedBytes = fFrameSize - fMaxSize;  

  87.         fFrameSize = fMaxSize;  

  88.     }  

  89.     else  

  90.     {  

  91.         fNumTruncatedBytes = 0;  

  92.     }  


  93.     afterGetting(this);  

  94. }  

修改live555MediaServer.cpp文件如下

  1. /********** 

  2. This library is free software; you can redistribute it and/or modify it under 

  3. the terms of the GNU Lesser General Public License as published by the 

  4. Free Software Foundation; either version 2.1 of the License, or (at your 

  5. option) any later version. (See <http://www./copyleft/lesser.html>.) 


  6. This library is distributed in the hope that it will be useful, but WITHOUT 

  7. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 

  8. FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for 

  9. more details. 


  10. You should have received a copy of the GNU Lesser General Public License 

  11. along with this library; if not, write to the Free Software Foundation, Inc., 

  12. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA 

  13. **********/  

  14. // Copyright (c) 1996-2013, Live Networks, Inc.  All rights reserved  

  15. // LIVE555 Media Server  

  16. // main program  


  17. #include <BasicUsageEnvironment.hh>  

  18. #include "DynamicRTSPServer.hh"  

  19. #include "version.hh"  

  20. #include "WW_H264VideoSource.h"  

  21. #include "WW_H264VideoServerMediaSubsession.h"  


  22. int main(int argc, char** argv) {  

  23.     // Begin by setting up our usage environment:  

  24.     TaskScheduler* scheduler = BasicTaskScheduler::createNew();  

  25.     UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);  


  26.     UserAuthenticationDatabase* authDB = NULL;  

  27. #ifdef ACCESS_CONTROL  

  28.     // To implement client access control to the RTSP server, do the following:  

  29.     authDB = new UserAuthenticationDatabase;  

  30.     authDB->addUserRecord("username1""password1"); // replace these with real strings  

  31.     // Repeat the above with each <username>, <password> that you wish to allow  

  32.     // access to the server.  

  33. #endif  


  34.     // Create the RTSP server:  

  35.     RTSPServer* rtspServer = RTSPServer::createNew(*env, 554, authDB);  

  36.     if (rtspServer == NULL) {  

  37.         *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";  

  38.         exit(1);  

  39.     }  


  40.     // Add live stream  


  41.     WW_H264VideoSource * videoSource = 0;  


  42.     ServerMediaSession * sms = ServerMediaSession::createNew(*env, "live", 0, "ww live test");  

  43.     sms->addSubsession(WW_H264VideoServerMediaSubsession::createNew(*env, videoSource));  

  44.     rtspServer->addServerMediaSession(sms);  


  45.     char * url = rtspServer->rtspURL(sms);  

  46.     *env << "using url \"" << url << "\"\n";  

  47.     delete[] url;  


  48.     // Run loop  

  49.     env->taskScheduler().doEventLoop();  


  50.     rtspServer->removeServerMediaSession(sms);  


  51.     Medium::close(rtspServer);  


  52.     env->reclaim();  


  53.     delete scheduler;  


  54.     return 1;  

  55. }  


发送H264视频流的RTSPStream

  1. /********************************************************************  

  2. filename:   RTSPStream.h 

  3. created:    2013-08-01 

  4. author:     firehood  

  5. purpose:    通过live555实现H264 RTSP直播 

  6. *********************************************************************/   

  7. #pragma once  

  8. #include <stdio.h>  

  9. #ifdef WIN32  

  10. #include <windows.h>  

  11. #else  

  12. #include <pthread.h>  

  13. #endif  


  14. #ifdef WIN32  

  15. typedef HANDLE       ThreadHandle;  

  16. #define mSleep(ms)   Sleep(ms)  

  17. #else  

  18. typedef unsigned int SOCKET;  

  19. typedef pthread_t    ThreadHandle;  

  20. #define mSleep(ms)   usleep(ms*1000)  

  21. #endif  


  22. #define FILEBUFSIZE (1024 * 1024)   



  23. class CRTSPStream  

  24. {  

  25. public:  

  26.     CRTSPStream(void);  

  27.     ~CRTSPStream(void);  

  28. public:  

  29.     // 初始化  

  30.     bool Init();  

  31.     // 卸载  

  32.     void Uninit();  

  33.     // 发送H264文件  

  34.     bool SendH264File(const char *pFileName);  

  35.     // 发送H264数据帧  

  36.     int SendH264Data(const unsigned char *data,unsigned int size);  

  37. };  



  1. /********************************************************************  

  2. filename:   RTSPStream.cpp 

  3. created:    2013-08-01 

  4. author:     firehood  

  5. purpose:    通过live555实现H264 RTSP直播 

  6. *********************************************************************/   

  7. #include "RTSPStream.h"  

  8. #ifdef WIN32  

  9. #else  

  10. #include <sys/types.h>  

  11. #include <sys/stat.h>  

  12. #include <string.h>  

  13. #include <fcntl.h>  

  14. #include <unistd.h>  

  15. #include <limits.h>  

  16. #include <errno.h>  

  17. #endif  


  18. #define FIFO_NAME    "/tmp/H264_fifo"  

  19. #define BUFFERSIZE   PIPE_BUF  


  20. CRTSPStream::CRTSPStream(void)  

  21. {  


  22. }  


  23. CRTSPStream::~CRTSPStream(void)  

  24. {  


  25. }  


  26. bool CRTSPStream::Init()  

  27. {  

  28.     if(access(FIFO_NAME,F_OK) == -1)  

  29.     {  

  30.         int res = mkfifo(FIFO_NAME,0777);  

  31.         if(res != 0)  

  32.         {  

  33.             printf("[RTSPStream] Create fifo failed.\n");  

  34.             return false;  

  35.         }  

  36.     }  

  37.     return true;  

  38. }  



  39. void CRTSPStream::Uninit()  

  40. {  


  41. }  


  42. bool CRTSPStream::SendH264File(const char *pFileName)  

  43. {  

  44.     if(pFileName == NULL)  

  45.     {  

  46.         return false;  

  47.     }  

  48.     FILE *fp = fopen(pFileName, "rb");    

  49.     if(!fp)    

  50.     {    

  51.         printf("[RTSPStream] error:open file %s failed!",pFileName);  

  52.     }    

  53.     fseek(fp, 0, SEEK_SET);  


  54.     unsigned char *buffer  = new unsigned char[FILEBUFSIZE];  

  55.     int pos = 0;  

  56.     while(1)  

  57.     {  

  58.         int readlen = fread(buffer+pos, sizeof(unsigned char), FILEBUFSIZE-pos, fp);  


  59.         if(readlen<=0)  

  60.         {  

  61.             break;  

  62.         }  


  63.         readlen+=pos;  


  64.         int writelen = SendH264Data(buffer,readlen);  

  65.         if(writelen<=0)  

  66.         {  

  67.             break;  

  68.         }  

  69.         memcpy(buffer,buffer+writelen,readlen-writelen);  

  70.         pos = readlen-writelen;  


  71.         mSleep(25);  

  72.     }  

  73.     fclose(fp);  

  74.     delete[] buffer;  

  75.     return true;  

  76. }  


  77. // 发送H264数据帧  

  78. int CRTSPStream::SendH264Data(const unsigned char *data,unsigned int size)  

  79. {  

  80.     if(data == NULL)  

  81.     {  

  82.         return 0;  

  83.     }  

  84.     // open pipe with non_block mode  

  85.     int pipe_fd = open(FIFO_NAME, O_WRONLY|O_NONBLOCK);  

  86.     //printf("[RTSPStream] open fifo result = [%d]\n",pipe_fd);  

  87.     if(pipe_fd == -1)  

  88.     {  

  89.         return 0;  

  90.     }  


  91.     int send_size = 0;  

  92.     int remain_size = size;  

  93.     while(send_size < size)  

  94.     {  

  95.         int data_len = (remain_size<BUFFERSIZE) ? remain_size : BUFFERSIZE;  

  96.         int len = write(pipe_fd,data+send_size,data_len);  

  97.         if(len == -1)  

  98.         {  

  99.             static int resend_conut = 0;  

  100.             if(errno == EAGAIN && ++resend_conut<=3)  

  101.             {  

  102.                 printf("[RTSPStream] write fifo error,resend..\n");  

  103.                 continue;  

  104.             }  

  105.             resend_conut = 0;  

  106.             printf("[RTSPStream] write fifo error,errorcode[%d],send_size[%d]\n",errno,send_size);  

  107.             break;  

  108.         }  

  109.         else  

  110.         {    

  111.             send_size+= len;  

  112.             remain_size-= len;  

  113.         }  

  114.     }  

  115.     close(pipe_fd);  

  116.     //printf("[RTSPStream] SendH264Data datalen[%d], sendsize = [%d]\n",size,send_size);  

  117.     return 0;  

  118. }  


测试程序代码


  1. #include <stdio.h>  

  2. #include "RTSPStream.h"  


  3. int main(int argc,char* argv[])  

  4. {  

  5.     CRTSPStream rtspSender;  

  6.     bool bRet = rtspSender.Init();  

  7.     rtspSender.SendH264File("E:\\测试视频\\test.264");  

  8.     system("pause");    

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多