我有连续录制的视频文件的时间表。我需要以相同的顺序在我的应用程序中播放它们。
MediaElement
中嵌入ElementHost
。似乎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();
}
}
非常感谢任何帮助。
答案 0 :(得分:3)
您似乎每MediaElement
只能定位1 MediaTimeline
。作为一种解决方法,我现在为每个MediaElement
创建一个专用的MediaTimeline
。在我看来,这不是一个好的解决方案,但除非我想处理轮询/定时和动态更改视频源,否则我想不出更好的方法。但是,我使用Storyboard
的全部理由是我可以避免这样做。
我决定发布一个非常淡化的例子来改善这个答案。
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);
};
}
}