Exemple #1
0
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;
}
Exemple #3
0
  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;
}
Exemple #9
0
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;
}