TEST(TestHttpHeader, General) { CHttpHeader a; CStdString str = "Host: xbmc.org\r\n" "Accept: text/*, text/html, text/html;level=1, */*\r\n" "Accept-Language: en\r\n" "Accept-Encoding: gzip, deflate\r\n" "Content-Type: text/html; charset=ISO-8859-4\r\n" "User-Agent: XBMC/snapshot (compatible; MSIE 5.5; Windows NT" " 4.0)\r\n" "Connection: Keep-Alive\r\n"; CStdString refstr, varstr; a.Parse(str); refstr = "accept: text/*, text/html, text/html;level=1, */*\n" "accept-encoding: gzip, deflate\n" "accept-language: en\n" "connection: Keep-Alive\n" "content-type: text/html; charset=ISO-8859-4\n" "host: xbmc.org\n" "user-agent: XBMC/snapshot (compatible; MSIE 5.5; Windows NT 4.0)\n" "\n"; varstr.clear(); a.GetHeader(varstr); EXPECT_STREQ(refstr.c_str(), varstr.c_str()); refstr = "XBMC/snapshot (compatible; MSIE 5.5; Windows NT 4.0)"; varstr = a.GetValue("User-Agent"); EXPECT_STREQ(refstr.c_str(), varstr.c_str()); refstr = "text/html; charset=ISO-8859-4"; varstr = a.GetMimeType(); EXPECT_STREQ(refstr.c_str(), varstr.c_str()); refstr = ""; varstr = a.GetProtoLine(); EXPECT_STREQ(refstr.c_str(), varstr.c_str()); a.Clear(); refstr = ""; varstr = a.GetMimeType(); EXPECT_STREQ(refstr.c_str(), varstr.c_str()); }
bool CDVDDemuxShoutcast::Open(CDVDInputStream* pInput) { Dispose(); m_pInput = pInput; // the input stream should be a http stream if (!pInput->IsStreamType(DVDSTREAM_TYPE_HTTP)) return false; CDVDInputStreamHttp* pInputStreamHttp = (CDVDInputStreamHttp*)pInput; CHttpHeader* pHeader = pInputStreamHttp->GetHttpHeader(); std::string strMetaInt = pHeader->GetValue(ICY_METAINTERVAL); std::string strMimeType = pHeader->GetMimeType(); // create new demuxer stream m_pDemuxStream = new CDemuxStreamAudioShoutcast(); m_pDemuxStream->iId = 0; m_pDemuxStream->iPhysicalId = 0; m_pDemuxStream->iDuration = 0; m_pDemuxStream->iChannels = 2; m_pDemuxStream->iSampleRate = 0; // set meta interval m_iMetaStreamInterval = atoi(strMetaInt.c_str()); if (stricmp(strMimeType.c_str(), CONTENT_TYPE_AAC) == 0 || stricmp(strMimeType.c_str(), CONTENT_TYPE_AACPLUS) == 0) { // need an aac decoder first m_pDemuxStream->codec = AV_CODEC_ID_AAC; } else // (stricmp(strMimeType, CONTENT_TYPE_MP3) == 0) { // default to mp3 m_pDemuxStream->codec = AV_CODEC_ID_MP3; } return true; }
void CheckRangesTestFileResponse(const CCurlFile& curl, const std::string& result, const CHttpRanges& ranges) { // get the HTTP header details const CHttpHeader& httpHeader = curl.GetHttpHeader(); // check the protocol line for the expected HTTP status std::string httpStatusString = StringUtils::Format(" %d ", MHD_HTTP_PARTIAL_CONTENT); std::string protocolLine = httpHeader.GetProtoLine(); ASSERT_TRUE(protocolLine.find(httpStatusString) != std::string::npos); // Accept-Ranges must be "bytes" EXPECT_STREQ("bytes", httpHeader.GetValue(MHD_HTTP_HEADER_ACCEPT_RANGES).c_str()); // check Last-Modified CDateTime lastModified; ASSERT_TRUE(GetLastModifiedOfTestFile(TEST_FILES_RANGES, lastModified)); ASSERT_STREQ(lastModified.GetAsRFC1123DateTime().c_str(), httpHeader.GetValue(MHD_HTTP_HEADER_LAST_MODIFIED).c_str()); // Cache-Control must contain "mag-age=0" and "no-cache" std::string cacheControl = httpHeader.GetValue(MHD_HTTP_HEADER_CACHE_CONTROL); EXPECT_TRUE(cacheControl.find("max-age=31536000") != std::string::npos); EXPECT_TRUE(cacheControl.find("public") != std::string::npos); // If there's no range Content-Length must be "20" if (ranges.IsEmpty()) { EXPECT_STREQ("20", httpHeader.GetValue(MHD_HTTP_HEADER_CONTENT_LENGTH).c_str()); EXPECT_STREQ(TEST_FILES_DATA_RANGES, result.c_str()); return; } // check Content-Range uint64_t firstPosition, lastPosition; ASSERT_TRUE(ranges.GetFirstPosition(firstPosition)); ASSERT_TRUE(ranges.GetLastPosition(lastPosition)); EXPECT_STREQ(HttpRangeUtils::GenerateContentRangeHeaderValue(firstPosition, lastPosition, 20).c_str(), httpHeader.GetValue(MHD_HTTP_HEADER_CONTENT_RANGE).c_str()); std::string expectedContent = TEST_FILES_DATA_RANGES; const std::string expectedContentType = "text/plain"; if (ranges.Size() == 1) { // Content-Type must be "text/html" EXPECT_STREQ(expectedContentType.c_str(), httpHeader.GetMimeType().c_str()); // check the content CHttpRange firstRange; ASSERT_TRUE(ranges.GetFirst(firstRange)); expectedContent = expectedContent.substr(firstRange.GetFirstPosition(), firstRange.GetLength()); EXPECT_STREQ(expectedContent.c_str(), result.c_str()); // and Content-Length EXPECT_STREQ(StringUtils::Format("%u", static_cast<unsigned int>(expectedContent.size())).c_str(), httpHeader.GetValue(MHD_HTTP_HEADER_CONTENT_LENGTH).c_str()); return; } // Content-Type contains the multipart boundary const std::string expectedMimeType = "multipart/byteranges"; std::string mimeType = httpHeader.GetMimeType(); ASSERT_STREQ(expectedMimeType.c_str(), mimeType.c_str()); std::string contentType = httpHeader.GetValue(MHD_HTTP_HEADER_CONTENT_TYPE); std::string contentTypeStart = expectedMimeType + "; boundary="; // it must start with "multipart/byteranges; boundary=" followed by the boundary ASSERT_EQ(0, contentType.find(contentTypeStart)); ASSERT_GT(contentType.size(), contentTypeStart.size()); // extract the boundary std::string multipartBoundary = contentType.substr(contentTypeStart.size()); ASSERT_FALSE(multipartBoundary.empty()); multipartBoundary = "--" + multipartBoundary; ASSERT_EQ(0, result.find(multipartBoundary)); std::vector<std::string> rangeParts = StringUtils::Split(result, multipartBoundary); // the first part is not really a part and is therefore empty (the place before the first boundary) ASSERT_TRUE(rangeParts.front().empty()); rangeParts.erase(rangeParts.begin()); // the last part is the end of the end multipart boundary ASSERT_STREQ("--", rangeParts.back().c_str()); rangeParts.erase(rangeParts.begin() + rangeParts.size() - 1); ASSERT_EQ(ranges.Size(), rangeParts.size()); for (size_t i = 0; i < rangeParts.size(); ++i) { std::string data = rangeParts.at(i); StringUtils::Trim(data, " \r\n"); // find the separator between header and data size_t pos = data.find("\r\n\r\n"); ASSERT_NE(std::string::npos, pos); std::string header = data.substr(0, pos + 4); data = data.substr(pos + 4); // get the expected range CHttpRange range; ASSERT_TRUE(ranges.Get(i, range)); // parse the header of the range part CHttpHeader rangeHeader; rangeHeader.Parse(header); // check Content-Type EXPECT_STREQ(expectedContentType.c_str(), rangeHeader.GetMimeType().c_str()); // parse and check Content-Range std::string contentRangeHeader = rangeHeader.GetValue(MHD_HTTP_HEADER_CONTENT_RANGE); std::vector<std::string> contentRangeHeaderParts = StringUtils::Split(contentRangeHeader, "/"); ASSERT_EQ(2, contentRangeHeaderParts.size()); // check the length of the range EXPECT_TRUE(StringUtils::IsNaturalNumber(contentRangeHeaderParts.back())); uint64_t contentRangeLength = str2uint64(contentRangeHeaderParts.back()); EXPECT_EQ(range.GetLength(), contentRangeLength); // remove the leading "bytes " string from the range definition std::string contentRangeDefinition = contentRangeHeaderParts.front(); ASSERT_EQ(0, contentRangeDefinition.find("bytes ")); contentRangeDefinition = contentRangeDefinition.substr(6); // check the start and end positions of the range std::vector<std::string> contentRangeParts = StringUtils::Split(contentRangeDefinition, "-"); ASSERT_EQ(2, contentRangeParts.size()); EXPECT_TRUE(StringUtils::IsNaturalNumber(contentRangeParts.front())); uint64_t contentRangeStart = str2uint64(contentRangeParts.front()); EXPECT_EQ(range.GetFirstPosition(), contentRangeStart); EXPECT_TRUE(StringUtils::IsNaturalNumber(contentRangeParts.back())); uint64_t contentRangeEnd = str2uint64(contentRangeParts.back()); EXPECT_EQ(range.GetLastPosition(), contentRangeEnd); // make sure the length of the content matches the one of the expected range EXPECT_EQ(range.GetLength(), data.size()); EXPECT_STREQ(expectedContent.substr(range.GetFirstPosition(), range.GetLength()).c_str(), data.c_str()); } }
void CHttpRequest::AddHeader(const CHttpHeader& header) { AddHeader(header.GetName(),header.GetValue()); }
CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream) { if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTTP)) { CDVDInputStreamHttp* pHttpStream = (CDVDInputStreamHttp*)pInputStream; CHttpHeader *header = pHttpStream->GetHttpHeader(); /* check so we got the meta information as requested in our http header */ if( header->GetValue("icy-metaint").length() > 0 ) { auto_ptr<CDVDDemuxShoutcast> demuxer(new CDVDDemuxShoutcast()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } } #ifdef HAS_FILESYSTEM_HTSP if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTSP)) { auto_ptr<CDVDDemuxHTSP> demuxer(new CDVDDemuxHTSP()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } #endif if (pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)) { CDVDInputStreamPVRManager* pInputStreamPVR = (CDVDInputStreamPVRManager*)pInputStream; CDVDInputStream* pOtherStream = pInputStreamPVR->GetOtherStream(); if(pOtherStream) { /* Used for MediaPortal PVR addon (uses PVR otherstream for playback of rtsp streams) */ if (pOtherStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG)) { auto_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg()); if(demuxer->Open(pOtherStream)) return demuxer.release(); else return NULL; } } std::string filename = pInputStream->GetFileName(); /* Use PVR demuxer only for live streams */ if (filename.substr(0, 14) == "pvr://channels") { PVR_SERVERPROPS *pProps = g_PVRManager.GetCurrentClientProps(); if (pProps && pProps->HandleDemuxing) { auto_ptr<CDVDDemuxPVRClient> demuxer(new CDVDDemuxPVRClient()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } } } auto_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; }
CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream, bool fileinfo) { if (!pInputStream) return NULL; // Try to open the AirTunes demuxer if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FILE) && pInputStream->GetContent().compare("audio/x-xbmc-pcm") == 0 ) { // audio/x-xbmc-pcm this is the used codec for AirTunes // (apples audio only streaming) unique_ptr<CDVDDemuxBXA> demuxer(new CDVDDemuxBXA()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTTP)) { CDVDInputStreamHttp* pHttpStream = (CDVDInputStreamHttp*)pInputStream; CHttpHeader *header = pHttpStream->GetHttpHeader(); /* check so we got the meta information as requested in our http header */ if( header->GetValue("icy-metaint").length() > 0 ) { unique_ptr<CDVDDemuxShoutcast> demuxer(new CDVDDemuxShoutcast()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } } bool streaminfo = true; /* Look for streams before playback */ if (pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)) { CDVDInputStreamPVRManager* pInputStreamPVR = (CDVDInputStreamPVRManager*)pInputStream; CDVDInputStream* pOtherStream = pInputStreamPVR->GetOtherStream(); /* Don't parse the streaminfo for some cases of streams to reduce the channel switch time */ bool useFastswitch = URIUtils::IsUsingFastSwitch(pInputStream->GetFileName()); streaminfo = !useFastswitch; if(pOtherStream) { /* Used for MediaPortal PVR addon (uses PVR otherstream for playback of rtsp streams) */ if (pOtherStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG)) { unique_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg()); if(demuxer->Open(pOtherStream, streaminfo)) return demuxer.release(); else return NULL; } } /* Use PVR demuxer only for live streams */ if (URIUtils::IsPVRChannel(pInputStream->GetFileName())) { std::shared_ptr<CPVRClient> client; if (g_PVRClients->GetPlayingClient(client) && client->HandlesDemuxing()) { unique_ptr<CDVDDemuxPVRClient> demuxer(new CDVDDemuxPVRClient()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } } } if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG)) { bool useFastswitch = URIUtils::IsUsingFastSwitch(pInputStream->GetFileName()); streaminfo = !useFastswitch; } unique_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg()); if(demuxer->Open(pInputStream, streaminfo, fileinfo)) return demuxer.release(); else return NULL; }
ConnectionResult CGenericServer::OpenConnection(const char* network_name, const char* eib_server_adress, int eib_server_port,const char* initial_key,const char* local_ip, const char* user_name, const char* password) { if(IsConnected()) { return STATUS_ALREADY_CONNECTED; } _status = STATUS_DURING_CONNECT; CString ini_key(initial_key); CString s_address; int len = 0,s_port; CDataBuffer raw_data; char buff[MAX_URL_LENGTH]; _network_name = network_name; _eib_address = eib_server_adress; _eib_port = eib_server_port; _user_name = user_name; _data_sock.SetLocalAddressAndPort(local_ip,0); int num_tries = 1; ConnectionResult res; while ((res = FirstPhaseConnection(ini_key, local_ip, buff, MAX_URL_LENGTH, len)) != STATUS_CONN_OK && num_tries > 0){ --num_tries; } if(num_tries == 0){ return res; } CDataBuffer raw_reply(buff,len); raw_reply.Decrypt(&ini_key); CHttpReply reply; CHttpParser parser(reply,raw_reply); if(!parser.IsLegalRequest() || reply.GetStatusCode() != STATUS_OK){ _status = STATUS_DISCONNECTED; return STATUS_INRERNAL_ERR; } CHttpHeader header; int64 s_interim,g,n,r_interim,key; if(!reply.GetHeader(NETWORK_SESSION_ID_HEADER, header)){ _status = STATUS_DISCONNECTED; GetLog()->Log(LOG_LEVEL_ERROR, "Missing header from reply: %s", NETWORK_SESSION_ID_HEADER); return STATUS_INRERNAL_ERR; } _session_id = header.GetValue().ToInt(); if(!reply.GetHeader(DIFFIE_HELLAM_MODULUS,header)){ _status = STATUS_DISCONNECTED; GetLog()->Log(LOG_LEVEL_ERROR, "Missing header from reply: %s", DIFFIE_HELLAM_MODULUS); return STATUS_INRERNAL_ERR; } n = header.GetValue().ToInt64(); if(!reply.GetHeader(DIFFIE_HELLAM_INTERIM, header)){ _status = STATUS_DISCONNECTED; GetLog()->Log(LOG_LEVEL_ERROR, "Missing header from reply: %s", DIFFIE_HELLAM_INTERIM); return STATUS_INRERNAL_ERR; } s_interim = header.GetValue().ToInt64(); if(!reply.GetHeader(DIFFIE_HELLAM_GENERATOR, header)){ _status = STATUS_DISCONNECTED; GetLog()->Log(LOG_LEVEL_ERROR, "Missing header from reply: %s", DIFFIE_HELLAM_GENERATOR); return STATUS_INRERNAL_ERR; } g = header.GetValue().ToInt64(); if(!reply.GetHeader(DATA_PORT_HEADER, header)){ _status = STATUS_DISCONNECTED; GetLog()->Log(LOG_LEVEL_ERROR, "Missing header from reply: %s", DATA_PORT_HEADER); return STATUS_INRERNAL_ERR; } _eib_port = header.GetValue().ToInt(); if(!reply.GetHeader(KEEPALIVE_PORT_HEADER, header)){ _status = STATUS_DISCONNECTED; GetLog()->Log(LOG_LEVEL_ERROR, "Missing header from reply: %s", KEEPALIVE_PORT_HEADER); return STATUS_INRERNAL_ERR; } GetLog()->SetConsoleColor(YELLOW); GetLog()->Log(LOG_LEVEL_INFO,"[EIB] [Received] Server Public key"); int eib_ka_port = header.GetValue().ToInt(); _encryptor.CreateRecipientInterKey(r_interim,g,n); _encryptor.CreateRecipientEncryptionKey(key,s_interim); CHttpRequest http_request; http_request.SetMethod(GET_M); http_request.SetRequestURI(DIFFIE_HELLMAN_CLIENT_PUBLIC_DATA); http_request.SetVersion(HTTP_1_0); http_request.AddHeader(DIFFIE_HELLAM_INTERIM,r_interim); http_request.AddHeader(CLIENT_TYPE_HEADER,(int)GetNetworkID()); http_request.Finalize(raw_data); raw_data.Encrypt(&ini_key); _data_sock.SendTo(raw_data.GetBuffer(),raw_data.GetLength(),_eib_address,_eib_port); GetLog()->SetConsoleColor(YELLOW); GetLog()->Log(LOG_LEVEL_INFO,"[%s] [Send] Client Public key",GetUserName().GetBuffer()); len = _data_sock.RecvFrom(buff,sizeof(buff),s_address,s_port); raw_data.Clear(); raw_data.Add(buff,len); raw_data.Decrypt(&_encryptor.GetSharedKey()); parser.SetData(reply,raw_data); if(!parser.IsLegalRequest() || reply.GetStatusCode() != STATUS_OK){ _status = STATUS_DISCONNECTED; return STATUS_INRERNAL_ERR; } GetLog()->SetConsoleColor(YELLOW); GetLog()->Log(LOG_LEVEL_INFO,"[EIB] [Received] Keys exchanged succesfuly."); if(!Authenticate(user_name, password, &_encryptor.GetSharedKey())){ _status = STATUS_DISCONNECTED; return STATUS_INCORRECT_CREDENTIALS; } //set marker _status = STATUS_CONNECTED; //start keep alive thread here _thread->Init(eib_ka_port,_eib_address, this); _thread->start(); return STATUS_CONN_OK; }
bool CGenericServer::DiscoverEIBServer(const char* localIpAddr, const char* initialKey, CString& ipAddr, int& port) { if(this->IsConnected()){ GetLog()->Log(LOG_LEVEL_ERROR, "Error: Cannot open connection - Already connected."); return false; } _status = STATUS_DURING_CONNECT; CString ini_key(initialKey); //Send discovery reuqest UDPSocket discovery_sock; //Bind to some random port discovery_sock.SetLocalAddressAndPort(localIpAddr, 0); //Generate the actual request CHttpRequest discovery_req(GET_M, EIB_SERVER_AUTO_DISCOVERY_REQ, HTTP_1_0, EMPTY_STRING); discovery_req.AddHeader(ADDRESS_HEADER, localIpAddr); discovery_req.AddHeader(DATA_PORT_HEADER, discovery_sock.GetLocalPort()); CDataBuffer raw_req; discovery_req.Finalize(raw_req); //encrypt request using the key raw_req.Encrypt(&ini_key); //send the request discovery_sock.SendTo(raw_req.GetBuffer(), raw_req.GetLength(), AUTO_DISCOVERY_SERVICE_ADDRESS, AUTO_DISCOVERY_SERVICE_PORT); //wait (max 10 seconds) to response char buffer[MAX_URL_LENGTH]; CString tmp_addr; int tmp_port; int len = discovery_sock.RecvFrom(buffer, sizeof(buffer), tmp_addr, tmp_port,5000); if(len == 0){ GetLog()->Log(LOG_LEVEL_ERROR,"No data received. timeout."); return false; } CDataBuffer dbf(buffer,len); dbf.Decrypt(&ini_key); CHttpReply reply; CHttpParser parser(reply, dbf); if(!parser.IsLegalRequest()) { return false; } if(reply.GetStatusCode() != STATUS_OK){ return false; } CHttpHeader header; if(!reply.GetHeader(ADDRESS_HEADER, header)){ GetLog()->Log(LOG_LEVEL_ERROR, "Missing header from reply: %s", ADDRESS_HEADER); return false; } CString eibserveraddr = header.GetValue(); if(!reply.GetHeader(DATA_PORT_HEADER, header)){ GetLog()->Log(LOG_LEVEL_ERROR, "Missing header from reply: %s", DATA_PORT_HEADER); return false; } int eibserverport = header.GetValue().ToInt(); //set values and return ipAddr = eibserveraddr; port = eibserverport; return true; }
CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream) { // Try to open the AirTunes demuxer if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FILE) && pInputStream->GetContent().compare("audio/x-xbmc-pcm") == 0 ) { // audio/x-xbmc-pcm this is the used codec for AirTunes // (apples audio only streaming) auto_ptr<CDVDDemuxBXA> demuxer(new CDVDDemuxBXA()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } if (pInputStream->IsStreamType(DVDSTREAM_TYPE_SPOTIFY)) { auto_ptr<CDVDDemuxSpotify> demuxer(new CDVDDemuxSpotify()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTTP)) { CDVDInputStreamHttp* pHttpStream = (CDVDInputStreamHttp*)pInputStream; CHttpHeader *header = pHttpStream->GetHttpHeader(); /* check so we got the meta information as requested in our http header */ if( header->GetValue("icy-metaint").length() > 0 ) { auto_ptr<CDVDDemuxShoutcast> demuxer(new CDVDDemuxShoutcast()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } } #ifdef HAS_FILESYSTEM_HTSP if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTSP)) { auto_ptr<CDVDDemuxHTSP> demuxer(new CDVDDemuxHTSP()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } #endif if (pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER)) { CDVDInputStreamPVRManager* pInputStreamPVR = (CDVDInputStreamPVRManager*)pInputStream; CDVDInputStream* pOtherStream = pInputStreamPVR->GetOtherStream(); if(pOtherStream) { /* Used for MediaPortal PVR addon (uses PVR otherstream for playback of rtsp streams) */ if (pOtherStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG)) { auto_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg()); if(demuxer->Open(pOtherStream)) return demuxer.release(); else return NULL; } } std::string filename = pInputStream->GetFileName(); /* Use PVR demuxer only for live streams */ if (filename.substr(0, 14) == "pvr://channels") { boost::shared_ptr<CPVRClient> client; if (g_PVRClients->GetPlayingClient(client) && client->HandlesDemuxing()) { auto_ptr<CDVDDemuxPVRClient> demuxer(new CDVDDemuxPVRClient()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; } } } auto_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg()); if(demuxer->Open(pInputStream)) return demuxer.release(); else return NULL; }