對live555封裝的比較好的一個類,網上找到的,覺得不錯,給大家共享
對live555封裝的比較好的一個類,網上找到的,覺得不錯,給大家共享,也不記得從哪裡下載的了,版權歸原作者!
這個類的主要特點是可以建立多個客戶端,連線多路碼流;我們可以參考他的設計,在sink中將碼流回撥出來,在外部解碼;
檔案如下:
#pragma once
#include "BasicUsageEnvironment\BasicUsageEnvironment.hh"
#include "groupsock\GroupsockHelper.hh"
#include "liveMedia\liveMedia.hh"
#include <iostream>
#include <list>
#include <map>
struct YHRTSPClient
{
TaskScheduler* pTaskScheduler;
UsageEnvironment* pEnv;
RTSPClient* pClient;
MediaSession *pMediaSession;
MediaSubsessionIterator *iter;
Boolean bMadeProgress;
unsigned fileSinkBufferSize;
unsigned socketInputBufferSize;
Boolean bStreamUsingTCP;
Authenticator* pAuthenticator;
char m_cEventLoop;
YHRTSPClient()
{
pClient = NULL;
pMediaSession = NULL;
iter = NULL;
bMadeProgress = False;
fileSinkBufferSize = 100000;
socketInputBufferSize = 524288;
bStreamUsingTCP = False;
pAuthenticator = NULL;
m_cEventLoop = 0;
}
YHRTSPClient(RTSPClient *client)
{
pClient = client;
pMediaSession = NULL;
iter = NULL;
bMadeProgress = False;
fileSinkBufferSize = 100000;
socketInputBufferSize = 524288;
bStreamUsingTCP = False;
pAuthenticator = NULL;
m_cEventLoop = 0;
}
};
class CYHMediaClient
{
public:
static CYHMediaClient* GetInstance();
CYHMediaClient(void);
~CYHMediaClient(void);
public:
BOOL CreateRTPClient(LONG lID, const char *chServerURL);
//BOOL StartStreaming(char *chWatchVariable = NULL);
void StopStreaming(int nClientID);
void GetSDPDescription(RTSPClient* pRTSPClient, RTSPClient::responseHandler* afterFunc);
void SetupStreams(RTSPClient* pRTSPClient);
void SetupSubsession(RTSPClient* pRTSPClient,MediaSubsession* subsession, Boolean streamUsingTCP, RTSPClient::responseHandler* afterFunc);
void StartPlayingSession(RTSPClient* pRTSPClient,MediaSession* session, double start, double end, float scale, RTSPClient::responseHandler* afterFunc);
void TearDownSession(RTSPClient* pRTSPClient,MediaSession* session, RTSPClient::responseHandler* afterFunc);
void SetFileSinkAndSocket(YHRTSPClient *pYHClient,unsigned fileSinkBufferSize,unsigned socketInputBufferSize);
void SetStreamUsingTCP(YHRTSPClient* pYHClient, Boolean bStreamUsingTCP){pYHClient->bStreamUsingTCP = bStreamUsingTCP;};
UsageEnvironment *GetEnvironment(RTSPClient* pRTSPClient)
{
UsageEnvironment *pEnv = NULL;
if (NULL == pRTSPClient)
{
return pEnv;
}
YHRTSPClient *pYHClient = GetYHRTSPClient(pRTSPClient);
if (NULL != pYHClient)
{
pEnv = pYHClient->pEnv;
}
return pEnv;
};
private:
void GetOptions(RTSPClient* pRTSPClient, RTSPClient::responseHandler* afterFunc);
void Shutdown(RTSPClient *pClient = NULL);
YHRTSPClient* GetYHRTSPClient(RTSPClient *pClient);
void EraseYHRTSPClient(RTSPClient *pClient);
LONG GetRTSPClientID(RTSPClient* pClient);
void CloseMediaSinks(RTSPClient *pClient);
static void ContinueAfterOptions(RTSPClient* pClient, int resultCode, char* resultString);
static void ContinueAfterDescribe(RTSPClient* pClient, int resultCode, char* resultString);
static void ContinueAfterSetup(RTSPClient* pClient, int resultCode, char* resultString);
static void ContinueAfterPlay(RTSPClient* pClient, int resultCode, char* resultString);
static void SubsessionAfterPlaying(void* clientData);
static void SubsessionByeHandler(void* clientData);
static void ContinueAfterTearDown(RTSPClient* pClient, int resultCode, char* resultString) ;
public:
std::list<YHRTSPClient*> m_listRTSPClient;
std::map<int, RTSPClient*> m_mapClientID;
private:
static CYHMediaClient* pYHMediaClient;
//TaskScheduler* pTaskScheduler;
//UsageEnvironment* pEnv;
};
原始檔如下:
<pre class="cpp" name="code">//#include "stdafx.h"
#include "YHMediaClient.h"
#include "WinCriticalSection.h"
#include "MetMediaSink.h"
//#include "YHWMPlayDemoDlg.h"
char const* clientProtocolName = "RTSP";
CYHMediaClient* CYHMediaClient::pYHMediaClient = NULL;
WinCriticalSection g_cs;
CYHMediaClient* CYHMediaClient::GetInstance()
{
Mutex mutex(g_cs);
if (CYHMediaClient::pYHMediaClient == NULL)
{
pYHMediaClient = new CYHMediaClient;
}
return pYHMediaClient;
}
CYHMediaClient::CYHMediaClient(void)
{
}
CYHMediaClient::~CYHMediaClient(void)
{
m_listRTSPClient.empty();
}
BOOL CYHMediaClient::CreateRTPClient(LONG lID, const char *chServerURL)
{
g_cs.Enter();
TaskScheduler *pTaskScheduler = BasicTaskScheduler::createNew();
UsageEnvironment *pEnv = BasicUsageEnvironment::createNew(*pTaskScheduler);
RTSPClient* pRTSPClient = (RTSPClient*)RTSPClient::createNew(*pEnv, chServerURL, 0, NULL, 0);
if (NULL == pRTSPClient)
{
*pEnv << "Failed to create" << clientProtocolName << " client: " << pEnv->getResultMsg() << "\n";
return FALSE;
}
m_mapClientID.insert(std::make_pair(lID, pRTSPClient));
YHRTSPClient *stucClient = new YHRTSPClient(pRTSPClient);
stucClient->pTaskScheduler = pTaskScheduler;
stucClient->pEnv = pEnv;
CYHMediaClient::GetInstance()->m_listRTSPClient.push_back(stucClient);
GetOptions(pRTSPClient, ContinueAfterOptions);
g_cs.Leave();
stucClient->pEnv->taskScheduler().doEventLoop(&stucClient->m_cEventLoop);
if (pTaskScheduler)
{
delete pTaskScheduler;
pTaskScheduler = NULL;
}
if(stucClient)
{
delete stucClient;
stucClient = NULL;
}
return TRUE;
}
void CYHMediaClient::StopStreaming(int nClientID)
{
Mutex mutex(g_cs);
std::map<int, RTSPClient*>::iterator iter = m_mapClientID.find(nClientID);
if (iter != m_mapClientID.end())
{
RTSPClient* pRTSPClient = iter->second;
Shutdown(pRTSPClient);
EraseYHRTSPClient(pRTSPClient);
m_mapClientID.erase(iter);
}
}
void CYHMediaClient::Shutdown(RTSPClient *pClient)
{
YHRTSPClient* pYHRTSPClient = GetYHRTSPClient(pClient);
if (pYHRTSPClient != NULL)
{
if (pYHRTSPClient->pMediaSession != NULL)
{
TearDownSession(pClient,pYHRTSPClient->pMediaSession, ContinueAfterTearDown);
}
else
{
ContinueAfterTearDown(NULL, 0, NULL);
}
CYHMediaClient::GetInstance()->CloseMediaSinks(pClient);
if (pYHRTSPClient->pMediaSession)
{
Medium::close(pYHRTSPClient->pMediaSession);
pYHRTSPClient->pMediaSession = NULL;
}
// Finally, shut down our client:
if (pClient)
{
Medium::close(pClient);
pClient = NULL;
}
pYHRTSPClient->m_cEventLoop = 1;
}
}
void CYHMediaClient::GetOptions(RTSPClient* pRTSPClient, RTSPClient::responseHandler* afterFunc)
{
Mutex mutex(g_cs);
if (pRTSPClient)
{
YHRTSPClient *pYHClient = CYHMediaClient::GetInstance()->GetYHRTSPClient(pRTSPClient);
pRTSPClient->sendOptionsCommand(afterFunc, pYHClient->pAuthenticator);
}
}
void CYHMediaClient::GetSDPDescription(RTSPClient* pRTSPClient,RTSPClient::responseHandler* afterFunc)
{
Mutex mutex(g_cs);
if (pRTSPClient)
{
YHRTSPClient *pYHClient = CYHMediaClient::GetInstance()->GetYHRTSPClient(pRTSPClient);
pRTSPClient->sendDescribeCommand(afterFunc, pYHClient->pAuthenticator);
}
}
void CYHMediaClient::SetupSubsession(RTSPClient* pRTSPClient,MediaSubsession* subsession, Boolean streamUsingTCP, RTSPClient::responseHandler* afterFunc)
{
Mutex mutex(g_cs);
Boolean forceMulticastOnUnspecified = False;
if (pRTSPClient)
{
YHRTSPClient *pYHClient = CYHMediaClient::GetInstance()->GetYHRTSPClient(pRTSPClient);
pRTSPClient->sendSetupCommand(*subsession, afterFunc, False, streamUsingTCP, forceMulticastOnUnspecified, pYHClient->pAuthenticator);
}
}
void CYHMediaClient::StartPlayingSession(RTSPClient* pRTSPClient,MediaSession* session, double start, double end, float scale, RTSPClient::responseHandler* afterFunc)
{
//Mutex mutex(g_cs);
if (pRTSPClient)
{
YHRTSPClient *pYHClient = CYHMediaClient::GetInstance()->GetYHRTSPClient(pRTSPClient);
pRTSPClient->sendPlayCommand(*session, afterFunc, start, end, scale, pYHClient->pAuthenticator);
}
}
void CYHMediaClient::TearDownSession(RTSPClient* pRTSPClient,MediaSession* session, RTSPClient::responseHandler* afterFunc)
{
Mutex mutex(g_cs);
if (pRTSPClient)
{
YHRTSPClient *pYHClient = CYHMediaClient::GetInstance()->GetYHRTSPClient(pRTSPClient);
pRTSPClient->sendTeardownCommand(*session, afterFunc, pYHClient->pAuthenticator);
}
}
void CYHMediaClient::ContinueAfterOptions(RTSPClient* pClient, int resultCode, char* resultString)
{
Mutex mutex(g_cs);
if(CYHMediaClient::GetInstance() != NULL)
{
if (resultCode != 0)
{
*(CYHMediaClient::GetInstance()->GetEnvironment(pClient)) << clientProtocolName << " \"OPTIONS\" request failed: " << resultString << "\n";
return;
}
else
{
*(CYHMediaClient::GetInstance()->GetEnvironment(pClient)) << clientProtocolName << " \"OPTIONS\" request returned: " << resultString << "\n";
}
delete[] resultString;
CYHMediaClient::GetInstance()->GetSDPDescription(pClient, ContinueAfterDescribe);
}
return;
}
void CYHMediaClient::ContinueAfterDescribe(RTSPClient* pClient, int resultCode, char* resultString)
{
Mutex mutex(g_cs);
if (CYHMediaClient::GetInstance() != NULL)
{
if (resultCode != 0)
{
CYHMediaClient::GetInstance()->Shutdown();
return;
}
char* sdpDescription = resultString;
// Create a media session object from this SDP description:
MediaSession *pMediaSession = MediaSession::createNew(*(CYHMediaClient::GetInstance()->GetEnvironment(pClient)), sdpDescription);
delete[] sdpDescription;
if (pMediaSession == NULL)
{
*(CYHMediaClient::GetInstance()->GetEnvironment(pClient)) << "Failed to create a MediaSession object from the SDP description: " << CYHMediaClient::GetInstance()->GetEnvironment(pClient)->getResultMsg() << "\n";
CYHMediaClient::GetInstance()->Shutdown(pClient);
return;
}
else if (!pMediaSession->hasSubsessions())
{
*(CYHMediaClient::GetInstance()->GetEnvironment(pClient)) << "This session has no media subsessions (i.e., \"m=\" lines)\n";
CYHMediaClient::GetInstance()->Shutdown(pClient);
return;
}
// Then, setup the "RTPSource"s for the session:
MediaSubsessionIterator iter(*pMediaSession);
MediaSubsession *subsession;
YHRTSPClient *pYHClient = CYHMediaClient::GetInstance()->GetYHRTSPClient(pClient);
pYHClient->bMadeProgress = False;
pYHClient->pMediaSession = pMediaSession;
while ((subsession = iter.next()) != NULL)
{
if (!subsession->initiate())
{
*(CYHMediaClient::GetInstance()->GetEnvironment(pClient)) << "Unable to create receiver for \"" << subsession->mediumName()
<< "/" << subsession->codecName()
<< "\" subsession: " << CYHMediaClient::GetInstance()->GetEnvironment(pClient)->getResultMsg() << "\n";
}
else
{
*(CYHMediaClient::GetInstance()->GetEnvironment(pClient)) << "Created receiver for \"" << subsession->mediumName()
<< "/" << subsession->codecName()
<< "\" subsession (client ports " << subsession->clientPortNum()
<< "-" << subsession->clientPortNum()+1 << ")\n";
pYHClient->bMadeProgress = True;
if (subsession->rtpSource() != NULL)
{
// Because we're saving the incoming data, rather than playing
// it in real time, allow an especially large time threshold
// (1 second) for reordering misordered incoming packets:
unsigned const thresh = 500000; // 0.5 second
subsession->rtpSource()->setPacketReorderingThresholdTime(thresh);
// Set the RTP source's OS socket buffer size as appropriate - either if we were explicitly asked (using -B),
// or if the desired FileSink buffer size happens to be larger than the current OS socket buffer size.
// (The latter case is a heuristic, on the assumption that if the user asked for a large FileSink buffer size,
// then the input data rate may be large enough to justify increasing the OS socket buffer size also.)
int socketNum = subsession->rtpSource()->RTPgs()->socketNum();
unsigned curBufferSize = getReceiveBufferSize(*CYHMediaClient::GetInstance()->GetEnvironment(pClient), socketNum);
if (pYHClient->socketInputBufferSize > 0 || pYHClient->fileSinkBufferSize > curBufferSize)
{
unsigned newBufferSize = pYHClient->socketInputBufferSize > 0 ? pYHClient->socketInputBufferSize : pYHClient->fileSinkBufferSize;
newBufferSize = setReceiveBufferTo(*CYHMediaClient::GetInstance()->GetEnvironment(pClient), socketNum, newBufferSize);
}
}
}
}
if (!pYHClient->bMadeProgress)
{
CYHMediaClient::GetInstance()->Shutdown(pClient);
return;
}
// Perform additional 'setup' on each subsession, before playing them:
CYHMediaClient::GetInstance()->SetupStreams(pClient);
}
}
void CYHMediaClient::SetupStreams(RTSPClient* pRTSPClient)
{
Mutex mutex(g_cs);
YHRTSPClient *struClient = GetYHRTSPClient(pRTSPClient);
if (struClient->iter == NULL)
struClient->iter = new MediaSubsessionIterator(*(struClient->pMediaSession));
MediaSubsession *subsession = NULL;
while ((subsession = struClient->iter->next()) != NULL)
{
// We have another subsession left to set up:
if (subsession->clientPortNum() == 0)
continue; // port # was not set
if (pRTSPClient != NULL)
{
SetupSubsession(pRTSPClient, subsession, /*struClient->bStreamUsingTCP*/True, ContinueAfterSetup);
}
return;
}
// We're done setting up subsessions.
if (!struClient->bMadeProgress)
{
Shutdown(pRTSPClient);
return;
}
// Create and start "FileSink"s for each subsession:
struClient->bMadeProgress = False;
MediaSubsessionIterator iter(*(struClient->pMediaSession));
while ((subsession = iter.next()) != NULL)
{
if (subsession->readSource() == NULL)
continue; // was not initiated
// Create an output file for each desired stream:
CMetMediaSink* pMediaSink;
unsigned int requestedBufferSize = 524288;
pMediaSink = CMetMediaSink::createNew(*struClient->pEnv, struClient->socketInputBufferSize);
pMediaSink->SetMediaSession(struClient->pMediaSession);
pMediaSink->SetPlayHandle(GetRTSPClientID(pRTSPClient));
subsession->sink = pMediaSink;
if (subsession->sink == NULL)
{
*struClient->pEnv << "Failed to create MediaSink for \"" << "MediaClient"<< "\": " << struClient->pEnv->getResultMsg() << "\n";
}
else
{
subsession->sink->startPlaying(*(subsession->readSource()),SubsessionAfterPlaying,subsession);
// Also set a handler to be called if a RTCP "BYE" arrives
// for this subsession:
if (subsession->rtcpInstance() != NULL)
{
subsession->rtcpInstance()->setByeHandler(SubsessionByeHandler, subsession);
}
struClient->bMadeProgress = True;
}
}
if (!struClient->bMadeProgress)
{
Shutdown(pRTSPClient);
return;
}
double duration = 0;
YHRTSPClient* pYHRTSPClient = GetYHRTSPClient(pRTSPClient);
duration = pYHRTSPClient->pMediaSession->playEndTime();
if (duration < 0)
duration = 0.0;
double dwEnd = duration;
StartPlayingSession(pRTSPClient,pYHRTSPClient->pMediaSession, 0, dwEnd, 1.0, ContinueAfterPlay);
}
void CYHMediaClient::ContinueAfterSetup(RTSPClient* pClient, int resultCode, char* resultString)
{
Mutex mutex(g_cs);
if (pClient == NULL)
{
return;
}
if (CYHMediaClient::GetInstance() != NULL)
{
if (resultCode == 0)
{
YHRTSPClient *pYHClient = CYHMediaClient::GetInstance()->GetYHRTSPClient(pClient);
pYHClient->bMadeProgress = True;
}
// Set up the next subsession, if any:
CYHMediaClient::GetInstance()->SetupStreams(pClient);
}
}
void CYHMediaClient::ContinueAfterPlay(RTSPClient* pClient, int resultCode, char* resultString)
{
Mutex mutex(g_cs);
if (CYHMediaClient::GetInstance() != NULL)
{
if (resultCode != 0)
{
*(CYHMediaClient::GetInstance()->GetEnvironment(pClient)) << "Failed to start playing session: " << resultString << "\n";
CYHMediaClient::GetInstance()->Shutdown(pClient);
return;
}
else
{
*(CYHMediaClient::GetInstance()->GetEnvironment(pClient)) << "Started playing session\n";
}
char const* actionString ="Receiving streamed data...";
*(CYHMediaClient::GetInstance()->GetEnvironment(pClient)) << actionString << "...\n";
}
}
void CYHMediaClient::SubsessionAfterPlaying(void* clientData)
{
Mutex mutex(g_cs);
MediaSubsession* subsession = (MediaSubsession*)clientData;
Medium::close(subsession->sink);
subsession->sink = NULL;
}
void CYHMediaClient::SubsessionByeHandler(void* clientData)
{
Mutex mutex(g_cs);
MediaSubsession* subsession = (MediaSubsession*)clientData;
if (subsession != NULL)
{
// Act now as if the subsession had closed:
SubsessionAfterPlaying(subsession);
}
}
void CYHMediaClient::ContinueAfterTearDown(RTSPClient* pClient, int resultCode, char* resultString)
{
/*
Mutex mutex(g_cs);
// Now that we've stopped any more incoming data from arriving, close our output files:
if (CYHMediaClient::GetInstance()!= NULL)
{
CYHMediaClient::GetInstance()->CloseMediaSinks(pClient);
YHRTSPClient *struClient = CYHMediaClient::GetInstance()->GetYHRTSPClient(pClient);
if (struClient->pMediaSession)
{
Medium::close(struClient->pMediaSession);
}
// Finally, shut down our client:
if (struClient->pAuthenticator)
{
delete struClient->pAuthenticator;
}
Medium::close(pClient);
struClient->m_cEventLoop = 1;
}*/
}
void CYHMediaClient::CloseMediaSinks(RTSPClient *pClient)
{
YHRTSPClient* pYHRTSPClient = GetYHRTSPClient(pClient);
if (pYHRTSPClient->pMediaSession == NULL)
return;
MediaSubsessionIterator iter(*pYHRTSPClient->pMediaSession);
MediaSubsession* subsession;
while ((subsession = iter.next()) != NULL)
{
Medium::close(subsession->sink);
subsession->sink = NULL;
}
}
YHRTSPClient* CYHMediaClient::GetYHRTSPClient(RTSPClient *pClient)
{
if (m_listRTSPClient.size() == 0)
{
return NULL;
}
std::list<YHRTSPClient*>::iterator iter;
for (iter = m_listRTSPClient.begin(); iter != m_listRTSPClient.end(); ++iter)
{
if (pClient == (*iter)->pClient)
{
return *iter;
}
else
continue;
}
return NULL;
}
void CYHMediaClient::EraseYHRTSPClient(RTSPClient *pClient)
{
if (m_listRTSPClient.size() == 0)
{
return ;
}
std::list<YHRTSPClient*>::iterator iter;
for (iter = m_listRTSPClient.begin(); iter != m_listRTSPClient.end(); ++iter)
{
if (pClient == (*iter)->pClient)
{
break;
}
else
continue;
}
m_listRTSPClient.erase(iter);
}
LONG CYHMediaClient::GetRTSPClientID(RTSPClient* pClient)
{
std::map<int, RTSPClient*>::iterator iter = m_mapClientID.begin();
int nClientID = -1;
for (; iter != m_mapClientID.end(); ++iter)
{
if (pClient == iter->second)
{
nClientID = iter->first;
}
}
return nClientID;
}
void CYHMediaClient::SetFileSinkAndSocket(YHRTSPClient *pYHClient,unsigned fileSinkBufferSize,unsigned socketInputBufferSize)
{
if (NULL == pYHClient)
{
return;
}
pYHClient->fileSinkBufferSize = fileSinkBufferSize;
pYHClient->socketInputBufferSize = socketInputBufferSize;
return;
}
相關文章
- 給大家分享一個案例分析-比較偏僻
- 請大家推薦一個比較好的XML序列化工具!XML
- 一個比較好的shell指令碼指令碼
- 一個比較好的oracle blogOracle
- 一些比較好的網站網站
- awk的一個比較不錯的總結網頁網頁
- 找到的比較好的工作面試題筆試題面試題筆試
- 幾種遠端呼叫方式,大家感覺哪種比較好?
- 一種我認為比較好的MVP寫法封裝,你值得擁有MVP封裝
- 大家討論一下比較好Criteria框架。框架
- 求一個全能的封裝好的jdbc bean封裝JDBCBean
- 一個比較float是否相等的工具類
- 全網比較好的 Markdown 教程
- Go和Python比較的話,哪個比較好?GoPython
- 大家好,有對基於Onethink框架設計一個網上商城瞭解的嗎框架
- 學習sybase較好的一個網站網站
- 一、類的封裝性封裝
- 給大家推薦幾個好的學習Oracle和Linux的網站OracleLinux網站
- 一個最簡單的類JQuery封裝jQuery封裝
- 【linux shell】推薦一個比較好的部落格Linux
- 【JavaScript框架封裝】實現一個類似於JQuery的動畫框架的封裝JavaScript框架封裝jQuery動畫
- 網站設計:“瀑布流”比較好 還是“下一頁”比較好?網站
- JVM上容錯庫的初步比較 - frankelJVM
- 一個不錯的關於mysql和posgresql比較的帖子MySql
- 一個字串比較的題字串
- 剛做了一個EDA類庫,大家給看看
- 封裝一個簡易的上傳附件方法封裝
- golang的比較好的一些超連結Golang
- 一個比較完整的Inno Setup 安裝指令碼指令碼
- 一個比較不錯的儲存過程分頁儲存過程
- 【JavaScript框架封裝】實現一個類似於JQuery的CSS樣式框架的封裝JavaScript框架封裝jQueryCSS
- PHP封裝的一個單例模式Mysql操作類PHP封裝單例模式MySql
- 一個C#封裝的加密解密類程式碼C#封裝加密解密
- 別人搭建的比較好的框架框架
- 封裝一個在react上更易用的redux框架封裝ReactRedux框架
- Apache與Nginx的優缺點、效能比較,到底選擇哪個比較好?ApacheNginx
- 給大家介紹一個不錯的資料庫處理程式包資料庫
- 一個較好的linux shell 程式設計網站Linux程式設計網站