【问题标题】:DirectShow: Video-Preview and Image (with working code)DirectShow:视频预览和图像(带有工作代码)
【发布时间】:2011-01-23 05:37:32
【问题描述】:

问题/问题

  • 如果有人可以向我推荐一个好的免费托管网站,我可以提供整个项目文件。
  • 如下文所述,TakePicture() 方法在 HTC HD 2 设备上无法正常工作。如果有人可以查看下面的代码并告诉我我在做什么是对还是错,那就太好了。

简介

我最近向question 询问了有关使用 DirectShow 显示视频预览、拍摄相机图像和旋转视频流的问题。关于这个主题的棘手之处在于,很难找到好的示例,文档和框架本身对于 Windows 编程和一般 C++ 的新手来说很难理解。

尽管如此,我还是设法创建了一个类来实现大部分这些功能,并且可能适用于大多数移动设备。可能是因为 DirectShow 的实现很大程度上取决于设备本身。我只能用HTC HD和HTC HD2来测试它,它们被称为非常不兼容。

宏达高清

  • 工作:视频预览,将照片写入文件
  • 不工作:设置视频分辨率 (CRASH),设置照片分辨率(低质量)

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::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 对象的其他方法:

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);
}

完整的头文件:

#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

【问题讨论】:

    标签: c++ windows-mobile video-streaming directshow


    【解决方案1】:

    很遗憾,由于法律原因,我无法在此处分享解决方案。

    不过,我可以告诉您,无需使用 HTC HD 特定库,就可以在 HTC HD 2 上捕获具有全分辨率支持的视频和图像。

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

    【讨论】:

      【解决方案2】:

      我最近使用这样的方法遇到了一个问题,快照第一次可以工作,但第二次失败了。问题与您的问题相似,设置分辨率会导致 FindPin 失败,但它只是第二次出现。

      解决方法是在 SetResolution 结束时释放配置对象!

      config->Release();
      

      之后,它每次都有效。

      【讨论】:

        猜你喜欢
        • 2012-06-04
        • 2011-11-24
        • 2020-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多