?? netoutput.cpp
字號:
/******************************************************************************** netoutput.cpp: network output*-------------------------------------------------------------------------------* (c)1999-2001 VideoLAN* $Id: netoutput.cpp,v 1.11.4.5 2003/05/16 19:43:59 nitrox Exp $** Authors: Benoit Steiner <benny@via.ecp.fr>* Arnaud de Bossoreille de Ribou <bozo@via.ecp.fr>** This program is free software; you can redistribute it and/or* modify it under the terms of the GNU General Public License* as published by the Free Software Foundation; either version 2* of the License, or (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.**-------------------------------------------------------------------------------********************************************************************************///------------------------------------------------------------------------------// Preamble//------------------------------------------------------------------------------#ifdef WIN32#include <winsock2.h>#include <ws2tcpip.h>#endif#include "../../core/defs.h"#include "../../core/core.h"#include "../../mpeg/mpeg.h"#include "../../mpeg/ts.h"#include "../../mpeg/rtp.h"#include "../../server/buffer.h"#include "../../server/output.h"#ifdef HAVE_NET_IF_H#include <net/if.h>#endif#include "netoutput.h"//******************************************************************************// C_NetOutput class//******************************************************************************////******************************************************************************//------------------------------------------------------------------------------// //------------------------------------------------------------------------------C_NetOutput::C_NetOutput(const C_String& strChannelName) : C_Output(TS_IN_ETHER), m_cSocketBuff(TS_IN_ETHER+1){ C_Application* pApp = C_Application::GetApp(); ASSERT(pApp); m_strSrcHost = pApp->GetSetting(strChannelName+".SrcHost", ""); m_strSrcPort = pApp->GetSetting(strChannelName+".SrcPort", ""); m_strDstHost = pApp->GetSetting(strChannelName+".DstHost", ""); m_strDstPort = pApp->GetSetting(strChannelName+".DstPort", "1234"); m_strType = pApp->GetSetting(strChannelName+".Type", "unicast").ToLower(); m_strInterface = pApp->GetSetting(strChannelName+".Interface", ""); C_String strTTL = pApp->GetSetting(strChannelName+".TTL", "0"); m_iTTL = strTTL.ToInt(); // Init the buffer // The first slot is reserved for the Rtp Header m_cSocketBuff.SetSlotSize(0, RTP_HEADER_LEN); for(int iIndex = 1; iIndex < TS_IN_ETHER + 1; iIndex++) m_cSocketBuff.SetSlotSize(iIndex, TS_PACKET_LEN);}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------C_NetOutput::~C_NetOutput(){}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------void C_NetOutput::OnInit(){ ASSERT( (m_strType == "unicast") || (m_strType == "multicast") || (m_strType == "broadcast")); int iOptVal=1; if(m_strType == "broadcast") { // Allow the socket to send broadcast packets iOptVal = 1; m_cSocket.SetOption(SOL_SOCKET, SO_BROADCAST, (char *)&iOptVal, sizeof(iOptVal)); } // Allow to use the ip/port couple more than once at a time to be // able to send several streams to a same client using the same port iOptVal = 1; m_cSocket.SetOption(SOL_SOCKET, SO_REUSEADDR, (char *)&iOptVal, sizeof(iOptVal)); // Try to increase the size of the socket output buffer to 1/2MB (8Mb/s // during 1/2s) to avoid packet loss iOptVal = 524288; for(;;) { try { m_cSocket.SetOption(SOL_SOCKET, SO_SNDBUF, (char *)&iOptVal, sizeof(iOptVal)); break; } catch(E_Exception e) { iOptVal = iOptVal / 2; if(iOptVal <= 524288/16) throw E_Output("Unable to allocate output buffer", e); } }#ifdef HAVE_IPV6 if ((m_cSocket.GetDomain() == AF_INET6)&& (m_strType == "multicast")&& (m_strInterface != "")) { /* now get the ifindex for this interface */ /* and set the appropriate option */ int mcif = if_nametoindex(m_strInterface.GetString()); if (mcif == 0) perror("if_nametoindex()\n"); else m_cSocket.SetOption(IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&mcif, sizeof(mcif)); }#endif#ifdef HAVE_SO_BINDTODEVICE // If an interface is specified then bind to it // (Very useful when several interfaces are connected to the same subnet) if(m_strInterface != "") { struct ifreq sInterface; strncpy(sInterface.ifr_ifrn.ifrn_name, m_strInterface.GetString(), IFNAMSIZ); m_cSocket.SetOption(SOL_SOCKET, SO_BINDTODEVICE, (char *)&sInterface, sizeof(sInterface)); }#endif // Set the Time To Live value if != 0 if(m_iTTL) { if (m_cSocket.GetDomain() == AF_INET) { if((m_strType == "unicast") || (m_strType == "broadcast")) m_cSocket.SetOption(IPPROTO_IP, IP_TTL, (char *)&m_iTTL, sizeof(m_iTTL)); else if(m_strType == "multicast") m_cSocket.SetOption(IPPROTO_IP, IP_MULTICAST_TTL, (char *)&m_iTTL, sizeof(m_iTTL)); }#ifdef HAVE_IPV6 else if (m_cSocket.GetDomain() == AF_INET6) { /* of course broadcast does not exist in IPv6 */ if((m_strType == "unicast") || (m_strType == "broadcast")) m_cSocket.SetOption(IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *)&m_iTTL, sizeof(m_iTTL)); else if(m_strType == "multicast") m_cSocket.SetOption(IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&m_iTTL, sizeof(m_iTTL)); }#endif } // Bind it to the local address if specified if(m_strSrcHost.Length() != 0) m_cSocket.Bind(m_strSrcHost, m_strSrcPort);#ifndef BUGGY_VLC // Connect it m_cSocket.Connect(m_strDstHost, m_strDstPort);#endif}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------void C_NetOutput::OnClose(){ try { m_cSocket.Close(); } catch(E_Exception e) { throw E_Output("Output termination failed", e); }}//------------------------------------------------------------------------------////------------------------------------------------------------------------------////------------------------------------------------------------------------------void C_NetOutput::WriteToPort(bool RtpEncapsulation, u32 RtpSendTime){ ASSERT(m_pTsProvider); unsigned int iPacketNumber = m_cTsBuff.Size(); int HeaderOffset; bool HasDiscontinuity = 0; if(iPacketNumber > 0) { // To avoid problems with the socket buff ASSERT(iPacketNumber <= TS_IN_ETHER); if (RtpEncapsulation) { HeaderOffset = RTP_HEADER_LEN; m_pRtpHeader->BuildHeader(m_iRtpCounter++); // Check for discontinuity in one of the TS packets for(unsigned int iIndex = 0; iIndex < iPacketNumber; iIndex++) HasDiscontinuity |= m_cTsBuff[iIndex].IsDiscontinuity(); m_pRtpHeader->SetRtpDiscontinuity(HasDiscontinuity); // Convert to the 90kHzClock : RtpSendTime()*90 000/1 000 000 // Doing a /10 *9 /10 fo conversion / integer issues. m_pRtpHeader->SetRtpTimeStamp( ((RtpSendTime/10)*9)/10 );#ifdef BUGGY_VLC memcpy(m_ByteBuff, *m_pRtpHeader, RTP_HEADER_LEN);#endif } else HeaderOffset = 0;#ifdef BUGGY_VLC // TS concatenation for(unsigned int iIndex = 0; iIndex < iPacketNumber; iIndex++) memcpy(m_ByteBuff + HeaderOffset + TS_PACKET_LEN * iIndex, m_cTsBuff[iIndex], TS_PACKET_LEN); // Send the data that were stored in the buffer int iRc = PrivateWriteTo(HeaderOffset + TS_PACKET_LEN * iPacketNumber); if(iRc != HeaderOffset + TS_IN_ETHER * TS_PACKET_LEN) m_iByteLost += HeaderOffset + TS_IN_ETHER * TS_PACKET_LEN - iRc;#else // Fill in the socketbuff if (RtpEncapsulation) { // Rtp Header First m_cSocketBuff.SetSlotBuff(0,(char*)(byte*)*m_pRtpHeader); } for(unsigned int iIndex = 1; iIndex < iPacketNumber+1; iIndex++) { m_cSocketBuff.SetSlotBuff(iIndex,(char*)(byte*)m_cTsBuff[iIndex-1]); } // Send the data that were stored in the buffer try { int iRc; if (RtpEncapsulation) { iRc = m_cSocket.Send(m_cSocketBuff, iPacketNumber + 1 , 0); } else { // No Rtp : skip first SockBuff -> iOffset=1 iRc = m_cSocket.Send(m_cSocketBuff, iPacketNumber, 1); } if(iRc != HeaderOffset + TS_IN_ETHER * TS_PACKET_LEN) m_iByteLost += HeaderOffset + TS_IN_ETHER * TS_PACKET_LEN - iRc; } catch(E_Exception e) { throw E_Output("Connection lost", e); }#endif // Free the now unused packets C_TsPacket* pPacket; for(unsigned int i = 0; i < iPacketNumber; i++) { // Pop the packet from the buffer pPacket = m_cTsBuff.Pop(); ASSERT(pPacket); // And release it m_pTsProvider->ReleasePacket(pPacket); } }}//******************************************************************************// C_Net4Output class//******************************************************************************////******************************************************************************//------------------------------------------------------------------------------// //------------------------------------------------------------------------------C_Net4Output::C_Net4Output(const C_String& strChannelName) : C_NetOutput(strChannelName){}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------C_Net4Output::~C_Net4Output(){}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------void C_Net4Output::OnInit(){ try {#ifdef BUGGY_VLC /* Build the destination address */ m_cOutputInetAddr.Build(m_strDstHost, m_strDstPort);#endif // Open the socket m_cSocket.Open(AF_INET, SOCK_DGRAM); C_NetOutput::OnInit();#ifndef _WIN32 if(m_strType == "multicast") { struct ip_mreq imr; C_Inet4Addr cAddr; imr.imr_interface.s_addr = INADDR_ANY; cAddr.Build(m_strDstHost, m_strDstPort); imr.imr_multiaddr.s_addr = cAddr.GetInetAddr()->sin_addr.s_addr; m_cSocket.SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&imr, sizeof(imr)); }#endif } catch(E_Exception e) { throw E_Output("Net4Output initialisation failed", e); }}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------void C_Net4Output::OnClose(){ try {#ifndef _WIN32 if(m_strType == "multicast") { struct ip_mreq imr; C_Inet4Addr cAddr; imr.imr_interface.s_addr = INADDR_ANY; cAddr.Build(m_strDstHost, m_strDstPort); imr.imr_multiaddr.s_addr = cAddr.GetInetAddr()->sin_addr.s_addr; m_cSocket.SetOption(IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&imr, sizeof(imr)); }#endif C_NetOutput::OnClose(); } catch(E_Exception e) { throw E_Output("Net4Output termination failed", e); }}#ifdef BUGGY_VLC//------------------------------------------------------------------------------////------------------------------------------------------------------------------int C_Net4Output::PrivateWriteTo(int iBuffLen){ return m_cSocket.WriteTo(m_cOutputInetAddr, (char *)m_ByteBuff, iBuffLen);}#endif//******************************************************************************// C_Net6Output class//******************************************************************************////******************************************************************************#ifdef HAVE_IPV6//------------------------------------------------------------------------------// //------------------------------------------------------------------------------C_Net6Output::C_Net6Output(const C_String& strChannelName) : C_NetOutput(strChannelName){}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------C_Net6Output::~C_Net6Output(){}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------void C_Net6Output::OnInit(){ try {#ifdef BUGGY_VLC /* Build the destination address */ m_cOutputInetAddr.Build(m_strDstHost, m_strDstPort, SOCK_DGRAM);#endif // Open the socket m_cSocket.Open(AF_INET6, SOCK_DGRAM); C_NetOutput::OnInit(); if(m_strType == "multicast") { struct ipv6_mreq imr; C_Inet6Addr cAddr; imr.ipv6mr_interface = 0; cAddr.Build(m_strDstHost, m_strDstPort, SOCK_DGRAM); imr.ipv6mr_multiaddr = cAddr.GetInetAddr()->sin6_addr; m_cSocket.SetOption(IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&imr, sizeof(imr)); } } catch(E_Exception e) { throw E_Output("Net6Output initialisation failed", e); }}//------------------------------------------------------------------------------// //------------------------------------------------------------------------------void C_Net6Output::OnClose(){ try { if(m_strType == "multicast") { struct ipv6_mreq imr; C_Inet6Addr cAddr; imr.ipv6mr_interface = 0; cAddr.Build(m_strDstHost, m_strDstPort, SOCK_DGRAM); imr.ipv6mr_multiaddr = cAddr.GetInetAddr()->sin6_addr; m_cSocket.SetOption(IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&imr, sizeof(imr)); } C_NetOutput::OnClose(); } catch(E_Exception e) { throw E_Output("Net6Output termination failed", e); }}#ifdef BUGGY_VLC//------------------------------------------------------------------------------////------------------------------------------------------------------------------int C_Net6Output::PrivateWriteTo(int iBuffLen){ return m_cSocket.WriteTo(m_cOutputInetAddr, (const char *) m_ByteBuff, iBuffLen);}#endif#endif
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -