在WPF中以120FPS播放图像序列 [英] Playing an image sequence in WPF at 120FPS

查看:343
本文介绍了在WPF中以120FPS播放图像序列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个程序,该程序需要一个图像序列并以所需的帧速率(最高120 FPS)播放它.

I'm trying to create a program that takes an image sequence and plays it at the desired framerate (up to 120 FPS).

到目前为止,我有一个Image控件的Source绑定到的类.此类存储文件位置的列表,并且可以调用下一帧的文件位置.看起来像这样:

So far, I have a class that the Source of an Image control is bound to. This class stores a list of file locations and can recall the file location of the next frame. It looks like this:

public class VideoViewer : INotifyPropertyChanged
{
    private string image;
    private List<string> imageLocs = new List<string>();
    private int imageIndex = 0;

    public event PropertyChangedEventHandler PropertyChanged;

    public string imageSource
    {
        get
        {
            return image;
        }
        set
        {
            image = value;
            OnPropertyChanged("imageSource");
        }
    }

    public List<string> imagesArray
    {
        get
        {
            return imageLocs;
        }
        set
        {
            imageLocs = value;
            OnPropertyChanged("imagesArray");
        }
    }

    public void NextFrame()
    {
        //If not on last frame
        if(imageIndex < (imageLocs.Count - 1))
        {
            //Add one to the index to select the next frame in the array
            imageIndex += 1;
            imageSource = imagesArray[imageIndex];

            //Update the image
            OnPropertyChanged("imageSource");
        }
        //If on the last frame of the array, reset to 0
        else if(imageIndex == (imageLocs.Count - 1))
        {
            imageIndex = 0;
            imageSource = imagesArray[imageIndex];
            OnPropertyChanged("imageSource");
        }
    }

    // Create the OnPropertyChanged method to raise the event
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

在MainWindow中,我有3个按钮,一个用于加载类的浏览按钮,一个用于启动DispatcherTimer(每1/120秒调用我的类的NextFrame()方法)的播放按钮以及一个用于停止计时器的停止按钮.

In my MainWindow I have 3 buttons, a browse button which loads the class, a play button that starts a DispatcherTimer which calls the NextFrame() method of my class every 1/120 seconds, and a stop button that stops the timer.

public partial class MainWindow : Window
{
    OpenFileDialog openFileDialog1 = new OpenFileDialog();
    VideoViewer vV = new VideoViewer();
    DispatcherTimer timer = new DispatcherTimer();

    public MainWindow()
    {
        InitializeComponent();

        this.DataContext = vV;
    }

    private void PlayButton_Click(object sender, RoutedEventArgs e)
    {
        timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1/120) };
        timer.Tick += TimerTick;
        timer.Start();
    }

    private void PauseButton_Click(object sender, RoutedEventArgs e)
    {
        timer.Stop();
    }

    private void TimerTick(object sender, EventArgs e)
    {
        vV.NextFrame();
    }

    private void BrowseButton_Click(object sender, RoutedEventArgs e)
    {
        // Set the file dialog to filter for graphics files.
        this.openFileDialog1.Filter =
            "Images (*.BMP;*.JPG;*.GIF;*.PNG)|*.BMP;*.JPG;*.GIF;*.PNG|" +
            "All files (*.*)|*.*";

        // Allow the user to select multiple images.
        this.openFileDialog1.Multiselect = true;
        this.openFileDialog1.Title = "My Image Browser";

        DialogResult dr = this.openFileDialog1.ShowDialog();
        if (dr == System.Windows.Forms.DialogResult.OK)
        {
            if (dr == System.Windows.Forms.DialogResult.OK)
            {
                List<string> images = new List<string>();

                // Read the files
                foreach (String file in openFileDialog1.FileNames)
                {
                    images.Add(file);
                }

                vV.imagesArray = images;
            }
        }
    }
}

这在较低的帧率下可以正常工作,但播放视频的速度似乎不会超过30 FPS(例如,当设置为120 FPS时,我希望30 FPS的视频以4倍的速度播放)

This works fine at lower framerates, but does not seem to play the video any faster than 30 FPS (for example i would expect a 30 FPS video to play at 4x speed when set to 120 FPS)

除了DispatcherTimer之外,我还可以使用其他东西来实现所需的效果吗?

Is there something other than a DispatcherTimer I can use to achieve the desired effect?

推荐答案

不幸的是,DispatcherTimer的Interval属性不够精确.

The Interval property of the DispatcherTimer is unfortunately not precise enough.

  1. 它永远不会在指定的时间间隔启动之前触发"Tick"事件,但是...
  2. 很有可能会比间隔时间长15-25毫秒,因为还有其他东西要完成.

如果您使用...可能会稍微改善

It might improve slightly if you use...

DispatcherTimer dt = new DispatcherTimer(DispatcherPriority.Send);

...增加优先级,但没有达到120FPS(8.3ms间隔).

...to increase the priority level but nowhere near 120FPS (8.3ms interval).

也许这会有所帮助: 无需订阅DispatcherTimer的"Tick"事件,您可以订阅...

Maybe this helps a little: Instead of subscribing to the "Tick" event of a DispatcherTimer you can subscribe to...

System.Windows.Media.CompositionTarget.Rendering += DoSomething;

...并且至少可以在现代PC上以相当可靠的60FPS触发事件.

...and at least get the events fired at a pretty reliable 60FPS on a modern PC.

这篇关于在WPF中以120FPS播放图像序列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆