如何在 Windows Phone 的相机应用程序中录制视频

2012/2/9

使用 Windows Phone OS 7.1,您可以采用编程方式访问设备相机。除了拍摄照片之外,您还可以使用设备相机拍摄视频。本主题介绍如何创建录像机应用程序并演示如何拍摄、显示以及如何将视频存储在 Windows Phone 应用程序中。有关如何使用设备相机拍摄照片的信息,请参阅如何为 Windows Phone 创建基本相机应用程序

注意注意:

本主题与录像机示例相对应。若要下载完整的项目,请参阅 Windows Phone 的代码示例

本主题涉及以下步骤:

  1. 创建应用程序和 UI

  2. 更新 UI

  3. 初始化相机

  4. 在预览和录制之间切换相机状态

  5. 处理按钮点按

  6. 处置录制和播放对象

  7. 完成应用程序

下图显示已完成的应用程序示例。

AP_Con_CameraVideoHowTo

在录制期间,该应用程序使用 FileSink 类传递 CaptureSource 对象中的视频并通过 IsolatedStorageFileStream 对象将其存储到独立存储。若要为应用程序提供相机取景器,也可以使用 CaptureSource 作为 VideoBrush 控件的源。当 CaptureSource 连接到 FileSink 或将前者从后者中删除时,不能运行前者。如果在连接到 FileSink 时运行 CaptureSource,则会发生视频录制。

为了播放录制的视频,IsolatedStorageFileStream 对象读取录制的视频文件并将其作为 MediaElement 控件的源提供。有关如何实现该应用程序的更多信息,请参阅以下各节。

在本节中,您创建应用程序并为开发准备该应用程序。

注意注意:

当升级 Windows Phone OS 7.0 应用程序以使用 Windows Phone OS 7.1 中的功能时,相机功能 ID_CAP_ISV_CAMERA 不会自动添加到应用程序清单文件 WMAppManifest.xml 中。如果没有 ID_CAP_ISV_CAMERA,则使用相机 API 的应用程序将无法工作。在新的 Windows Phone OS 7.1 项目中,该功能包含在应用程序的清单文件中。

以下过程中的步骤用于 Visual Studio 2010 Express for Windows Phone。 当您使用用于 Visual Studio 2010 Professional 或 Visual Studio 2010 Ultimate 的插件时,您可能会看到菜单命令或窗口布局中的一些微小改变。

创建应用程序

  1. 在 Visual Studio 2010 Express for Windows Phone 中,通过选择“文件 | 新建项目”菜单命令创建一个新项目。

  2. 将显示“新建项目”窗口。展开“Visual C#”模板,然后选择“Silverlight for Windows Phone”模板。

  3. 选择“Windows Phone 应用程序”模板。用您选择的名称填写“名称”框。

  4. 单击“确定”。将显示“新建 Windows Phone 应用程序”窗口。

  5. “Windows Phone 目标版本”菜单中,确保已选择 Windows Phone 7.1。

  6. 单击“确定”。将创建一个新的项目,并且“MainPage.xaml”将在 Visual Studio 设计器窗口中打开。

指定应用程序功能

  1. 若要创建相机应用程序,必须在应用程序清单文件中声明相机功能。由于视频应用程序还录制声音,因此还必须声明麦克风功能。如果不声明这些功能,此应用程序将无法使用。打开 WMAppManifest.xml 并确认其中存在以下功能元素。

    <Capability Name="ID_CAP_ISV_CAMERA"/>
    <Capability Name="ID_CAP_MICROPHONE"/>
    
    

    重要说明重要说明:

    在使用 CaptureSource 类的 Windows Phone 应用程序中,您还必须使用 Microsoft.Devices.CameraMicrosoft.Devices.PhotoCameraMicrosoft.Xna.Framework.Audio.Microphone 类,在应用程序中启用音频捕获和准确的功能检测。

    尽管此特定的应用程序不需要上述任何类,但仍还需包含其中一个类的代码,用来提示商城功能检测过程在摄取时将 ID_CAP_MICROPHONE 功能添加到应用程序功能列表中。有关示例,请参阅 Windows Phone 的代码示例“录像机示例”中的 CapabilityPlaceholder 文件。

  2. (可选)如果要使应用程序要求正面相机,请额外将正面相机功能添加到应用程序清单文件中的 Capabilities 元素。

    <Capability Name="ID_HW_FRONTCAMERA"/>
    

    此功能将不会自动添加到新项目,必须手动添加。没有正面相机的用户将收到通知,说明他们的设备不符合您应用程序的要求,不过它们仍然可以选择下载该功能。此应用程序不专门使用正面相机;此应用程序不要求此功能。有关更多信息,请参阅 Windows Phone 的相机和照片概述中的功能部分。

添加应用程序所使用的图标

  1. “解决方案资源管理器”中,右键单击项目,选择“添加”,然后选择“新文件夹”

  2. 将新文件夹命名为 Icons

  3. “解决方案资源管理器”中,右键单击 Icons 文件夹,选择“添加”,然后选择“现有项”。这将打开“添加现有项”菜单,从中您可以选择应用程序使用的图标。

  4. “添加现有项”窗口中,导航到以下路径之一以选择这些图标。此步骤假定采用的是以默认方式安装的 Visual Studio。如果您将其安装在其他位置,则在相应的位置查找图标。

    • 64 位操作系统C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.1\Icons\dark

    • 32 位操作系统C:\Program Files\Microsoft SDKs\Windows Phone\v7.1\Icons\dark

    从该文件夹中,选择以下图标:

    • appbar.feature.video.rest.png

    • appbar.stop.rest.png

    • appbar.transport.pause.rest.png

    • appbar.transport.play.rest.png

    这些图标是专门用深色背景设计的并且颜色为白色;在白色的“添加现有项”窗口背景上图标可能显示为空白。

  5. “解决方案资源管理器”中,右键单击每个图标并设置文件属性,以便将图标生成为“内容”,并始终复制到输出目录(“始终复制”)。

生成 UI

  1. MainPage.xaml 上,更新 phone:PhoneApplicationPage 元素,如以下代码中所示。

    SupportedOrientations="Landscape" Orientation="LandscapeLeft"
        shell:SystemTray.IsVisible="False"
    
    

    该代码隐藏系统托盘并且使应用程序保持横向。不能旋转 CaptureSource 对象中的视频;如果是面朝下拍摄的,则也是面朝下录制视频。

    注意注意:

    可以旋转 PhotoCamera 类中的图像。有关如何执行此操作的示例,请参阅如何为 Windows Phone 创建基本相机应用程序

  2. MainPage.xaml 中,将名为 LayoutRootGrid 替换为以下代码。

        <!--LayoutRoot is the root grid where all page content is placed-->
        <Canvas x:Name="LayoutRoot" Background="Transparent">
    
            <!--Camera viewfinder >-->
            <Rectangle 
                x:Name="viewfinderRectangle"
                Width="640" 
                Height="480" 
                HorizontalAlignment="Left" 
                Canvas.Left="80"/>
    
            <MediaElement 
                x:Name="VideoPlayer" 
                Width="640" 
                Height="480"
                AutoPlay="True" 
                RenderTransformOrigin="0.5, 0.5" 
                VerticalAlignment="Center" 
                HorizontalAlignment="Center" 
                Stretch="Fill"
                Canvas.Left="80"/>
    
            <!--Used for debugging >-->
            <TextBlock 
                Height="40" 
                HorizontalAlignment="Left" 
                Margin="100,428,0,0"
                Name="txtDebug" 
                VerticalAlignment="Top"
                Width="626"
                FontSize="24" 
                FontWeight="ExtraBold"/>
    
        </Canvas>
    
    

    该代码指定一个名为 viewfinderRectangleRectangle、一个名为 VideoPlayerMediaElement 和一个名为 txtDebugTextBlockviewfinderRectangle 用于显示 CaptureSource 对象中的视频图像,VideoPlayer 用于在保存到独立存储之后播放录制的视频,txtDebug 用于交流应用程序状态。

  3. MainPage.xaml 的名为 LayoutRootGrid 下面添加以下代码。

        <phone:PhoneApplicationPage.ApplicationBar>
            <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True" x:Name="PhoneAppBar" Opacity="0.0">
                <shell:ApplicationBarIconButton IconUri="/Icons/appbar.feature.video.rest.png" Text="record"  x:Name="StartRecording" Click="StartRecording_Click" />
                <shell:ApplicationBarIconButton IconUri="/Icons/appbar.stop.rest.png" Text="stop" x:Name="StopPlaybackRecording" Click="StopPlaybackRecording_Click"/>
                <shell:ApplicationBarIconButton IconUri="/Icons/appbar.transport.play.rest.png" Text="play" x:Name="StartPlayback" Click="StartPlayback_Click"  />
                <shell:ApplicationBarIconButton IconUri="/Icons/appbar.transport.pause.rest.png" Text="pause" x:Name="PausePlayback" Click="PausePlayback_Click"/>
            </shell:ApplicationBar>
        </phone:PhoneApplicationPage.ApplicationBar>
    
    

    该代码指定一个具有四个按钮的应用程序栏:recordstopplaypause。在该应用程序中,stop 按钮用于停止录制和播放。有关使用应用程序栏的更多信息,请参阅 Windows Phone 的应用程序栏概述

准备代码隐藏文件

  1. 在主页的代码隐藏文件 MainPage.xaml.cs 中,向应用程序中添加以下指令。

    // Directives
    using System.ComponentModel;
    using System.Threading;
    using System.IO;
    using System.IO.IsolatedStorage;
    using Microsoft.Phone.Shell;
    using System.Windows.Navigation;
    using Microsoft.Devices;
    
    
  2. MainPage.xaml.cs 中,在 MainPage 构造函数上面添加以下变量。

    // Viewfinder for capturing video.
    private VideoBrush videoRecorderBrush;
    
    // Source and device for capturing video.
    private CaptureSource captureSource;
    private VideoCaptureDevice videoCaptureDevice;
    
    // File details for storing the recording.        
    private IsolatedStorageFileStream isoVideoFile;
    private FileSink fileSink;
    private string isoVideoFileName = "CameraMovie.mp4";
    
    // For managing button and application state.
    private enum ButtonState { Initialized, Ready, Recording, Playback, Paused, NoChange, CameraNotSupported };
    private ButtonState currentAppState;
    
    

    该代码声明稍后在应用程序中使用的变量。

  3. MainPage.xaml.cs 中,向 MainPage 构造函数中添加以下代码,放在 InitializeComponent 调用的正下方。

    // Prepare ApplicationBar and buttons.
    PhoneAppBar = (ApplicationBar)ApplicationBar;
    PhoneAppBar.IsVisible = true;
    StartRecording = ((ApplicationBarIconButton)ApplicationBar.Buttons[0]);
    StopPlaybackRecording = ((ApplicationBarIconButton)ApplicationBar.Buttons[1]);
    StartPlayback = ((ApplicationBarIconButton)ApplicationBar.Buttons[2]);
    PausePlayback = ((ApplicationBarIconButton)ApplicationBar.Buttons[3]);
    
    

    在此代码中,指定了应用程序栏按钮,以便它们能够在代码中引用。有关应用程序栏的更多信息,请参阅 Windows Phone 的应用程序栏概述

  4. MainPage.xaml.cs 中,向 MainPage 类中添加以下代码。

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
    
        // Initialize the video recorder.
        InitializeVideoRecorder();
    }
    
    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
        // Dispose of camera and media objects.
        DisposeVideoPlayer();
        DisposeVideoRecorder();
    
        base.OnNavigatedFrom(e);
    }
    

    当导航离开页面时处置与相机相关的对象和事件处理程序,这一点非常重要。这有助于在未使用应用程序时释放内存。每次导航页面时,都需要启动录制操作工作线程和相机对象(如果这些对象未运行)。

为了提高该代码的可读性,使用一个枚举和方法通过应用程序的各种状态来管理应用程序栏按钮的可见性。方法 UpdateUI 也更新 txtDebug。通过提取单个方法调用的 UI 更新,应用程序的其他部分需要很少代码。

更新 UI

  • 在主页的代码隐藏文件 MainPage.xaml.cs 中,向 MainPage 类中添加以下代码。

    // Update the buttons and text on the UI thread based on app state.
    private void UpdateUI(ButtonState currentButtonState, string statusMessage)
    {
        // Run code on the UI thread.
        Dispatcher.BeginInvoke(delegate
        {
    
            switch (currentButtonState)
            {
                // When the camera is not supported by the device.
                case ButtonState.CameraNotSupported:
                    StartRecording.IsEnabled = false;
                    StopPlaybackRecording.IsEnabled = false;
                    StartPlayback.IsEnabled = false;
                    PausePlayback.IsEnabled = false;
                    break;
    
                // First launch of the application, so no video is available.
                case ButtonState.Initialized:
                    StartRecording.IsEnabled = true;
                    StopPlaybackRecording.IsEnabled = false;
                    StartPlayback.IsEnabled = false;
                    PausePlayback.IsEnabled = false;
                    break;
    
                // Ready to record, so video is available for viewing.
                case ButtonState.Ready:
                    StartRecording.IsEnabled = true;
                    StopPlaybackRecording.IsEnabled = false;
                    StartPlayback.IsEnabled = true;
                    PausePlayback.IsEnabled = false;
                    break;
    
                // Video recording is in progress.
                case ButtonState.Recording:
                    StartRecording.IsEnabled = false;
                    StopPlaybackRecording.IsEnabled = true;
                    StartPlayback.IsEnabled = false;
                    PausePlayback.IsEnabled = false;
                    break;
    
                // Video playback is in progress.
                case ButtonState.Playback:
                    StartRecording.IsEnabled = false;
                    StopPlaybackRecording.IsEnabled = true;
                    StartPlayback.IsEnabled = false;
                    PausePlayback.IsEnabled = true;
                    break;
    
                // Video playback has been paused.
                case ButtonState.Paused:
                    StartRecording.IsEnabled = false;
                    StopPlaybackRecording.IsEnabled = true;
                    StartPlayback.IsEnabled = true;
                    PausePlayback.IsEnabled = false;
                    break;
    
                default:
                    break;
            }
    
            // Display a message.
            txtDebug.Text = statusMessage;
    
            // Note the current application state.
            currentAppState = currentButtonState;
        });
    }
    
    

    该代码更新应用程序栏按钮和应用程序状态。它使用 BeginInvoke 方法以便可以在 UI 线程上执行语句。为了进一步简化代码,使用一个名为 ButtonState 的枚举来指定应用程序的状态。

在本节中,您初始化 CaptureSourceFileSink 对象,并且显示描述如何开始使用应用程序的消息。

初始化相机

  • 在主页的代码隐藏文件 MainPage.xaml.cs 中,向 MainPage 类中添加以下代码。

    public void InitializeVideoRecorder()
    {
        if (captureSource == null)
        {
            // Create the VideoRecorder objects.
            captureSource = new CaptureSource();
            fileSink = new FileSink();
    
            videoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
    
            // Add eventhandlers for captureSource.
            captureSource.CaptureFailed += new EventHandler<ExceptionRoutedEventArgs>(OnCaptureFailed);
    
            // Initialize the camera if it exists on the device.
            if (videoCaptureDevice != null)
            {
                // Create the VideoBrush for the viewfinder.
                videoRecorderBrush = new VideoBrush();
                videoRecorderBrush.SetSource(captureSource);
    
                // Display the viewfinder image on the rectangle.
                viewfinderRectangle.Fill = videoRecorderBrush;
    
                // Start video capture and display it on the viewfinder.
                captureSource.Start();
    
                // Set the button state and the message.
                UpdateUI(ButtonState.Initialized, "Tap record to start recording...");
            }
            else
            {
                // Disable buttons when the camera is not supported by the device.
                UpdateUI(ButtonState.CameraNotSupported, "A camera is not supported on this device.");
            }
        }
    }
    
    

    该代码每次导航应用程序时执行大量任务。尽管创建了 fileSink,但它未连接到 captureSource,直到用户想录制视频为止。在这之前,未将任何视频保存到独立存储。

    静态方法 GetDefaultVideoCaptureDevicecaptureSource 连接到设备上的主要相机。若要提供相机取景器,将 captureSource 设置为用于填充 viewfinderRectangleVideoBrush 的源。直到 captureSource 启动,视频图像才会显示在取景器上。

    提示提示:

    如果设备支持多个相机,则使用 GetAvailableVideoCaptureDevices 方法来获得视频拍摄设备的集合。例如,某些设备可能具有一个面向正面的相机,还有另一个位于设备背面的相机。还有可能设备没有相机。这种情况下,使用 CameraNotSupported 按钮状态来禁用应用程序栏按钮。

在本节中,您添加在预览和录制之间更改相机状态的代码。在本主题的上下文中,“录制”视频意味着正在将相机中的视频流式传输到独立存储中的某个文件。为此,将 fileSink 连接到 captureSource,然后在您希望保持在视频文件中的时间段内运行 captureSource。当 captureSource 未运行或 fileSink 未连接到 captureSource 时,视频将不会流式传输到独立存储中的文件。

在预览和录制之间切换相机状态

  • MainPage.xaml.cs 中,向 MainPage 类中添加以下代码。

    // Set recording state: start recording.
    private void StartVideoRecording()
    {
        try
        {
            // Connect fileSink to captureSource.
            if (captureSource.VideoCaptureDevice != null
                && captureSource.State == CaptureState.Started)
            {
                captureSource.Stop();
    
                // Connect the input and output of fileSink.
                fileSink.CaptureSource = captureSource;
                fileSink.IsolatedStorageFileName = isoVideoFileName;
            }
    
            // Begin recording.
            if (captureSource.VideoCaptureDevice != null
                && captureSource.State == CaptureState.Stopped)
            {
                captureSource.Start();
            }
    
            // Set the button states and the message.
            UpdateUI(ButtonState.Recording, "Recording...");
        }
    
        // If recording fails, display an error.
        catch (Exception e)
        {
            this.Dispatcher.BeginInvoke(delegate()
            {
                txtDebug.Text = "ERROR: " + e.Message.ToString();
            });
        }
    }
    
    // Set the recording state: stop recording.
    private void StopVideoRecording()
    {
        try
        {
            // Stop recording.
            if (captureSource.VideoCaptureDevice != null
            && captureSource.State == CaptureState.Started)
            {
                captureSource.Stop();
    
                // Disconnect fileSink.
                fileSink.CaptureSource = null;
                fileSink.IsolatedStorageFileName = null;
    
                // Set the button states and the message.
                UpdateUI(ButtonState.NoChange, "Preparing viewfinder...");
    
                StartVideoPreview();
            }
        }
        // If stop fails, display an error.
        catch (Exception e)
        {
            this.Dispatcher.BeginInvoke(delegate()
            {
                txtDebug.Text = "ERROR: " + e.Message.ToString();
            });
        }
    }
    
    // Set the recording state: display the video on the viewfinder.
    private void StartVideoPreview()
    {
        try
        {
            // Display the video on the viewfinder.
            if (captureSource.VideoCaptureDevice != null
            && captureSource.State == CaptureState.Stopped)
            {
                // Add captureSource to videoBrush.
                videoRecorderBrush.SetSource(captureSource);
    
                // Add videoBrush to the visual tree.
                viewfinderRectangle.Fill = videoRecorderBrush;
    
                captureSource.Start();
    
                // Set the button states and the message.
                UpdateUI(ButtonState.Ready, "Ready to record.");
            }
        }
        // If preview fails, display an error.
        catch (Exception e)
        {
            this.Dispatcher.BeginInvoke(delegate()
            {
                txtDebug.Text = "ERROR: " + e.Message.ToString();
            });
        }
    }
    

    该代码更新相机的录制状态。StartVideoRecording 方法停止 captureSource,将 fileSink 连接到相机和独立存储,然后再次启动 captureSourceStopVideoRecording 方法停止 captureSource 并断开 fileSink 与相机和独立存储的连接。StartVideoPreview 方法将 captureSource 重新连接到取景器,然后启动它。

在本节中,您添加四个应用程序栏按钮的代码:“录制”“停止”“播放”“暂停”。为了避免通过点按两次重复调用这些方法,每个方法会立即禁用相应的按钮。

在应用程序 UI 中一次只能显示一个视频流。视频播放之前,视频预览控件已从可视化树中删除,在视频预览之前反之亦然。删除是由稍后在本主题中创建的方法 DisposeVideoPlayerDisposeVideoRecorder 执行。

处理按钮点按

  • MainPage.xaml.cs 中,向 MainPage 类中添加以下代码。

    // Start the video recording.
    private void StartRecording_Click(object sender, EventArgs e)
    {
        // Avoid duplicate taps.
        StartRecording.IsEnabled = false;
    
        StartVideoRecording();
    }
    
    // Handle stop requests.
    private void StopPlaybackRecording_Click(object sender, EventArgs e)
    {
        // Avoid duplicate taps.
        StopPlaybackRecording.IsEnabled = false;
    
        // Stop during video recording.
        if (currentAppState == ButtonState.Recording)
        {
            StopVideoRecording();
    
            // Set the button state and the message.
            UpdateUI(ButtonState.NoChange, "Recording stopped.");
        }
    
        // Stop during video playback.
        else
        {
            // Remove playback objects.
            DisposeVideoPlayer();
    
            StartVideoPreview();
    
            // Set the button state and the message.
            UpdateUI(ButtonState.NoChange, "Playback stopped.");
        }
    }
    
    // Start video playback.
    private void StartPlayback_Click(object sender, EventArgs e)
    {
        // Avoid duplicate taps.
        StartPlayback.IsEnabled = false;
    
        // Start video playback when the file stream exists.
        if (isoVideoFile != null)
        {
            VideoPlayer.Play();
        }
        // Start the video for the first time.
        else
        {
            // Stop the capture source.
            captureSource.Stop();
    
            // Remove VideoBrush from the tree.
            viewfinderRectangle.Fill = null;
    
            // Create the file stream and attach it to the MediaElement.
            isoVideoFile = new IsolatedStorageFileStream(isoVideoFileName,
                                    FileMode.Open, FileAccess.Read,
                                    IsolatedStorageFile.GetUserStoreForApplication());
    
            VideoPlayer.SetSource(isoVideoFile);
    
            // Add an event handler for the end of playback.
            VideoPlayer.MediaEnded += new RoutedEventHandler(VideoPlayerMediaEnded);
    
            // Start video playback.
            VideoPlayer.Play();
        }
    
        // Set the button state and the message.
        UpdateUI(ButtonState.Playback, "Playback started.");
    }
    
    // Pause video playback.
    private void PausePlayback_Click(object sender, EventArgs e)
    {
        // Avoid duplicate taps.
        PausePlayback.IsEnabled = false;
    
        // If mediaElement exists, pause playback.
        if (VideoPlayer != null)
        {
            VideoPlayer.Pause();
        }
    
        // Set the button state and the message.
        UpdateUI(ButtonState.Paused, "Playback paused.");
    }
    
    
    

    该代码处理应用程序栏上的按钮点按。StartRecording_Click 方法通过调用 StartVideoRecording 方法开始录制。

    StopPlaybackRecording_Click 方法停止视频录制或视频播放,具体情况取决于应用程序的状态。在视频录制期间,该方法调用 StopVideoRecording 方法以断开 fileSinkcaptureSource 的连接。在视频播放期间,该方法处置视频播放对象并调用 StartVideoPreview 方法以在取景器上显示视频。

    StartPlayback_Click 方法停止 captureSource,然后将 VideoPlayer MediaElement 控件连接到独立存储中的视频文件 CameraMovie.mp4。当调用 VideoPlayerPlay 方法时,在屏幕上显示视频。当视频的播放结束时,MediaEnded 事件的事件处理程序确保该应用程序返回预览状态。

在本节中,您添加处置视频播放和视频录制对象的代码。在应用程序 UI 中一次只能运行一个视频流。这些方法用于停止一个流以便可以启动其他流。它们还删除相应对象的事件处理程序以便在不使用这些对象时帮助释放内存。

处置录制和播放对象

  • MainPage.xaml.cs 中,向 MainPage 类中添加以下代码。

    private void DisposeVideoPlayer()
    {
        if (VideoPlayer != null)
        {
            // Stop the VideoPlayer MediaElement.
            VideoPlayer.Stop();
    
            // Remove playback objects.
            VideoPlayer.Source = null;
            isoVideoFile = null;
    
            // Remove the event handler.
            VideoPlayer.MediaEnded -= VideoPlayerMediaEnded;
        }
    }
    
    private void DisposeVideoRecorder()
    {
        if (captureSource != null)
        {
            // Stop captureSource if it is running.
            if (captureSource.VideoCaptureDevice != null
                && captureSource.State == CaptureState.Started)
            {
                captureSource.Stop();
            }
    
            // Remove the event handler for captureSource.
            captureSource.CaptureFailed -= OnCaptureFailed;
    
            // Remove the video recording objects.
            captureSource = null;
            videoCaptureDevice = null;
            fileSink = null;
            videoRecorderBrush = null;
        }
    }
    
    

    尽管这些对象都不实现 Dispose 方法,但将它们设置为等于 null 将允许垃圾收集器在需要时回收这些对象使用的内存。

在本节中,您添加剩余的代码并启动该应用程序。

完成应用程序

  1. MainPage.xaml.cs 中,向 MainPage 类中添加以下代码。

    // If recording fails, display an error message.
    private void OnCaptureFailed(object sender, ExceptionRoutedEventArgs e)
    {
        this.Dispatcher.BeginInvoke(delegate()
        {
            txtDebug.Text = "ERROR: " + e.ErrorException.Message.ToString();
        });
    }
    
    // Display the viewfinder when playback ends.
    public void VideoPlayerMediaEnded(object sender, RoutedEventArgs e)
    {
        // Remove the playback objects.
        DisposeVideoPlayer();
    
        StartVideoPreview();
    }
    
    

    该代码分别处理 CaptureSource 中的 CaptureFailed 事件以及 MediaPlayer 对象中的 MediaEnded 事件。

  2. 现在您已经完成了该应用程序。按 F5 开始调试并测试该应用程序。

显示: