正在寻找可以使用h.264 RTSP流作为视频源的SIP客户端

正在寻找可以使用h.264 RTSP流作为视频源的SIP客户端,sip,voip,h.264,video-conferencing,Sip,Voip,H.264,Video Conferencing,我们希望将IP摄像头(h.264 RTSP流)与星号PBX系统集成在一起,用于学校的分布式教育(以便远程教师可以“拨入并教学”) 理想情况下,我们希望能够创建一个SIP客户端作为自动应答pbx扩展 我们正在考虑运行一个*nix盒,它可以使用网络视频流作为视频源,混合一个单独的音频源,并提供一个SIP端点 我理解,您可能能够: 调用一个外部C脚本,该脚本可以解析和更改它所使用的客户端的SIP头中的SDP信息,并更改它希望从中接收媒体的地址 但我认为,寻找一种将h.264 rtsp流表示为/dev/

我们希望将IP摄像头(h.264 RTSP流)与星号PBX系统集成在一起,用于学校的分布式教育(以便远程教师可以“拨入并教学”)

理想情况下,我们希望能够创建一个SIP客户端作为自动应答pbx扩展

我们正在考虑运行一个*nix盒,它可以使用网络视频流作为视频源,混合一个单独的音频源,并提供一个SIP端点

我理解,您可能能够:

调用一个外部C脚本,该脚本可以解析和更改它所使用的客户端的SIP头中的SDP信息,并更改它希望从中接收媒体的地址

但我认为,寻找一种将h.264 rtsp流表示为/dev/videoX并使用标准SIP客户端的方法可能更容易

如果有人对研究有任何建议或想法,我会非常感激:-)

谢谢你的阅读

W


p、 在美国,有IP摄像机声称拥有SIP客户端,但我所看到的只是提供用于建立双向音频会话的SIP。

live555
有一些开源实现,如and,可以满足您的需求。

live555
有一些开源实现,如and,可以满足您的需求。

我不知道您是否需要经过这么长时间,我是否找到了这个问题的正确答案,但也许我可以给你一些关于VoIP和IP摄像头管理的建议,这将帮助任何有同样问题的人

您的目标(如果我正确理解您的问题)基本上是创建一个电话会议解决方案,回答所有来电,并将IP摄像头视频连接到所有这些电话。我目前在一家名为Ozeki的公司工作,我不知道是否有开源解决方案可以解决您的问题,我将向您展示一个SIP帐户注册、IP摄像头连接的示例代码,并用摄像头视频接听所有来电

下面是源代码:

public partial class Form1 : Form
{
    private IIPCamera _camera;
    private DrawingImageProvider _imageProvider;
    private MediaConnector _connector;
    private VideoViewerWF _videoViewerWf;
    private ISoftPhone _softphone;
    private IPhoneLine _phoneLine;
    private IPhoneCall _call;
    private PhoneCallAudioSender _audioSender;
    private PhoneCallVideoSender _videoSender;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        _softphone = SoftPhoneFactory.CreateSoftPhone(5000, 10000);
        _softphone.IncomingCall += softphone_IncomingCall;
        _connector = new MediaConnector();
        _videoSender = new PhoneCallVideoSender();
        _audioSender = new PhoneCallAudioSender();
        _imageProvider = new DrawingImageProvider();
        _videoViewerWf = new VideoViewerWF();
        SetVideoViewer();
    }

    private void SetVideoViewer()
    {
        CameraBox.Controls.Add(_videoViewerWf);
        _videoViewerWf.Size = new Size(260, 180);
        _videoViewerWf.BackColor = Color.Black;
        _videoViewerWf.TabStop = false;
        _videoViewerWf.FlipMode = FlipMode.None;
        _videoViewerWf.Location = new Point(35, 30);
        _videoViewerWf.Name = "_videoViewerWf";
    }

    private void Register(bool registrationRequired, string displayName, string userName, string authenticationId, string registerPassword, string domainHost)
    {
        try
        {
            var account = new SIPAccount(registrationRequired, displayName, userName, authenticationId, registerPassword, domainHost);
            _phoneLine = _softphone.CreatePhoneLine(account);
            _phoneLine.RegistrationStateChanged += phoneLine_RegistrationStateChanged;
            _softphone.RegisterPhoneLine(_phoneLine);
        }
        catch (Exception ex)
        {
            label_Phoneline.Text = ex.Message;
        }
    }

    private void phoneLine_RegistrationStateChanged(object sender, RegistrationStateChangedArgs e)
    {
        InvokeGuiThread(() => label_Phoneline.Text = e.State.ToString());
    }

    private void softphone_IncomingCall(object sender, VoIPEventArgs<iphonecall> e)
    {
        if (_camera != null)
        {
            _call = e.Item;
            _call.CallStateChanged += call_CallStateChanged;
            ConnectToCall();
            _call.Answer();
        }
    }

    private void ConnectToCall()
    {
        _videoSender.AttachToCall(_call);
        _audioSender.AttachToCall(_call);
        _connector.Connect(_camera.VideoChannel, _videoSender);
        _connector.Connect(_camera.AudioChannel, _audioSender);
    }

    private void call_CallStateChanged(object sender, CallStateChangedArgs e)
    {
        InvokeGuiThread(() => label_Call.Text = e.State.ToString());

        if (e.State == CallState.Completed)
            if (_call != null)
            {
                _call.CallStateChanged -= call_CallStateChanged;
                _connector.Disconnect(_camera.VideoChannel, _videoSender);
                _connector.Disconnect(_camera.AudioChannel, _audioSender);
            }
    }

    private void button_Connect_Click(object sender, EventArgs e)
    {
        _camera = IPCameraFactory.GetCamera("cameraIPAddress:8080", "admin", "admin");
        _connector.Connect(_camera.VideoChannel, _imageProvider);
        _videoViewerWf.SetImageProvider(_imageProvider);
        _videoViewerWf.Start();
        _camera.Start();
    }

    private void button_SIPRegister_Click(object sender, EventArgs e)
    {
        Register(true, "100", "100", "100", "100", "PBXAddress");
    }

    private void InvokeGuiThread(Action action)
    {
        BeginInvoke(action);
    }
}
公共部分类表单1:表单
{
私人IIP摄像机;
私人绘图图像提供商_图像提供商;
专用MediaConnector\u连接器;
私人视频浏览者;
专用ISoftPhone(软电话),;
私人IPhoneLine(电话线),;
私人IPhoneCall(IPhoneCall);;
私人电话呼叫audioSender\u audioSender;
私人电话呼叫视频发送者(u videoSender);;
公共表格1()
{
初始化组件();
}
私有void Form1\u加载(对象发送方、事件参数e)
{
_softphone=SoftPhoneFactory.CreateSoftPhone(500010000);
_softphone.IncomingCall+=softphone\u IncomingCall;
_连接器=新的MediaConnector();
_videoSender=新电话呼叫videoSender();
_audioSender=新电话呼叫audioSender();
_imageProvider=新建DrawingImageProvider();
_videoViewerWf=新的videoViewerWf();
SetVideoViewer();
}
私有void SetVideoViewer()
{
CameraBox.Controls.Add(\u videoViewerWf);
_videoViewerWf.Size=新尺寸(260,180);
_videoViewerWf.BackColor=Color.Black;
_videoViewerWf.TabStop=false;
_videoViewerWf.FlipMode=FlipMode.None;
_videoViewerWf.Location=新点(35,30);
_videoViewerWf.Name=“\u videoViewerWf”;
}
私有无效寄存器(需要bool注册、字符串显示名称、字符串用户名、字符串身份验证ID、字符串注册表密码、字符串域主机)
{
尝试
{
var account=新SIPAccount(需要注册、显示名称、用户名、身份验证ID、registerPassword、domainHost);
_phoneLine=\u softphone.CreatePhoneLine(帐户);
_phoneLine.RegistrationStateChanged+=phoneLine\u RegistrationStateChanged;
_软电话。注册电话线(电话线);
}
捕获(例外情况除外)
{
label_Phoneline.Text=ex.消息;
}
}
专用无效电话线_RegistrationStateChanged(对象发送方,RegistrationStateChangedArgs e)
{
InvokeGuiThread(()=>label_Phoneline.Text=e.State.ToString());
}
专用无效软电话(对象发送方,VoIPEventArgs e)
{
如果(_camera!=null)
{
_call=e.项目;
_call.CallStateChanged+=call_CallStateChanged;
ConnectToCall();
_call.Answer();
}
}
私有void ConnectToCall()
{
_videoSender.AttachToCall(_call);
_audioSender.AttachToCall(_call);
_连接器。连接(摄像头、视频频道、视频发送器);
_连接器。连接(_camera.AudioChannel,_audioSender);
}
私有无效调用\u CallStateChanged(对象发送方,CallStateChangedArgs e)
{
InvokeGuiThread(()=>label_Call.Text=e.State.ToString());
if(e.State==CallState.Completed)
如果(_call!=null)
{
_call.CallStateChanged-=call_CallStateChanged;
_连接器。断开(摄像头、视频通道、视频发送器);
_连接器。断开(_camera.AudioChannel,_audioSender);
}
}
私有无效按钮\u连接\u单击(对象发送者,事件参数e)
{
_camera=IPCameraFactory.GetCamera(“cameraIPAddress:8080”,“admin”,“admin”);
_connector.Connect(_camera.VideoChannel,_imageProvider);
_videoViewerWf.SetImageProvider(_imageProvider);
_videoViewerWf.Start();
_camera.Start();
}
私有无效按钮\u SIPRegister\u单击(对象发送者,事件参数e)
{
寄存器(真,“100”、“100”、“100”、“100”、“PBX地址”);
}
私有void InvokeGuiThread(操作)
{
开始(行动);
}
}
以及(示例)GUI:

如果单击“连接”按钮,则IPCameraFactory.GetCamera()将