2010-03-03 42 views
1

疑問/問題的DirectShow:視頻預覽和圖像(有工作代碼)

  • 如果有人可以推薦我一個很好的免費託管的網站,我可以提供整個項目文件。
  • 正如下面的文字所述,TakePicture()方法在HTC HD 2設備上無法正常工作。如果有人能看下面的代碼並告訴我這是對還是錯,我會這麼做。

介紹

最近,我問一個關於question顯示視頻預覽,同時相機的圖像和旋轉與DirectShow的視頻流。關於這個主題的棘手問題是,很難找到好的例子,而且對於那些對Windows編程和C++不熟悉的人來說,文檔和框架本身很難理解。

不過,我設法創建了一個實現大多數這些功能的類,並且可能適用於大多數移動設備。可能是因爲DirectShow的實現在很大程度上依賴於設備本身。我只能用HTC HD和HTC HD2來測試它,它們被稱爲非常不兼容。

HTC HD

  • 工作:視頻預覽,寫圖片文件
  • 不工作:設置視頻分辨率(崩潰),設置照片分辨率(低質量)

HTC HD 2

  • 工作:設置視頻分辨率,設置照片分辨率
  • 問題的:視頻預覽旋轉
  • 不工作:寫照片文件

通過提供工作的例子更容易爲別人,我決定分享一切我有這麼遠低於。爲了簡單起見,我刪除了所有的錯誤處理。就文檔而言,我可以推薦您閱讀MSDN documentation,之後的代碼非常簡單。

void Camera::Init() 
{ 
    CreateComObjects(); 

    _captureGraphBuilder->SetFiltergraph(_filterGraph); 

    InitializeVideoFilter(); 
    InitializeStillImageFilter(); 
} 

Dipslay視頻預覽(使用任何手持式測試工作):

void Camera::DisplayVideoPreview(HWND windowHandle) 
{ 
    IVideoWindow *_vidWin; 

    _filterGraph->QueryInterface(IID_IMediaControl,(void **) &_mediaControl); 
    _filterGraph->QueryInterface(IID_IVideoWindow, (void **) &_vidWin); 
    _videoCaptureFilter->QueryInterface(IID_IAMVideoControl, 
     (void**) &_videoControl); 

    _captureGraphBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, 
     &MEDIATYPE_Video, _videoCaptureFilter, NULL, NULL); 

    CRect rect; 
    long width, height; 

    GetClientRect(windowHandle, &rect); 

    _vidWin->put_Owner((OAHWND)windowHandle); 
    _vidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS); 

    _vidWin->get_Width(&width); 
    _vidWin->get_Height(&height); 
    height = rect.Height(); 

    _vidWin->put_Height(height); 
    _vidWin->put_Width(rect.Width()); 
    _vidWin->SetWindowPosition(0,0, rect.Width(), height); 

    _mediaControl->Run(); 
} 

HTC HD2:如果設置SetPhotoResolution()被調用FindPin將返回E_FAIL。如果不是,它將創建一個充滿空字節的文件。 HTC HD:作品

void Camera::TakePicture(WCHAR *fileName) 
{ 
    CComPtr<IFileSinkFilter> fileSink; 
    CComPtr<IPin> stillPin; 
    CComPtr<IUnknown> unknownCaptureFilter; 
    CComPtr<IAMVideoControl> videoControl; 

    _imageSinkFilter.QueryInterface(&fileSink); 
    fileSink->SetFileName(fileName, NULL); 

    _videoCaptureFilter.QueryInterface(&unknownCaptureFilter); 

    _captureGraphBuilder->FindPin(unknownCaptureFilter, PINDIR_OUTPUT, 
     &PIN_CATEGORY_STILL, &MEDIATYPE_Video, FALSE, 0, &stillPin); 

    _videoCaptureFilter.QueryInterface(&videoControl); 
    videoControl->SetMode(stillPin, VideoControlFlag_Trigger); 
} 

設置分辨率:適用於HTC HD2。HTC HD不允許SetVideoResolution(),僅提供一個低分辨率照片分辨率:

void Camera::CreateComObjects() 
{ 
    CoInitialize(NULL); 

    CoCreateInstance(CLSID_CaptureGraphBuilder, NULL, CLSCTX_INPROC_SERVER, 
     IID_ICaptureGraphBuilder2, (void **) &_captureGraphBuilder); 

    CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
     IID_IGraphBuilder, (void **) &_filterGraph); 

    CoCreateInstance(CLSID_VideoCapture, NULL, CLSCTX_INPROC, 
     IID_IBaseFilter, (void**) &_videoCaptureFilter); 

    CoCreateInstance(CLSID_IMGSinkFilter, NULL, CLSCTX_INPROC, 
     IID_IBaseFilter, (void**) &_imageSinkFilter); 
} 

void Camera::InitializeVideoFilter() 
{ 
    _videoCaptureFilter->QueryInterface(&_propertyBag); 

    wchar_t deviceName[MAX_PATH] = L"\0"; 
    GetDeviceName(deviceName); 
    CComVariant comName = deviceName; 

    CPropertyBag propertyBag; 
    propertyBag.Write(L"VCapName", &comName); 
    _propertyBag->Load(&propertyBag, NULL); 

    _filterGraph->AddFilter(_videoCaptureFilter, 
     L"Video Capture Filter Source"); 
} 

void Camera::InitializeStillImageFilter() 
{ 
    _filterGraph->AddFilter(_imageSinkFilter, L"Still image filter"); 

    _captureGraphBuilder->RenderStream(&PIN_CATEGORY_STILL, 
     &MEDIATYPE_Video, _videoCaptureFilter, NULL, _imageSinkFilter); 
} 

void Camera::GetDeviceName(WCHAR *deviceName) 
{ 
    HRESULT hr = S_OK; 
    HANDLE handle = NULL; 
    DEVMGR_DEVICE_INFORMATION di; 
    GUID guidCamera = { 0xCB998A05, 0x122C, 0x4166, 0x84, 0x6A, 0x93, 0x3E, 
     0x4D, 0x7E, 0x3C, 0x86 }; 

    di.dwSize = sizeof(di); 

    handle = FindFirstDevice(DeviceSearchByGuid, &guidCamera, &di); 
    StringCchCopy(deviceName, MAX_PATH, di.szLegacyName); 
} 

全頭文件:

void Camera::SetVideoResolution(int width, int height) 
{ 
    SetResolution(true, width, height); 
} 

void Camera::SetPhotoResolution(int width, int height) 
{ 
    SetResolution(false, width, height); 
} 


void Camera::SetResolution(bool video, int width, int height) 
{ 
    IAMStreamConfig *config; 
    config = NULL; 

    if (video) 
    { 
     _captureGraphBuilder->FindInterface(&PIN_CATEGORY_PREVIEW, 
      &MEDIATYPE_Video, _videoCaptureFilter, IID_IAMStreamConfig, 
      (void**) &config); 
    } 
    else 
    { 
     _captureGraphBuilder->FindInterface(&PIN_CATEGORY_STILL, 
      &MEDIATYPE_Video, _videoCaptureFilter, IID_IAMStreamConfig, 
      (void**) &config); 

    } 

    int resolutions, size; 
    VIDEO_STREAM_CONFIG_CAPS caps; 
    config->GetNumberOfCapabilities(&resolutions, &size); 

    for (int i = 0; i < resolutions; i++) 
    { 
     AM_MEDIA_TYPE *mediaType; 
     if (config->GetStreamCaps(i, &mediaType, 
      reinterpret_cast<BYTE*>(&caps)) == S_OK) 
     { 
      int maxWidth = caps.MaxOutputSize.cx; 
      int maxHeigth = caps.MaxOutputSize.cy; 

      if(maxWidth == width && maxHeigth == height) 
      { 
       VIDEOINFOHEADER *info = 
        reinterpret_cast<VIDEOINFOHEADER*>(mediaType->pbFormat); 

       info->bmiHeader.biWidth = maxWidth; 
       info->bmiHeader.biHeight = maxHeigth; 
       info->bmiHeader.biSizeImage = DIBSIZE(info->bmiHeader); 
       config->SetFormat(mediaType); 

       DeleteMediaType(mediaType); 
       break; 

      } 

      DeleteMediaType(mediaType); 
     } 
    } 
} 

用於構建過濾器圖表並創建COM對象的其他方法:

#ifndef __CAMERA_H__ 
#define __CAMERA_H__ 

class Camera 
{ 
    public: 
     void Init(); 
     void DisplayVideoPreview(HWND windowHandle); 
     void TakePicture(WCHAR *fileName); 
     void SetVideoResolution(int width, int height); 
     void SetPhotoResolution(int width, int height); 

    private: 
     CComPtr<ICaptureGraphBuilder2> _captureGraphBuilder; 
     CComPtr<IGraphBuilder> _filterGraph; 
     CComPtr<IBaseFilter> _videoCaptureFilter; 
     CComPtr<IPersistPropertyBag> _propertyBag; 
     CComPtr<IMediaControl> _mediaControl; 
     CComPtr<IAMVideoControl> _videoControl; 
     CComPtr<IBaseFilter> _imageSinkFilter; 

     void GetDeviceName(WCHAR *deviceName); 
     void InitializeVideoFilter(); 
     void InitializeStillImageFilter(); 
     void CreateComObjects(); 
     void SetResolution(bool video, int width, int height); 
}; 

#endif 

回答

0

不幸的是,由於法律原因,我不能在這裏分享解決方案。

不過,我可以告訴你,無需使用HTC HD專用庫,即可在HTC HD 2上以全分辨率支持進行視頻和圖像捕捉。

提示:您可能需要一個NULL渲染器。

0

我最近遇到了一個問題,使用這種方法,快照將在第一時間運行,但第二次失敗。問題與您的問題類似,在此設置分辨率會導致FindPin失敗,但只是第二次。

解決的辦法是在SetResolution結束時釋放配置對象!

config->Release(); 

之後,它每次都有效。