10

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

我有一个 Microsoft LifeCam Cinema 摄像机,我使用 .NET DirectShowLib 来捕获视频流。好吧,实际上我使用的是 WPFMediaKit,但我现在在直接处理直接显示库的源代码中。

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

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

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

在 WPFMediaKit 中,我更改了一个功能,因为显然使用 Microsoft 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.Asf,它会变为 320x240 并且输出是相同的。

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

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

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

2 回答 2

13

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

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

  2. 转到文件夹 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;
    }
    

现在,只要您的相机支持它,它将以您想要的任何所需分辨率整理您的屏幕显示。

接下来,您很快就会发现,在将视频写入磁盘时,您没有应用这个新的正确捕获。

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

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

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

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

因此,您有 2 个选择

  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;
    }
    
  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 文件。是的,我知道我放入的代码相当杂乱,但我会留给你来完善它。

于 2011-11-22T06:12:59.363 回答
2

Lifecam 以设置捕获格式(更具体地说,回退到其他格式)的不明显行为而闻名。请参阅之前的讨论,这些讨论可能会为您提供解决方案:

于 2011-11-21T18:07:27.460 回答