使用MediaElement + Storyboard连续播放视频
本文关键字:播放 视频 连续 Storyboard MediaElement 使用 | 更新日期: 2023-09-27 18:08:45
我有一个连续录制的视频文件的时间轴。我需要在我的应用程序中以相同的顺序播放它们。
- 我已经知道每个视频的相对开始时间和持续时间。
- 下一个视频可能在前一个视频停止录制几秒钟、几分钟甚至几小时后才开始录制。
- 我需要某种位置更改通知,以便我可以同步其他UI元素到视频位置(例如图形)。
- 在没有录制视频的部分,视频窗口将显示空白屏幕。
- 不幸的是,我现在使用WinForms卡住了,但是我在
ElementHost
中嵌入了MediaElement
。
看来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();
}
}
似乎每个MediaTimeline
只能针对1个MediaElement
。作为一种解决方法,我现在为每个MediaTimeline
创建一个专用的MediaElement
。在我看来,这不是一个很好的解决方案,但我想不出更好的方法,除非我想处理轮询/定时和动态更改视频源。然而,我使用Storyboard
的全部原因是为了避免这样做。
更新7/24/14
我决定贴一个很淡的例子来改进这个答案。
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);
};
}
}