2010-03-03 89 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(); 

之后,它每次都有效。