有什么方法可以从视频等媒体元素中抓取帧而不会感到任何延迟? - WPF

Is there any way to grab the frames from media element like a video without feeling any delay? - WPF

我必须像视频一样在图像控件中显示来自媒体元素的帧。我试图使用计时器从媒体元素中获取连续帧,并将该位图绑定到图像源。但是,当将比例设置为 1 时,似乎抓取帧的速度非常慢。当将比例降低到 0.3 或以下时,抓取速度非常快。但框架的质量正在下降。 有什么办法可以解决这个问题吗? 简而言之,我想显示从媒体元素到图像源的帧,没有任何延迟,并且具有原始质量。

    <MediaElement x:Name="MediaEL" Volume="0" ScrubbingEnabled="True"  SnapsToDevicePixels="True" MediaOpened="MediaEL_MediaOpened" LoadedBehavior="Manual"  MediaEnded="MediaEL_MediaEnded"  MediaFailed="MediaEL_MediaFailed">
        </MediaElement>
        <Image Name="ImageViewerMediaEL" />

        ScreenShotimer = new DispatcherTimer();
        ScreenShotimer.Interval = TimeSpan.FromMilliseconds(35);//35//
        ScreenShotimer.Tick += ScreenShotimer_Tick;

  public Bitmap TakeScreenshot(MediaElement medElement, double scale)
    {
        Bitmap screenBitmap = null;     
        double actualHeight = medElement.NaturalVideoHeight;
        double actualWidth = medElement.NaturalVideoWidth;

        double renderHeight = actualHeight * scale;
        double renderWidth = actualWidth * scale;       

            if ((int)renderWidth > 0 && (int)renderHeight > 0)
            {
                RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)renderWidth,
                    (int)renderHeight, 96, 96, PixelFormats.Default);

                VisualBrush sourceBrush = new VisualBrush(medElement);

                DrawingVisual drawingVisual = new DrawingVisual();
                DrawingContext drawingContext = drawingVisual.RenderOpen();

                using (drawingContext)
                {
                    drawingContext.PushTransform(new ScaleTransform(scale, scale));
                    drawingContext.DrawRectangle(sourceBrush, null, new Rect(new System.Windows.Point(0, 0),
                        new System.Windows.Point(actualWidth, actualHeight)));
                }
                renderTarget.Render(drawingVisual);

                MemoryStream stream = new MemoryStream();
                BitmapEncoder encoder = new BmpBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(renderTarget));
                encoder.Save(stream);
                screenBitmap = new Bitmap(stream);
            }
        return screenBitmap;
    }

似乎没有必要在 WPF 应用程序中使用 WinForms Bitmap

重复使用仅在必要时创建并分配给图像元素的源 属性 的 RenderTargetBitmap 的单个实例。

同样,重用 DrawingVisual 并仅在大小更改时使用 VisualBrush 绘制矩形。

private readonly DrawingVisual visual = new DrawingVisual();
private RenderTargetBitmap bitmap;

...

private void OnTimerTick(object sender, EventArgs e)
{
    var width = MediaEL.NaturalVideoWidth;
    var height = MediaEL.NaturalVideoHeight;

    if (width > 0 && height > 0)
    {
        if (bitmap == null ||
            bitmap.PixelWidth != width ||
            bitmap.PixelHeight != height)
        {
            using (var dc = visual.RenderOpen())
            {
                dc.DrawRectangle(
                    new VisualBrush(MediaEL), null,
                    new Rect(0, 0, width, height));
            }

            bitmap = new RenderTargetBitmap(
                width, height, 96, 96, PixelFormats.Default);

            ImageViewerMediaEL.Source = bitmap;
        }

        bitmap.Render(visual);
    }
}

上面的代码适用于 Microsoft 的 Wildlife.wmv 和 35 毫秒计时器间隔。