/* --------------------------------------------------------------------------- ** This software is in the public domain, furnished "as is", without technical ** support, and with no warranty, express or implied, as to its usefulness for ** any purpose. ** ** V4l2RTSPServer.h ** ** V4L2 RTSP server ** ** -------------------------------------------------------------------------*/ #pragma once #include // live555 #include #include #include "UnicastServerMediaSubsession.h" #include "MulticastServerMediaSubsession.h" #include "TSServerMediaSubsession.h" #include "HTTPServer.h" class V4l2RTSPServer { public: V4l2RTSPServer(unsigned short rtspPort, unsigned short rtspOverHTTPPort = 0, int timeout = 10, unsigned int hlsSegment = 0, const std::list & userPasswordList = std::list(), const char* realm = NULL, const std::string & webroot = "", const char *sslkeycert = NULL) : m_stop(0) , m_env(BasicUsageEnvironment::createNew(*BasicTaskScheduler::createNew())) , m_rtspPort(rtspPort) { UserAuthenticationDatabase* auth = createUserAuthenticationDatabase(userPasswordList, realm); m_rtspServer = HTTPServer::createNew(*m_env, rtspPort, auth, timeout, hlsSegment, webroot, sslkeycert); if (m_rtspServer != NULL) { if (rtspOverHTTPPort) { m_rtspServer->setUpTunnelingOverHTTP(rtspOverHTTPPort); } } } virtual ~V4l2RTSPServer() { Medium::close(m_rtspServer); TaskScheduler* scheduler = &(m_env->taskScheduler()); m_env->reclaim(); delete scheduler; } bool available() { return ((m_env != NULL) && (m_rtspServer != NULL)); } std::string getResultMsg() { std::string result("UsageEnvironment not exists"); if (m_env) { result = m_env->getResultMsg(); } return result; } void eventLoop(char * stop) { m_env->taskScheduler().doEventLoop(stop); } void eventLoop() { m_env->taskScheduler().doEventLoop(&m_stop); } void stopLoop() { m_stop = 1; } UsageEnvironment* env() { return m_env; } // ----------------------------------------- // create video capture & replicator // ----------------------------------------- StreamReplicator* CreateVideoReplicator( const V4L2DeviceParameters& inParam, int queueSize, V4L2DeviceSource::CaptureMode captureMode, int repeatConfig, const std::string& outputFile, V4l2IoType ioTypeOut, V4l2Output*& out); #ifdef HAVE_ALSA StreamReplicator* CreateAudioReplicator( const std::string& audioDev, const std::list& audioFmtList, int audioFreq, int audioNbChannels, int verbose, int queueSize, V4L2DeviceSource::CaptureMode captureMode); #endif // ----------------------------------------- // Add unicast Session // ----------------------------------------- ServerMediaSession* AddUnicastSession(const std::string& url, StreamReplicator* videoReplicator, StreamReplicator* audioReplicator) { // Create Unicast Session std::list subSession; if (videoReplicator) { subSession.push_back(UnicastServerMediaSubsession::createNew(*this->env(), videoReplicator)); } if (audioReplicator) { subSession.push_back(UnicastServerMediaSubsession::createNew(*this->env(), audioReplicator)); } return this->addSession(url, subSession); } // ----------------------------------------- // Add HLS & MPEG# Session // ----------------------------------------- ServerMediaSession* AddHlsSession(const std::string& url, int hlsSegment, StreamReplicator* videoReplicator, StreamReplicator* audioReplicator) { std::list subSession; if (videoReplicator) { subSession.push_back(TSServerMediaSubsession::createNew(*this->env(), videoReplicator, audioReplicator, hlsSegment)); } ServerMediaSession* sms = this->addSession(url, subSession); struct in_addr ip; #if LIVEMEDIA_LIBRARY_VERSION_INT < 1611878400 ip.s_addr = ourIPAddress(*this->env()); #else ip.s_addr = ourIPv4Address(*this->env()); #endif LOG(NOTICE) << "HLS http://" << inet_ntoa(ip) << ":" << m_rtspPort << "/" << url << ".m3u8"; LOG(NOTICE) << "MPEG-DASH http://" << inet_ntoa(ip) << ":" << m_rtspPort << "/" << url << ".mpd"; return sms; } // ----------------------------------------- // Add multicats Session // ----------------------------------------- ServerMediaSession* AddMulticastSession(const std::string& url, in_addr destinationAddress, unsigned short & rtpPortNum, unsigned short & rtcpPortNum, StreamReplicator* videoReplicator, StreamReplicator* audioReplicator) { LOG(NOTICE) << "RTP address " << inet_ntoa(destinationAddress) << ":" << rtpPortNum; LOG(NOTICE) << "RTCP address " << inet_ntoa(destinationAddress) << ":" << rtcpPortNum; unsigned char ttl = 5; std::list subSession; if (videoReplicator) { subSession.push_back(MulticastServerMediaSubsession::createNew(*this->env(), destinationAddress, Port(rtpPortNum), Port(rtcpPortNum), ttl, videoReplicator)); // increment ports for next sessions rtpPortNum+=2; rtcpPortNum+=2; } if (audioReplicator) { subSession.push_back(MulticastServerMediaSubsession::createNew(*this->env(), destinationAddress, Port(rtpPortNum), Port(rtcpPortNum), ttl, audioReplicator)); // increment ports for next sessions rtpPortNum+=2; rtcpPortNum+=2; } return this->addSession(url, subSession); } // ----------------------------------------- // get rtsp url // ----------------------------------------- std::string getRtspUrl(ServerMediaSession* sms) { std::string url; char* rtspurl = m_rtspServer->rtspURL(sms); if (rtspurl != NULL) { url = rtspurl; delete[] rtspurl; } return url; } protected: UserAuthenticationDatabase* createUserAuthenticationDatabase(const std::list & userPasswordList, const char* realm) { UserAuthenticationDatabase* auth = NULL; if (userPasswordList.size() > 0) { auth = new UserAuthenticationDatabase(realm, (realm != NULL) ); std::list::const_iterator it; for (it = userPasswordList.begin(); it != userPasswordList.end(); ++it) { std::istringstream is(*it); std::string user; getline(is, user, ':'); std::string password; getline(is, password); auth->addUserRecord(user.c_str(), password.c_str()); } } return auth; } ServerMediaSession* addSession(const std::string & sessionName, ServerMediaSubsession* subSession) { std::list subSessionList; if (subSession) { subSessionList.push_back(subSession); } return this->addSession(sessionName, subSessionList); } ServerMediaSession* addSession(const std::string & sessionName, const std::list & subSession) { ServerMediaSession* sms = NULL; if (subSession.empty() == false) { sms = ServerMediaSession::createNew(*m_env, sessionName.c_str()); if (sms != NULL) { std::list::const_iterator subIt; for (subIt = subSession.begin(); subIt != subSession.end(); ++subIt) { sms->addSubsession(*subIt); } m_rtspServer->addServerMediaSession(sms); char* url = m_rtspServer->rtspURL(sms); if (url != NULL) { LOG(NOTICE) << "Play this stream using the URL \"" << url << "\""; delete[] url; } } } return sms; } protected: char m_stop; UsageEnvironment* m_env; RTSPServer* m_rtspServer; int m_rtspPort; };