如何从网络源获取事件

源解析程序使应用程序能够创建网络源并打开与特定 URL 的连接。 网络源引发事件以标记打开连接的异步操作的开始和结束。 应用程序可以使用 IMFSourceOpenMonitor 接口注册这些事件。

此接口公开网络源在异步打开 URL 时直接调用的 IMFSourceOpenMonitor::OnSourceEvent 方法。 网络源通过引发 MEConnectStart 事件在应用程序开始打开 URL 时通知应用程序。 然后,网络源在完成打开操作时引发 MEConnectEnd 事件。

注意

若要将这些事件发送到应用程序,网络源不使用 IMFMediaEventGenerator 接口,因为这些事件是在创建网络源之前引发的。 应用程序可以使用媒体会话的 IMFMediaEventGenerator 接口获取所有其他网络源事件。

 

从网络源获取事件

  1. 实现 IMFSourceOpenMonitor 接口。 在 IMFSourceOpenMonitor::OnSourceEvent 方法的实现中,执行以下操作:
    1. 通过调用 IMFMediaEvent::GetStatus 获取事件状态。 此方法指示触发事件的操作(如源解析程序方法调用)是否成功。 如果操作不成功,则状态为失败代码。
    2. 根据事件类型 MEConnectStartMEConnectEnd 处理事件,应用程序可以通过调用 IMFMediaEvent::GetType 获取该类型。
  2. 在属性存储对象中配置键值对,以存储指向步骤 1 中所述的 IMFSourceOpenMonitor 实现的指针。
    1. 通过调用 PSCreateMemoryPropertyStore 函数创建属性存储对象。
    2. PROPERTYKEY 结构中设置 MFPKEY_SourceOpenMonitor 属性。
    3. 通过将 IUnknown 指针设置为应用程序实现的 IMFSourceOpenMonitor 接口,在 PROPVARIANT 结构中提供VT_UNKNOWN类型数据值。
    4. 通过调用 IPropertyStore::SetValue 在属性存储中设置键值对。
  3. 将属性存储指针传递给应用程序用于创建网络源的源解析程序方法,例如 IMFSourceResolver::CreateObjectFromURL 等。

示例

以下示例演示如何实现 IMFSourceOpenMonitor 接口以从网络源获取事件。

class CSourceOpenMonitor : public IMFSourceOpenMonitor
{
public:
    CSourceOpenMonitor () : m_cRef(1) { }

    STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
    {
        static const QITAB qit[] = 
        {
            QITABENT(CSourceOpenMonitor, IMFSourceOpenMonitor),
            { 0 }
        };
        return QISearch(this, qit, riid, ppv);
    }

    STDMETHODIMP_(ULONG) AddRef()
    {
        return InterlockedIncrement(&m_cRef);
    }

    STDMETHODIMP_(ULONG) Release()
    {
        LONG cRef = InterlockedDecrement(&m_cRef);
        if (cRef == 0)
        {
            delete this;
        }
        // For thread safety, return a temporary variable.
        return cRef;
    }


    STDMETHODIMP OnSourceEvent(IMFMediaEvent* pEvent)
    {
        MediaEventType eventType = MEUnknown;   // Event type
        HRESULT hrStatus = S_OK;                // Event status

        // Get the event type.
        HRESULT hr = pEvent->GetType(&eventType);

        // Get the event status. If the operation that triggered the event
        // did not succeed, the status is a failure code.
        if (SUCCEEDED(hr))
        {
            hr = pEvent->GetStatus(&hrStatus);
        }

        if (FAILED(hrStatus))
        {
            hr = hrStatus;
        }

        if (SUCCEEDED(hr))
        {
            // Switch on the event type.
            switch(eventType)
            {
                case MEConnectStart:
                    // The application does something. (Not shown.)
                    OutputDebugString(L"Connecting...\n");
                    break;

                case MEConnectEnd:
                    // The application does something. (Not shown.)
                    OutputDebugString(L"Connect End.\n");
                    break;
            }
        }
        else
        {
            // Event failed.
            // The application handled a failure. (Not shown.)
        }
        return S_OK;
    }
private:
    long    m_cRef;
};

以下示例演示如何在打开 URL 时在网络源上设置 MFPKEY_SourceOpenMonitor 属性:

HRESULT CreateMediaSourceWithSourceOpenMonitor(
    PCWSTR pszURL, 
    IMFMediaSource **ppSource
    )
{
    IPropertyStore *pConfig = NULL;

    CSourceOpenMonitor *pMonitor = new (std::nothrow) CSourceOpenMonitor();

    if (pMonitor == NULL)
    {
        return E_OUTOFMEMORY;
    }

    // Configure the property store.
    HRESULT hr = PSCreateMemoryPropertyStore(IID_PPV_ARGS(&pConfig));

    if (SUCCEEDED(hr))
    {
        PROPVARIANT var;
        var.vt = VT_UNKNOWN;
        pMonitor->QueryInterface(IID_PPV_ARGS(&var.punkVal));

        hr = pConfig->SetValue(MFPKEY_SourceOpenMonitor, var);

        PropVariantClear(&var);
    }

    // Create the source media source.
    if (SUCCEEDED(hr))
    {
        hr = CreateMediaSource(pszURL, pConfig, ppSource);
    }

    SafeRelease(&pConfig);
    SafeRelease(&pMonitor);

    return hr;
}

媒体基础中的网络