Есть ли какой-нибудь способ захватить кадры из медиа-элемента, например видео, без каких-либо задержек? — WPF

#c# #asp.net #wpf #mediaelement

#c# #asp.net #wpf #mediaelement

Вопрос:

Я должен показывать кадры из медиа-элемента в элементе управления изображением, например, в видео. Я попытался захватить продолжающиеся кадры из медиа-элемента с помощью таймера и привязать это растровое изображение к источнику изображения. Но при установке масштаба равным 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 amp;amp; (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;
    }
  

Ответ №1:

Использование WinForms Bitmap в приложении WPF, похоже, не требуется.

Повторно используйте один экземпляр 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 amp;amp; 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);
    }
}
  

Приведенный выше код отлично работает для меня с Wildlife.wmv от Microsoft и интервалом таймера 35 мс.