jjzjj

c# - 尽管更改分辨率,视频捕获输出始终为 320x240

coder 2024-06-02 原文

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

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

我的工作是: - 查看摄像机的视频输出 - 以 ASF 或 AVI 格式记录摄像机的视频输出(ICaptureGraphBuilder2 仅支持这两种 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 的文件大小很小。

最佳答案

我想通了。所以我将它张贴在这里,供任何路过的可怜人想知道为什么它不起作用。

  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),这太高了。

所以你有两个选择

  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 文件。 是的,我知道我放置的代码相当草率,但我会把它留给你来完善它。

关于c# - 尽管更改分辨率,视频捕获输出始终为 320x240,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8213574/

有关c# - 尽管更改分辨率,视频捕获输出始终为 320x240的更多相关文章

  1. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  2. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  3. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  4. [工业相机] 分辨率、精度和公差之间的关系 - 2

    📢博客主页:https://blog.csdn.net/weixin_43197380📢欢迎点赞👍收藏⭐留言📝如有错误敬请指正!📢本文由Loewen丶原创,首发于CSDN,转载注明出处🙉📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨文章预览:一.分辨率(Resolution)1、工业相机的分辨率是如何定义的?2、工业相机的分辨率是如何选择的?二.精度(Accuracy)1、像素精度(PixelAccuracy)2、定位精度和重复定位精度(RepeatPrecision)三.公差(Tolerance)四.课后作业(Post-ClassExercises)视觉行业的初学者,甚至是做了1~2年

  5. c# - C# 中的 Flatten Ruby 方法 - 2

    我如何做Ruby方法"Flatten"RubyMethod在C#中。此方法将锯齿状数组展平为一维数组。例如:s=[1,2,3]#=>[1,2,3]t=[4,5,6,[7,8]]#=>[4,5,6,[7,8]]a=[s,t,9,10]#=>[[1,2,3],[4,5,6,[7,8]],9,10]a.flatten#=>[1,2,3,4,5,6,7,8,9,10 最佳答案 递归解决方案:IEnumerableFlatten(IEnumerablearray){foreach(variteminarray){if(itemisIEnume

  6. ruby - 可以像在 C# 中使用#region 一样在 Ruby 中使用 begin/end 吗? - 2

    我最近从C#转向了Ruby,我发现自己无法制作可折叠的标记代码区域。我只是想到做这种事情应该没问题:classExamplebegin#agroupofmethodsdefmethod1..enddefmethod2..endenddefmethod3..endend...但是这样做真的可以吗?method1和method2最终与method3是同一种东西吗?还是有一些我还没有见过的用于执行此操作的Ruby惯用语? 最佳答案 正如其他人所说,这不会改变方法定义。但是,如果要标记方法组,为什么不使用Ruby语义来标记它们呢?您可以使用

  7. c# - Ruby 等效于 C# Linq 聚合方法 - 2

    什么是Linq聚合方法的ruby​​等价物。它的工作原理是这样的varfactorial=new[]{1,2,3,4,5}.Aggregate((acc,i)=>acc*i);每次将数组序列中的值传递给lambda时,变量acc都会累积。 最佳答案 这在数学以及几乎所有编程语言中通常称为折叠。它是更普遍的变形概念的一个实例。Ruby从Smalltalk中继承了这个特性的名称,它被称为inject:into:(像aCollectioninject:aStartValueinto:aBlock一样使用。)所以,在Ruby中,它称为inj

  8. c# - 先学什么? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭8年前。Improvethisquestion几年前我去学校学习编程,毕业后我找到了一份系统管理方面的工作,这就是我职业生涯的方向。我想重新开始某种开发,并且一直在“玩”C#和ASP.NET,但我已经听到很多关于其他"new"语言的讨论(新的意思是它们是新的)我)喜欢Ruby和F#。我想我想知道我是否在浪费时间学习主要的MS语言,而不是成为一名通才。很长一段时间没有离开开发社区(如果我曾经离开过的话)让我在潮流中挣扎,我不想落在时代的

  9. c# - 在 C# 中重现 Ruby OpenSSL private_encrypt 输出 - 2

    我有一个简单的Ruby脚本,我用它在某些HTTPheader上执行private_encrypt以签署要发送到ruby​​RESTAPI的Web请求,该API会根据Base64编码字符串测试Base64编码字符串生成而不是解码Base64和解密数据然后测试原始字符串。我使用的脚本是require"openssl"require"base64"path_to_cert=ARGV[0].dupplain_text=Base64.decode64(ARGV[1].dup)private_key=OpenSSL::PKey::RSA.new(File.read(path_to_cert))pu

  10. C# 的 LINQ 用于在 ruby​​ 中等效的集合操作 - 2

    我是ruby​​开发的新手,我目前正在使用rails2.3.11在ruby​​1.8.7中开发一个项目,我想知道这种语言是否有与C#的linq等效的集合操作,例如where子句。谢谢。 最佳答案 Ruby中Linq的where等价于find_all检查documentationfortheEnumerableModule用于其他功能。 关于C#的LINQ用于在ruby​​中等效的集合操作,我们在StackOverflow上找到一个类似的问题: https://

随机推荐