使用MediaElement + Storyboard连续播放视频

时间:2014-06-16 13:59:39

标签: c# winforms video storyboard mediaelement

我有连续录制的视频文件的时间表。我需要以相同的顺序在我的应用程序中播放它们。

  1. 我已经知道每个视频的相对开始时间和持续时间。
  2. 下一个视频可能尚未开始录制,直到上一个视频停止录制后几秒钟,几分钟甚至几小时。
  3. 我需要某种位置更改通知,以便我可以将其他UI元素同步到视频位置(例如图表)。
  4. 在未录制视频的部分中,视频窗口将显示空白屏幕。
  5. 不幸的是,我现在暂时使用WinForms,但我在MediaElement中嵌入ElementHost
  6. 似乎MediaTimeline + Storyboard组合很适合我的需求。 Storyboard提供满足条件3的CurrentTimeInvalidated事件。至于条件1和2,我相信我可以为每个视频创建一个MediaTimeline,并将每个视频中的每一个添加为Storyboard。似乎我已经部分工作,但我仍然遇到一些问题。

    通过我当前的实现,故事板从头到尾播放就好了。但是,视频仅显示添加到故事板的最后一个视频。

    以下是我想要实现的视频时间线播放器的一些简化伪代码。

    public class VideoTimelineEntry
    {
        public Uri Uri;
        public TimeSpan RelativeStartTime;
        public TimeSpan Duration;
    }
    
    public class VideoTimelinePlayer : System.Windows.Forms.UserControl
    {
        private MediaElement _mediaElement = ...; // Contained in ElementHost
        private Storyboard _storyboard = new Storyboard();
    
        public void LoadTimeline(IEnumerable<VideoTimelineEntry> entries)
        {
            foreach (VideoTimelineEntry entry in entries)
            {
                MediaTimeline mediaTimeline = new MediaTimeline
                {
                    BeginTime = entry.RelativeStartTime,
                    Duration  = new Duration(entry.Duration),
                    Source    = entry.Uri
                };
    
                _storyboard.Children.Add(mediaTimeline);
    
                // I think this is my problem. How do I set the target
                // so that it is always playing the current video, and
                // not just the last one in my timeline?
                Storyboard.SetTarget(mediaTimeline, _mediaElement);
            }
        }
    
        public void Play()
        {
            _storyboard.Begin();
        }
    
        public void Pause()
        {
            _storyboard.Pause();
        }
    
        public void Stop()
        {
            _storyboard.Stop();
        }
    }
    

    非常感谢任何帮助。

1 个答案:

答案 0 :(得分:3)

您似乎每MediaElement只能定位1 MediaTimeline。作为一种解决方法,我现在为每个MediaElement创建一个专用的MediaTimeline。在我看来,这不是一个好的解决方案,但除非我想处理轮询/定时和动态更改视频源,否则我想不出更好的方法。但是,我使用Storyboard的全部理由是我可以避免这样做。

2014年7月24日更新

我决定发布一个非常淡化的例子来改善这个答案。

public void LoadTimeline(IEnumerable<MediaTimeline> mediaTimelines)
{
    // Check that none of the timelines overlap as specified by the
    // acceptance criteria.
    // e.g. timeline2.BeginTime < timeline1.BeginTime + timeline1.Duration.

    _storyboard.Children.Clear();

    foreach (MediaTimeline mediaTimeline in mediaTimelines)
    {
        _storyboard.Children.add(mediaTimeline);

        MediaElement mediaElement = new MediaElement();

        // _grid is just an empty <Grid></Grid> in the xaml layer.
        _grid.Children.Add(mediaElement);

        // Each media timeline now targets a dedicated media element.
        Storyboard.SetTarget(mediaTimeline, mediaElement);

        // Bring the active media element to the top.
        mediaTimeline.CurrentStateInvalidated += (sender, args) =>
        {
            Panel.SetZIndex(mediaElement, int.MaxValue);
        };
    }
}