视频采集输出始终在320×240,尽管分辨率变 [英] Video Capture output always in 320x240 despite changing resolution

查看:1407
本文介绍了视频采集输出始终在320×240,尽管分辨率变的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,我一直在这2天,需要利用这最后一部分帮助。



我有一个微软的LifeCam摄像头电影,我使用.NET DirectShowLib到捕获视频流。那么实际上我用WPFMediaKit,但我在与直接显示库现在直接打交道的源代码



我有什么工作是:
- 观看相机
的视频输出 - 记录摄像机的视频输出中的ASF或AVI(与ICaptureGraphBuilder2支持的唯一2的MediaType的)



问题是:我可以将其保存为.AVI。这工作得很好,并在1280×720的分辨率,但它保存在RAW输出的文件。这意味着它是大约每秒50-60MB。太高了。



或者,我可以切换为.ASF,它输出WMV,但是当我这样做的采集和输出都去分辨率320×240。



在WPFMediaKit有我改变了,因为显然与微软LifeCam的电影摄像机有很多人有这个问题的功能。因此,而不是创建或更改您完成迭代,然后AMMediaType用它来打电话和setFormat。

  /// *使VIDEOINFOHEADER'读'* / 
变种videoInfo =新VIDEOINFOHEADER();

INT ICOUNT = 0,iSize = 0;
videoStreamConfig.GetNumberOfCapabilities(出ICOUNT,出iSize);

IntPtr的TaskMemPointer = Marshal.AllocCoTaskMem(iSize);


AMMediaType pmtConfig = NULL;
为(INT iFormat = 0; iFormat< ICOUNT; iFormat ++)
{
IntPtr的PTR = IntPtr.Zero;

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

videoInfo =(VIDEOINFOHEADER)Marshal.PtrToStructure(pmtConfig.formatPtr的typeof(VIDEOINFOHEADER));

如果(videoInfo.BmiHeader.Width == DesiredWidth&放大器;&安培; videoInfo.BmiHeader.Height == DesiredHeight)
{

/// *设置的VIDEOINFOHEADER我们想要* / $的参数b $ b videoInfo.AvgTimePerFrame = DSHOW_ONE_SECOND_UNIT / FPS;

如果(mediaSubType = Guid.Empty!)
{
INT四字符码= 0;
的byte [] B = mediaSubType.ToByteArray();
四字符码= B [0];
四字符码| = B [1];&下; 8;
四字符码| = B [2]&下;&下; 16;
四字符码| = B [3]所述;&下; 24;

videoInfo.BmiHeader.Compression =四字符码;
// pmtConfig.subType = mediaSubType;

}

/ *复制数据恢复到非托管内存* /
Marshal.StructureToPtr(videoInfo,pmtConfig.formatPtr,真正的);

HR = videoStreamConfig.SetFormat(pmtConfig);
中断;
}

}

/ *可用内存* /
Marshal.FreeCoTaskMem(TaskMemPointer);
DsUtils.FreeAMMediaType(pmtConfig);

如果(hr的0)
返回false;

返回真;

在已实现只要我终于可以查看拍摄的视频作为1280×720,因为我设置SetOutputFilename为一个MediaType.Avi。



如果我将其设置为它去为320x240,并且输出是一样的一个MediaType.Asf。



还是AVI工作和产出以正确的格式,但在原始视频,所以非常大的文件大小这样做​​。我试图压缩机添加到图形,但没有运气,这远远超出我的经验。



我找了1 2的答案。




  1. 在1280×720录制ASF

  2. 添加压缩到图形,使我的输出AVI的文件大小为小的。


解决方案

我想通了这一点。所以,我在这里张贴任何其他可怜的灵魂谁被奇怪,为什么这是行不通的通行证。




  1. 在源码下载在WPFMediaKit,你将需要修改一些代码。


  2. 前往文件夹的DirectShow> MediaPlayers开拓VideoCapturePlayer.cs


  3. 查找功能SetVideoCaptureParameters以及与此替换它:

      ///< ;总结> 
    ///设置视频采集设备
    的拍摄参数///< /总结>
    私人布尔SetVideoCaptureParameters(ICaptureGraphBuilder2 capGraph,IBaseFilter captureFilter中GUID mediaSubType)
    {
    / *流配置接口* /
    对象streamConfig;

    / *获取流的配置界面* /
    INT HR = capGraph.FindInterface(PinCategory.Capture,
    MediaType.Video,
    captureFilter,
    typeof运算(IAMStreamConfig).GUID,
    OUT streamConfig);

    DsError.ThrowExceptionForHR(小时);

    VAR videoStreamConfig = streamConfig为IAMStreamConfig;

    / *如果失败的QueryInterface ... * /
    如果(videoStreamConfig == NULL)
    {
    抛出新的异常(无法得到IAMStreamConfig);
    }

    /// *使VIDEOINFOHEADER'读'* /
    变种videoInfo =新VIDEOINFOHEADER();

    INT ICOUNT = 0,iSize = 0;
    videoStreamConfig.GetNumberOfCapabilities(出ICOUNT,出iSize);

    IntPtr的TaskMemPointer = Marshal.AllocCoTaskMem(iSize);


    AMMediaType pmtConfig = NULL;
    为(INT iFormat = 0; iFormat< ICOUNT; iFormat ++)
    {
    IntPtr的PTR = IntPtr.Zero;

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

    videoInfo =(VIDEOINFOHEADER)Marshal.PtrToStructure(pmtConfig.formatPtr的typeof(VIDEOINFOHEADER));

    如果(videoInfo.BmiHeader.Width == DesiredWidth&放大器;&安培; videoInfo.BmiHeader.Height == DesiredHeight)
    {

    /// *设置的VIDEOINFOHEADER我们想要* / $的参数b $ b videoInfo.AvgTimePerFrame = DSHOW_ONE_SECOND_UNIT / FPS;

    如果(mediaSubType = Guid.Empty!)
    {
    INT四字符码= 0;
    的byte [] B = mediaSubType.ToByteArray();
    四字符码= B [0];
    四字符码| = B [1];&下; 8;
    四字符码| = B [2]&下;&下; 16;
    四字符码| = B [3]所述;&下; 24;

    videoInfo.BmiHeader.Compression =四字符码;
    // pmtConfig.subType = mediaSubType;

    }

    / *复制数据恢复到非托管内存* /
    Marshal.StructureToPtr(videoInfo,pmtConfig.formatPtr,真正的);

    HR = videoStreamConfig.SetFormat(pmtConfig);
    中断;
    }

    }

    / *可用内存* /
    Marshal.FreeCoTaskMem(TaskMemPointer);
    DsUtils.FreeAMMediaType(pmtConfig);

    如果(hr的0)
    返回false;

    返回真;
    }




现在,将排序出你想要什么都想要的分辨率的屏幕显示,提供您的相机支持它。



接下来你会很快弄清楚,这个新的正确捕获你的心不是应用时写视频磁盘。



由于ICaptureBuilder2方法只支持AVI和ASF(这是WMV),您需要将您的MediaType设置为其中之一。

  HR = graphBuilder.SetOutputFileName(MediaSubType.Asf,this.m_fileName,出多路,走出下沉); 

您会发现在SetupGraph功能该行。



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



所以这让你有2个选项




  1. 弄清楚如何添加一个编码器(压缩过滤器)到阿维输出


  2. 弄清楚如何改变WMV简介




我试过1,没有成功。主要是由于这一事实,这是用DirectShow的工作我第一次也是唯一只掌握图的含义。



不过,我是成功的#2,这里是我怎么做吧。



特别感谢(http://www.codeproject.com/KB/audio-video/vi​​deosav.aspx)我从这里驶出所需的代码。




  1. 创建在同一文件夹名为WMLib.cs一个新的类,并将按照它



下载演示项目:// WWW。 codeproject.com/KB/audio-video/vi​​deosav.aspx 并复制并粘贴WMLib.cs到您的项目(根据需要更改命名空间)




  1. 创建了VideoCapturePlayer.cs类的函数

      ///<总结> 
    ///从文件的ASF文件作家
    ///<配置配置文件; /总结>
    ///< PARAM NAME =asfWriter>< /参数>
    ///< PARAM NAME =文件名>< /参数>
    ///<&回报GT;< /回报>
    公共BOOL ConfigProfileFromFile(IBaseFilter asfWriter,字符串文件名)
    {
    INT小时;
    //字符串PROFILEPATH =test.prx;
    //设置的配置文件用于转换
    如果((文件名= NULL)及!及(File.Exists(文件名)))
    {
    //加载配置文件的XML内容
    串profileData;使用
    (StreamReader的读者=新的StreamReader(File.OpenRead(文件名)))
    {
    profileData = reader.ReadToEnd();
    }

    //创建一个从数据
    适当IWMProfile //打开文件管理器
    IWMProfileManager profileManager;
    IWMProfile wmProfile = NULL;
    HR = WMLib.WMCreateProfileManager(出profileManager);
    如果(HR> = 0)
    {
    //错误消息:该配置文件是无效的(0xC00D0BC6)
    //例如无<&PRX GT;标签
    HR = profileManager.LoadProfileByData(profileData,出wmProfile);
    }

    如果(profileManager!= NULL)
    {
    对Marshal.ReleaseComObject(pr​​ofileManager);
    profileManager = NULL;
    }

    //配置仅当有一个轮廓检索
    如果(hr的GT; = 0)
    {
    //上设置轮廓笔者
    IConfigAsfWriter configWriter =(IConfigAsfWriter)asfWriter;
    HR = configWriter.ConfigureFilterUsingProfile(wmProfile);
    如果(HR> = 0)
    {
    返回真;
    }
    }
    }
    返回false;
    }


  2. 在SetupGraph功能找到SetOutputFileName和它下面放



    ConfigProfileFromFile(MUXC:\wmv.prx);


  3. 现在创建一个文件所谓wmv.prx在C:驱动器,并把相关的信息在里面。




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



和享受现在在合适的大小输出的.wmv文件。
是的,我知道我在代码中是相当零碎,但我会离开它你来擦亮它。


Ok I have been at this for 2 days and need help with this last part.

I have a Microsoft LifeCam Cinema camera and I use the .NET DirectShowLib to capture the video stream. Well actually I use WPFMediaKit, but I am in the source code of that dealing directly with the direct show library now.

What I have working is: - View the video output of the camera - Record the video output of the camera in ASF or AVI (the only 2 MediaType's supported with ICaptureGraphBuilder2)

The problem is: I can save it as a .avi. This works fine and at a resolution of 1280x720 but it saves the file in RAW output. Meaning it is about 50-60MB per second. Way too high.

Or I can switch it to .asf and it outputs a WMV, but when I do this the capture and the output both go to resolution 320x240.

In WPFMediaKit there is a function I changed because apparently with Microsoft LifeCam Cinema cameras a lot of people have this problem. So instead of creating or changing the AMMediaType you iterate through and then use that to call 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;

When that was implemented I could finally view the captured video as 1280x720 as long as I set the SetOutputFilename to a MediaType.Avi.

If I set it to a MediaType.Asf it goes to 320x240 and the output is the same.

Or the AVI works and outputs in the correct format but does so in RAW video, hence a very large file size. I have attempted to add a compressor to the graph but with no luck, this is far out of my experience.

I am looking for 1 of 2 answers.

  1. Recording the ASF at 1280x720
  2. Adding a compressor to the graph so that the filesize of my outputted AVI is small.

解决方案

I figured this out. So I am posting it here for any other poor soul who passes by wondering why it doesn't work.

  1. Download the source of the WPFMediaKit, you are going to need to change some code.

  2. Go to Folder DirectShow > MediaPlayers and open up VideoCapturePlayer.cs

  3. Find the function SetVideoCaptureParameters and replace it with this:

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

Now that will sort out your screen display at what ever desired resolution you want, provided that your camera supports it.

Next you will soon figure out that this new correct capture you have isnt applied when writing the video to disk.

Since the ICaptureBuilder2 method only supports Avi and Asf (which is wmv) you need to set your mediatype to one of them.

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

You will find that line in the SetupGraph function.

Asf will only output in 320x240, yet the Avi will output in the desired resolution, but uncompressed (meaning 50-60MB per second for a 1280x720 video feed), which is too high.

So that leaves you with 2 options

  1. Figure out how to add a encoder (compression filter) to the Avi output

  2. Figure out how to change the WMV profile

I tried 1, with no success. Mainly due to the fact this is my first time working with DirectShow and only just grasp the meaning of graphs.

But I was successful with #2 and here is how I did it.

Special thanks to (http://www.codeproject.com/KB/audio-video/videosav.aspx) I pulled out the needed code from here.

  1. Create a new class in the same folder called WMLib.cs and place the following in it

Download the demo project from http://www.codeproject.com/KB/audio-video/videosav.aspx and copy and paste the WMLib.cs into your project (change the namespace as necessary)

  1. Create a function in the VideoCapturePlayer.cs class

    /// <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. In the SetupGraph function find the SetOutputFileName and below it put

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

  3. Now create a file called wmv.prx on your c: drive and place the relevant information in it.

You can see a sample of a PRX file from the demo project here: http://www.codeproject.com/KB/audio-video/videosav.aspx (Pal90.prx)

And now enjoy your .wmv file outputted at the right size. Yes I know the code I placed in was rather scrappy but I will leave it up to you to polish it up.

这篇关于视频采集输出始终在320×240,尽管分辨率变的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆