生活随笔
收集整理的這篇文章主要介紹了
通过live555实现H264 RTSP直播
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
轉載自:http://blog.csdn.net/firehood_/article/details/16844397
? ? ? 前面的文章中介紹了《H264視頻通過RTMP流直播》,下面將介紹一下如何將H264實時視頻通過RTSP直播。
? ? ? 實現思路是將視頻流發送給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
[cpp]?view plaincopy
#pragma?once?? ?? #include?"liveMedia.hh"?? #include?"BasicUsageEnvironment.hh"?? #include?"GroupsockHelper.hh"?? ?? #include?"OnDemandServerMediaSubsession.hh"?? #include?"WW_H264VideoSource.h"?? ?? class?WW_H264VideoServerMediaSubsession?:?public?OnDemandServerMediaSubsession?? {?? public:?? ????WW_H264VideoServerMediaSubsession(UsageEnvironment?&?env,?FramedSource?*?source);?? ????~WW_H264VideoServerMediaSubsession(void);?? ?? public:?? ????virtual?char?const?*?getAuxSDPLine(RTPSink?*?rtpSink,?FramedSource?*?inputSource);?? ????virtual?FramedSource?*?createNewStreamSource(unsigned?clientSessionId,?unsigned?&?estBitrate);??? ????virtual?RTPSink?*?createNewRTPSink(Groupsock?*?rtpGroupsock,?unsigned?char?rtpPayloadTypeIfDynamic,?FramedSource?*?inputSource);?? ?? ????static?WW_H264VideoServerMediaSubsession?*?createNew(UsageEnvironment?&?env,?FramedSource?*?source);?? ?? ????static?void?afterPlayingDummy(void?*?ptr);?? ?? ????static?void?chkForAuxSDPLine(void?*?ptr);?? ????void?chkForAuxSDPLine1();?? ?? private:?? ????FramedSource?*?m_pSource;?? ????char?*?m_pSDPLine;?? ????RTPSink?*?m_pDummyRTPSink;?? ????char?m_done;?? };?? ? ? ? ??
WW_H264VideoServerMediaSubsession.cpp
[cpp]?view plaincopy
#include?"WW_H264VideoServerMediaSubsession.h"?? ?? WW_H264VideoServerMediaSubsession::WW_H264VideoServerMediaSubsession(UsageEnvironment?&?env,?FramedSource?*?source)?:?OnDemandServerMediaSubsession(env,?True)?? {?? ????m_pSource?=?source;?? ????m_pSDPLine?=?0;?? }?? ?? WW_H264VideoServerMediaSubsession::~WW_H264VideoServerMediaSubsession(void)?? {?? ????if?(m_pSDPLine)?? ????{?? ????????free(m_pSDPLine);?? ????}?? }?? ?? WW_H264VideoServerMediaSubsession?*?WW_H264VideoServerMediaSubsession::createNew(UsageEnvironment?&?env,?FramedSource?*?source)?? {?? ????return?new?WW_H264VideoServerMediaSubsession(env,?source);?? }?? ?? FramedSource?*?WW_H264VideoServerMediaSubsession::createNewStreamSource(unsigned?clientSessionId,?unsigned?&?estBitrate)?? {?? ????return?H264VideoStreamFramer::createNew(envir(),?new?WW_H264VideoSource(envir()));?? }?? ?? RTPSink?*?WW_H264VideoServerMediaSubsession::createNewRTPSink(Groupsock?*?rtpGroupsock,?unsigned?char?rtpPayloadTypeIfDynamic,?FramedSource?*?inputSource)?? {?? ????return?H264VideoRTPSink::createNew(envir(),?rtpGroupsock,?rtpPayloadTypeIfDynamic);?? }?? ?? char?const?*?WW_H264VideoServerMediaSubsession::getAuxSDPLine(RTPSink?*?rtpSink,?FramedSource?*?inputSource)?? {?? ????if?(m_pSDPLine)?? ????{?? ????????return?m_pSDPLine;?? ????}?? ?? ????m_pDummyRTPSink?=?rtpSink;?? ?? ?????? ????m_pDummyRTPSink->startPlaying(*inputSource,?0,?0);?? ?? ????chkForAuxSDPLine(this);?? ?? ????m_done?=?0;?? ?? ????envir().taskScheduler().doEventLoop(&m_done);?? ?? ????m_pSDPLine?=?strdup(m_pDummyRTPSink->auxSDPLine());?? ?? ????m_pDummyRTPSink->stopPlaying();?? ?? ????return?m_pSDPLine;?? }?? ?? void?WW_H264VideoServerMediaSubsession::afterPlayingDummy(void?*?ptr)?? {?? ????WW_H264VideoServerMediaSubsession?*?This?=?(WW_H264VideoServerMediaSubsession?*)ptr;?? ?? ????This->m_done?=?0xff;?? }?? ?? void?WW_H264VideoServerMediaSubsession::chkForAuxSDPLine(void?*?ptr)?? {?? ????WW_H264VideoServerMediaSubsession?*?This?=?(WW_H264VideoServerMediaSubsession?*)ptr;?? ?? ????This->chkForAuxSDPLine1();?? }?? ?? void?WW_H264VideoServerMediaSubsession::chkForAuxSDPLine1()?? {?? ????if?(m_pDummyRTPSink->auxSDPLine())?? ????{?? ????????m_done?=?0xff;?? ????}?? ????else?? ????{?? ????????double?delay?=?1000.0?/?(FRAME_PER_SEC);???? ????????int?to_delay?=?delay?*?1000;???? ?? ????????nextTask()?=?envir().taskScheduler().scheduleDelayedTask(to_delay,?chkForAuxSDPLine,?this);?? ????}?? }?? WW_H264VideoSource.h
[cpp]?view plaincopy
#ifndef?_WW_H264VideoSource_H?? #define?_WW_H264VideoSource_H?? ?? #include?"liveMedia.hh"?? #include?"BasicUsageEnvironment.hh"?? #include?"GroupsockHelper.hh"?? #include?"FramedSource.hh"?? ?? #define?FRAME_PER_SEC?25?? ?? class?WW_H264VideoSource?:?public?FramedSource?? {?? public:?? ????WW_H264VideoSource(UsageEnvironment?&?env);?? ????~WW_H264VideoSource(void);?? ?? public:?? ????virtual?void?doGetNextFrame();?? ????virtual?unsigned?int?maxFrameSize()?const;?? ?? ????static?void?getNextFrame(void?*?ptr);?? ????void?GetFrameData();?? ?? private:?? ????void?*m_pToken;?? ????char?*m_pFrameBuffer;?? ????int??m_hFifo;?? };?? ?? #endif??
WW_H264VideoSource.cpp
[cpp]?view plaincopy
#include?"WW_H264VideoSource.h"?? #include?<stdio.h>?? #ifdef?WIN32?? #include?<windows.h>?? #else?? #include?<sys/types.h>?? #include?<sys/stat.h>?? #include?<string.h>?? #include?<fcntl.h>?? #include?<unistd.h>?? #include?<limits.h>?? #endif?? ?? #define?FIFO_NAME?????"/tmp/H264_fifo"?? #define?BUFFER_SIZE???PIPE_BUF?? #define?REV_BUF_SIZE??(1024*1024)?? ?? #ifdef?WIN32?? #define?mSleep(ms)????Sleep(ms)?? #else?? #define?mSleep(ms)????usleep(ms*1000)?? #endif?? ?? ?? WW_H264VideoSource::WW_H264VideoSource(UsageEnvironment?&?env)?:??? FramedSource(env),?? m_pToken(0),?? m_pFrameBuffer(0),?? m_hFifo(0)?? {?? ????m_hFifo?=?open(FIFO_NAME,O_RDONLY);?? ????????printf("[MEDIA?SERVER]?open?fifo?result?=?[%d]\n",m_hFifo);?? ????if(m_hFifo?==?-1)?? ????{?? ????????return;?? ????}?? ?????? ????m_pFrameBuffer?=?new?char[REV_BUF_SIZE];?? ????if(m_pFrameBuffer?==?NULL)?? ????{?? ????????printf("[MEDIA?SERVER]?error?malloc?data?buffer?failed\n");?? ????????return;?? ????}?? ????memset(m_pFrameBuffer,0,REV_BUF_SIZE);?? }?? ?? WW_H264VideoSource::~WW_H264VideoSource(void)?? {?? ????if(m_hFifo)?? ????{?? ????????::close(m_hFifo);?? ????}?? ?????? ????envir().taskScheduler().unscheduleDelayedTask(m_pToken);?? ?? ????if(m_pFrameBuffer)?? ????{?? ????????delete[]?m_pFrameBuffer;?? ????????m_pFrameBuffer?=?NULL;?? ????}?? ?? ????printf("[MEDIA?SERVER]?rtsp?connection?closed\n");?? }?? ?? void?WW_H264VideoSource::doGetNextFrame()?? {?? ?????? ????double?delay?=?1000.0?/?(FRAME_PER_SEC?*?2);???? ????int?to_delay?=?delay?*?1000;???? ?? ????m_pToken?=?envir().taskScheduler().scheduleDelayedTask(to_delay,?getNextFrame,?this);?? }?? ?? unsigned?int?WW_H264VideoSource::maxFrameSize()?const?? {?? ????return?1024*200;?? }?? ?? void?WW_H264VideoSource::getNextFrame(void?*?ptr)?? {?? ????((WW_H264VideoSource?*)ptr)->GetFrameData();?? }?? ?? void?WW_H264VideoSource::GetFrameData()?? {?? ????gettimeofday(&fPresentationTime,?0);?? ?? ????fFrameSize?=?0;?? ?? ????int?len?=?0;?? ????unsigned?char?buffer[BUFFER_SIZE]?=?{0};?? ????while((len?=?read(m_hFifo,buffer,BUFFER_SIZE))>0)?? ????{?? ????????memcpy(m_pFrameBuffer+fFrameSize,buffer,len);?? ????????fFrameSize+=len;?? ????}?? ?????? ?? ?????? ????memcpy(fTo,m_pFrameBuffer,fFrameSize);?? ?? ????if?(fFrameSize?>?fMaxSize)?? ????{?? ????????fNumTruncatedBytes?=?fFrameSize?-?fMaxSize;?? ????????fFrameSize?=?fMaxSize;?? ????}?? ????else?? ????{?? ????????fNumTruncatedBytes?=?0;?? ????}?? ??????????????????? ????afterGetting(this);?? }?? [cpp]?view plaincopy
??
修改live555MediaServer.cpp文件如下
[cpp]?view plaincopy
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ?? ?? ?? ?? #include?<BasicUsageEnvironment.hh>?? #include?"DynamicRTSPServer.hh"?? #include?"version.hh"?? #include?"WW_H264VideoSource.h"?? #include?"WW_H264VideoServerMediaSubsession.h"?? ?? int?main(int?argc,?char**?argv)?{?? ?????? ????TaskScheduler*?scheduler?=?BasicTaskScheduler::createNew();?? ????UsageEnvironment*?env?=?BasicUsageEnvironment::createNew(*scheduler);?? ?? ????UserAuthenticationDatabase*?authDB?=?NULL;?? #ifdef?ACCESS_CONTROL?? ?????? ????authDB?=?new?UserAuthenticationDatabase;?? ????authDB->addUserRecord("username1",?"password1");??? ?????? ?????? #endif?? ?? ?????? ????RTSPServer*?rtspServer?=?RTSPServer::createNew(*env,?554,?authDB);?? ????if?(rtspServer?==?NULL)?{?? ????????*env?<<?"Failed?to?create?RTSP?server:?"?<<?env->getResultMsg()?<<?"\n";?? ????????exit(1);?? ????}?? ?? ?????? ?? ????WW_H264VideoSource?*?videoSource?=?0;?? ?? ????ServerMediaSession?*?sms?=?ServerMediaSession::createNew(*env,?"live",?0,?"ww?live?test");?? ????sms->addSubsession(WW_H264VideoServerMediaSubsession::createNew(*env,?videoSource));?? ????rtspServer->addServerMediaSession(sms);?? ?? ????char?*?url?=?rtspServer->rtspURL(sms);?? ????*env?<<?"using?url?\""?<<?url?<<?"\"\n";?? ????delete[]?url;?? ?? ?????? ????env->taskScheduler().doEventLoop();?? ?? ????rtspServer->removeServerMediaSession(sms);?? ?? ????Medium::close(rtspServer);?? ?? ????env->reclaim();?? ?? ????delete?scheduler;?? ?? ????return?1;?? }?? 發送H264視頻流的RTSPStream
[cpp]?view plaincopy
? ? ? ? ? ??? #pragma?once?? #include?<stdio.h>?? #ifdef?WIN32?? #include?<windows.h>?? #else?? #include?<pthread.h>?? #endif?? ?? #ifdef?WIN32?? typedef?HANDLE???????ThreadHandle;?? #define?mSleep(ms)???Sleep(ms)?? #else?? typedef?unsigned?int?SOCKET;?? typedef?pthread_t????ThreadHandle;?? #define?mSleep(ms)???usleep(ms*1000)?? #endif?? ?? #define?FILEBUFSIZE?(1024?*?1024)??? ?? ?? class?CRTSPStream?? {?? public:?? ????CRTSPStream(void);?? ????~CRTSPStream(void);?? public:?? ?????? ????bool?Init();?? ?????? ????void?Uninit();?? ?????? ????bool?SendH264File(const?char?*pFileName);?? ?????? ????int?SendH264Data(const?unsigned?char?*data,unsigned?int?size);?? };?? [cpp]?view plaincopy
? ? ? ? ? ??? #include?"RTSPStream.h"?? #ifdef?WIN32?? #else?? #include?<sys/types.h>?? #include?<sys/stat.h>?? #include?<string.h>?? #include?<fcntl.h>?? #include?<unistd.h>?? #include?<limits.h>?? #include?<errno.h>?? #endif?? ?? #define?FIFO_NAME????"/tmp/H264_fifo"?? #define?BUFFERSIZE???PIPE_BUF?? ?? CRTSPStream::CRTSPStream(void)?? {?? ?????? }?? ?? CRTSPStream::~CRTSPStream(void)?? {?? ?????? }?? ?? bool?CRTSPStream::Init()?? {?? ????if(access(FIFO_NAME,F_OK)?==?-1)?? ????{?? ????????int?res?=?mkfifo(FIFO_NAME,0777);?? ????????if(res?!=?0)?? ????????{?? ????????????printf("[RTSPStream]?Create?fifo?failed.\n");?? ????????????return?false;?? ????????}?? ????}?? ????return?true;?? }?? ?? ?? void?CRTSPStream::Uninit()?? {?? ?????? }?? ?? bool?CRTSPStream::SendH264File(const?char?*pFileName)?? {?? ????if(pFileName?==?NULL)?? ????{?? ????????return?false;?? ????}?? ????FILE?*fp?=?fopen(pFileName,?"rb");???? ????if(!fp)???? ????{???? ????????printf("[RTSPStream]?error:open?file?%s?failed!",pFileName);?? ????}???? ????fseek(fp,?0,?SEEK_SET);?? ?? ????unsigned?char?*buffer??=?new?unsigned?char[FILEBUFSIZE];?? ????int?pos?=?0;?? ????while(1)?? ????{?? ????????int?readlen?=?fread(buffer+pos,?sizeof(unsigned?char),?FILEBUFSIZE-pos,?fp);?? ?? ????????if(readlen<=0)?? ????????{?? ????????????break;?? ????????}?? ?? ????????readlen+=pos;?? ?? ????????int?writelen?=?SendH264Data(buffer,readlen);?? ????????if(writelen<=0)?? ????????{?? ????????????break;?? ????????}?? ????????memcpy(buffer,buffer+writelen,readlen-writelen);?? ????????pos?=?readlen-writelen;?? ?? ????????mSleep(25);?? ????}?? ????fclose(fp);?? ????delete[]?buffer;?? ????return?true;?? }?? ?? ?? int?CRTSPStream::SendH264Data(const?unsigned?char?*data,unsigned?int?size)?? {?? ????if(data?==?NULL)?? ????{?? ????????return?0;?? ????}?? ?????? ????int?pipe_fd?=?open(FIFO_NAME,?O_WRONLY|O_NONBLOCK);?? ?????? ????if(pipe_fd?==?-1)?? ????{?? ????????return?0;?? ????}?? ??? ????int?send_size?=?0;?? ????int?remain_size?=?size;?? ????while(send_size?<?size)?? ????{?? ????????int?data_len?=?(remain_size<BUFFERSIZE)???remain_size?:?BUFFERSIZE;?? ????????int?len?=?write(pipe_fd,data+send_size,data_len);?? ????????if(len?==?-1)?? ????????{?? ????????????static?int?resend_conut?=?0;?? ????????????if(errno?==?EAGAIN?&&?++resend_conut<=3)?? ????????????{?? ????????????????printf("[RTSPStream]?write?fifo?error,resend..\n");?? ????????????????continue;?? ????????????}?? ????????????resend_conut?=?0;?? ????????????printf("[RTSPStream]?write?fifo?error,errorcode[%d],send_size[%d]\n",errno,send_size);?? ????????????break;?? ????????}?? ????????else?? ????????{???? ????????????send_size+=?len;?? ????????????remain_size-=?len;?? ????????}?? ????}?? ????close(pipe_fd);?? ?????? ????return?0;?? }?? 測試程序代碼
[cpp]?view plaincopy
#include?<stdio.h>?? #include?"RTSPStream.h"?? ?? int?main(int?argc,char*?argv[])?? {?? ????CRTSPStream?rtspSender;?? ????bool?bRet?=?rtspSender.Init();?? ????rtspSender.SendH264File("E:\\測試視頻\\test.264");?? ????system("pause");???? }??
FROM: ?http://www.cppblog.com/tx7do/archive/2014/05/31/207155.html
總結
以上是生活随笔為你收集整理的通过live555实现H264 RTSP直播的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。