_寒潭雁影 2020-01-06 11:32 采纳率: 66.7%
浏览 335
已采纳

MFC框架下自定义类中定义多线程问题

本人尝试在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;
    }
};
  • 写回答

3条回答 默认 最新

      报告相同问题?

      相关推荐 更多相似问题

      悬赏问题

      • ¥15 ffmpeg 图片合成视频
      • ¥15 如何修改损失函数以及代码讲解
      • ¥15 有偿咨询!!程序的小数点怎么取到后四位啊!
      • ¥15 IRS智能反射面相关文章代码
      • ¥15 landsat5的两幅影像镶嵌前波段是123457,为什么镶嵌后波段变成了123456?
      • ¥15 关于#matlab#中fmincon函数如何处理约束问题?
      • ¥60 Java程序,控制台输出
      • ¥40 cad 平面线段偏移计算方法
      • ¥20 深度学习可视化工具的使用
      • ¥15 本地的远程软件连接不上华为云服务器