2016-06-23 76 views
0

私はMicrosoft Media Foundationを使用して書き込み中のビデオ録画アプリケーションに問題があります。は、同期モードでIMFSourceから読み込みできません

具体的には、(私はそれ自身のスレッドに住んでループ上に置く)の読み取り/書き込み機能は、それがReadSampleに電話を渡すことはありません。

HRESULT WinCapture::rwFunction(void) { 

    HRESULT hr; 
    DWORD streamIndex, flags; 
    LONGLONG llTimeStamp; 
    IMFSample *pSample = NULL; 

    EnterCriticalSection(&m_critsec); 
    // Read another sample. 
    hr = m_pReader->ReadSample(
     (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 
     0, 
     &streamIndex, // actual 
     &flags,//NULL, // flags 
     &llTimeStamp,//NULL, // timestamp 
     &pSample // sample 
     ); 

    if (FAILED(hr)) { goto done; } 

    hr = m_pWriter->WriteSample(0, pSample); 

    goto done; 

done: 
    return hr; 
    SafeRelease(&pSample); 
    LeaveCriticalSection(&m_critsec); 
} 

時間の値は例外ですコード:0xc00d3704のコードスニペットはWriteSampleへの呼び出しをスキップします。

多くの手順がありますが、m_pReader(タイプIMFSource *)を正しく設定していることは確かです。

HRESULT WinCapture::OpenMediaSource(IMFMediaSource *pSource) 
{ 
    HRESULT hr = S_OK; 

    IMFAttributes *pAttributes = NULL; 

    hr = MFCreateAttributes(&pAttributes, 2); 


    // use a callback 
    //if (SUCCEEDED(hr)) 
    //{ 
    // hr = pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, this); 
    //} 

    // set the desired format type 
    DWORD dwFormatIndex = (DWORD)formatIdx; 

    IMFPresentationDescriptor *pPD = NULL; 
    IMFStreamDescriptor *pSD = NULL; 
    IMFMediaTypeHandler *pHandler = NULL; 
    IMFMediaType *pType = NULL; 

    // create the source reader 
    if (SUCCEEDED(hr)) 
    { 
     hr = MFCreateSourceReaderFromMediaSource(
      pSource, 
      pAttributes, 
      &m_pReader 
      ); 
    } 

    // steps to set the selected format type 
    hr = pSource->CreatePresentationDescriptor(&pPD); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 

    BOOL fSelected; 
    hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 

    hr = pSD->GetMediaTypeHandler(&pHandler); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 

    hr = pHandler->GetMediaTypeByIndex(dwFormatIndex, &pType); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 

    hr = pHandler->SetCurrentMediaType(pType); 
    { 
     goto done; 
    } 

    hr = m_pReader->SetCurrentMediaType(
     (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 
     NULL, 
     pType 
     ); 

    // set to maximum framerate? 
    hr = pHandler->GetCurrentMediaType(&pType); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 

    // Get the maximum frame rate for the selected capture format. 

    // Note: To get the minimum frame rate, use the 
    // MF_MT_FRAME_RATE_RANGE_MIN attribute instead. 

    PROPVARIANT var; 
    if (SUCCEEDED(pType->GetItem(MF_MT_FRAME_RATE_RANGE_MAX, &var))) 
    { 
     hr = pType->SetItem(MF_MT_FRAME_RATE, var); 

     PropVariantClear(&var); 

     if (FAILED(hr)) 
     { 
      goto done; 
     } 

     hr = pHandler->SetCurrentMediaType(pType); 
     { 
      goto done; 
     } 

     hr = m_pReader->SetCurrentMediaType(
      (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 
      NULL, 
      pType 
      ); 
    } 




    goto done; 

done: 
    SafeRelease(&pPD); 
    SafeRelease(&pSD); 
    SafeRelease(&pHandler); 
    SafeRelease(&pType); 
    SafeRelease(&pAttributes); 
    return hr; 
} 

このコードはすべて、MicrosoftのマニュアルページとSDKのサンプルコードからコピーされています。変数formatIdxは0です、私はカメラのフォーマットを列挙し、最初のものを選ぶことからそれを得ます。

UPDATE

ではなく、ブロッキングの読み取り/書き込み機能のコールバックを使用して、私は正確に同じ問題を持っているように、私はこのプログラムを書き換えています。

ここで私は、デバイスを取得し、コールバックメソッドを開始:

HRESULT WinCapture::initCapture(const WCHAR *pwszFileName, IMFMediaSource *pSource) { 

    HRESULT hr = S_OK; 

    EncodingParameters params; 
    params.subtype = MFVideoFormat_WMV3; // TODO, paramterize this 
    params.bitrate = TARGET_BIT_RATE; 
    m_llBaseTime = 0; 
    IMFMediaType *pType = NULL; 
    DWORD sink_stream = 0; 

    EnterCriticalSection(&m_critsec); 
    hr = m_ppDevices[selectedDevice]->ActivateObject(IID_PPV_ARGS(&pSource)); 
    //m_bIsCapturing = false; // this is set externally here 

    if (SUCCEEDED(hr)) 
     hr = OpenMediaSource(pSource); // also creates the reader 


    if (SUCCEEDED(hr)) 
    { 
     hr = m_pReader->GetCurrentMediaType(
      (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 
      &pType 
      ); 
    } 


    // Create the sink writer 
    if (SUCCEEDED(hr)) 
    { 
     hr = MFCreateSinkWriterFromURL(
      pwszFileName, 
      NULL, 
      NULL, 
      &m_pWriter 
      ); 
    } 

    if (SUCCEEDED(hr)) 
     hr = ConfigureEncoder(params, pType, m_pWriter, &sink_stream); 


    // kick off the recording 
    if (SUCCEEDED(hr)) 
    { 

     m_llBaseTime = 0; 
     m_bIsCapturing = TRUE; 

     hr = m_pReader->ReadSample(
      (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 
      0, 
      NULL, 
      NULL, 
      NULL, 
      NULL 
      ); 


    } 



    SafeRelease(&pType); 
    SafeRelease(&pSource); 
    pType = NULL; 
    LeaveCriticalSection(&m_critsec); 
    return hr; 
} 

OpenMediaSource方法はここにある:

ここ
HRESULT WinCapture::OpenMediaSource(IMFMediaSource *pSource) 
{ 
    HRESULT hr = S_OK; 

    IMFAttributes *pAttributes = NULL; 

    hr = MFCreateAttributes(&pAttributes, 2); 


    // use a callback 
    if (SUCCEEDED(hr)) 
    { 
     hr = pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, this); 
    } 

    // set the desired format type 
    DWORD dwFormatIndex = (DWORD)formatIdx; 

    IMFPresentationDescriptor *pPD = NULL; 
    IMFStreamDescriptor *pSD = NULL; 
    IMFMediaTypeHandler *pHandler = NULL; 
    IMFMediaType *pType = NULL; 

    // create the source reader 
    if (SUCCEEDED(hr)) 
    { 
     hr = MFCreateSourceReaderFromMediaSource(
      pSource, 
      pAttributes, 
      &m_pReader 
      ); 
    } 

    // steps to set the selected format type 
    if (SUCCEEDED(hr)) hr = pSource->CreatePresentationDescriptor(&pPD); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 

    BOOL fSelected; 
    hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 

    hr = pSD->GetMediaTypeHandler(&pHandler); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 

    hr = pHandler->GetMediaTypeByIndex(dwFormatIndex, &pType); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 

    hr = pHandler->SetCurrentMediaType(pType); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 

    // get available framerates 
    hr = MFGetAttributeRatio(pType, MF_MT_FRAME_RATE, &frameRate, &denominator); 
    std::cout << "frameRate " << frameRate << " denominator " << denominator << std::endl; 


    hr = m_pReader->SetCurrentMediaType(
     (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 
     NULL, 
     pType 
     ); 

    // set to maximum framerate? 
    hr = pHandler->GetCurrentMediaType(&pType); 
    if (FAILED(hr)) 
    { 
     goto done; 
    } 

    goto done; 

done: 
    SafeRelease(&pPD); 
    SafeRelease(&pSD); 
    SafeRelease(&pHandler); 
    SafeRelease(&pType); 
    SafeRelease(&pAttributes); 
    return hr; 
} 

formatIdxはユーザーによってセットを取得し、このクラスのフィールドですGUIを介して。私はそれをテストするために0のままにします。だから、私はカメラを動かすための足かせがないとは思っていませんが、おそらく私はそうです。

ActivateObjectを呼び出した後で、どのアプリケーションがウェブカメラ(using this method)を使用しているかを調べると、自分のアプリケーションが期待どおりにウェブカメラを使用していることがわかります。しかし、コールバックルーチンに入ると、Webカメラを使用するアプリケーションが2つあることがわかります。これはブロッキング方法を使用した場合と同じです。

それが良いか悪いかである場合、私は知らないが、私は私のコールバックメソッドを入力したとき:

HRESULT WinCapture::OnReadSample(
    HRESULT hrStatus, 
    DWORD /*dwStreamIndex*/, 
    DWORD /*dwStreamFlags*/, 
    LONGLONG llTimeStamp, 
    IMFSample *pSample  // Can be NULL 
    ) 
{ 
    EnterCriticalSection(&m_critsec); 

    if (!IsCapturing() || m_bIsCapturing == false) 
    { 
     LeaveCriticalSection(&m_critsec); 
     return S_OK; 
    } 

    HRESULT hr = S_OK; 

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

    if (pSample) 
    { 
     if (m_bFirstSample) 
     { 
      m_llBaseTime = llTimeStamp; 
      m_bFirstSample = FALSE; 
     } 

     // rebase the time stamp 
     llTimeStamp -= m_llBaseTime; 

     hr = pSample->SetSampleTime(llTimeStamp); 

     if (FAILED(hr)) { goto done; } 

     hr = m_pWriter->WriteSample(0, pSample); 

     if (FAILED(hr)) { goto done; } 
    } 

    // Read another sample. 
    hr = m_pReader->ReadSample(
     (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 
     0, 
     NULL, // actual 
     NULL, // flags 
     NULL, // timestamp 
     NULL // sample 
     ); 

done: 
    if (FAILED(hr)) 
    { 
     //NotifyError(hr); 
    } 

    LeaveCriticalSection(&m_critsec); 
    return hr; 
} 

hrStatusは私が前になっていた0x00d3704誤りがあり、コールバックは、このように殺害doneに直進コールバック

最後に、私はWindows SDKのサンプルのMFCaptureToFileサンプルからモデリングしています(読み込み、コピーしています)。ただし、失敗したHRESULTのこの奇妙な負の数があります。-1072875772。

+2

エラー[0xC00D3704]: "ハードウェアリソースが不足しているためハードウェアMFTがストリーミングを開始できませんでした" MF_E_HW_MFT_FAILED_START_STREAMINGがmferror.hで定義されています – Jeff

+0

ありがとうございました!カメラのリソースを有効にするために紛失している電話があるとしますか? QtをGUIのバックエンドとして使用しています。QCameraInfo :: availableCameras()を呼び出して使用可能なカメラの初期リストをGUIに取得しますが、それ以降は触れません。 – dmedine

+0

わかりません。キャプチャデバイス(ビデオとオーディオの両方)を列挙するためにMFEnumDeviceSourcesを使用します。それを簡単にアクティブにして、各ネイティブメディアタイプ(IMFSourceReader :: GetNativeMediaType)を取得することができます。 – Jeff

答えて

-3

エラー[0xC00D3704]がある場合は、ソースが初期化されていないことを意味します。このようなエラーは、初期化ミス、他のアプリケーション(プロセス)によるビジーカメラ、またはUVCドライバによるカメラのサポート解除によって引き起こされる可能性があります(古いカメラはDirectShowドライバをサポートし、UVCと部分的に互換性があります。しかし、古いカメラはDirectShowモデルをサポートしています.PUSHはカメラがバイトをパイプラインにプッシュし、Media Foundation PULLデータは特殊な信号と待機データを送信します。 あなたのコードをチェックするには、 "codeProject"というサイトのWebカムからビデオをキャプチャする方法についての記事を調べることをお勧めします。 - "videoInput"の名前を検索してください。

+0

私は、デバイスが正しく起動されていないことに同意します(そのコードは含まれていません)。しかし、このPUSH/PULLのすべては単に誤解を招くだけです(COMスレッディングアパートメントモデルに対するあなたのコメントと同様)。 – Jeff

関連する問題