與眾不同 windows phone (21) - Device(設備)之攝像頭(拍攝照片, 錄制視頻)
作者:webabcd
介紹
與眾不同 windows phone 7.5 (sdk 7.1) 之設備
- 用攝像頭拍攝照片
- 用攝像頭錄制視頻
示例
1、演示如何使用攝像頭拍攝照片
ImageDemo.xaml
<phone:PhoneApplicationPage x:Class="Demo.Device.Camera.ImageDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Landscape" Orientation="Landscape" mc:Ignorable="d" d:DesignHeight="480" d:DesignWidth="800" shell:SystemTray.IsVisible="False"> <Grid x:Name="LayoutRoot" Background="Transparent"> <StackPanel Orientation="Vertical"> <StackPanel Orientation="Horizontal"> <Canvas Width="320" Height="240"> <Canvas.Background> <VideoBrush x:Name="videoBrush" /> </Canvas.Background> </Canvas> <!--顯示拍攝到的圖片--> <Image Name="imgCapture" Width="320" Height="240" Margin="20 0 0 0" /> <!--顯示拍攝到的圖片的縮略圖--> <Image Name="imgCaptureThumbnail" Width="32" Height="24" Margin="20 0 0 0" /> </StackPanel> <StackPanel Orientation="Horizontal"> <Button x:Name="btnShutter" Content="快門" Click="btnShutter_Click" /> <Button x:Name="btnFlash" Content="閃光燈" Click="btnFlash_Click" /> <Button x:Name="btnResolution" Content="分辨率" Click="btnResolution_Click" /> </StackPanel> <TextBlock Name="lblMsg" /> </StackPanel> </Grid> </phone:PhoneApplicationPage>
ImageDemo.xaml.cs
/* * 演示如何使用攝像頭拍攝照片 * * PhotoCamera - 用於提供相機功能 * CameraType - 攝像頭的類型(Microsoft.Devices.CameraType 枚舉) * Primary - 主攝像頭 * FrontFacing - 前置攝像頭 * AvailableResolutions - 獲取攝像頭的可用分辨率集合(返回一個 IEnumerable<Size> 類型的對象) * FlashMode - 相機的閃光燈模式(Microsoft.Devices.FlashMode 枚舉) * On - 啟用閃光燈 * Off - 禁用閃光燈 * Auto - 自動閃光燈 * RedEyeReduction - 消除紅眼閃光燈 * Resolution - 相機的分辨率 * Orientation - 取景器與相機傳感器對齊所需要順時針旋轉的度數(只讀) * * CaptureImage() - 拍攝相機當前捕獲到的照片 * IsFlashModeSupported(FlashMode mode) - 相機是否支持指定的閃光燈模式 * * Initialized - 相機初始化時觸發的事件(事件參數為 CameraOperationCompletedEventArgs 類型) * CaptureStarted - 相機開始捕獲圖片時觸發的事件 * CaptureCompleted - 相機捕獲圖片完成時觸發的事件(事件參數為 CameraOperationCompletedEventArgs 類型) * CaptureImageAvailable - 獲得了捕獲到的圖片時觸發的事件(事件參數為 ContentReadyEventArgs 類型) * CaptureThumbnailAvailable - 獲得了捕獲到的圖片的縮略圖時觸發的事件(事件參數為 ContentReadyEventArgs 類型) * * * CameraOperationCompletedEventArgs * Succeeded - 操作是否成功 * Exception - 異常信息 * * * ContentReadyEventArgs * ImageStream - 獲取到的圖像流 * * * 注:如果要求只使用前置攝像頭的話,則在 manifest 中添加 <Capability Name="ID_HW_FRONTCAMERA"/> */ using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; using Microsoft.Devices; using System.IO; using System.IO.IsolatedStorage; using Microsoft.Xna.Framework.Media; using System.Windows.Navigation; using System.Windows.Media.Imaging; namespace Demo.Device.Camera { public partial class ImageDemo : PhoneApplicationPage { private PhotoCamera _camera; // 當前使用的攝像頭分辨率在攝像頭支持的分辨率集合中的索引 private int _currentResolutionIndex = 0; public ImageDemo() { InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { // 設備是否支持主攝像頭 if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary)) { // 獲取主攝像頭,並注冊相關事件 _camera = new PhotoCamera(CameraType.Primary); _camera.Initialized += _camera_Initialized; _camera.CaptureStarted += _camera_CaptureStarted; _camera.CaptureCompleted += _camera_CaptureCompleted; _camera.CaptureImageAvailable += _camera_CaptureImageAvailable; _camera.CaptureThumbnailAvailable += _camera_CaptureThumbnailAvailable; // 在 VideoBrush 上顯示攝像頭捕獲到的實時信息 videoBrush.SetSource(_camera); lblMsg.Text = "設備的主攝像頭正在工作"; } else { lblMsg.Text = "此設備沒有主攝像頭"; btnShutter.IsEnabled = false; btnFlash.IsEnabled = false; btnResolution.IsEnabled = false; } } protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) { // 釋放相關資源 if (_camera != null) { _camera.Dispose(); _camera.Initialized -= _camera_Initialized; _camera.CaptureStarted -= _camera_CaptureStarted; _camera.CaptureCompleted -= _camera_CaptureCompleted; _camera.CaptureImageAvailable -= _camera_CaptureImageAvailable; _camera.CaptureThumbnailAvailable -= _camera_CaptureThumbnailAvailable; } } void _camera_Initialized(object sender, CameraOperationCompletedEventArgs e) { if (e.Succeeded) { this.Dispatcher.BeginInvoke(delegate() { // 初始化閃光燈模式 _camera.FlashMode = FlashMode.Off; btnFlash.Content = "閃光燈:Off"; // 初始化分辨率設置 _camera.Resolution = _camera.AvailableResolutions.ElementAt<Size>(_currentResolutionIndex); btnResolution.Content = "分辨率:" + _camera.AvailableResolutions.ElementAt<Size>(_currentResolutionIndex); lblMsg.Text = "主攝像頭初始化成功"; }); } } void _camera_CaptureStarted(object sender, EventArgs e) { // 開始捕獲 this.Dispatcher.BeginInvoke(delegate() { lblMsg.Text = "圖片開始捕獲"; }); } void _camera_CaptureCompleted(object sender, CameraOperationCompletedEventArgs e) { // 拍照完成 this.Dispatcher.BeginInvoke(delegate() { lblMsg.Text = "圖片捕獲完成"; }); } void _camera_CaptureImageAvailable(object sender, ContentReadyEventArgs e) { // 獲得了所拍攝的圖片 this.Dispatcher.BeginInvoke(delegate() { var bitmapImage = new BitmapImage(); bitmapImage.SetSource(e.ImageStream); imgCapture.Source = bitmapImage; }); } public void _camera_CaptureThumbnailAvailable(object sender, ContentReadyEventArgs e) { // 獲得了所拍攝的圖片的縮略圖 this.Dispatcher.BeginInvoke(delegate() { var bitmapImage = new BitmapImage(); bitmapImage.SetSource(e.ImageStream); imgCaptureThumbnail.Source = bitmapImage; }); } private void btnShutter_Click(object sender, RoutedEventArgs e) { if (_camera != null) { try { // 拍攝攝像頭當前捕獲的圖片 _camera.CaptureImage(); } catch (Exception ex) { lblMsg.Text = "拍攝失敗:" + ex.Message; } } } // 攝像頭分辨率的輪換 private void btnResolution_Click(object sender, RoutedEventArgs e) { if (++_currentResolutionIndex >= _camera.AvailableResolutions.Count()) _currentResolutionIndex = 0; _camera.Resolution = _camera.AvailableResolutions.ElementAt<Size>(_currentResolutionIndex); btnResolution.Content = "分辨率:" + _camera.AvailableResolutions.ElementAt<Size>(_currentResolutionIndex); } // 閃光燈模式的輪換 private void btnFlash_Click(object sender, RoutedEventArgs e) { switch (_camera.FlashMode) { case FlashMode.Off: if (_camera.IsFlashModeSupported(FlashMode.On)) { _camera.FlashMode = FlashMode.On; btnFlash.Content = "閃光燈:On"; } break; case FlashMode.On: if (_camera.IsFlashModeSupported(FlashMode.RedEyeReduction)) { _camera.FlashMode = FlashMode.RedEyeReduction; btnFlash.Content = "閃光燈:RedEyeReduction"; } else if (_camera.IsFlashModeSupported(FlashMode.Auto)) { _camera.FlashMode = FlashMode.Auto; btnFlash.Content = "閃光燈:Auto"; } else { _camera.FlashMode = FlashMode.Off; btnFlash.Content = "閃光燈:Off"; } break; case FlashMode.RedEyeReduction: if (_camera.IsFlashModeSupported(FlashMode.Auto)) { _camera.FlashMode = FlashMode.Auto; btnFlash.Content = "閃光燈:Auto"; } else { _camera.FlashMode = FlashMode.Off; btnFlash.Content = "閃光燈:Off"; } break; case FlashMode.Auto: if (_camera.IsFlashModeSupported(FlashMode.Off)) { _camera.FlashMode = FlashMode.Off; btnFlash.Content = "閃光燈:Off"; } break; } } } }
2、演示如何使用攝像頭錄制視頻
VideoDemo.xaml
<phone:PhoneApplicationPage x:Class="Demo.Device.Camera.VideoDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Landscape" Orientation="Landscape" mc:Ignorable="d" d:DesignHeight="480" d:DesignWidth="800" shell:SystemTray.IsVisible="False"> <Grid x:Name="LayoutRoot" Background="Transparent"> <StackPanel Orientation="Vertical"> <StackPanel Orientation="Horizontal"> <!--用於實時顯示攝像頭捕獲到的信息--> <Canvas Width="320" Height="240"> <Canvas.Background> <VideoBrush x:Name="videoBrush" /> </Canvas.Background> </Canvas> <!--用於播放視頻--> <MediaElement x:Name="mediaElement" Width="320" Height="240" /> </StackPanel> <StackPanel Orientation="Horizontal"> <Button x:Name="btnStartRecord" Content="開始錄制" Click="btnStartRecord_Click" /> <Button x:Name="btnStopRecord" Content="停止錄制" Click="btnStopRecord_Click" /> <Button x:Name="btnStartPlayback" Content="開始播放" Click="btnStartPlayback_Click" /> <Button x:Name="btnPausePlayback" Content="暫停播放" Click="btnPausePlayback_Click" /> </StackPanel> <TextBlock Name="lblMsg" /> </StackPanel> </Grid> </phone:PhoneApplicationPage>
VideoDemo.xaml.cs
/* * 演示如何通過攝像頭錄制視頻並保存到獨立存儲,以及如何播放獨立存儲中的視頻 * * CaptureSource - 操作相關捕獲設備的類 * VideoCaptureDevice - 關聯的視頻捕獲設備(System.Windows.Media.VideoCaptureDevice 類型) * AudioCaptureDevice - 關聯的音頻捕獲設備(System.Windows.Media.AudioCaptureDevice 類型) * State - 捕獲的相關狀態(System.Windows.Media.CaptureState 枚舉) * Stopped, Started, Failed * Start() - 啟動關聯的視頻捕獲設備和音頻捕獲設備 * Stop() - 關閉關聯的視頻捕獲設備和音頻捕獲設備 * CaptureImageAsync() - 異步捕獲圖像 * CaptureImageCompleted - 異步捕獲圖像完成后所觸發的事件 * CaptureFailed - 捕獲失敗時所觸發的事件 * * * FileSink - 用於將捕獲到的視頻保存到獨立存儲的類 * CaptureSource - 關聯的 CaptureSource 對象 * IsolatedStorageFileName - 需要保存到的獨立存儲的地址 * * * CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice() - 獲取默認的視頻捕獲設備,返回一個 VideoCaptureDevice 對象 * CaptureDeviceConfiguration.GetAvailableVideoCaptureDevices() - 獲取可用的視頻捕獲設備集合,返回一個 VideoCaptureDevice 對象集合 * CaptureDeviceConfiguration.GetDefaultAudioCaptureDevice() - 獲取默認的音頻捕獲設備,返回一個 AudioCaptureDevice 對象 * CaptureDeviceConfiguration.GetAvailableAudioCaptureDevices() - 獲取可用的音頻捕獲設備集合,返回一個 AudioCaptureDevice 對象集合 * * * VideoCaptureDevice - 用於描述視頻捕獲設備的類 * DesiredFormat - 期望的視頻格式 * SupportedFormats - 支持的視頻格式 * FriendlyName - 設備的名稱 * IsDefaultDevice - 是否是視頻捕獲的默認設備 * * * AudioCaptureDevice - 用於描述音頻捕獲設備的類 * AudioFrameSize - 音頻的幀大小(緩沖大小),10 毫秒 - 2000 毫秒之間,默認值是 1000 毫秒 * DesiredFormat - 期望的音頻格式 * SupportedFormats - 支持的音頻格式 * FriendlyName - 設備的名稱 * IsDefaultDevice - 是否是音頻捕獲的默認設備 */ using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; using System.Windows.Navigation; using System.IO.IsolatedStorage; using System.IO; namespace Demo.Device.Camera { public partial class VideoDemo : PhoneApplicationPage { private CaptureSource _captureSource; private FileSink _fileSink; // 保存到獨立存儲的視頻的地址 private string _isoVideoFileName = "myVideo.mp4"; // 需要播放的獨立存儲中的視頻文件的視頻流 private IsolatedStorageFileStream _isoVideoFile; public VideoDemo() { InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); if (_captureSource == null) { _captureSource = new CaptureSource(); _captureSource.CaptureFailed += _captureSource_CaptureFailed; _fileSink = new FileSink(); VideoCaptureDevice videoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice(); if (videoCaptureDevice == null) { lblMsg.Text = "該設備不支持視頻捕獲"; } else { // 讓 VideoBrush 顯示視頻捕獲的實時信息 videoBrush.SetSource(_captureSource); // 調用了 CaptureSource.Start() 之后才會開始捕獲視頻 _captureSource.Start(); lblMsg.Text = "設備正在捕獲視頻中。。。"; } } } protected override void OnNavigatedFrom(NavigationEventArgs e) { // 垃圾回收 DisposeVideoPlayer(); DisposeVideoRecorder(); base.OnNavigatedFrom(e); } private void _captureSource_CaptureFailed(object sender, ExceptionRoutedEventArgs e) { this.Dispatcher.BeginInvoke(delegate() { lblMsg.Text = "視頻捕獲失敗:" + e.ToString(); }); } public void mediaElement_MediaEnded(object sender, RoutedEventArgs e) { // 視頻播放完成后,重播 mediaElement.Position = TimeSpan.Zero; mediaElement.Play(); } // 清理視頻播放的相關資源 private void DisposeVideoPlayer() { // 注:對於那些沒有實現 Dispose() 方法的對象,就把他們設置為 null,這樣垃圾收集器會在需要的時候回收這些對象占用的內存 mediaElement.Stop(); mediaElement.MediaEnded -= mediaElement_MediaEnded; mediaElement.Source = null; _isoVideoFile = null; } // 清理視頻錄制的相關資源 private void DisposeVideoRecorder() { // 注:對於那些沒有實現 Dispose() 方法的對象,就把他們設置為 null,這樣垃圾收集器會在需要的時候回收這些對象占用的內存 if (_captureSource != null) { if (_captureSource.VideoCaptureDevice != null && _captureSource.State == CaptureState.Started) _captureSource.Stop(); _captureSource.CaptureFailed -= _captureSource_CaptureFailed; _captureSource = null; _fileSink = null; } } // 錄制捕獲到的視頻 private void btnStartRecord_Click(object sender, RoutedEventArgs e) { try { // 清除視頻播放的相關資源,因為系統無法同時錄制視頻和播放視頻(也無法同時播放兩個視頻) DisposeVideoPlayer(); if (_captureSource.VideoCaptureDevice != null && _captureSource.State == CaptureState.Started) { _captureSource.Stop(); // 將 FileSink 與 CaptureSource 做關聯 _fileSink.CaptureSource = _captureSource; // 設置錄制好的視頻所需保存到的獨立存儲的地址 _fileSink.IsolatedStorageFileName = _isoVideoFileName; } if (_captureSource.VideoCaptureDevice != null && _captureSource.State == CaptureState.Stopped) { // 開始捕獲,如果關聯了 FileSink,則會將捕獲到的視頻流以流的方式寫入到指定的獨立存儲地址 _captureSource.Start(); } lblMsg.Text = "開始錄制視頻"; } catch (Exception ex) { lblMsg.Text = "開始錄制視頻失敗:" + ex.ToString(); } } // 停止錄制 private void btnStopRecord_Click(object sender, RoutedEventArgs e) { try { if (_captureSource.VideoCaptureDevice != null && _captureSource.State == CaptureState.Started) { _captureSource.Stop(); // 清空 FileSink 的相關聯信息 _fileSink.CaptureSource = null; _fileSink.IsolatedStorageFileName = null; } lblMsg.Text = "停止錄制視頻"; } catch (Exception ex) { lblMsg.Text = "停止錄制視頻失敗:" + ex.ToString(); } } // 播放視頻 private void btnStartPlayback_Click(object sender, RoutedEventArgs e) { if (_isoVideoFile != null) { mediaElement.Play(); } else { // 停止視頻捕獲,因為系統無法同時錄制視頻和播放視頻(也無法同時播放兩個視頻) _captureSource.Stop(); _isoVideoFile = new IsolatedStorageFileStream(_isoVideoFileName, FileMode.Open, FileAccess.Read, IsolatedStorageFile.GetUserStoreForApplication()); // 用 MediaElement 播放獨立存儲中的指定視頻 mediaElement.SetSource(_isoVideoFile); mediaElement.MediaEnded += mediaElement_MediaEnded; mediaElement.Play(); } lblMsg.Text = "開始播放視頻"; } // 暫停播放視頻 private void btnPausePlayback_Click(object sender, RoutedEventArgs e) { mediaElement.Pause(); lblMsg.Text = "暫停播放視頻"; } } }
OK
[源碼下載]