Windows Media Foundation 请求无效,因为已调用 Shutdown()

问题描述 投票:0回答:1

我有一个类存储所有网络摄像头设备的数据以及它是否处于活动状态。初始化后。我从 IMFSourceReader 获取媒体类型,然后我不想让它保持活动状态,所以我关闭了 IMFMediaSource。然而,当我尝试重新激活它时,尽管创建了 IMFMediaSource 类型的新对象,但我得到了

request is invalid because Shutdown() has been called.

Webcam::Webcam(IMFActivate *device, IMFAttributes *config) : device_(device), active_device_(nullptr), source_reader_(nullptr), active_(false), media_types_(), config_(config) {
    ...

    hr = this->device_->ActivateObject(IID_PPV_ARGS(&this->active_device_));

    if (SUCCEEDED(hr)) {
        this->active_device_->AddRef();
        hr = MFCreateSourceReaderFromMediaSource(this->active_device_, this->config_, &this->source_reader_);
    }

    if (SUCCEEDED(hr)) {
        this->source_reader_->AddRef();
        uint32_t index = 0;
        IMFMediaType *media_type = nullptr;
        while (SUCCEEDED(source_reader_->GetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, index, &media_type))) {
           ... // FIll the media types vector
        }
        std::sort(this->media_types_.begin(), this->media_types_.end(), [](IMFMediaType *a, IMFMediaType *b) {
              ... // Sorting Algorythm that puts higher resolutions an MJPEG encoding on top
            });

    }
    if (this->active_device_) {
        this->active_device_->Shutdown();
        this->active_device_->Release();
        this->active_device_ = nullptr;
    }
    if (this->source_reader_) {
        this->source_reader_->Release();
        this->source_reader_ = nullptr;
    }

}

HRESULT Webcam::activate() {
    HRESULT hr = S_OK;

    if (this->device_ && !this->active_device_) {
        hr = this->device_->ActivateObject(IID_PPV_ARGS(&this->active_device_));
    }

    if (SUCCEEDED(hr)) {
        this->active_device_->AddRef();
        hr = MFCreateSourceReaderFromMediaSource(this->active_device_, this->config_, &this->source_reader_);
    }

    if (SUCCEEDED(hr)) {
        this->source_reader_->AddRef();
        hr = this->source_reader_->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, this->media_types_[0]);
        this->active_ = true;
    }

    if (FAILED(hr)) {
        // cleanup of source_reader_ and active_device_
        error(hr, L"unable to activate webcam " + this->name_);
    }
    else {
        std::wcout << L"Activation succesfull " + this->name_ << std::endl;
    }

    return hr;
}

我发现的唯一方法是在ActivateObject之前使用(IMFActivate)

device_->ShutdownObject()
,这在尝试执行
ActivateObject
时应该会导致相同的错误,因为现在IMFActivate处于关闭状态,但不知何故它工作得很好,我不明白吗文档,如何以正确的方式完成。


编辑:我还要求 GPT 给我写一些类似的内容,他的版本有效,我不明白有什么区别


class MediaSourceManager {
public:
    MediaSourceManager(IMFActivate *pActivator)
        : m_pActivator(pActivator), m_pMediaSource(nullptr) {
        if (m_pActivator)
            m_pActivator->AddRef();
    }

    ~MediaSourceManager() {
        ShutdownMediaSource();
        if (m_pActivator)
            m_pActivator->Release();
    }

    HRESULT CreateMediaSource() {
        ShutdownMediaSource();

        if (m_pActivator) {
            HRESULT hr = m_pActivator->ActivateObject(__uuidof(IMFMediaSource), reinterpret_cast<void **>(&m_pMediaSource));
            return hr;
        }
        return E_UNEXPECTED;
    }

    void ShutdownMediaSource() {
        if (m_pMediaSource) {
            m_pMediaSource->Shutdown();
            m_pMediaSource->Release();
            m_pMediaSource = nullptr;
        }
    }

private:
    IMFActivate *m_pActivator;
    IMFMediaSource *m_pMediaSource;
};

HRESULT GetFirstVideoCaptureDevice(IMFActivate **ppActivate) {
    IMFAttributes *pAttributes = nullptr;
    IMFActivate **ppDevices = nullptr;
    UINT32 count = 0;
    HRESULT hr = MFCreateAttributes(&pAttributes, 1);
    if (SUCCEEDED(hr)) {
        hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
        if (SUCCEEDED(hr)) {
            hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
            if (SUCCEEDED(hr) && count > 0) {
                // Get the first available video capture device
                *ppActivate = ppDevices[0];
                (*ppActivate)->AddRef();

                // Release all other devices
                for (UINT32 i = 1; i < count; ++i) {
                    ppDevices[i]->Release();
                }
            }
            else {
                hr = E_FAIL; // No devices found or failed to enumerate devices
            }
            CoTaskMemFree(ppDevices);
        }
        pAttributes->Release();
    }
    return hr;
}

int main() {
    HRESULT hr = InitializeMediaFoundation();
    if (FAILED(hr)) {
        return 1;
    }

    IMFActivate *pActivator = nullptr;
    hr = GetFirstVideoCaptureDevice(&pActivator);
    if (SUCCEEDED(hr)) {
        std::cout << "Video capture device obtained successfully." << std::endl;

        // Example usage of MediaSourceManager
        MediaSourceManager manager(pActivator);

        hr = manager.CreateMediaSource();
        if (SUCCEEDED(hr)) {
            std::cout << "Media source created successfully." << std::endl;
        }

        // Use the media source as needed, then shut it down
        manager.ShutdownMediaSource();

        // Recreate the media source when needed
        hr = manager.CreateMediaSource();
        if (SUCCEEDED(hr)) {
            std::cout << "Media source recreated successfully." << std::endl;
        }

        pActivator->Release();
    }
    else {
        std::cerr << "Failed to obtain a video capture device." << std::endl;
    }

    ShutdownMediaFoundation();
    return 0;
}
c++ windows winapi webcam
1个回答
0
投票

好吧,答案不是我所期望的,基本上,尽管

IMFSourceReader
IMFAttributes
Release
d、
Shutdowne
d 和
nullptr
d,仍然保存在 COM 对象中的某个位置,无法访问用户,每当您在
ActivateObject
上调用
IMFActivate
时,您都会收到相同的对象,即使您调用
Shutdown
也不会重置,您必须调用
ShutdownObject
来告诉系统创建另一个对象,而不是已经损坏的对象一个你无论如何都已经摧毁的东西。但直到 ShutdownObject 或 DetachObject 被调用之前,你就可以开始兜风了


在一个完全不相关的笔记上。伙计,我怀念能够看到函数做什么、结构中有哪些数据,希望有一种方法至少可以从 mfplat.pdb 中看到一些东西

© www.soinside.com 2019 - 2024. All rights reserved.