我有一个连续录制的视频文件的时间表.我需要以相同的顺序在应用程序中播放它们.
>我已经知道每个视频的相对开始时间和持续时间.
>下一个视频可能要等到上一个视频停止录制后的几秒钟,几分钟甚至几小时才能开始录制.
>我需要某种位置更改通知,以便可以将其他UI元素同步到视频位置(例如图形).
>在未录制任何视频的部分中,视频窗口将显示空白屏幕.
>不幸的是,我暂时仍无法使用WinForms,但是我将MediaElement嵌入到ElementHost中.
MediaTimeline故事板组合似乎很适合我的需求.情节提要提供一个满足条件3的CurrentTimeInvalidated事件.关于条件1和2,我相信我可以为每个视频创建MediaTimeline并将它们中的每个作为子元素添加到情节提要中.看来我有部分工作,但仍然有一些问题.
在我当前的实现中,情节提要从头到尾都可以正常播放.但是,仅显示添加到情节提要中的最后一个视频的视频.
这是我要实现的视频时间线播放器的一些简化的伪代码.
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);
};
}
}