读书人

新时尚Windows8开发(29):多媒体捕杀

发布时间: 2012-11-23 22:54:33 作者: rapoo

新时尚Windows8开发(29):多媒体捕捉(高级篇)

这今说的这个所谓高级篇,是相对而言的,就是比上一节说的内容稍稍灵活了一些,不过我想我们在做应用的时候,也很少这么高级去搞,你要说专业的拍摄程序,那压根用不着你做,人家设备提供商就已经开发了,就像我买的Dell的产品,人家就已经提供了一个很强大的拍摄程序了。

不过呢,了解一下,研究一下还是有意义的。这个“高级”内容便是和MediaCapture类有关,主要就是它,你看它的人生阅历不浅,N多个方法,当然,这些方法我们总的来说就可能用到三个,即预览的,拍照片的,录制视频的,是啊你想摄像就这几个用途而已。可能有人说,那视频聊天呢?视频聊天不就动态录制视频呗。

所以,很多事情,我们不必须弄得太复杂,就像今天这例子一样,很简单,不过也许是可以说明其应用价值的。

那么,我们今天玩什么呢?弄一个定时拍摄好不?这还有点意思的。

1、新建项目,不会的回家复习。

2、XAML页面不用多东西,既然要拍东西,那得能够预览摄像头中的内容,这样方便拍摄,所以,先弄一个CaptureElement,这是专门在UI上显晃摄像头预览用的;另外,我们要显示定时拍到的照片,所以,要一个ListView控件;要进行相关操作,需要扔几个按钮。

<Page    x:Class="App1.MainPage"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:local="using:App1"    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    mc:Ignorable="d">    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">        <Grid.RowDefinitions>            <RowDefinition Height="*"/>            <RowDefinition Height="auto"/>        </Grid.RowDefinitions>        <CaptureElement x:Name="ce" Grid.Row="0" Margin="13"/>        <Grid Grid.Row="1">            <Grid.ColumnDefinitions>                <ColumnDefinition Width="*"/>                <ColumnDefinition Width="auto"/>            </Grid.ColumnDefinitions>            <ListView x:Name="lv" Grid.Column="0" Margin="3,2,3,3" SelectionMode="None" Height="150">                <ListView.ItemTemplate>                    <DataTemplate>                        <Image Width="120" Height="120" Stretch="Uniform" Source="{Binding}"/>                    </DataTemplate>                </ListView.ItemTemplate>                <ListView.ItemsPanel>                    <ItemsPanelTemplate>                        <VirtualizingStackPanel Orientation="Horizontal"/>                    </ItemsPanelTemplate>                </ListView.ItemsPanel>            </ListView>            <StackPanel Grid.Column="1" Margin="10">                <Button Content="开始" Click="onStart" x:Name="btnStart"/>                <Button Content="停止" Click="onStop" x:Name="btnStop" IsEnabled="False"/>            </StackPanel>        </Grid>    </Grid></Page>


3、要定时拍摄,自然要有个计时器,这个有,在Windows.System.Threading命名空间下,其名曰:ThreadPoolTimer,我们将用它来计时。

先引入以下命名空间:

using Windows.System.Threading;using System.Collections.ObjectModel;using Windows.UI.Xaml.Media.Imaging;using Windows.Media.Capture;using Windows.Media.MediaProperties;using Windows.Storage.Streams;


在MainPage类中定义以下成员:

    public sealed partial class MainPage : Page    {        ObservableCollection<BitmapImage> images = null;        MediaCapture myCapture = null;        ThreadPoolTimer myTimer = null;


在MainPage的构造函数里面帮它们化妆一下。

        public  MainPage()        {            this.InitializeComponent();            this.myCapture = new MediaCapture();            this.images = new ObservableCollection<BitmapImage>();            this.lv.ItemsSource = images;        }


我们希望在导航到页面时就开启摄像头并开始预览,所以,在OnNavigatedTo方法中要做点手脚。

        protected override async void OnNavigatedTo(NavigationEventArgs e)        {            await this.myCapture.InitializeAsync();            this.ce.Source = myCapture;            await this.myCapture.StartPreviewAsync();        }


ThreadPoolTimer类是通过调用一个静态方法CreatePeriodicTimer来创建计时器的,而我们看到这个方法的两个重载中,参数都需要一个委托,这个委托要绑定一个方法,当计时器到了执行任务的时间,就会调用这个委托,从而调用指定的方法。

所以我们要先定义好这个处理方法:

        private async void timerHandler(ThreadPoolTimer t)        {            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>                {                    IRandomAccessStream stream = new InMemoryRandomAccessStream();                    await myCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreatePng(), stream);                    // 在向流写入数据时,已经把指针移到结尾处                    // 所以在初始化图像是要先把指针移回开始位置                    stream.Seek(0);                    BitmapImage bmpimg = new BitmapImage();                    bmpimg.SetSource(stream);                    this.images.Add(bmpimg);                });        }


注意,在调用CreatePeriodicTimer方法成功返回后就马上开始计时了,如果要取消计时,就调用Cancel方法。

4、这时候,我们需要的组件代码基本可以了,下面就处理那两个控制开始拍摄和停止拍摄的按钮的Click事件。

        private void onStop(object sender, RoutedEventArgs e)        {            if (this.myTimer != null)            {                this.myTimer.Cancel(); //取消            }            btnStop.IsEnabled = false;            btnStart.IsEnabled = true;        }        private void onStart(object sender, RoutedEventArgs e)        {            this.images.Clear();             // 开始计时            this.myTimer = ThreadPoolTimer.CreatePeriodicTimer(timerHandler, TimeSpan.FromSeconds(5));            btnStart.IsEnabled = false;            btnStop.IsEnabled = true;        }


完整的代码如下:

using System;using System.Collections.Generic;using System.IO;using System.Linq;using Windows.Foundation;using Windows.Foundation.Collections;using Windows.UI.Xaml;using Windows.UI.Xaml.Controls;using Windows.UI.Xaml.Controls.Primitives;using Windows.UI.Xaml.Data;using Windows.UI.Xaml.Input;using Windows.UI.Xaml.Media;using Windows.UI.Xaml.Navigation;using Windows.System.Threading;using System.Collections.ObjectModel;using Windows.UI.Xaml.Media.Imaging;using Windows.Media.Capture;using Windows.Media.MediaProperties;using Windows.Storage.Streams;// “空白页”项模板在 http://go.microsoft.com/fwlink/?LinkId=234238 上有介绍namespace App1{    /// <summary>    /// 可用于自身或导航至 Frame 内部的空白页。    /// </summary>    public sealed partial class MainPage : Page    {        ObservableCollection<BitmapImage> images = null;        MediaCapture myCapture = null;        ThreadPoolTimer myTimer = null;        public  MainPage()        {            this.InitializeComponent();            this.myCapture = new MediaCapture();            this.images = new ObservableCollection<BitmapImage>();            this.lv.ItemsSource = images;        }        /// <summary>        /// 在此页将要在 Frame 中显示时进行调用。        /// </summary>        /// <param name="e">描述如何访问此页的事件数据。Parameter        /// 属性通常用于配置页。</param>        protected override async void OnNavigatedTo(NavigationEventArgs e)        {            await this.myCapture.InitializeAsync();            this.ce.Source = myCapture;            await this.myCapture.StartPreviewAsync();        }        private async void timerHandler(ThreadPoolTimer t)        {            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>                {                    IRandomAccessStream stream = new InMemoryRandomAccessStream();                    await myCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreatePng(), stream);                    // 在向流写入数据时,已经把指针移到结尾处                    // 所以在初始化图像是要先把指针移回开始位置                    stream.Seek(0);                    BitmapImage bmpimg = new BitmapImage();                    bmpimg.SetSource(stream);                    this.images.Add(bmpimg);                });        }        private void onStop(object sender, RoutedEventArgs e)        {            if (this.myTimer != null)            {                this.myTimer.Cancel(); //取消            }            btnStop.IsEnabled = false;            btnStart.IsEnabled = true;        }        private void onStart(object sender, RoutedEventArgs e)        {            this.images.Clear();             // 开始计时            this.myTimer = ThreadPoolTimer.CreatePeriodicTimer(timerHandler, TimeSpan.FromSeconds(5));            btnStart.IsEnabled = false;            btnStop.IsEnabled = true;        }    }}


5、打开清单文件,切换到“功能”选项卡,同时勾选“麦克风”和“网络摄像机”,并保存。

6、运行应用程序,等预览开始后,点击“开始”按钮,程序就会每隔5秒钟(因为代码中指定的是秒)拍摄一张照片,并显示在ListView中。

新时尚Windows8开发(29):多媒体捕杀(高级篇)

读书人网 >windows

热点推荐