好的,我已经做了2天了,最后一部分需要帮助。
我有一个微软LifeCam电影摄像机,我使用。net DirectShowLib来捕获视频流。好吧,实际上我使用WPFMediaKit,但我在源代码直接处理直接显示库现在。
我的工作是:—查看摄像机的视频输出-将摄像机的视频输出记录为ASF或AVI格式(ICaptureGraphBuilder2唯一支持的两种MediaType)
问题是:我可以保存为。avi格式。这在1280x720的分辨率下工作得很好,但它将文件保存为RAW输出。这意味着它大约是每秒50-60MB。太高了
或者我可以切换到。asf,它输出一个WMV,但是当我这样做时,捕获和输出都是320x240的分辨率。
在WPFMediaKit中,我改变了一个功能,因为显然微软LifeCam电影相机很多人都有这个问题。而不是创建或改变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;
当这实现时,我终于可以查看捕获的视频为1280x720,只要我将SetOutputFilename设置为MediaType.Avi。
如果我将它设置为MediaType。当它转到320x240时,输出是相同的。
或者AVI以正确的格式工作和输出,但在RAW视频中这样做,因此文件大小非常大。我曾尝试在图中添加一个压缩器,但运气不好,这远远超出了我的经验。
我正在寻找2个答案中的1个。
- 以1280x720记录ASF
- 在图形中添加压缩器,以便我输出的AVI文件大小较小。
我明白了。所以我把它贴在这里,为那些路过想知道为什么它不起作用的可怜的灵魂。
-
下载WPFMediaKit的源代码,你需要修改一些代码。
-
进入文件夹DirectShow> MediaPlayers,打开VideoCapturePlayer.cs
-
找到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将输出所需的分辨率,但未压缩(意味着每秒50-60MB的1280x720视频馈送),这太高了。
那么剩下两个选项
找出如何添加编码器(压缩过滤器)到Avi输出
了解如何更改WMV配置文件
我试过了,但没有成功。主要是由于这是我第一次使用DirectShow,对图表的含义只是掌握。
但是我成功地做到了#2,下面是我是如何做到的。
特别感谢(http://www.codeproject.com/KB/audio-video/videosav.aspx)我从这里取出了所需的代码。
- 在同一个文件夹中创建一个名为WMLib.cs的新类,并将以下内容放入其中
从http://www.codeproject.com/KB/audio-video/videosav.aspx下载演示项目,将WMLib.cs复制并粘贴到您的项目中(根据需要更改名称空间)
在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; }
在SetupGraph函数中找到SetOutputFileName并在其下方放置
ConfigProfileFromFile (mux,"c: wmv.prx");
现在创建名为wmv的文件。把PRX文件放到你的c: drive上,并把相关信息放进去。
您可以在这里看到演示项目中的一个PRX文件示例:http://www.codeproject.com/KB/audio-video/videosav.aspx (Pal90.prx)
现在享受你的。wmv文件以正确的大小输出。是的,我知道我所放置的代码是相当混乱的,但我将把它留给你来完善它。
Lifecam以设置捕获格式的不明显行为而闻名(更具体地说,是退回到其他格式)。请参阅前面的讨论,这些讨论可能会给您提供解决方案:
- 不能使IAMStreamConfig.SetFormat()与LifeCam Studio一起工作
- IAMStreamConfig设置被流忽略-微软LifeCam影院记录仅在640x480
- 微软LifeCam能以低于30fps的帧率记录吗?