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

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条回答 默认 最新

  • 白色一大坨 2020-01-06 12:30
    关注

    我看了你的描述,你应该好好看看这几个类的数据是怎么做的,为什么会串,你要是可以贴一下你类的代码,更好

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥20 搭建pt1000三线制高精度测温电路
  • ¥15 使用Jdk8自带的算法,和Jdk11自带的加密结果会一样吗,不一样的话有什么解决方案,Jdk不能升级的情况
  • ¥15 画两个图 python或R
  • ¥15 在线请求openmv与pixhawk 实现实时目标跟踪的具体通讯方法
  • ¥15 八路抢答器设计出现故障
  • ¥15 opencv 无法读取视频
  • ¥15 按键修改电子时钟,C51单片机
  • ¥60 Java中实现如何实现张量类,并用于图像处理(不运用其他科学计算库和图像处理库))
  • ¥20 5037端口被adb自己占了
  • ¥15 python:excel数据写入多个对应word文档