有没有办法从媒体元素如视频中抓取帧而不会感到任何延迟? -WPF

问题描述

我必须在Image控件(如视频)中显示来自媒体元素的帧。我试图使用计时器从媒体元素中获取连续帧,并将该位图绑定到Image源。但是,将比例设置为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,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

重用仅在必要时创建并分配给Image元素的Source属性的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,width,height));
            }

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

            ImageViewerMediaEL.Source = bitmap;
        }

        bitmap.Render(visual);
    }
}

上面的代码对于Microsoft的Wildlife.wmv和35毫秒的计时器间隔对我来说很好用。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...