本人尝试在MFC框架下自定义一个类,该类负责接收和解码视频数据,因此需要在该类中定义多线程来做这件事情,以防止在对话框调用该类的时候卡死。
目前本人在自定义类中使用了static的方式开启了多线程,在win10下运行也很正常。然而在测试兼容性的时候发现该程序在win7 64位下会出错,出错的原因似乎是因为我在类内使用了static函数定义了多线程,而我又声明了该类的几个实体,因此static函数出现了调用实体出错的问题。
想问问看:
1.有没有老哥遇到过这种问题?
2.有没有比较好的解决思路?
3.是不是不应该在一个类中用static函数的形式定义线程?
4.像多路接收解码的功能除了封装成一个类然后使用多个实体来做外,还有没有更好的封装方式?
class HWdecode
{
public:
bool changertspurl = false;//是否改变rtsp的地址标志
bool reconnect = false;//需要断线重连标志
bool haveconnect = false;//正常连接标志位
CCriticalSection* mlock;//线程临界区
bool dodecodesave = false;//像素转换开启标志位
//参数对象
FFmpegDemuxer* demuxer = NULL;//FFMPEG对象
CUcontext cuContext;//Cuda设备
NvDecoder* dec = NULL;//Cuda解码对象
CUdeviceptr dpFrame = 0;//数据存储对象初始化
int hwinit()//显卡设备初始化
{
int iGpu = 0;//选择解码播放的GPU,只有一个的话直接设置为0就行
//检测硬件GPU设备
ck(cuInit(0));
int nGpu = 0;
ck(cuDeviceGetCount(&nGpu));
if (iGpu < 0 || iGpu >= nGpu)
{
std::cout << "没有相应的GPU" << std::endl;
return 0;
}
//获得CUDA对象
CUdevice cuDevice = 0;
ck(cuDeviceGet(&cuDevice, iGpu));
char szDeviceName[80];
ck(cuDeviceGetName(szDeviceName, sizeof(szDeviceName), cuDevice));
std::cout << "GPU in use: " << szDeviceName << std::endl;
ck(cuCtxCreate(&cuContext, CU_CTX_SCHED_BLOCKING_SYNC, cuDevice));
return 1;
}
int ffmpeginit(char* url)//ffmpeg对象初始化
{
demuxer = new FFmpegDemuxer(url);
if (demuxer->fmtc == NULL)
{
return 0;
}
else
{
//RGBA帧存储显存初始化
return 1;
}
}
void cudadecoderinit()//cuda解码对象初始化
{
ck(cuMemAlloc(&dpFrame, demuxer->GetWidth() * demuxer->GetHeight() * 4));
//解码器初始化
dec = new NvDecoder(cuContext, (*demuxer).GetWidth(), (*demuxer).GetHeight(), true, FFmpeg2NvCodecId((*demuxer).GetVideoCodec()));
}
DWORD decAndshow()//解码和播放
{
int nVideoBytes = 0, nFrameReturned = 0, nFrame = 0;
uint8_t* pVideo = NULL, ** ppFrame;
long bt = clock();
do
{
uint8_t* getdpframe = (uint8_t*)dpFrame;
demuxer->Demux(&pVideo, &nVideoBytes);//获取一帧视频数据
dec->Decode(pVideo, nVideoBytes, &ppFrame, &nFrameReturned);//解码这一帧数据
//if (!nFrame && nFrameReturned)
// LOG(INFO) << HWD.dec->GetVideoInfo();
if (dodecodesave)
{
for (int i = 0; i < nFrameReturned; i++)
{
mlock->Lock();
//对解码出来的图像数据类型做转换,转到BGRA
printf("GetWidth %d\n", dec->GetWidth());
printf("GetHeight %d\n", dec->GetHeight());
if (dec->GetBitDepth() == 8)
{
if (dec->GetOutputFormat() == cudaVideoSurfaceFormat_YUV444)
YUV444ToColor32<RGBA32>((uint8_t*)ppFrame[i], dec->GetWidth(), getdpframe, 4 * dec->GetWidth(), dec->GetWidth(), dec->GetHeight());
else // default assumed as NV12
Nv12ToColor32<RGBA32>((uint8_t*)ppFrame[i], dec->GetWidth(), getdpframe, 4 * dec->GetWidth(), dec->GetWidth(), dec->GetHeight());
}
mlock->Unlock();
}
}
nFrame += nFrameReturned;
} while (nVideoBytes && changertspurl == false);
changertspurl = false;//将rtsp地址修改标志位重新设置为否
printf("退出,尝试断线连回\n");
reconnect = true;
delete demuxer;
std::cout << "Total frame decoded: " << nFrame << std::endl;
std::cout << "花费时间:" << clock() - bt << "ms" << std::endl;
std::cout << "FPS:" << nFrame / ((clock() - bt) / 1000.0) << std::endl;
return 1;
}
HANDLE pRecvAndShowThread;//接收显示线程对象
static DWORD ThreadRtspRecvShowFun(LPVOID lpParam)
{
return ((HWdecode*)lpParam)->decAndshow();//调用线程的处理函数
}
int Star(char* url, CCriticalSection * lock)
{
mlock = lock;
if (!hwinit())//初始化硬件设备
{
std::cout << "硬件初始化失败!" << std::endl;
return 0;
}
if (!ffmpeginit(url))//初始化硬件设备
{
std::cout << "无法连接码流!" << std::endl;
return 0;
}
cudadecoderinit();
pRecvAndShowThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)HWdecode::ThreadRtspRecvShowFun, this, 0, NULL);
return 1;
}
int ReStar(char* url, CCriticalSection* lock)//断线重连
{
if (!ffmpeginit(url))//初始化硬件设备
{
std::cout << "无法连接码流!" << std::endl;
return 0;
}
if (!haveconnect)
{
cudadecoderinit();
}
pRecvAndShowThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)HWdecode::ThreadRtspRecvShowFun, this, 0, NULL);
return 1;
}
};