对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;
- }