好的,我已经在这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个答案之一。
答案 0 :(得分:13)
我想出来了。所以我在这里张贴任何其他可怜的灵魂,想知道为什么它不起作用。
下载WPFMediaKit的源代码,您需要更改一些代码。
转到Folder DirectShow&gt; 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),因此您需要将mediatype设置为其中一个。
hr = graphBuilder.SetOutputFileName(MediaSubType.Asf, this.m_fileName, out mux, out sink);
您将在SetupGraph函数中找到该行。
Asf仅输出320x240,但Avi将以所需的分辨率输出,但未压缩(意味着1280x720视频输入每秒50-60MB),这太高了。
因此,您可以选择2个选项
了解如何将编码器(压缩过滤器)添加到Avi输出
了解如何更改WMV配置文件
我尝试了1,没有成功。主要是因为这是我第一次使用DirectShow并且只是掌握了图形的含义。
但是我在#2中取得了成功,我就是这样做的。
特别感谢(http://www.codeproject.com/KB/audio-video/videosav.aspx)我从这里提取了所需的代码。
从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”);
现在在c:驱动器上创建一个名为wmv.prx的文件,并在其中放置相关信息。
您可以在此处查看演示项目中PRX文件的示例:http://www.codeproject.com/KB/audio-video/videosav.aspx(Pal90.prx)
现在享受以正确尺寸输出的.wmv文件。 是的,我知道我放入的代码非常糟糕但是我会留给你去修饰它。
答案 1 :(得分:2)
Lifecam以设置捕获格式(更具体地说,回归到其他格式)的不明显行为而闻名。请参阅可能建议您解决方案的prevoius讨论: