【问题标题】:DirectShow Custom Source PinDirectShow 自定义源引脚
【发布时间】:2013-11-09 01:51:51
【问题描述】:

我是 DirectShow 的新手。我和其他许多人一样,正在尝试为基于 WPF 的纸牌游戏创建基于套接字的 P2P 流解决方案。我希望每个玩家都能通过小视频窗口看到对方。

我的问题有两个方面。第一个是如何降低帧采样率和分辨率?我相信 320x200 x 15 到 20 fps 应该没问题。我正在使用 SampleGrabber 回调来获取帧数据并通过套接字发送;这实际上在 640x480 分辨率下没有压缩。

我的第二个问题是,由于每帧包含 921,600 字节,这真的很慢,而且我在本地 WiFi 连接的 LAN 上渲染速度非常慢。我添加了一个简单的 MJPEG 压缩(以后想切换到 h.264),我注意到字节下降到大约 330-360k。不错的改进。

在接收端我是否需要创建自定义 DirectShow Source Pin 以提供从套接字接收的字节,以便我可以附加解码器并在窗口中呈现字节?

我只是想先问这个问题,因为创建一个新的 COM 对象(大约 15 年没有这样做了!)、注册它并使用/调试它似乎需要做很多工作。

还有其他方法吗?

另外,如果这是要走的路,我应该在接收端使用 SampleGrabber 并从解压缩的字节创建一个 BitmapSource,还是应该允许 DirectShow 创建一个子窗口?问题是,我想拥有多个其他玩家,我在套接字中设置了一个额外的字节来告诉他们在什么桌子位置。如何依次渲染每个位置?

【问题讨论】:

    标签: wpf sockets directshow.net streaming-video


    【解决方案1】:

    对于那些感兴趣的人,这里是设置分辨率和添加编码器/压缩器的方法:

            // Create a graph builder
            int hr = captureGraphBuilder.SetFiltergraph(graphBuilder);
    
            // Find a capture device (WebCam) and attach it to the graph
            sourceFilter = FindCaptureDevice();
            hr = graphBuilder.AddFilter(sourceFilter, "Video Capture");
    
            // Get the source output Pin
            IPin sourcePin = DsFindPin.ByDirection((IBaseFilter)sourceFilter, PinDirection.Output, 0);
            IAMStreamConfig sc = (IAMStreamConfig)sourcePin;
            int count;
            int size;
            sc.GetNumberOfCapabilities(out count, out size);
            VideoInfoHeader v;
            AMMediaType media2 = null;
            IntPtr memPtr = Marshal.AllocCoTaskMem(size);
            for (int i = 0; i < count; ++i)
            {
                sc.GetStreamCaps(i, out media2, memPtr);
    
                v = (VideoInfoHeader)Marshal.PtrToStructure(media2.formatPtr, typeof(VideoInfoHeader));
                // Break when width is 160
                if (v.BmiHeader.Width == 160)
                    break;
            }
    
            // Set the new media format t0 160 x 120
            hr = sc.SetFormat(media2);
            Marshal.FreeCoTaskMem(memPtr);
            DsUtils.FreeAMMediaType(media2);
    
            // Create a FramGrabber
            IBaseFilter grabberF = (IBaseFilter)new SampleGrabber();
            ISampleGrabber grabber = (ISampleGrabber)grabberF;
    
            // Set the media type
            var media = new AMMediaType
            {
                majorType = MediaType.Video,
                subType = MediaSubType.MJPG
                //subType = MediaSubType.RGB24
            };
    
            // The media sub type will be MJPG
            hr = grabber.SetMediaType(media);
            DsUtils.FreeAMMediaType(media);
            hr = grabber.SetCallback(this, 1);
            hr = graphBuilder.AddFilter(grabberF, "Sample Grabber");
            IPin grabberPin = DsFindPin.ByDirection(grabberF, PinDirection.Input, 0);
    
            // Get the MPEG compressor
            Guid iid = typeof(IBaseFilter).GUID;
            object compressor = null;
            foreach (DsDevice device in DsDevice.GetDevicesOfCat(FilterCategory.VideoCompressorCategory))//.MediaEncoderCategory))
            {
                if (device.Name == "MJPEG Compressor")
                {
                    device.Mon.BindToObject(null, null, ref iid, out compressor);
                    hr = graphBuilder.AddFilter((IBaseFilter)compressor, "Compressor");
                    break;
                }
                string name = device.Name;
            }
    
            // This also works!
            //IBaseFilter enc = (IBaseFilter)new MJPGEnc();
            //graphBuilder.AddFilter(enc, "MJPEG Encoder");
    
            // Get the input and out pins of the compressor
            IBaseFilter enc = (IBaseFilter)compressor;
            IPin encPinIn = DsFindPin.ByDirection(enc, PinDirection.Input, 0);
            IPin encPinOut = DsFindPin.ByDirection(enc, PinDirection.Output, 0);
    
            // Attach the pins: source to input, output to grabber
            hr = graphBuilder.Connect(sourcePin, encPinIn);
            hr = graphBuilder.Connect(encPinOut, grabberPin);
    
            // Free the pin resources
            Marshal.ReleaseComObject(sourcePin);
            Marshal.ReleaseComObject(enc);
            Marshal.ReleaseComObject(encPinIn);
            Marshal.ReleaseComObject(encPinOut);
            Marshal.ReleaseComObject(grabberPin);
    
            // Create a render stream
            hr = captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, null, grabberF);
            Marshal.ReleaseComObject(sourceFilter);
            Configure(grabber);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-07
      • 2013-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-13
      相关资源
      最近更新 更多