有用C#写过DirectShow的朋友请进

zengliu 2009-07-17 11:53:11
最近在用DirectShow来写一视频处理软件,这方面的技术资料网上实在太少
郁闷... 向各位求救来了... HELP...

哪位朋友有这方面的C#示例,请给我发一份 我的邮箱是: ggview@qq.com
示例越简单越好 大概功能 读取文件--->编码--->写文件 和 读取文件--->解码--->显示到窗口
我需要将视频压缩成mpeg4格式流,使其得到文件最大高清压缩比

代码越简节越好,比如

int hr;
IAMTimeline m_pTimeline = (IAMTimeline)new AMTimeline();

hr = m_pTimeline.SetDefaultFPS(30);
DESError.ThrowExceptionForHR(hr);

IAMTimelineObj pGroupObj;
hr = m_pTimeline.CreateEmptyNode(out pGroupObj, TimelineMajorType.Group);
DESError.ThrowExceptionForHR(hr);

IAMTimelineGroup pGroup = (IAMTimelineGroup)pGroupObj;

AMMediaType m_pMediaType = GetVideoMediaType(24, 800, 600);
hr = pGroup.SetMediaType(m_pMediaType);
DESError.ThrowExceptionForHR(hr);

DsUtils.FreeAMMediaType(m_pMediaType);

hr = m_pTimeline.AddGroup(pGroupObj);
DESError.ThrowExceptionForHR(hr);

IAMTimelineObj pTrack1Obj;
hr = m_pTimeline.CreateEmptyNode(out pTrack1Obj, TimelineMajorType.Track);
DESError.ThrowExceptionForHR(hr);

IAMTimelineComp pRootComp = (IAMTimelineComp)pGroupObj;
hr = pRootComp.VTrackInsBefore(pTrack1Obj, -1);
DESError.ThrowExceptionForHR(hr);

IAMTimelineObj pSource1Obj;
hr = m_pTimeline.CreateEmptyNode(out pSource1Obj, TimelineMajorType.Source);
DESError.ThrowExceptionForHR(hr);
//...
...全文
623 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
zzw369846827 2011-07-18
  • 打赏
  • 举报
回复
友情帮顶~~~
dlm516 2010-01-15
  • 打赏
  • 举报
回复
恢复
mydudu2005 2010-01-05
  • 打赏
  • 举报
回复
C#写过DirectShow资料很少,谢谢了
zengliu 2009-07-18
  • 打赏
  • 举报
回复
代码太长,分两次贴上来了

private long GetLength(String m_FileName)
{
int hr;
double d;
long i;

IMediaDet imd = (IMediaDet)new MediaDet();

// Set the name
hr = imd.put_Filename(m_FileName);
DESError.ThrowExceptionForHR(hr);

// Read from stream zero
hr = imd.put_CurrentStream(0);
DESError.ThrowExceptionForHR(hr);

// Get the length in seconds
hr = imd.get_StreamLength(out d);
DESError.ThrowExceptionForHR(hr);

Marshal.ReleaseComObject(imd);

// Convert to UNITS
i = (long)(d * (1000000000/100));
return i;
}

private bool IsVideo(IPin pPin)
{
int hr;
bool bRet = false;
AMMediaType[] pmt = new AMMediaType[1];
IEnumMediaTypes ppEnum;

// Walk the MediaTypes for the pin
hr = pPin.EnumMediaTypes(out ppEnum);
DESError.ThrowExceptionForHR(hr);

try
{
// Just read the first one
hr = ppEnum.Next(1, pmt, IntPtr.Zero);
DESError.ThrowExceptionForHR(hr);

bRet = pmt[0].majorType == MediaType.Video;
}
finally
{
Marshal.ReleaseComObject(ppEnum);
}
DsUtils.FreeAMMediaType(pmt[0]);

return bRet;
}

public interface IDESCombineCB
{
int BufferCB(
string sFileName,
double SampleTime,
System.IntPtr pBuffer,
int BufferLen
);
}

public class MyCallbacks : IDESCombineCB
{
private int m_FrameCount;
private long m_TotBytes;
private DateTime m_StartTime;
private double m_LastSampleTime;
private bool m_KeepTime;


public MyCallbacks()
{

}

~MyCallbacks()
{

}

public void KeepTime()
{
m_KeepTime = true;
}

public int BufferCB(string sFilename, double SampleTime, System.IntPtr pBuffer, int BufferLen)
{
return 0;
}
}

internal class MyCallback : ISampleGrabberCB
{
#region Data members

protected IDESCombineCB m_pCallback;
protected IMediaEventSink m_pEventSink;
protected EventCode m_ec;
protected int m_iCurFile;
protected int m_iCurFrame;
protected int m_iMaxFrame;
protected string m_CurFileName;

#endregion

public MyCallback(
IDESCombineCB pCallback,
IMediaEventSink pEventSink,
EventCode ec,
String mCurFileName,
int miMaxFrame
)
{
m_pCallback = pCallback;
m_pEventSink = pEventSink;
m_ec = ec;

m_iCurFrame = 0;
m_iCurFile = 0;


m_CurFileName = mCurFileName;
m_iMaxFrame = miMaxFrame;
}

public int SampleCB(double SampleTime, IMediaSample pSample)
{
Marshal.ReleaseComObject(pSample);
return 0;
}
public int BufferCB(double SampleTime, System.IntPtr pBuffer, int BufferLen)
{
int iRet;

if (m_pCallback != null)
{
iRet = m_pCallback.BufferCB(m_CurFileName, SampleTime, pBuffer, BufferLen);
}
else
{
iRet = 0;
}

m_iCurFrame++;

// Have we finished the current file?
if (m_iCurFrame >= m_iMaxFrame)
{
int hr = m_pEventSink.Notify(m_ec, new IntPtr(m_iCurFile), new IntPtr(m_iCurFrame));

m_iCurFile++;

}

return iRet;
}
}


private AMMediaType GetVideoMediaType(short BitCount, int Width, int Height)
{
Guid mediaSubType;
AMMediaType VideoGroupType = new AMMediaType();

// Calculate the SubType from the Bit count
switch (BitCount)
{
case 16:
mediaSubType = MediaSubType.RGB555;
break;
case 24:
mediaSubType = MediaSubType.RGB24;
break;
case 32:
mediaSubType = MediaSubType.RGB32;
break;
default:
throw new Exception("Unrecognized bit format");
}

VideoGroupType.majorType = MediaType.Video;
VideoGroupType.subType = mediaSubType;
VideoGroupType.formatType = FormatType.VideoInfo;
VideoGroupType.fixedSizeSamples = true;

VideoGroupType.formatSize = Marshal.SizeOf(typeof(VideoInfoHeader));
VideoInfoHeader vif = new VideoInfoHeader();
vif.BmiHeader = new BitmapInfoHeader();

// The HEADER macro returns the BITMAPINFO within the VIDEOINFOHEADER
vif.BmiHeader.Size = Marshal.SizeOf(typeof(BitmapInfoHeader));
vif.BmiHeader.Compression = 0;
vif.BmiHeader.BitCount = BitCount;
vif.BmiHeader.Width = Width;
vif.BmiHeader.Height = Height;
vif.BmiHeader.Planes = 1;

int iSampleSize = vif.BmiHeader.Width * vif.BmiHeader.Height * (vif.BmiHeader.BitCount / 8);
vif.BmiHeader.ImageSize = iSampleSize;
VideoGroupType.sampleSize = iSampleSize;
VideoGroupType.formatPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(vif));

Marshal.StructureToPtr(vif, VideoGroupType.formatPtr, false);

return VideoGroupType;
}

zengliu 2009-07-18
  • 打赏
  • 举报
回复
读取文件--->解码--->显示到窗口 这个功能
我将实现的代码贴出来,供大家参考学习
程序引用了 DirectShowLib-2005,需要去下载一个
就一个函数,调用一下即可;里面可修改播放的文件名称及一些属性

public void getTest()
{
int hr;
IAMTimeline m_pTimeline = (IAMTimeline)new AMTimeline();

hr = m_pTimeline.SetDefaultFPS(30);
DESError.ThrowExceptionForHR(hr);

AMMediaType m_pMediaType = GetVideoMediaType(24, 320, 240);

IAMTimelineObj pGroupObj;
hr = m_pTimeline.CreateEmptyNode(out pGroupObj, TimelineMajorType.Group);
DESError.ThrowExceptionForHR(hr);

IAMTimelineGroup pGroup = (IAMTimelineGroup)pGroupObj;

hr = pGroup.SetMediaType(m_pMediaType);
DESError.ThrowExceptionForHR(hr);

DsUtils.FreeAMMediaType(m_pMediaType);

hr = m_pTimeline.AddGroup(pGroupObj);
DESError.ThrowExceptionForHR(hr);

IAMTimelineObj pTrack1Obj;
hr = m_pTimeline.CreateEmptyNode(out pTrack1Obj, TimelineMajorType.Track);
DESError.ThrowExceptionForHR(hr);

IAMTimelineComp pRootComp = (IAMTimelineComp)pGroupObj;
hr = pRootComp.VTrackInsBefore(pTrack1Obj, -1);
DESError.ThrowExceptionForHR(hr);

IAMTimelineObj pSource1Obj;
hr = m_pTimeline.CreateEmptyNode(out pSource1Obj, TimelineMajorType.Source);
DESError.ThrowExceptionForHR(hr);

String mFileName = @"G:\cake.mpeg";
long lStart = 0;
long lEnd = GetLength(mFileName);
hr = pSource1Obj.SetStartStop(lStart, lEnd);
DESError.ThrowExceptionForHR(hr);

IAMTimelineSrc pSource1Src = (IAMTimelineSrc)pSource1Obj;
hr = pSource1Src.SetMediaName(mFileName);
DESError.ThrowExceptionForHR(hr);

hr = pSource1Src.SetMediaTimes(lStart, lEnd);
DESError.ThrowExceptionForHR(hr);

IAMTimelineTrack m_Track = (IAMTimelineTrack)pTrack1Obj;

hr = m_Track.SrcAdd(pSource1Obj);
DESError.ThrowExceptionForHR(hr);

hr = pSource1Src.FixMediaTimes(ref lStart, ref lEnd);
DESError.ThrowExceptionForHR(hr);

IRenderEngine m_pRenderEngine = (IRenderEngine)new RenderEngine();
hr = m_pRenderEngine.SetTimelineObject(m_pTimeline);
DESError.ThrowExceptionForHR(hr);

hr = m_pRenderEngine.ConnectFrontEnd();
DESError.ThrowExceptionForHR(hr);

IGraphBuilder m_pGraph;
hr = m_pRenderEngine.GetFilterGraph(out m_pGraph);
DESError.ThrowExceptionForHR(hr);


ICaptureGraphBuilder2 icgb = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
hr = icgb.SetFiltergraph(m_pGraph);
DESError.ThrowExceptionForHR(hr);

IPin pPin = null;
int NumGroups;
IAMTimelineObj pGroupz;
hr = m_pTimeline.GetGroupCount(out NumGroups);
DESError.ThrowExceptionForHR(hr);

for (int i = 0; i < NumGroups; i++)
{
hr = m_pTimeline.GetGroup(out pGroupz, i);
DESError.ThrowExceptionForHR(hr);

IAMTimelineGroup pTLGroup = (IAMTimelineGroup)pGroupz;
hr = pTLGroup.SetPreviewMode(true);
DESError.ThrowExceptionForHR(hr);

hr = m_pRenderEngine.GetGroupOutputPin(i, out pPin);
DESError.ThrowExceptionForHR(hr);

if (IsVideo(pPin))
{
IBaseFilter ibfVideoRenderer = (IBaseFilter)new VideoRenderer();

//MyCallback mcb = new MyCallback(m_Video, pVideoCallback, (IMediaEventSink)m_pGraph, EC_VideoFileComplete);
hr = m_pGraph.AddFilter(ibfVideoRenderer, "Video Renderer");
DESError.ThrowExceptionForHR(hr);

IBaseFilter ibfSampleGrabber = null;
ISampleGrabber isg = (ISampleGrabber)new SampleGrabber();

MyCallbacks cb = new MyCallbacks();
MyCallback pCallback = new MyCallback(cb, (IMediaEventSink)m_pGraph, (EventCode)0x8000, mFileName, 1951);

hr = isg.SetCallback(pCallback, 1);
DESError.ThrowExceptionForHR(hr);

ibfSampleGrabber = (IBaseFilter)isg;

hr = m_pGraph.AddFilter(ibfSampleGrabber, "Video sample grabber");
DESError.ThrowExceptionForHR(hr);

hr = icgb.RenderStream(null, null, pPin, ibfSampleGrabber, ibfVideoRenderer);
DESError.ThrowExceptionForHR(hr);
}
}

IVideoWindow pVidWindow;
pVidWindow = (IVideoWindow)m_pGraph;

hr = pVidWindow.put_Caption("Video Rendering Window");
DESError.ThrowExceptionForHR(hr);
WindowStyle lStyle = 0;
hr = pVidWindow.get_WindowStyle(out lStyle);
DESError.ThrowExceptionForHR(hr);
lStyle &= ~(WindowStyle.MinimizeBox | WindowStyle.MaximizeBox | WindowStyle.SysMenu);
hr = pVidWindow.put_WindowStyle(lStyle);
DESError.ThrowExceptionForHR(hr);


IMediaControl m_pControl;
m_pControl = (IMediaControl)m_pGraph;
hr = m_pControl.Run( );
DESError.ThrowExceptionForHR(hr);

}
zengliu 2009-07-18
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 lcl_data 的回复:]
C# code要使 C# 代码引用 COM 对象和接口,需要在 C# 内部版本中包含 COM 接口的 .NET 框架定义。完成此操作的最简单方法是使用 TlbImp.exe(类型库导入程序),它是一个包括在 .NET 框架 SDK 中的命令行工具。TlbImp 将 COM 类型库转换为 .NET 框架元数据,从而有效地创建一个可以从任何托管语言调用的托管包装。用 TlbImp 创建的 .NET 框架元数据可以通过 /R 编译器选项包括在 C# 内部版本中。如果使用 Visual Studio 开发环境,则只需添加对 COM 类型库的引用,将为您自动完成此转换。
例如,我们要播放当前目录下的demo.avi文件,需要用到包含在位于 Windows 系统目录中的 Quartz.dll 中的媒体播放机。(c:\winnt\system32\quartz.dll)。可在命令行中运行TlbImp文件(D:\ Microsoft Visual Studio .NET\FrameworkSDK\Bin\Tlbimp.exe)
............
[/Quote]
感谢你的回答,这种方式能实现 读取文件--->解码--->显示到窗口 这个功能
你所回答的功能代码我在网上找到过,但不是我需要的;由于特殊需求(有对视频处理的环节,具我所知;我已经确定使用DirectShow来实现),这个简单的播放示例我已经实现了
你有没有 读取文件--->编码--->写文件 这个功能,我最需要的是这个
能其它格式媒体文件编码成mpeg2或者mpeg4的编码保存到文件,相当于媒体文件压缩或转码
sxmonsy 2009-07-18
  • 打赏
  • 举报
回复
友情UP
yhf365 2009-07-18
  • 打赏
  • 举报
回复

只知道VC调用DirectShow的资料比较多...
十八道胡同 2009-07-17
  • 打赏
  • 举报
回复
可以参考
十八道胡同 2009-07-17
  • 打赏
  • 举报
回复
要使 C# 代码引用 COM 对象和接口,需要在 C# 内部版本中包含 COM 接口的 .NET 框架定义。完成此操作的最简单方法是使用 TlbImp.exe(类型库导入程序),它是一个包括在 .NET 框架 SDK 中的命令行工具。TlbImp 将 COM 类型库转换为 .NET 框架元数据,从而有效地创建一个可以从任何托管语言调用的托管包装。用 TlbImp 创建的 .NET 框架元数据可以通过 /R 编译器选项包括在 C# 内部版本中。如果使用 Visual Studio 开发环境,则只需添加对 COM 类型库的引用,将为您自动完成此转换。
例如,我们要播放当前目录下的demo.avi文件,需要用到包含在位于 Windows 系统目录中的 Quartz.dll 中的媒体播放机。(c:\winnt\system32\quartz.dll)。可在命令行中运行TlbImp文件(D:\ Microsoft Visual Studio .NET\FrameworkSDK\Bin\Tlbimp.exe)
tlbimp c:\winnt\system32\quartz.dll /out:QuartzTypeLib.dll
请注意,得到的 DLL 需要命名为 QuartzTypeLib,以便 .NET 框架可以在运行时正确加载包含类型。
生成程序时使用 C# 编译器选项 /R 以包含 QuartzTypeLib.dll 文件;如果使用 Visual Studio 开发环境,直接添加引用即可(using QuartzTypeLib)。
然后就可以使用此程序显示影片了。
具体编写代码时,用到了RenderFile 和 Run 方法。例:
private void menuItemOpen_Click(object sender, System.EventArgs e)
{
FilgraphManager m_FilGraphManager = null;
IBasicAudio m_BasicAudio = null;
IVideoWindow m_VideoWindow = null;
IMediaEvent m_MediaEvent = null;
IMediaEventEx m_MediaEventEx = null;
IMediaPosition m_MediaPosition = null;
IMediaControl m_MediaControl = null;
OpenFileDialog OpenDialog = new OpenFileDialog();
OpenDialog.Filter = "Media Files|*.mpg;*.avi;*.wma;*.mov;*.wav;*.mp2;*.mp3|All Files|*.*"; //本例用对话框读入要显示的影片文件名
if (DialogResult.OK == OpenDialog.ShowDialog())
{
m_FilGraphManager = new FilgraphManager();
m_FilGraphManager.RenderFile(OpenDialog.FileName);
m_BasicAudio = m_FilGraphManager as IBasicAudio ;
try
{
m_VideoWindow = m_FilGraphManager as IVideoWindow;
m_VideoWindow.Owner = (int) panel1.Handle;
m_VideoWindow.WindowStyle = WS_CHILD | WS_CLIPCHILDREN;
//此设置可以不显示播放器的title,使播放器像嵌在窗体中。
//可设置 private const int WS_CHILD = 0x40000000;
// private const int WS_CLIPCHILDREN = 0x2000000;
m_VideoWindow.SetWindowPosition(panel1.ClientRectangle.Left,
panel1.ClientRectangle.Top,
panel1.ClientRectangle.Width,
panel1.ClientRectangle.Height);
// 在panel1中显示,要求影片可随panel1大小而变化。
}
catch (Exception)
{
m_VideoWindow = null;
}

m_MediaEvent = m_FilGraphManager as IMediaEvent;
m_MediaEventEx = m_FilGraphManager as IMediaEventEx;
m_MediaEventEx.SetNotifyWindow((int) this.Handle,WM_GRAPHNOTIFY, 0);
m_MediaPosition = m_FilGraphManager as IMediaPosition;
m_MediaControl = m_FilGraphManager as IMediaControl;
this.Text = "DirectShow - [" + OpenDialog.FileName + "]";
m_MediaControl.Run();
}
}

也可以加入pause,stop命令来控制影片的播放。
m_MediaControl.Pause()
m_MediaControl.Stop()


zengliu 2009-07-17
  • 打赏
  • 举报
回复
朋友:
你们是不是发给我了?
可我还没有收到, 不会是邮箱有问题,QQ邮箱还从来没有出现过问题的!
我再提供一个邮箱地址吧,有劳在发一份给我。。。
邮箱地址: zengliu1@gmail.com
注意 zengliu 后面跟着的是 123456 中的 1
benzite 2009-07-17
  • 打赏
  • 举报
回复
mark
chaozi_249 2009-07-17
  • 打赏
  • 举报
回复
mark

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧