尽管改变了分辨率,但视频捕获输出始终为320x240

Ada*_*ley 10 c# directshow directshow.net

好的,我已经在这2天了,需要最后一部分的帮助.

我有一台Microsoft LifeCam Cinema相机,我使用.NET DirectShowLib来捕获视频流.实际上我使用WPFMediaKit,但我现在直接处理直接显示库的源代码.

我的工作是: - 查看摄像机的视频输出 - 以ASF或AVI记录摄像机的视频输出(ICaptureGraphBuilder2支持的唯一2个MediaType)

问题是:我可以将其保存为.avi.这工作正常,分辨率为1280x720,但它将文件保存在RAW输出中.这意味着它大约是每秒50-60MB.方式太高了.

或者我可以将其切换为.asf并输出WMV,但是当我这样做时,捕获和输出都转到分辨率320x240.

在WPFMediaKit中有一个我改变的功能,因为很明显有微软LifeCam Cinema相机很多人都有这个问题.因此,不是创建或更改您迭代的AMMediaType,而是使用它来调用SetFormat.

        ///* Make the VIDEOINFOHEADER 'readable' */
        var videoInfo = new VideoInfoHeader();

        int iCount = 0, iSize = 0;
        videoStreamConfig.GetNumberOfCapabilities(out iCount, out iSize);

        IntPtr TaskMemPointer = Marshal.AllocCoTaskMem(iSize);


        AMMediaType pmtConfig = null;
        for (int iFormat = 0; iFormat < iCount; iFormat++)
        {
            IntPtr ptr = IntPtr.Zero;

            videoStreamConfig.GetStreamCaps(iFormat, out pmtConfig, TaskMemPointer);

            videoInfo = (VideoInfoHeader)Marshal.PtrToStructure(pmtConfig.formatPtr, typeof(VideoInfoHeader));

            if (videoInfo.BmiHeader.Width == DesiredWidth && videoInfo.BmiHeader.Height == DesiredHeight)
            {

                ///* Setup the VIDEOINFOHEADER with the parameters we want */
                videoInfo.AvgTimePerFrame = DSHOW_ONE_SECOND_UNIT / FPS;

                if (mediaSubType != Guid.Empty)
                {
                    int fourCC = 0;
                    byte[] b = mediaSubType.ToByteArray();
                    fourCC = b[0];
                    fourCC |= b[1] << 8;
                    fourCC |= b[2] << 16;
                    fourCC |= b[3] << 24;

                    videoInfo.BmiHeader.Compression = fourCC;
                   // pmtConfig.subType = mediaSubType;

                }

                /* Copy the data back to unmanaged memory */
                Marshal.StructureToPtr(videoInfo, pmtConfig.formatPtr, true);

                hr = videoStreamConfig.SetFormat(pmtConfig);
                break;
            }

        }

        /* Free memory */
        Marshal.FreeCoTaskMem(TaskMemPointer);
        DsUtils.FreeAMMediaType(pmtConfig);

        if (hr < 0)
            return false;

        return true;
Run Code Online (Sandbox Code Playgroud)

实现后,只要我将SetOutputFilename设置为MediaType.Avi,我就可以最终将捕获的视频视为1280x720.

如果我将它设置为MediaType.如果它转到320x240并且输出相同.

或者AVI以正确的格式工作和输出,但在RAW视频中这样做,因此文件非常大.我试图在图表中添加压缩器,但没有运气,这远远超出了我的经验.

我正在寻找2个答案中的1个.

  1. 以1280x720录制ASF
  2. 将压缩器添加到图形中,以便输出的AVI的文件大小.

Ada*_*ley 13

我想通了.因此,我在这里发布任何其他可怜的灵魂,并想知道为什么它不起作用.

  1. 下载WPFMediaKit的源代码,您将需要更改一些代码.

  2. 转到Folder DirectShow> MediaPlayers并打开VideoCapturePlayer.cs

  3. 找到函数SetVideoCaptureParameters并将其替换为:

    /// <summary>
    /// Sets the capture parameters for the video capture device
    /// </summary>
    private bool SetVideoCaptureParameters(ICaptureGraphBuilder2 capGraph, IBaseFilter captureFilter, Guid mediaSubType)
    {
        /* The stream config interface */
        object streamConfig;
    
        /* Get the stream's configuration interface */
        int hr = capGraph.FindInterface(PinCategory.Capture,
                                        MediaType.Video,
                                        captureFilter,
                                        typeof(IAMStreamConfig).GUID,
                                        out streamConfig);
    
        DsError.ThrowExceptionForHR(hr);
    
        var videoStreamConfig = streamConfig as IAMStreamConfig;
    
        /* If QueryInterface fails... */
        if (videoStreamConfig == null)
        {
            throw new Exception("Failed to get IAMStreamConfig");
        }
    
        ///* Make the VIDEOINFOHEADER 'readable' */
        var videoInfo = new VideoInfoHeader();
    
        int iCount = 0, iSize = 0;
        videoStreamConfig.GetNumberOfCapabilities(out iCount, out iSize);
    
        IntPtr TaskMemPointer = Marshal.AllocCoTaskMem(iSize);
    
    
        AMMediaType pmtConfig = null;
        for (int iFormat = 0; iFormat < iCount; iFormat++)
        {
            IntPtr ptr = IntPtr.Zero;
    
            videoStreamConfig.GetStreamCaps(iFormat, out pmtConfig, TaskMemPointer);
    
            videoInfo = (VideoInfoHeader)Marshal.PtrToStructure(pmtConfig.formatPtr, typeof(VideoInfoHeader));
    
            if (videoInfo.BmiHeader.Width == DesiredWidth && videoInfo.BmiHeader.Height == DesiredHeight)
            {
    
                ///* Setup the VIDEOINFOHEADER with the parameters we want */
                videoInfo.AvgTimePerFrame = DSHOW_ONE_SECOND_UNIT / FPS;
    
                if (mediaSubType != Guid.Empty)
                {
                    int fourCC = 0;
                    byte[] b = mediaSubType.ToByteArray();
                    fourCC = b[0];
                    fourCC |= b[1] << 8;
                    fourCC |= b[2] << 16;
                    fourCC |= b[3] << 24;
    
                    videoInfo.BmiHeader.Compression = fourCC;
                   // pmtConfig.subType = mediaSubType;
    
                }
    
                /* Copy the data back to unmanaged memory */
                Marshal.StructureToPtr(videoInfo, pmtConfig.formatPtr, true);
    
                hr = videoStreamConfig.SetFormat(pmtConfig);
                break;
            }
    
        }
    
        /* Free memory */
        Marshal.FreeCoTaskMem(TaskMemPointer);
        DsUtils.FreeAMMediaType(pmtConfig);
    
        if (hr < 0)
            return false;
    
        return true;
    }
    
    Run Code Online (Sandbox Code Playgroud)

现在,只要您的相机支持,您就可以按照您想要的分辨率对屏幕显示进行分类.

接下来,您很快就会发现,在将视频写入磁盘时,您所应用的这种新的正确捕获功能并未应用.

由于ICaptureBuilder2方法仅支持Avi和Asf(即wmv),因此您需要将mediatype设置为其中一个.

hr = graphBuilder.SetOutputFileName(MediaSubType.Asf, this.m_fileName, out mux, out sink);
Run Code Online (Sandbox Code Playgroud)

您将在SetupGraph函数中找到该行.

ASF将只在320×240的输出,然而阿维将在期望的分辨率输出,但是未压缩的(意思是每秒50-60MB为1280×720的视频馈送),这是太高了.

所以这给你留下了两个选择

  1. 了解如何将编码器(压缩过滤器)添加到Avi输出

  2. 弄清楚如何更改WMV配置文件

我试过1,没有成功.主要是因为这是我第一次使用DirectShow并且只是掌握了图形的含义.

但我在#2中取得了成功,这就是我的表现.

特别感谢(http://www.codeproject.com/KB/audio-video/videosav.aspx)我从这里提取了所需的代码.

  1. 在名为WMLib.cs的同一文件夹中创建一个新类,并将以下内容放入其中

从下载演示项目http://www.codeproject.com/KB/audio-video/videosav.aspx,复制和粘贴WMLib.cs到您的项目(如需要更改命名空间)

  1. 在VideoCapturePlayer.cs类中创建一个函数

    /// <summary>
    /// Configure profile from file to Asf file writer
    /// </summary>
    /// <param name="asfWriter"></param>
    /// <param name="filename"></param>
    /// <returns></returns>
    public bool ConfigProfileFromFile(IBaseFilter asfWriter, string filename)
    {
        int hr;
        //string profilePath = "test.prx";
        // Set the profile to be used for conversion
        if ((filename != null) && (File.Exists(filename)))
        {
            // Load the profile XML contents
            string profileData;
            using (StreamReader reader = new StreamReader(File.OpenRead(filename)))
            {
                profileData = reader.ReadToEnd();
            }
    
            // Create an appropriate IWMProfile from the data
            // Open the profile manager
            IWMProfileManager profileManager;
            IWMProfile wmProfile = null;
            hr = WMLib.WMCreateProfileManager(out profileManager);
            if (hr >= 0)
            {
                // error message: The profile is invalid (0xC00D0BC6)
                // E.g. no <prx> tags
                hr = profileManager.LoadProfileByData(profileData, out wmProfile);
            }
    
            if (profileManager != null)
            {
                Marshal.ReleaseComObject(profileManager);
                profileManager = null;
            }
    
            // Config only if there is a profile retrieved
            if (hr >= 0)
            {
                // Set the profile on the writer
                IConfigAsfWriter configWriter = (IConfigAsfWriter)asfWriter;
                hr = configWriter.ConfigureFilterUsingProfile(wmProfile);
                if (hr >= 0)
                {
                    return true;
                }
            }
        }
        return false;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在SetupGraph函数中找到SetOutputFileName并在其下面放置

    ConfigProfileFromFile(mux,"c:\ wmv.prx");

  3. 现在在c:驱动器上创建一个名为wmv.prx的文件,并在其中放置相关信息.

你可以看到从演示项目这里PRX文件的样本:http://www.codeproject.com/KB/audio-video/videosav.aspx(Pal90.prx)

现在享受以正确尺寸输出的.wmv文件.是的,我知道我放入的代码非常糟糕但是我会留给你去修饰它.

  • 非常感谢您花时间发布您的解决方案.不得不使用prx配置文件解决方法.令人惊讶的是,在.NET中对视频捕获的支持是多么糟糕. (3认同)