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

时间:2011-11-21 14:41:52

标签: 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;

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

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

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

我正在寻找2个答案之一。

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

2 个答案:

答案 0 :(得分:13)

我想出来了。所以我在这里张贴任何其他可怜的灵魂,想知道为什么它不起作用。

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

  2. 转到Folder DirectShow&gt; 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;
    }
    
  4. 现在,只要您的相机支持,您就可以按照您想要的分辨率对屏幕显示进行分类。

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

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

    hr = graphBuilder.SetOutputFileName(MediaSubType.Asf, this.m_fileName, out mux, out sink);
    

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

    Asf仅输出320x240,但Avi将以所需的分辨率输出,但未压缩(意味着1280x720视频输入每秒50-60MB),这太高了。

    因此,您可以选择2个选项

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

    2. 了解如何更改WMV配置文件

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

      但是我在#2中取得了成功,我就是这样做的。

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

      1. 在名为WMLib.cs的同一文件夹中创建一个新类,并将以下内容放入其中
      2. 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;
          }
          
        2. 在SetupGraph函数中找到SetOutputFileName并在其下面放置

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

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

        4. 您可以在此处查看演示项目中PRX文件的示例:http://www.codeproject.com/KB/audio-video/videosav.aspx(Pal90.prx)

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

答案 1 :(得分:2)

Lifecam以设置捕获格式(更具体地说,回归到其他格式)的不明显行为而闻名。请参阅可能建议您解决方案的prevoius讨论: