這篇隨筆主要介紹照相預覽功能,重要使用的是MediaCapture對象,MediaCapture對象還能夠用來處理錄音和錄製視頻,本文只討論照相功能。app
後置攝像頭優先,找不到後置攝像頭就返回找到的可用的攝像頭列表的第一個。async
1 /// <summary> 2 /// Queries the available video capture devices to try and find one mounted on the desired panel. 3 /// </summary> 4 /// <param name="desiredPanel">The panel on the device that the desired camera is mounted on.</param> 5 /// <returns>A DeviceInformation instance with a reference to the camera mounted on the desired panel if available, 6 /// any other camera if not, or null if no camera is available.</returns> 7 private static async Task<DeviceInformation> FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel desiredPanel) 8 { 9 // Get available devices for capturing pictures. 10 var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture); 11 12 // Get the desired camera by panel. 13 DeviceInformation desiredDevice = allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desiredPanel); 14 15 // If there is no device mounted on the desired panel, return the first device found. 16 return desiredDevice ?? allVideoDevices.FirstOrDefault(); 17 }
首先須要建立一個MediaCapture實例,MediaCapture類位於Windows.Media.Capture命名空間。而後須要容許App訪問Camera,須要修改Package.appxmanifest文件,選擇Capabilities Tab 勾選中 Microphone & Webcam。 調用MediaCapture.InitializeAsync方法並指定要初始化上一步找到的Camera。ide
若是MediaCapture使用的過程當中拋出了Error,此時就須要釋放MediaCapture資源,能夠在MediaCapture的Failed事件來處理。this
此外還使用了isInitialized 標誌位來判斷是否已經成功初始化了Camera。spa
須要調用MediaCapture.StartPreviewAsync(),在預覽過程當中使用了DisplayRequest對象RequestActive方法來防止設備屏幕休眠。
一樣使用了isPreviewing來判斷Camera是否處於預覽狀態。
通過三個步驟後,就能夠正常預覽Camera了。操作系統
MediaCapture對象的StopPreviewAsync方法用來中止預覽,中止預覽後,設備就能夠容許睡眠了,須要調用DisplayRequest對象RequestRelease。code
當App轉換爲Suspending狀態時,先使用SuspendingOperation.GetDeferral()請求延遲掛起操做,釋放完MediaCapture資源,最後調用SuspendingDeferral.Complete() 通知操做系統App已經準好被掛起了。當App轉換爲Resuming狀態時,須要再次開啓Camera。
能夠分別處理Application.Current.Suspending跟Application.Current.Resuming事件。orm
附上代碼:視頻
1 using System; 2 using System.Linq; 3 using System.Threading.Tasks; 4 using Windows.ApplicationModel; 5 using Windows.Devices.Enumeration; 6 using Windows.Media.Capture; 7 using Windows.System.Display; 8 using Windows.UI.Core; 9 using Windows.UI.Popups; 10 using Windows.UI.Xaml; 11 using Windows.UI.Xaml.Controls; 12 using Windows.UI.Xaml.Navigation; 13 14 // The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 15 16 namespace ScanQRCode 17 { 18 /// <summary> 19 /// An empty page that can be used on its own or navigated to within a Frame. 20 /// </summary> 21 public sealed partial class MainPage : Page 22 { 23 const int borderThickness = 5; 24 25 private MediaCapture mediaCapture; 26 private bool isInitialized = false; 27 private bool isPreviewing = false; 28 29 // Prevent the screen from sleeping while the camera is running. 30 private readonly DisplayRequest displayRequest = new DisplayRequest(); 31 32 public MainPage() 33 { 34 this.InitializeComponent(); 35 36 // Useful to know when to initialize/clean up the camera 37 Application.Current.Suspending += Application_Suspending; 38 Application.Current.Resuming += Application_Resuming; 39 } 40 41 /// <summary> 42 /// Occures on app suspending. Stops camera if initialized. 43 /// </summary> 44 /// <param name="sender"></param> 45 /// <param name="e"></param> 46 private async void Application_Suspending(object sender, SuspendingEventArgs e) 47 { 48 // Handle global application events only if this page is active. 49 if (Frame.CurrentSourcePageType == typeof(MainPage)) 50 { 51 var deferral = e.SuspendingOperation.GetDeferral(); 52 53 await CleanupCameraAsync(); 54 55 deferral.Complete(); 56 } 57 } 58 59 /// <summary> 60 /// Occures on app resuming. Initializes camera if available. 61 /// </summary> 62 /// <param name="sender"></param> 63 /// <param name="o"></param> 64 private async void Application_Resuming(object sender, object o) 65 { 66 // Handle global application events only if this page is active 67 if (Frame.CurrentSourcePageType == typeof(MainPage)) 68 { 69 await StartCameraAsync(); 70 } 71 } 72 73 private void InitFocusRec() 74 { 75 leftTopBorder.BorderThickness = new Thickness(borderThickness, borderThickness, 0, 0); 76 rightTopBorder.BorderThickness = new Thickness(0, borderThickness, borderThickness, 0); 77 leftBottomBorder.BorderThickness = new Thickness(borderThickness, 0, 0, borderThickness); 78 rightBottomBorder.BorderThickness = new Thickness(0, 0, borderThickness, borderThickness); 79 80 var borderLength = 20; 81 leftTopBorder.Width = leftTopBorder.Height = borderLength; 82 rightTopBorder.Width = rightTopBorder.Height = borderLength; 83 leftBottomBorder.Width = leftBottomBorder.Height = borderLength; 84 rightBottomBorder.Width = rightBottomBorder.Height = borderLength; 85 86 var focusRecLength = Math.Min(ActualWidth / 2, ActualHeight / 2); 87 scanGrid.Width = scanGrid.Height = focusRecLength; 88 scanCavas.Width = scanCavas.Height = focusRecLength; 89 90 scanStoryboard.Stop(); 91 scanLine.X2 = scanCavas.Width - 20; 92 scanAnimation.To = scanCavas.Height; 93 94 scanStoryboard.Begin(); 95 } 96 97 private void Page_SizeChanged(object sender, SizeChangedEventArgs e) 98 { 99 InitFocusRec(); 100 } 101 102 protected override async void OnNavigatedTo(NavigationEventArgs e) 103 { 104 await StartCameraAsync(); 105 } 106 107 private async Task StartCameraAsync() 108 { 109 if (!isInitialized) 110 { 111 await InitializeCameraAsync(); 112 } 113 114 if (isInitialized) 115 { 116 PreviewControl.Visibility = Visibility.Visible; 117 } 118 } 119 120 /// <summary> 121 /// Queries the available video capture devices to try and find one mounted on the desired panel. 122 /// </summary> 123 /// <param name="desiredPanel">The panel on the device that the desired camera is mounted on.</param> 124 /// <returns>A DeviceInformation instance with a reference to the camera mounted on the desired panel if available, 125 /// any other camera if not, or null if no camera is available.</returns> 126 private static async Task<DeviceInformation> FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel desiredPanel) 127 { 128 // Get available devices for capturing pictures. 129 var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture); 130 131 // Get the desired camera by panel. 132 DeviceInformation desiredDevice = allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desiredPanel); 133 134 // If there is no device mounted on the desired panel, return the first device found. 135 return desiredDevice ?? allVideoDevices.FirstOrDefault(); 136 } 137 138 /// Initializes the MediaCapture 139 /// </summary> 140 private async Task InitializeCameraAsync() 141 { 142 if (mediaCapture == null) 143 { 144 // Attempt to get the back camera if one is available, but use any camera device if not. 145 var cameraDevice = await FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel.Back); 146 147 if (cameraDevice == null) 148 { 149 //No camera device! 150 return; 151 } 152 153 // Create MediaCapture and its settings. 154 mediaCapture = new MediaCapture(); 155 156 // Register for a notification when something goes wrong 157 mediaCapture.Failed += MediaCapture_Failed; 158 159 var settings = new MediaCaptureInitializationSettings { VideoDeviceId = cameraDevice.Id }; 160 161 // Initialize MediaCapture 162 try 163 { 164 await mediaCapture.InitializeAsync(settings); 165 isInitialized = true; 166 } 167 catch (UnauthorizedAccessException) 168 { 169 await ShowMessage("Denied access to the camera."); 170 } 171 catch (Exception ex) 172 { 173 await ShowMessage("Exception when init MediaCapture. " + ex.Message); 174 } 175 176 // If initialization succeeded, start the preview. 177 if (isInitialized) 178 { 179 await StartPreviewAsync(); 180 } 181 } 182 } 183 184 /// <summary> 185 /// Starts the preview after making a request to keep the screen on and unlocks the UI. 186 /// </summary> 187 private async Task StartPreviewAsync() 188 { 189 // Prevent the device from sleeping while the preview is running. 190 displayRequest.RequestActive(); 191 192 // Set the preview source in the UI. 193 PreviewControl.Source = mediaCapture; 194 // Start the preview. 195 try 196 { 197 await mediaCapture.StartPreviewAsync(); 198 isPreviewing = true; 199 } 200 catch (Exception ex) 201 { 202 await ShowMessage("Exception starting preview." + ex.Message); 203 } 204 } 205 206 207 /// <summary> 208 /// Handles MediaCapture failures. Cleans up the camera resources. 209 /// </summary> 210 /// <param name="sender"></param> 211 /// <param name="errorEventArgs"></param> 212 private async void MediaCapture_Failed(MediaCapture sender, MediaCaptureFailedEventArgs errorEventArgs) 213 { 214 await CleanupCameraAsync(); 215 } 216 217 218 /// <summary> 219 /// Cleans up the camera resources (after stopping the preview if necessary) and unregisters from MediaCapture events. 220 /// </summary> 221 private async Task CleanupCameraAsync() 222 { 223 if (isInitialized) 224 { 225 if (isPreviewing) 226 { 227 // The call to stop the preview is included here for completeness, but can be 228 // safely removed if a call to MediaCapture.Dispose() is being made later, 229 // as the preview will be automatically stopped at that point 230 await StopPreviewAsync(); 231 } 232 233 isInitialized = false; 234 } 235 236 if (mediaCapture != null) 237 { 238 mediaCapture.Failed -= MediaCapture_Failed; 239 mediaCapture.Dispose(); 240 mediaCapture = null; 241 } 242 } 243 244 /// <summary> 245 /// Stops the preview and deactivates a display request, to allow the screen to go into power saving modes, and locks the UI 246 /// </summary> 247 /// <returns></returns> 248 private async Task StopPreviewAsync() 249 { 250 try 251 { 252 isPreviewing = false; 253 await mediaCapture.StopPreviewAsync(); 254 } 255 catch (Exception ex) 256 { 257 // Use the dispatcher because this method is sometimes called from non-UI threads. 258 await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => 259 { 260 await ShowMessage("Exception stopping preview. " + ex.Message); 261 }); 262 } 263 264 // Use the dispatcher because this method is sometimes called from non-UI threads. 265 await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => 266 { 267 PreviewControl.Source = null; 268 269 // Allow the device to sleep now that the preview is stopped. 270 displayRequest.RequestRelease(); 271 }); 272 } 273 274 private async Task ShowMessage(string message) 275 { 276 var messageDialog = new MessageDialog(message); 277 await messageDialog.ShowAsync(); 278 } 279 } 280 }