0

私は DirectShow を初めて使用します。私は、他の多くの人と同じように、WPF ベースのカード ゲーム用のソケット ベースの P2P ストリーミング ソリューションを作成しようとしています。各プレイヤーが小さなビデオ ウィンドウでお互いを確認できるようにしたいと考えています。

私の質問は 2 つあります。1 つ目は、フレームのサンプル レートと解像度を下げるにはどうすればよいですか? 320x200 x 15 ~ 20 fps で十分だと思います。フレーム データを取得してソケット経由で送信するために、SampleGrabber コールバックを使用しています。実際には、640x480 の解像度で圧縮なしで動作しています。

私の 2 番目の質問は、各フレームには 921,600 バイトが含まれているため、これは本当に行き詰まり、ローカルの WiFi 接続 LAN でレンダリングが非常に遅くなることです。シンプルな MJPEG 圧縮 (後で h.264 に切り替えたい) を追加したところ、バイト数が約 330 ~ 360k に減少したことに気付きました。悪い改善ではありません。

受信側 ソケットから受信したバイトを提供するために、カスタム DirectShow ソース ピンを作成して、デコーダーを接続し、ウィンドウにバイトをレンダリングできるようにする必要がありますか?

新しい COM オブジェクトを作成し (約 15 年間それを行っていません!)、登録し、使用/デバッグするのは大変な作業のように思われるので、最初にこれを尋ねたかっただけです。

おそらく別の方法がありますか?

また、それが進むべき道である場合、受信側で SampleGrabber を使用して、圧縮解除されたバイトから BitmapSource を作成する必要がありますか、それとも DirectShow に子ウィンドウを作成させる必要がありますか? つまり、他に複数のプレーヤーが必要で、ソケットに余分なバイトを設定して、彼らがどのテーブル位置にいるかを示します。各位置を順番にレンダリングするにはどうすればよいですか?

4

1 に答える 1

0

興味のある方のために、解像度を設定してエンコーダー/コンプレッサーを追加する方法を次に示します。

        // 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);
于 2013-11-06T15:22:51.757 に答える