You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Release版本中EnterCriticalSection调用致程序冻结问题求助

问题

我正在开发基于Microsoft Media Foundation的openframeworks扩展,Debug构建下运行正常,但Release构建中调用EnterCriticalSection后程序冻结。

Release构建无编译错误,启动ofApp后控制台持续挂起,永远输出不了"Pass 2b"行。

相关代码如下:

HRESULT ofxMMF::SetSourceReader(IMFActivate * device) {
    HRESULT hr = S_OK;

    IMFMediaSource * source = NULL;
    IMFAttributes * attributes = NULL;
    std::cout << "Pass 2a" << std::endl;

    EnterCriticalSection(&criticalSection);
    std::cout << "Pass 2b" << std::endl;
    hr = device -> ActivateObject(__uuidof(IMFMediaSource), (void **)&source);
    
    //get symbolic link for the device
    if (SUCCEEDED(hr))
        hr = device ->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &wSymbolicLink, &cchSymbolicLink);
    //Allocate attributes
    if (SUCCEEDED(hr))
        hr = MFCreateAttributes(&attributes, 2);
    //get attributes
    if (SUCCEEDED(hr))
        hr = attributes -> SetUINT32(MF_READWRITE_DISABLE_CONVERTERS, TRUE);
    // Set the callback pointer.
    if (SUCCEEDED(hr))
        hr = attributes -> SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, this);
    //Create the source reader
    if (SUCCEEDED(hr))
        hr = MFCreateSourceReaderFromMediaSource(source, attributes, &sourceReader);
        EnumerateCaptureFormats(source);

    bool foundCorrectMediaType = false;

    // Try to find a suitable output type.
    if (SUCCEEDED(hr)) {
        HRESULT nativeTypeErrorCode = S_OK;
        DWORD count = 0;
        UINT32 streamIndex = 0;
        //2688 x 1512
        UINT32 requiredWidth = reqW;
        UINT32 requiredheight = reqH;

        

        while (nativeTypeErrorCode == S_OK) {
            IMFMediaType * nativeType = NULL;
            nativeTypeErrorCode = sourceReader->GetNativeMediaType(streamIndex, count, &nativeType);
            if (nativeTypeErrorCode != S_OK) continue;

            GUID nativeGuid = { 0 };
            hr = nativeType->GetGUID(MF_MT_SUBTYPE, &nativeGuid);

            if (FAILED(hr)) return hr;

            UINT32 cwidth, cheight;
            hr = MFGetAttributeSize(nativeType, MF_MT_FRAME_SIZE, &cwidth, &cheight);
            if (FAILED(hr)) return hr;

            UINT32 yuv_video_matrix = 0;
            yuv_video_matrix = MFGetAttributeUINT32(nativeType, MF_MT_YUV_MATRIX, yuv_video_matrix);

            UINT32 sample_size = 0;
            sample_size = MFGetAttributeUINT32(nativeType, MF_MT_SAMPLE_SIZE, sample_size);

            UINT32 curstride = 0;
            curstride = MFGetAttributeUINT32(nativeType, MF_MT_DEFAULT_STRIDE, curstride);

            GUID subtype = GUID_NULL;
            LONG tempStride = 0;
            nativeType->GetGUID(MF_MT_SUBTYPE, &subtype);
            MFGetStrideForBitmapInfoHeader(subtype.Data1, cwidth, &tempStride);
            
            WCHAR * pGuidValName;
            hr = GetGUIDName(nativeGuid, &pGuidValName);
            
            
            std::cout << count << ":  " << ConvertWCharToString(pGuidValName) << "\t" << cwidth << " x " << cheight << " : yuv_decode: " << yuv_video_matrix << " : sample size: " << sample_size << ": stride: " << curstride << ": tmpstride: " << tempStride << std::endl;

            if (nativeGuid == MFVideoFormat_NV12 && cwidth == requiredWidth && cheight == requiredheight) {
                // found native config, set it

                hr = IsMediaTypeSupported(nativeType);
                if (FAILED(hr)) {
                    std::cout << "Media type is not supported" << std::endl;
                    //return hr;
                }

                hr = sourceReader->SetCurrentMediaType(streamIndex, NULL, nativeType);
                if (FAILED(hr)) {
                    std::cout << "Failed to set Media type" << std::endl;
                    //return hr;
                }

                MFGetAttributeSize(nativeType, MF_MT_FRAME_SIZE, &width, &height);
                
                foundCorrectMediaType = true;
                break;
            }

            
            count++;
        }

    }

    if (!foundCorrectMediaType) {
        hr = E_FAIL;
        std::cout << "Cant find appropriate mediatype,exiting" << std::endl;
    }

    if (SUCCEEDED(hr)) {
        // Ask for the first sample.
        hr = sourceReader -> ReadSample((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL);
    }

    if (FAILED(hr)) {
        if (source) {
            source -> Shutdown();
        }
        //Close();
    }
    if (source) {
        source -> Release();
        source = NULL;
    }
    if (attributes) {
        attributes -> Release();
        attributes = NULL;
    }
    

    LeaveCriticalSection(&criticalSection);
    return hr;
}

链接器通过以下指令引入库:

#pragma comment(lib, "Mfplat.lib")
#pragma comment(lib, "Mf.lib")
#pragma comment(lib, "Mfreadwrite.lib")
#pragma comment(lib, "mfuuid.lib")
#pragma comment(lib, "shlwapi.lib")

如果这在Release中不合适,我本以为会出现链接错误。


排查思路
  • 检查临界区初始化:Release模式下,criticalSection是否正确调用InitializeCriticalSection或InitializeCriticalSectionAndSpinCount完成初始化?Debug模式下编译器可能自动初始化全局临界区,但Release模式不会,未初始化的临界区调用EnterCriticalSection会直接导致死锁或冻结。
  • 排查死锁场景:确认是否有其他线程已持有该临界区,且在等待当前线程释放资源。比如MF_SOURCE_READER_ASYNC_CALLBACK回调函数中是否也尝试进入同一个临界区?Media Source Reader的回调在后台线程执行,若回调里调用EnterCriticalSection,而主线程进入临界区后调用ReadSample触发回调,就会形成死锁。
  • 检查Release优化导致的变量异常:确认criticalSection的存储类型,若为局部变量或类成员变量,排查是否被编译器优化后内存地址异常,或类实例在Release模式下被提前释放、内存被覆盖。
  • 排除输出缓冲干扰:std::cout在Release模式下默认是缓冲输出,"Pass 2b"可能已写入缓冲区但未刷新到控制台。可以在输出后添加std::cout.flush();,确认是否真的未执行到该行,排除假冻结情况。
  • 核对Media Foundation初始化:Debug和Release模式下,是否都正确调用了MFStartup?MFStartup必须在使用任何MF接口前调用,且两种模式的初始化参数需一致,否则Release模式下可能出现隐性错误。
  • 验证指针有效性:检查device指针在Release模式下是否有效,是否存在Debug模式下合法但Release下被优化为野指针的情况,比如传入的IMFActivate*是否在调用前已被释放。
  • 检查异常处理设置:Release模式下是否禁用了异常捕获,导致隐性异常触发后程序进入无响应状态?可在VS项目属性中开启C异常捕获(路径:C/C->代码生成->启用C++异常),排查是否存在未处理的异常。
  • 修复代码结构问题:注意到EnumerateCaptureFormats(source);一行未被大括号包裹,无论MFCreateSourceReaderFromMediaSource是否成功都会执行。若source为NULL(比如ActivateObject失败),调用该函数会导致访问违规,在Release模式下可能表现为冻结而非崩溃,需将该行放入if块内。

内容的提问来源于stack exchange,提问作者Epoxy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 08:13:12