PJSUA2视频如何将视频表单嵌入C#WinForm
我想通过C#WinForm制作一个视频通话演示usa pjsua2,我可以使用pjproject中的pjsua示例进行视频通话。但是当我开发一个C#winform演示来预览捕获视频时。我在PJSUA2中找不到控制SDL窗口的API。我找到了一种使用“FindWindow”和“SetParent”win32 API设置Preview SDL窗口的父控件的方法。这不是个好办法,不是吗。在pjsua2中有更好的方法来控制sdl窗口吗 这是我的端点初始化代码ep是一个静态变量PJSUA2视频如何将视频表单嵌入C#WinForm,c#,winforms,video,sdl,pjsip,C#,Winforms,Video,Sdl,Pjsip,我想通过C#WinForm制作一个视频通话演示usa pjsua2,我可以使用pjproject中的pjsua示例进行视频通话。但是当我开发一个C#winform演示来预览捕获视频时。我在PJSUA2中找不到控制SDL窗口的API。我找到了一种使用“FindWindow”和“SetParent”win32 API设置Preview SDL窗口的父控件的方法。这不是个好办法,不是吗。在pjsua2中有更好的方法来控制sdl窗口吗 这是我的端点初始化代码ep是一个静态变量 e
ep = new Endpoint();
ep.libCreate();
EpConfig epConfig = new EpConfig();
epConfig.logConfig.writer = new DebugLog();
ep.libInit(epConfig);
TransportConfig tcfg = new TransportConfig();
tcfg.port = 5060;
ep.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_UDP,tcfg);
ep.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_TCP,tcfg);
// Start library
ep.libStart();
这是视频预览代码
var epdev = ep.vidDevManager().enumDev2();
VideoPreview video = new VideoPreview(epdev[0].id);
VideoPreviewOpParam videoPreviewOpParam = new VideoPreviewOpParam();
videoPreviewOpParam.rendId = epdev[1].id;//(int)pjmedia_vid_dev_std_index.PJMEDIA_VID_DEFAULT_RENDER_DEV;
videoPreviewOpParam.window = new VideoWindowHandle();
videoPreviewOpParam.window.handle = new WindowHandle();
//videoPreviewOpParam.window.type = new SWIGTYPE_p_pjmedia_vid_dev_hwnd_type((long)1);
videoPreviewOpParam.window.handle.setWindow(this.sdlPreview.Handle.ToInt64());
Debug.WriteLine(this.sdlPreview.Handle);
Debug.WriteLine(this.sdlPreview.Handle.ToInt64());
videoPreviewOpParam.show = true;
video.start(videoPreviewOpParam);
var window = video.getVideoWindow();
var videoList = ep.vidDevManager().enumDev2();
var type = window.getInfo().winHandle.type;
//var epdev = ep.vidDevManager().getOutputWindowFlags(-1);
//window.Show(false);
MediaCoordinate coordinate = new MediaCoordinate();
coordinate.x = 0;// this.panelCamera.Top;
coordinate.y = 0;// this.panelCamera.Left;
window.setPos(coordinate);
MediaSize size = new MediaSize();
size.h = (uint)200;//this.panelCamera.Height;
size.w = (uint)200;//this.panelCamera.Width;
window.setSize(size);
//var intPtr = EmbedControl.FindWindow(null, "pjmedia-SDL video");
//EmbedControl.SetParent(intPtr, this.panelCamera.Handle);
////window.getInfo().isNative = false;
//window.Show(true);
window.Show(true);
这是win32 api代码
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
当设置videoPreviewOpParam.show=false时代码>设置后窗口显示(true)代码>视频表单仍然无法在windows中显示
过了一会儿,我发现我的代码挂起在pjsip源代码sdl_dev.c
atstrm->window=sdl_CreateWindowFrom(hwnd->info.window)
,我将UserControl.Hanlde发送到setWindow
,但是当通过DLLImport在这个C#WinForm中使用sdl2.dll时,它运行良好。我哪里出错了?
github中有我的示例代码
今天2020-09-02我发现SDL源代码需要调试,当我使用C#DLLImport这个SDL“SDL#U CreateWindowFrom”时,它工作得很好,但是当我使用PJSIP被C#代码调用时,为了调试SDL源代码,我发现它挂在“titleLen=GetWindowTextLength(hwnd)”,它调用win32 API“GetWindowTextLength”来获取windows标题。通过C#DLLImport调用SDL的方法也可以,尽管C#中窗口的hanle与SDL的数据相同
if (_this->CreateSDLWindowFrom(_this, window, data) < 0) {
SDL_DestroyWindow(window);
return NULL;
}
if(\u this->CreateSDLWindowFrom(\u this,window,data)<0){
SDL_窗口(窗口);
返回NULL;
}
但是pjsip通过C调用它只是挂起。我做错了什么
==========最终解决方案=========
我想我找到了原因,在SDL源中,SDL将调用“GetWindowTextLength”或其他win32 API,它将挂起。我发现了一个解释“GetWindowText”的博客
根据第一条规则,如果您试图在自己的进程中从窗口获取文本,并且窗口被挂起,那么GetWindowText()也将挂起。但既然这个窗口属于你的流程,那是你自己的错,你应该输。发送WM_GETTEXT消息可确保正确检索来自执行自定义文本管理(通常为自定义控件)的窗口的文本
我在C#UI线程中使用视频,因此当UI挂起时,获取windows信息的GetWindowText()或win32 api也将挂起。有一个博客