今天在项目中用到SDL2.0的库做视频显示用,在其中出现不少问题,这里一一记录下来,并作为以后的参考。
同一个窗口句柄在多次使用SDL_CreateWindowFrom和SDL_DestroyWindow以后,发现程序运行正常,但视频显示不出来的问题。
第一次将Hwnd传递给SDL_CreateWindowFrom,创建一个显示窗口给SDL,随后在不使用的时候,调用SDL_DestroyWindow,将刚刚创建的显示窗口销毁,释放显示相关资源之后,然后在再次使用SDL_CreateWindowFrom的时候,将同一个句柄传递给SDL_CreateWindowFrom,返回成功,后续的操作也全部正常进行,但视频在窗口上始终显示不出来。
对于其中的原因,我找了好久,后面从SDL的源码中才慢慢推测并怀疑一些问题,SDL源码如下:
1 void 2 SDL_DestroyWindow(SDL_Window * window) 3 { 4 SDL_VideoDisplay *display; 5 6 CHECK_WINDOW_MAGIC(window, ); 7 8 /* Restore video mode, etc. */ 9 SDL_HideWindow(window);/*注意这个地方哦*/ 10 11 /* Make sure this window no longer has focus */ 12 if (SDL_GetKeyboardFocus() == window) { 13 SDL_SetKeyboardFocus(NULL); 14 } 15 if (SDL_GetMouseFocus() == window) { 16 SDL_SetMouseFocus(NULL); 17 } 18 19 /* make no context current if this is the current context window. */ 20 if (window->flags & SDL_WINDOW_OPENGL) { 21 if (_this->current_glwin == window) { 22 SDL_GL_MakeCurrent(window, NULL); 23 } 24 } 25 26 if (window->surface) { 27 window->surface->flags &= ~SDL_DONTFREE; 28 SDL_FreeSurface(window->surface); 29 } 30 if (_this->DestroyWindowFramebuffer) { 31 _this->DestroyWindowFramebuffer(_this, window); 32 } 33 if (_this->DestroyWindow) { 34 _this->DestroyWindow(_this, window); 35 } 36 if (window->flags & SDL_WINDOW_OPENGL) { 37 SDL_GL_UnloadLibrary(); 38 } 39 40 display = SDL_GetDisplayForWindow(window); 41 if (display->fullscreen_window == window) { 42 display->fullscreen_window = NULL; 43 } 44 45 /* Now invalidate magic */ 46 window->magic = NULL; 47 48 /* Free memory associated with the window */ 49 SDL_free(window->title); 50 SDL_FreeSurface(window->icon); 51 SDL_free(window->gamma); 52 while (window->data) { 53 SDL_WindowUserData *data = window->data; 54 55 window->data = data->next; 56 SDL_free(data->name); 57 SDL_free(data); 58 } 59 60 /* Unlink the window from the list */ 61 if (window->next) { 62 window->next->prev = window->prev; 63 } 64 if (window->prev) { 65 window->prev->next = window->next; 66 } else { 67 _this->windows = window->next; 68 } 69 70 SDL_free(window); 71 }
从上面的代码,我开始怀疑是不是在调用SDL_DestroyWindow以后,SDL将窗口给隐藏了,导致在上面显示视频的时候,始终显示不出来的问题。
于是我在自己的测试代码中加入如下语句,在调用SDL_DestroyWindow以后,我一句:
vDisplay.ShowWindow(SW_SHOWNORMAL);//想显示窗口给显示出来,show出来
其中vDisplay对应于显示的窗口控件对象。
在测试的项目代码中加入这行代码以后,就完美的解决了项目的问题。
=============================================================
问题2:
当我在MFC的UI消息相应函数中创建显示窗口的一些相关资源,在后台创建的单独线程,用于刷新和更新显示数据,然后在UI的关闭消息响应中释放和销毁SDL窗口相关资源。
问题来了,当我使用全屏的时候,出现了后台更新数据线程一直报错:
1 if(o_pSdlHelper->SDL_RenderClear(pDispContext->pStruOut->pRender)<0) 2 { 3 char outstr[200]={0}; 4 const char *pbuf=o_pSdlHelper->SDL_GetError(); 5 _snprintf(outstr,sizeof(outstr),"%s \n",pbuf);//这里出错信息为:Reset(): INVALIDCALL 6 OutputDebugStringA(outstr); 7 memset(outstr,0,sizeof(outstr)); 8 9 return PCI_MC_UNKNOWN_ERR; 10 }
这就让我奇怪了,之前我全屏的时候,没有错误啊,现在为什么有错?而且显示窗口画面也没有显示刷新了!!
于是我想了下和之前的代码有什么不同,唯一的不同在于,我调用创建窗口和创建渲染,纹理等等这些操作等资源放在了和更新数据的同一个线程中,没办法,不知道原因,只有改回原来的代码,将创建的代码从UI消息响应中调入和后台刷新数据同一个线程中。结果奇怪的是,居然这样全屏操作能运行?
见鬼了,这是啥原因?
//这个原因,还有待查证相关资料和SDL源码才能知道。暂时解决了,但不知道原因何在。