C#发送视频帧

时间:2015-06-02 03:08:05

标签: c# video udp frame

我想使用UDP连接从客户端发送视频帧到服务器。

如何从网络摄像头获取视频帧?我是否需要将每个帧保存到我的计算机并从那里发送到服务器?如果我以30fps运行,这意味着我需要每秒在计算机上保存30个视频帧?或者我可以直接发送从网络摄像头获得的视频帧吗?

目前,我只能打开网络摄像头,并使用Aforge库将视频显示在客户端的UI上。

我查看了许多不同的主题,但我似乎并没有从中受益,因为我在C#中的基础薄弱。

提前致谢!

1 个答案:

答案 0 :(得分:1)

您可以使用DirectShow.NET库(可通过NuGet将其作为DirectShowLib提供)逐帧捕获网络摄像头视频。这是一个很好的DxSnap示例,展示了如何获取静态图像。最困难的部分是了解DirectShow API,如果你在C#中有一个薄弱的基础,它可能看起来很陌生。和/或之前没有处理COM代码。

根据分辨率,由于性能/带宽限制,帧速率可能会低于30 fps。如果您需要具有良好分辨率的高帧速率,则可能必须首先使用一些比特率高效的编码器对视频进行编码。

这两个选项 - 逐帧和视频编码 - 都可以使用这个库(虽然后者可能不容易通过UDP)。您只需要设置一个合适的图表。 GraphEditPlus可能对此有很大的帮助,特别是因为它可以为DirectShow.NET生成图形的C#代码(这里有点烦恼是你不能将代码复制到剪贴板,除非你购买了应用程序)。

基本上,如果您确定要发送每一帧,那么您只需要构建如下图形:视频捕获源>样品采集器>空渲染器。您可以设置示例抓取器以将每个帧重定向到ISampleGrabberCB的实现,并在BufferCB方法中为您提供指向帧位图数据的指针。下面是一些我尽量保持尽可能短的代码,从而牺牲了它的健壮性。看看但请不要将其保留在生产中,如果它有效的话。

class FrameGrabber : ISampleGrabberCB
{
    IMediaControl mediaCtrl;
    int width, height, stride;

    public FrameGrabber(DsDevice camDevice)
    {
        IFilterGraph2 filterGraph;
        ICaptureGraphBuilder2 graphBuilder;
        IBaseFilter camBase, nullRenderer;
        ISampleGrabber sampleGrabber;

        filterGraph = new FilterGraph() as IFilterGraph2;
        mediaCtrl = filterGraph as IMediaControl;

        graphBuilder = new CaptureGraphBuilder2() as ICaptureGraphBuilder2;
        HRCheck(graphBuilder.SetFiltergraph(filterGraph));

        // Add camera
        HRCheck(filterGraph.AddSourceFilterForMoniker(
            camDevice.Mon, null, camDevice.Name, out camBase));

        // Add sample grabber
        sampleGrabber = new SampleGrabber() as ISampleGrabber;
        var mType = new AMMediaType()
        {
            majorType = MediaType.Video,
            subType = MediaSubType.RGB24,
            formatType = FormatType.VideoInfo
        };
        HRCheck(sampleGrabber.SetMediaType(mType));
        DsUtils.FreeAMMediaType(mType);
        HRCheck(sampleGrabber.SetCallback(this, 1));
        HRCheck(filterGraph.AddFilter(sampleGrabber as IBaseFilter, "CamGrabber"));

        // Add null renderer
        nullRenderer = new NullRenderer() as IBaseFilter;
        HRCheck(filterGraph.AddFilter(nullRenderer, "Null renderer"));

        // Render the webcam through the grabber and the renderer
        HRCheck(graphBuilder.RenderStream(PinCategory.Capture, MediaType.Video,
            camBase, sampleGrabber as IBaseFilter, nullRenderer));

        // Get resulting picture size
        mType = new AMMediaType();
        HRCheck(sampleGrabber.GetConnectedMediaType(mType));
        if (mType.formatType != FormatType.VideoInfo || mType.formatPtr == IntPtr.Zero)
        {
            throw new NotSupportedException("Unknown grabber media format");
        }
        var videoInfoHeader = Marshal.PtrToStructure(mType.formatPtr,
            typeof(VideoInfoHeader)) as VideoInfoHeader;
        width = videoInfoHeader.BmiHeader.Width;
        height = videoInfoHeader.BmiHeader.Height;
        Console.WriteLine("{0} x {1}", width, height); 
        stride = width * (videoInfoHeader.BmiHeader.BitCount / 8);
        DsUtils.FreeAMMediaType(mType);

        HRCheck(mediaCtrl.Run());
    }

    public int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
    {
        Console.WriteLine("BufferCB: " + SampleTime.ToString());
        // This is the bitmap of the frame but you may want
        // to copy it to some other memory location to
        // process/save/send it from there
        var bmp = new Bitmap(width, height, stride,
                PixelFormat.Format24bppRgb, pBuffer);
        return 0;
    }

    public int SampleCB(double SampleTime, IMediaSample pSample)
    {
        // This won't be called because sampleGrabber.SetCallback(this, 1)
        // -- 1 means BufferCB
        return Marshal.ReleaseComObject(pSample);
    }

    static void HRCheck(int hr)
    {
        DsError.ThrowExceptionForHR(hr);
    }

这就是你怎么称呼它:

class Program
{
    static void Main(string[] args)
    {
        var cam = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice).First();
        var grabber = new FrameGrabber(cam);
        Console.ReadLine();
    }
}