声音和视频

WPF 对音频的支持相对于以前版本的 .NET 有了重大改进,但是还有很长的路要走。WPF 提供了播放多种声音格式的能力,包括 MP3 文件以及其他 Windows 媒体播放器支持的所有格式。然而,WPF 的声音功能和 DirectSound 相比仍然相差很远(DirectSound 是 DirectX 中高级音频 API),DirectSound 可以应用动态效果,在仿真的三维场景中放置声音。WPF 还缺乏检索音频数据的方式,以获取声音的高低,该功能对于创建某些类型的合成效果以及声音驱动的动画是非常有用的。

WPF 对视频的支持给人的印象更加深刻。尽管播放视频的功能(例如,播放 MPEG 文件和 WMV 文件)不是 WPF 中最震撼的功能,但是将它集成进 WPF 模型其他部分的方式是动态的。例如,可以使用视频同时填充几千个元素,并且联合使用效果、动画、透明、甚至 3D 对象。


播放 WAV 音频

.NET Framework 对声音的支持有一段简史。1.0 和 1.1 版没有为播放音频提供任何托管的方式,并且在拖了很长时间之后在 .NET 2.0 中才有了支持,且完全是通过 SoundPlayer 类支持声音。SoundPlayer 类的功能非常有限:只能播放 WAV 音频文件,不支持同时播放多个声音,并且没有提供任何控制音频播放任何方面的能力(如音量以及平衡等细节)。为了得到这些功能,使用 Windows 窗体工具包的开发人员必须使用非托管的 quartz.dll 库。

在 WPF 应用程序中仍然支持 SoundPlayer 类。如果能够忍受它的很大的局限性,它仍然是为应用程序添加音频功能最简单、最轻量级的方法。SoundPlayer 类又被 SoundPlayerAction 类进行了包装,使用该类可以通过声明的触发器播放声音。

SoundPlayer 类

使用 SoundPlayer 类播放声音,需要执行以下几个步骤:

  1. 创建一个 SoundPlayer 类的实例。
  2. 通过设置 Stream 属性或者 SoundLocation 属性指定声音内容。如果有一个基于流的包含 WAV 音频内容的对象,就用 Stream 属性。如果有一个指向 WAV 文件的文件路径或 URL,就使用 SoundLocation 属性。
  3. 一旦设置了 Stream 属性或 SoundLocation 属性,就可以通过调用 Load() 方法或 LoadAsync() 方法,通知 SoundPlayer 实例加载音频数据。Load() 方法是最简单的方法 —— 它暂停代码的执行,直到所有的音频数据都被加载到了内存。LoadAsync() 方法悄悄的在另一个线程中进行它的工作,并且当完成工作时引发 LoadCompleted 事件。

    从技术上讲,不需要使用 Load() 方法或者 LoadAsync() 方法。当调用 Play() 方法或 PlayAsync() 方法时,如果需要 SoundPlayer 类会自动加载音频数据。显示的加载音频数据时一个好主意 —— 当需要多次播放音频时不但可以降低开销,而且还使得分别处理与文件相关的异常和与音频播放相关的异常更加容易。

  4. 现在,当播放声音时可以调用 PlaySync() 方法暂停代码,或者可以使用 Play() 方法在另外一个线程中播放声音,确保应用程序的界面保持响应。唯一的另外一个选择是使用 PlayLooping() 方法,该方法永不停止的异步播放音频。若在任何时间为了停止播放,就需调用 Stop() 方法。

SoundPlayer 类不能很好的处理比较大的音频数据,因为它需要一次性的将整个文件加载到内存中。而且 SoundPlayer 类不支持通过以更小的块提交大的音频文件来解决这个问题。没有比较简单的方法可以同步 SoundPlayer 对象,从而逐块的播放多个音频片段,因为它没有提供任何排队功能。

实例

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Margin="10">
            <Button Content="播放"  x:Name="StartButton" Click="StartButton_Click"/>

        </StackPanel>
    </Grid>
</Window>


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Media;
using System.IO;

namespace WpfApplication2
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void StartButton_Click(object sender, RoutedEventArgs e)
        {
            SoundPlayer player = new SoundPlayer();
            player.SoundLocation = "test.wav";

            try
            {
                player.Load();
                player.Play();
            }
            catch (FileNotFoundException ex)
            {
                MessageBox.Show(ex.Message);
            }
            catch (FormatException ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}

SoundPlayerAction 类

SoundPlayerAction 类是 WPF 提供的一个新功能,它使得使用 SoundPlayer 类更加方便。SoundPlayerAction 类继承自 TriggerAction 类,可以使用该类响应任何事件。

实例

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Margin="10">
            <Button Content="播放"  x:Name="StartButton" Click="StartButton_Click"/>
            <Button Content="通过触发器播放">
                <Button.Style>
                    <Style>
                        <Style.Triggers>
                            <EventTrigger RoutedEvent="Button.Click">
                                <EventTrigger.Actions>
                                    <SoundPlayerAction Source="test.wav" />
                                </EventTrigger.Actions>
                            </EventTrigger>
                        </Style.Triggers>
                    </Style>
                </Button.Style>
            </Button>
        </StackPanel>
    </Grid>
</Window>

系统声音

Windows 操作系统能够将音频文件映射到特定的系统事件。除了 SoundPlayer 类之外,.NET 2.0 还引入了一个 System.Media.SystemSounds 类,通过该类可以访问这些声音中的大部分,并且还可以在自己的应用程序中使用它们。如果只希望使用简单的声音信号指示一个长时间运行的操作已经结束,或者使用一个报警声音提示一个警告情况, 这种技术是最有用的。

不过,SystemSounds 类构建在 MessageBeep 这个Win32 API 函数的基础上,因此它只能访问以下通用的系统声音:

  • Asterisk
  • Beep
  • Exclamation
  • Hand
  • Question

MediaPlayer 类

如果希望播放 MP3 音频或 MPEG 视频,就需要使用两个不同的类:MediaPlayer 类和 MediaElement 类。这两个类都依赖于 Windows 媒体播放器提供的技术的关键部分。但存在一个问题 —— 它们需要 Windows 媒体播放器 10 或更新的版本。

基本工作方式:创建一个 MediaPlayer 对象,调用 Open() 方法加载音频文件,并调用 Play() 方法开始异步播放声音(没有提供同步播放的功能)。

private MediaPlayer = new MediaPlayer();

private void cmdPlayWithMediaPlayer(object sender, RoutedEventArgs e)
{
    player.Open(new Uri("test.mp3", UriKind.Relative));
    player.Play();
}

在这个示例中有一些重要的细节需要注意:

  • 在事件处理程序中的外面创建 MediaPlayer 对象,从而该对象在整个窗口的生命期中都处于存活状态。如果在事件处理程序内部创建 MediaPlayer 对象,它会立即从内存中释放并且稍后可能会被垃圾回收器回收,这时会调用 Close() 方法并且会停止播放声音。

    应当创建一个 Window.Unloaded 事件处理程序来调用 Close() 方法,当关闭窗口时,停止所有当前正在播放的音频。

  • 通过 URI 提供文件的位置。不过,URI 不能使用之前学习过的应用程序打包语法,所以不可能嵌入音频文件,并使用 MediaPlayer 类播放它。这一限制是因为 MediaPlayer 类的基础功能不是 WPF 所应有的 —— 反而,它是由不同的。非托管的 Windows 媒体播放器组件提供的。

  • 没有异常处理代码。令人不愉快的是,Open() 方法和 Play() 方法不会抛出异常(异步加载和播放过程有部分责任)。如果希望确定是否正在播放音频,需要处理 MediaOpened 事件和 MediaFailed 事件。

MediaPlayer 类的常用方法、属性和事件。

  • Balance 使用 -1~1 之间的数值设置左声道和右声道之间的平衡,-1 代表只使用左声道,1 代表只使用右声道。
  • Volume 使用 0~1 之间的数值设置音量,0 表示没有音量,1 表示最大音量。
  • SpeedRatio 为播放音频(或视频)设置速度控制器,从而使用比正常速度更快或更慢的速度进行播放。默认值是 1 表示正常速度,而 2 表示正常速度的两倍,0.5 表示正常速度的一半。可以使用任意证的双精度数值。
  • HasAudio、HasVideo 指示当前加载的媒体文件是否分别包含音频或视频。为了显示视频,需要使用 MediaElement 类。
  • NaturalDuration、NaturalVideoHeight、NaturalVideoWidth 指定正常播放的持续时间和视频窗口的尺寸。
  • Position 通过 TimeSpan 对象指定在媒体文件中的当前位置。可以通过设置这个属性跳到特定的时间位置。
  • DownloadProgress、BufferingProgress 指示文件已经下载(如果 Source 是一个指向 Web 或远程计算机的 URL 时非常有用)或者缓冲(如果正在使用的媒体文件使用的是流格式编码,那么它可以在全部下载之前就开始播放)的百分比。百分比数用 0~1 之间的数值表示。
  • MediaClock 获取和设置与这个播放器相关联的 MediaClock 对象。只有当正在将音频同步到时间线时,才使用 MediaClock 对象。如果正在使用 MediaClock 类提供的方法控制播放,这个属性就为 null。
  • Open 加载一个新的媒体文件
  • Play 开始播放。如果文件已经开始播放该方法不起作用
  • Pause 暂停播放但是不会改变播放位置。如果再次调用 Play() 方法,会从当前位置开始播放。如果没有正在播放音频,该方法不起作用。
  • Stop 停止播放并将播放位置重新设置到文件的开头。如果再次调用 Play() 方法,将会从文件的开头播放。如果音频已经停止 ,该方法不起作用。

MediaElement 类

播放视频

MediaElement 类支持 Windows 媒体播放器支持的所有视频格式。如果在 Windows 上安装了解码器,只要解码器支持的格式都可以使用。

视频效果

  • 可以使用 MediaElement 元素作为一个内容控件(如按钮)的内容。
  • 可以同时使用多个 MediaElement 元素作为几千个内容控件设置内容 —— 尽管 CPU 可能不能很好的承受这种压力。
  • 还可以通过 LayoutTransform 属性和 RenderTransform 属性联合使用视频和变换。从而可以移动、拉伸、扭曲或者旋转视频窗口。
  • 可以设置 MediaElement 元素的 Clipping 属性,将视频窗口裁剪为特定的形状或路径,并显示这个窗口的一部分。
  • 可以设置 Opacity 属性,从而使其他内容能够透过视频窗口显示。实际上,甚至可以将多个半透明的视频窗口重叠在一起(当然这会严重的影响性能)。
  • 可以使用 VisualBrush 画刷,将视频窗口中的当前内容复制到用户界面中的其他地方,从而可以创建类似反射的特殊效果。
  • 可以在一个三维对象的表面上放置视频窗口,并且可以使用动画移动正在播放的视频。

语音

对音频和视频的支持是 WPF 平台的核心支柱。然而,WPF 还提供了包装两个用的非常多的媒体功能的库:语音合成和语音识别。

这两个功能都是通过 System.Speech.dll 程序集提供支持。默认情况下,Visual Studio 没有为新的 WPF 项目添加对这个程序集的引用,如果希望使用语音合成和语音识别功能,首先需要为项目添加该引用。

站内公告

A PHP Error was encountered

Severity: Core Warning

Message: PHP Startup: zip: Unable to initialize module Module compiled with module API=20060613 PHP compiled with module API=20090626 These options need to match

Filename: Unknown

Line Number: 0

Backtrace: