多线程SDL_DestroyWindow阻塞问题

Fcx_BiuBiuBiu 2017-10-13 03:44:04
运用多线程实现播放器,用ffmpeg解码sdl显示,在停止播放销毁窗体SDL_DestroyWindow时发生阻塞。
以下是部分代码:

//SDL线程
int sfp_refresh_thread(void *opaque)
{
while (thread_exit==0)
{
SDL_Event event;
event.type = SFM_REFRESH_EVENT;
SDL_PushEvent(&event);
}
//Quit
SDL_Event event;
event.type = SFM_BREAK_EVENT;
SDL_PushEvent(&event);
return 0;
}

//视频播放函数
int simplest_ffmpeg_player(LPVOID lpParam)
{
int i, videoindex;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame,*pFrameYUV;
uint8_t *out_buffer;
AVPacket packet;
int ret, got_picture;

//------------SDL----------------
int screen_w,screen_h;
SDL_Window *screen;
SDL_Renderer* sdlRenderer;
SDL_Texture* sdlTexture;
SDL_Rect sdlRect;
SDL_Thread *video_tid;
SDL_Event event;

struct SwsContext *img_convert_ctx;
CRTSPPlayerDlg *dlg=(CRTSPPlayerDlg *)lpParam;

static AVInputFormat *file_iformat;
AVFormatContext *ic = NULL;
AVDictionary **opts;
AVDictionaryEntry *t;

av_register_all();
avformat_network_init();
AVCodec *pACodec = avcodec_find_decoder(AV_CODEC_ID_H264);
pCodecCtx = NULL;
pCodecCtx = avcodec_alloc_context3(pACodec);
pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
pCodecCtx->width = 1920;
pCodecCtx->height = 1080;

if (avcodec_open2(pCodecCtx, pACodec, NULL) < 0)
{
AfxMessageBox("Could not open codec.\n");
return -1;
}

pFrame=av_frame_alloc();
pFrameYUV=av_frame_alloc();
out_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);

img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);


if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER))
{
AfxMessageBox( "Could not initialize SDL\n");
return -1;
}
//SDL 2.0 Support for multiple windows
screen_w = pCodecCtx->width;
screen_h = pCodecCtx->height;

//===========================================
//显示在MFC控件上
screen = SDL_CreateWindowFrom(dlg->GetDlgItem(IDC_SCREEN)->GetSafeHwnd());
//===========================================
if(!screen)
{
AfxMessageBox("SDL: could not create window - exiting\n");
return -1;
}
sdlRenderer = SDL_CreateRenderer(screen, -1, 0);
//IYUV: Y + U + V (3 planes)
//YV12: Y + V + U (3 planes)
sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING,pCodecCtx->width,pCodecCtx->height);

sdlRect.x=0;
sdlRect.y=0;
sdlRect.w=screen_w;
sdlRect.h=screen_h;

video_tid = SDL_CreateThread(sfp_refresh_thread,NULL,NULL);
//------------SDL End------------
//Event Loop
av_init_packet(&packet);
char dateBuf[DUMMY_SINK_RECEIVE_BUFFER_SIZE] = "";
for (;;)
{
//Wait
SDL_WaitEvent(&event);
if(event.type==SFM_REFRESH_EVENT)
{
//------------------------------
memset(dateBuf, 0, sizeof(dateBuf));
int len = dlg->read(dateBuf, 1);
if (len == 0)
{
if (thread_exit == 1)
{
break;
}
Sleep(20);
continue;
}
packet.data = (uint8_t *)dateBuf;
packet.size = len;
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);
if(ret < 0)
{
continue;
AfxMessageBox("Decode Error.\n");
return -1;
}
if(got_picture)
{
sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
SDL_UpdateTexture( sdlTexture, NULL, pFrameYUV->data[0], pFrameYUV->linesize[0] );
SDL_RenderClear( sdlRenderer );
SDL_RenderCopy( sdlRenderer, sdlTexture, NULL, NULL);
SDL_RenderPresent( sdlRenderer );
}
av_free_packet(&packet);
}
else if(event.type==SDL_QUIT)
{
thread_exit=1;
}
else if(event.type==SFM_BREAK_EVENT)
{
break;
}

}

sws_freeContext(img_convert_ctx);
SDL_DestroyWindow(screen); //此函数会阻塞
SDL_DestroyRenderer(sdlRenderer);
SDL_DestroyTexture(sdlTexture);
SDL_Quit(); //此函数会阻塞
dlg->GetDlgItem(IDC_SCREEN)->ShowWindow(SW_SHOWNORMAL);
av_free(out_buffer);
av_frame_free(&pFrameYUV);
av_frame_free(&pFrame);
avcodec_close(pCodecCtx);

return 0;
}

//播放线程
UINT Thread_Play(LPVOID lpParam){
simplest_ffmpeg_player(lpParam);
return 0;
}

//开启播放
void CRTSPPlayerDlg::OnBnClickedButtonPlay()
{
// TODO: 在此添加控件通知处理程序代码
m_ThreadHandleRetVal = CreateThread(NULL, 0, LPTHREAD_START_ROUTINE)Thread_Play, this, 0, NULL);
}

//停止播放
void CRTSPPlayerDlg::OnBnClickedButtonStop()
{
// TODO: 在此添加控件通知处理程序代码
thread_exit = 1;
m_pRtsp->stopRTSPClient();
WaitForSingleObject(m_ThreadHandleRetVal, INFINITE);//等待播放线程结束
.
.
.
.
}
...全文
2515 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
文三~ 2021-04-30
  • 打赏
  • 举报
回复
引用 10 楼 枫林港 的回复:
后来改了实现机制解决了改问题,SDL初始化和释放资源都放在主窗口的主线程中实现,就不会有该问题: {/* 主线程中 */ SDL初始化,调用SDL_Init、SDL_CreateWindowFrom、SDL_CreateRenderer、SDL_CreateTexture等函数。 创建解码线程、播放线程、刷新线程等,播放控制都放在这些线程里面。 } 用户关闭SDL窗口,释放资源: {/* SDL窗口的OnClose()中 */ PostMessage()通知主线程播放结束,关闭SDL窗口并释放资源。 } {/* 主线程中 */ 收到SDL窗口关闭消息后: 1、通知解码线程、播放线程、刷新线程等退出。 2、等待各线程完全退出。 3、调用SDL_DestroyTexture、SDL_DestroyRenderer、SDL_DestroyWindow、SDL_Quit释放SDL资源。 } 用户直接关闭主窗口,同时也需要关闭SDL窗口,释放资源: {/* 主窗口的OnClose()中 */ 1、通知解码线程、播放线程、刷新线程等退出。 2、等待各线程完全退出。 3、调用SDL_DestroyTexture、SDL_DestroyRenderer、SDL_DestroyWindow、SDL_Quit释放SDL资源。 }
你这么做 在ctrl+alt+delete切屏的时候不会导致画面卡死吗
枫林港 2021-06-21
  • 举报
回复
@文三~ 没有发现有啥问题。
枫林港 2021-02-07
  • 打赏
  • 举报
回复
后来改了实现机制解决了改问题,SDL初始化和释放资源都放在主窗口的主线程中实现,就不会有该问题: {/* 主线程中 */ SDL初始化,调用SDL_Init、SDL_CreateWindowFrom、SDL_CreateRenderer、SDL_CreateTexture等函数。 创建解码线程、播放线程、刷新线程等,播放控制都放在这些线程里面。 } 用户关闭SDL窗口,释放资源: {/* SDL窗口的OnClose()中 */ PostMessage()通知主线程播放结束,关闭SDL窗口并释放资源。 } {/* 主线程中 */ 收到SDL窗口关闭消息后: 1、通知解码线程、播放线程、刷新线程等退出。 2、等待各线程完全退出。 3、调用SDL_DestroyTexture、SDL_DestroyRenderer、SDL_DestroyWindow、SDL_Quit释放SDL资源。 } 用户直接关闭主窗口,同时也需要关闭SDL窗口,释放资源: {/* 主窗口的OnClose()中 */ 1、通知解码线程、播放线程、刷新线程等退出。 2、等待各线程完全退出。 3、调用SDL_DestroyTexture、SDL_DestroyRenderer、SDL_DestroyWindow、SDL_Quit释放SDL资源。 }
vge_ 2020-08-25
  • 打赏
  • 举报
回复
遇到了同样问题,,但是 SDL_DestroyWindow源码里有 showWIndow? 没有吧
狂奔吧码奴 2018-10-16
  • 打赏
  • 举报
回复
我是根据我的需求手动修改了SDK库
狂奔吧码奴 2018-10-16
  • 打赏
  • 举报
回复
引用 6 楼 weixin_37639921 的回复:
[quote=引用 4 楼 qq_37463450 的回复:] [quote=引用 2 楼 lcs182764 的回复:] 我也是这个问题 SDL_DestroyWindow阻塞。不知道什么原因。 但是 SDL_Window *screen; 定义为全局变量,然后将 SDL_DestroyWindow(screen);放到停止按钮里面销毁线程前就没问题。纠结中
死锁了 两个线程互相等待造成的。。。我刚刚解决的问题[/quote] 怎么解决的死锁[/quote]SDL_DestroyWindow这个函数内调用了showWIndow函数 这个函数要求UI主线程不能阻塞 否则一直等待 造成死锁。我是根据我的需求手动修改了SDK库
weixin_37639921 2018-10-16
  • 打赏
  • 举报
回复
引用 4 楼 qq_37463450 的回复:
[quote=引用 2 楼 lcs182764 的回复:]
我也是这个问题 SDL_DestroyWindow阻塞。不知道什么原因。
但是 SDL_Window *screen; 定义为全局变量,然后将 SDL_DestroyWindow(screen);放到停止按钮里面销毁线程前就没问题。纠结中

死锁了 两个线程互相等待造成的。。。我刚刚解决的问题[/quote]
怎么解决的死锁
weixin_37639921 2018-10-16
  • 打赏
  • 举报
回复
怎么解决的死锁
狂奔吧码奴 2018-09-04
  • 打赏
  • 举报
回复
引用 2 楼 lcs182764 的回复:
我也是这个问题 SDL_DestroyWindow阻塞。不知道什么原因。
但是 SDL_Window *screen; 定义为全局变量,然后将 SDL_DestroyWindow(screen);放到停止按钮里面销毁线程前就没问题。纠结中

死锁了 两个线程互相等待造成的。。。我刚刚解决的问题
草原_苍狼 2017-11-20
  • 打赏
  • 举报
回复
我也是这个问题 SDL_DestroyWindow阻塞。不知道什么原因。 但是 SDL_Window *screen; 定义为全局变量,然后将 SDL_DestroyWindow(screen);放到停止按钮里面销毁线程前就没问题。纠结中
枫林港 2017-10-24
  • 打赏
  • 举报
回复
楼主,这个问题是否解决了? 我也遇到了这个问题,我的代码和你的非常接近,单步跟踪看,是阻塞在ShowWindow(hwnd, SW_HIDE);这里了。不知道啥原因,郁闷了很多天了。 如果解决了,望楼主赐教!

1,451

社区成员

发帖
与我相关
我的任务
社区描述
多媒体/设计/Flash/Silverlight 开发 图象工具使用
社区管理员
  • 图象工具使用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧