【问题标题】:Playing an image sequence in WPF at 120FPS在 WPF 中以 120FPS 播放图像序列
【发布时间】:2017-09-05 09:38:58
【问题描述】:

我正在尝试创建一个程序来获取图像序列并以所需的帧速率(最高 120 FPS)播放它。

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

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() 方法,以及一个停止计时器的停止按钮.

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(例如,我希望 30 FPS 的视频在设置为 120 FPS 时以 4 倍的速度播放)

除了 DispatcherTimer 之外,还有什么可以用来达到预期效果的吗?

【问题讨论】:

  • 我想从文件中加载你的图像并解码它需要比你想要的帧长度更长的时间。
  • 如何正常工作? 1 / 120 将返回 0,因为涉及到 int 计算。这应该改为1D / 120DProof here
  • 从 1/120 更改为 1D/120D 没有任何作用,它仍然以相同的速度播放。是的,我在想,如果不是计时器限制,加载文件可能需要很长时间。
  • 您可以通过自己预先加载所有图像来验证该假设(因此您的 imagesArray 类型将是 List&lt;ImageSource&gt;)。
  • 您是否尝试过扩展UIElementFrameworkElement 并使用OnRender 方法来绘制图像?这应该比现在快很多。

标签: c# wpf image


【解决方案1】:

很遗憾,DispatcherTimer 的 Interval 属性不够精确。

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

如果你使用它可能会略有改善......

DispatcherTimer dt = new DispatcherTimer(DispatcherPriority.Send);

...提高优先级,但远不及 120FPS(8.3ms 间隔)。

也许这会有所帮助: 除了订阅 DispatcherTimer 的“Tick”事件,您还可以订阅...

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

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

【讨论】:

    猜你喜欢
    • 2012-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 2015-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多