【问题标题】:C# MediaElement -- Why does Play() sometimes silently fail after switching the source?C# MediaElement -- 为什么 Play() 在切换源后有时会静默失败?
【发布时间】:2016-09-27 22:14:37
【问题描述】:

我在自定义 UserControl 中为我一直在制作的视频播放器控件设置了 MediaElement——播放/暂停按钮、滑块、剩余时间等。我将 ScrubbingEnabled 设置为 True这样我就可以根据 SO 帖子 here 向用户显示视频的第一帧,还可以使用 Slider 元素来允许用户清理视频。

问题:我使用绑定来切换视频播放器的来源。有时,如果我在播放视频时切换视频MediaElement 会停止响应Play() 命令。即使在MediaFailed 事件中,也不会给出错误。每次调用Play()(或Pause() 然后Play())都会失败。我可以在MediaElement失败后切换视频源,然后它会重新开始工作。

XAML:

<MediaElement LoadedBehavior="Manual" ScrubbingEnabled="True" 
              UnloadedBehavior="Stop"
              MediaOpened="VideoPlayer_MediaOpened" x:Name="VideoPlayer"/>

相关控制代码:

public static DependencyProperty VideoSourceProperty =
            DependencyProperty.Register("VideoSource", typeof(string), typeof(MediaElementVideoPlayer),
                new FrameworkPropertyMetadata(null,
                    FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure,
                    new PropertyChangedCallback(OnSourceChanged)));

private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    MediaElementVideoPlayer player = d as MediaElementVideoPlayer;
    if (player != null)
    {
        player.Dispatcher.Invoke(() => {
            if (player.VideoSource != null && player.VideoSource != "")
            {
                if (player._isPlaying)
                {
                    player.VideoPlayer.Stop();
                    var uriSource = new Uri(@"/ImageResources/vid-play.png", UriKind.Relative);
                    player.PlayPauseImage.Source = new BitmapImage(uriSource);
                    player._isPlaying = false;
                } 
                player.VideoPlayer.Source = new Uri(player.VideoSource);
            }
        });
    }
}

private void VideoPlayer_MediaOpened(object sender, RoutedEventArgs e)
{
    Dispatcher.Invoke(() =>
    {
        VideoPlayer.Pause();
        VideoPlayer.Position = TimeSpan.FromTicks(0);
        Player.IsMuted = false;
        TimeSlider.Minimum = 0;
        // Set the time slider values & time label
        if (VideoPlayer.NaturalDuration != null && VideoPlayer.NaturalDuration != Duration.Automatic)
        {
            TimeSlider.Maximum = VideoPlayer.NaturalDuration.TimeSpan.TotalSeconds;
            TimeSlider.Value = 0;
            double totalSeconds = VideoPlayer.NaturalDuration.TimeSpan.TotalSeconds;
            _durationString = Utilities.numberSecondsToString((int)totalSeconds, true, true);
            TimeLabel.Content = "- / " + _durationString;
        }
    });
}

如果我让视频一直自动播放,那么播放器会 100% 正常工作,这很奇怪。不幸的是,我需要在设置源时暂停视频。 有谁知道如何避免MediaElement 的随机隐藏故障,同时仍然交换视频、显示加载视频的第一帧等?

herehere 有非常相似的问题,但我的问题有不同的症状,因为我只使用 1 个MediaElement

【问题讨论】:

    标签: c# wpf video mediaelement


    【解决方案1】:

    奇怪的是,如果将ScrubbingEnabled 设置为FalseMediaElement 将不再随机停止响应。禁用ScrubbingEnabled 会中断显示第一帧并使Slider 元素无法正常工作,因此这里介绍了如何在不损坏MediaElement 的情况下保留这些功能。

    显示第一帧:

    private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        MediaElementVideoPlayer player = d as MediaElementVideoPlayer;
        if (player != null)
        {
            player.Dispatcher.Invoke(() => {
                if (player.VideoSource != null && player.VideoSource != "")
                {
                    if (player._isPlaying)
                    {
                        player.VideoPlayer.Stop();
                        var uriSource = new Uri(@"/ImageResources/vid-play.png", UriKind.Relative);
                        player.PlayPauseImage.Source = new BitmapImage(uriSource);
                        player._isPlaying = false;
                    } 
                    player.VideoPlayer.Source = new Uri(player.VideoSource);
                    // Start the video playing so that it will show the first frame. 
                    // We're going to pause it immediately so that it doesn't keep playing.
                    player.VideoPlayer.IsMuted = true; // so sound won't be heard
                    player.VideoPlayer.Play();
                }
            });
        }
    }
    
    private void VideoPlayer_MediaOpened(object sender, RoutedEventArgs e)
    {
        Dispatcher.Invoke(() =>
        {
            // the video thumbnail is now showing!
            VideoPlayer.Pause();
            // reset video to initial position
            VideoPlayer.Position = TimeSpan.FromTicks(0);
            Player.IsMuted = false; // unmute video
            TimeSlider.Minimum = 0;
            // Set the time slider values & time label
            if (VideoPlayer.NaturalDuration != null && VideoPlayer.NaturalDuration != Duration.Automatic)
            {
                TimeSlider.Maximum = VideoPlayer.NaturalDuration.TimeSpan.TotalSeconds;
                TimeSlider.Value = 0;
                double totalSeconds = VideoPlayer.NaturalDuration.TimeSpan.TotalSeconds;
                _durationString = Utilities.numberSecondsToString((int)totalSeconds, true, true);
                TimeLabel.Content = "- / " + _durationString;
            }
        });
    }
    

    在拖动滑块时启用视频拖拽:

    // ValueChanged for Slider
    private void TimeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        Dispatcher.Invoke(() => {
            TimeSpan videoPosition = TimeSpan.FromSeconds(TimeSlider.Value);
            VideoPlayer.Position = videoPosition;
            TimeLabel.Content = Utilities.numberSecondsToString((int)VideoPlayer.Position.TotalSeconds, true, true) + " / " + _durationString;
        });
    }
    
    // DragStarted event
    private void slider_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
    {
        Dispatcher.Invoke(() => {
            VideoPlayer.ScrubbingEnabled = true;
            VideoPlayer.Pause();
        });
    }
    
    // DragCompleted event
    private void slider_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
    {
        Dispatcher.Invoke(() => {
            VideoPlayer.ScrubbingEnabled = false;
            TimeSpan videoPosition = TimeSpan.FromSeconds(TimeSlider.Value);
            VideoPlayer.Position = videoPosition;
            if (_isPlaying) // if was playing when drag started, resume playing
                VideoPlayer.Play();
            else
                VideoPlayer.Pause();
        });
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-26
      • 1970-01-01
      • 2020-08-17
      • 2010-11-23
      • 2018-02-26
      相关资源
      最近更新 更多