Introduction
This is another article about Windows 10 application programming. This article explains a few of the media elements in Windows Runtime programming and how to capture the media content (such as images, videos, and audio) from a device running on Windows 10. Usually, since this is about Windows Runtime, you can use the same code for Windows 8, 8.1 and for Windows Phone 8, 8.1 applications also. But, in this article, I will be talking about Windows 10 applications only.
I have been programming new things in the Windows Runtime for quite a long time since I was an Insider for Windows and after a while, I found a few things that I hate about the Windows Runtime and a few things that I love about it. I will talk about the topmost of both sides:
- The good thing is that since the entire framework is written with asynchronous programming in mind, it is much easier to maintain the responsiveness of user applications. You can at any time write the function with the async keyword for it and use the rest of the functions of the API with await, well many background threads may throttle the memory, but for smaller applications the framework is great! In my opinion, it is better in performance. The Windows Runtime was written on top of native code, Win32 was used as the base, so it makes it much better and easier to write efficient code in Windows Runtime, plus .NET Framework is also supported (not the entire .NET Framework, just a few).
- The Bad thing is that the abstraction layer applied to your application's sandbox is so narrow that you are not even able to communicate or use the directories outside your own application's AppData folder directory. If you try to write the data to somewhere other than that, the OS will prompt you with an "Access is denied" exception. Plus, the currently added capabilities in the application manifest are so reduced that you cannot even utilize the entire machine power, you just design an application. To do something useful you will need to get support from another framework, such as Win32, Native programming in C/C++ or you will need to use .NET Framework itself, there is indeed some support for the .NET Framework in Windows Runtime applications.
That said, now let us consider talking about a few other things before stepping into the writing process of the article. In the future sections, I will be talking about:
- Windows 10, not from a spammy or advertisement point of view, I understand you being shocked by this!
- Windows.Media.Capture namespace of Windows Runtime and what it offers us.
- How to enable capturing the images and audio from our application!
- Storing the images and the video files, using native Windows Runtime APIs, such as StorageFile object.
By the end of this article, you can feel free to download and build the source code package provided along with this article, the source code contains the sample that I made for the sake of this article, it can be used for your own use also. I would recommend that you read the article, vote and leave your feedback if you want me to fix something and explain something in-depth.
General concepts used in article and sample
I believe before going in-depth about the technical concepts of Windows Runtime and Windows 10 I must share a little knowledge about them, I must teach you the basics of these frameworks and how you should use them when you try to build your own applications that make use of media capturing and recording facilities provided in the Windows Runtime.
Windows 10 Capabilities of application
In a Windows Runtime application, you must first define all of the capabilities that your application has before the OS would let it do anything. It is similar to declaring the uses-feature or uses-permission in Android programming. If you ever have done Android programming, it notifies the user about your application, plus it allows the user to revoke access to those permissions later. A good abstraction (IMO) but from a developer point of view, there comes another module for you to program! For example, now, you also need to ensure that the application has access to resources, say a camera. The user can always revoke access to the camera from the settings, you cannot alter the settings yourself. The user would need to, you can at most request them to change the settings for your application.
For a basic camera-like application (like the one I will be teaching in this article) you require permissions for a Webcam as well as Microphone. The function StartRecordAsync of the MediaCapture object (discussed later) requires you to allow Microphones also, well you can turn off the microphone but still, permission is required. If you do not allow these permissions, there will be an exception raised.
Every application needs a package manifest; the same as for Android applications. The manifest file contains the information required by the Store to process the
application type. It holds the permissions the following (but not only) things in it.
- Application details, such as:
Display Name.
Application Title.
Entry point: The class that gets executed.
Description of the application.
- Visual Assets
The logo and splash screen images for your application.
- Capabilities
The permissions your application requires to load and run.
- Declarations
Services and other background processes that your application intends to perform; such as Alarm services, File Open and File Save services.
- URIs and packaging information for your application.
All of these are required to identify your application, its purpose, its intentions, and its features. Users will be able to see your application when they need it to work for them, such as if you want to show your application as an Internet Client you can set the settings in the manifest and Windows will show the icon in the list for the application that the user wants. That is not just what it is intended to do, but users will also see your application listed on the Store under the category that they are interested in downloading the applications for. Name, Capabilities and Visual Assets are used to preview the applications on a Store. Others are required by the OS for underground works.
I will show you how to edit the manifest (in Design View) to allow your application to get a camera and microphone resources, in a future section.
Further in the article, you will determine that the Windows Runtime uses these capabilities to determine whether or not your application is authorized to use that resource. It provides users with a layer of privacy, that abstracts the applications to use resources without letting the user know. In settings applications, users can manage what applications have permission to and which permission they must be denied access to. For example, you can deny Internet access request to an application that you don't want to have access to the internet, the same applies to other permissions. You can deny a request to access the camera, microphone and file system resources. In my opinion, it is a great feature in the Windows Runtime.
Windows.Media.Capture namespace In-depth overview
Most of the media related APIs and namespaces are present in Windows.Media.XXXX namespace, audio controllers, video controllers and other similar objects that allow us to work around with the media resources, such as camera and microphone are all present in these namespaces. Separated in their own categories. You can reference them all in your application when you need to.
In this article, I will reference and talk about Windows.Media.Capture namespace only, because this namespace contains the objects and structures required to create our application. Every modern laptop or computer system has a webcam and microphone installed. That is why Windows 10's
UAP platform supports these features natively for applications. If the feature is not present, it will simply notify the programmer.
The Windows.Media.Capture namespace actually provides the classes,
enums, structures, and other stuff to communicate or workaround with the media devices, such as cameras and microphones and other sensors installed to them.
For example, Windows.Media.Capture namespace's MediaCapture object holds a definition for the ThermalStatus field that provides you with the thermal status of the device. Capturing the data may cause the device to heat, if the device has the feature to expose the thermal status such as a secondary device installed, it will allow you to capture the thermal status and turn off the capturing of the photos or videos. Plus, there is an event included that can be used to determine when the thermal status gets down to cold so that you can continue capturing the videos from that device.
The actual
enum for managing the thermal status of a device is
MediaCaptureThermalStatus. There are only the following two values for this enum:
- Normal (0; zero)
- Overheated (1)
Hopefully, these are the only objects required. You can, however, divide them into much more advanced topics in this namespace, or in the
Windows. Media namespace collection. The
Windows. Media namespace (collection) allows you to work around with other media types, such as audio and video frames or photo frames in real. Windows.Media.Capture exposes methods to capture the photos, audios or videos. Whereas to work around in-depth with other content would require some other low-level programming, those namespaces provide you with the objects for that.
Visual Studio 2015 and Windows 10 apps
Visual Studio 2015 comes packed with resources that you will need to build Windows 10 applications, there are many articles already written and ready for you to read and learn how to create your applications in Visual Studio 2015! You will find this
CodeProject article helpful and of your own taste.
Visual Studio 2015 is the only IDE (currently) that supports Windows 10 application programming, plus you need to be running Windows 10 to write the software for Windows 10.
Tip
If you do not have Windows 10 or Visual Studio 2015, you can still use the code to write applications for Windows 8 and 8.1 or Windows Phone 8 and 8.1 applications! So, keep reading, and provide your feedback at the end in case of Windows 8 and 8.1 applications!
Writing the application
Let us head toward the main topic of this article, writing the source code for the application. This section will be divided into two main sections, one for writing the UI code and the other for writing the back-end code for our application. Both of them will be discussed as only the required sections because the purpose of the article is to teach the controls available in Windows Runtime with XAML (notice that this article covers the C# and XAML, in a later article someday I will show you C++ programming for the same application also) and how you can configure the application to capture the content and preview it on the screen. Plus, capturing and storing the content on your application's data folder.
As this section continues, I will show you the procedure to perform to create the application, so you can consider this guide to be a step-by-step creation of the application for capturing photos, audios and videos.
Building the XAML Page
The first step in this guide is to build the XAML and the XAML code in this sample is just a single
Page control with a few other child controls that create the UI for our application. The applications that show the display of a camera are usually using the
CaptureElement control in the XAML. The
CaptureElement control allows you to bind the
Source property to a media device, such as a camera (webcam). The Windows Runtime provides the content from a camera, microphone and other media devices to this control, that is then rendered on the screen. It is similar to previewing a stream of bytes for a video frame on a video element.
MSDN documentation for CaptureElement
Renders a stream from a capture device, such as a camera or webcam.
In the source code for the Page, I will be using this control only, and then programmatically I will provide it with the stream of video frames and other stuff that the Windows Runtime will manage the transfer and rendering on the screen for the user. The good thing for us is that the syntax to create this control is a single line (unless you want to add other functionality to the control also) as in the following.
- <CaptureElement Height="650" Name="captureElement" />
That is enough!
Now, since our control to capture the media content has been created, we need a few buttons to be created to handle the events. Although these interfaces are not presented natively, we need to build them for our use. XAML provides many controls that we can use in our application for our own purposes. That said, we need our application to provide the controls to change the video quality and video encoding type, we also need it to initiate the recording process and to stop it too. We also need our application to be able to capture the photos and to distinguish when not to, such as when capturing the videos already. We also need to be able to mute the microphone in our videos when we need to. The properties and so on are all provided to us in the Windows.Media.Capture.MediaCapture object, we now need to provide users with controls using which they can trigger the requests to change the state and content of the application, such as video quality, etc.
Since this was a Windows 10 application, I wanted to use the native controls provided rather than re-inventing the wheel. In the following sections, I will be using the built-in provided controls to create the UI for our application! We need the following functions in our application.
- Capturing photos
- Capturing the videos
When capturing videos:
- Allow users to mute/unmute the microphone.
- Allow them to stop capturing the videos; save the videos.
- Change the video encoding and video quality before starting the recordings.
Plus, a few checks to ensure that the user isn't capturing the photos when the video is being recorded and so on! These checks can be removed if not required and other checks can be added, such as changing the quality when recording the video. There are many things that are advanced topics and not covered in this basic guide.
To create the functionality, I used the
AppBar control of Windows applications that enables us to provide the controls in a form of a tray to the user that can be set open and closed when needed by the user. Also, it has a great UI and UX for the user for being easy to use. Another thing you might want to know is that Windows 10 comes with better Icons in the Symbol enumeration. You can find many more great resources in the MSDN documentation for Symbol and AppBar. Furthermore, usually, I created the buttons and commands using theAppBarButton (that inherits from the Button object and thus provides us with all of the events, functions, and members that the Button object has, we are interested in the Click event of the Button object). These buttons and controls would lead us to the creation of the control bar (command bar) for the camera handling, we can use these buttons to change the state of the MediaCapture object that is at the moment connected to the webcam and microphone.
- <Page.BottomAppBar>
- <AppBar Background="Transparent" IsOpen="True">
- <Grid>
- <AppBarButton Icon="Camera" Name="cameraIcon" Click="button_Click" />
- <AppBarButton Icon="Video" Name="videoIcon" Click="button_Click" Margin="70, 0, 0, 0" />
- <AppBarButton Icon="RotateCamera" Name="rotateCameraIcon" Click="button_Click" Margin="140, 0, 0, 0" />
- <ComboBox Margin="230, 10, 0, 0" Name="videoQuality" SelectionChanged="comboBox_SelectionChanged">
- <ComboBoxItem IsSelected="True">Auto</ComboBoxItem>
- <ComboBoxItem>1080p</ComboBoxItem>
- <ComboBoxItem>720p</ComboBoxItem>
- <ComboBoxItem>VGA</ComboBoxItem>
- </ComboBox>
- <ComboBox Margin="320, 10, 0, 0" Name="videoType" SelectionChanged="comboBox_SelectionChanged">
- <ComboBoxItem IsSelected="True">MP4</ComboBoxItem>
- <ComboBoxItem>WMV</ComboBoxItem>
- </ComboBox>
- <AppBarButton Icon="Microphone" Margin="400, 0, 0, 0" Name="muteIcon" Click="button_Click" />
- <AppBarButton Icon="Library" HorizontalAlignment="Right" Name="libraryIcon" Click="button_Click" />
- </Grid>
- </AppBar>
- </Page.BottomAppBar>
The preceding code acts as the command bar for our application, thus enabling us to interact with the UI of the application to initiate various commands and functions in the application.
Figure: Function in application
The preceding bar is what is displayed to the user. I would like to say that the Windows team has put a great effort into building great fonts for the Windows UI and UX. All of these icons (camera, video, and others) are in real character (if you don't know it before). These are mapped to Unicode codes for each of them and then these glyphs are rendered on the screen. The benefit of this (a simple benefit) is that you do not need to create multiple images for multiple colors and themes, you can change the color of these icons as you would change the color for text!
So far we have created the application's UI, now we need to write the back-end code so that we can actually show something on the screen to the user that he can interact with and capture and store on his machine.
Why do not set the Source property in XAML?
No matter what, this will bug you if you are a beginner, why didn't I set the property of the Source in the XAML itself? Well, the answer to this is simple. XAML is for initial settings, the settings allowed in XAML are already present, such as system resources, system themes and other same content. If something is null and is passed, as in the initial stages until we call the c
apture.InitializeAsync() function explicitly in the later code, our capture object is also null that will furthermore cause trouble in our application startup. To the XAML, it will cause an exception to be raised, generally of
NullReferenceException type. See the following, it was declared that this is caused as trouble.
For this sake, we leave all of such settings for later, we can set up the environment and other stuff in the contractor asynchronously. Then, once everything is ready, we can initialize the XAML view for our application, since everything for setting up the resources take less than 1 second (
in my system, yours might take 2, but 3 seconds is a result on Pentium processors; if they support) to initialize everything and get your device and application ready for processing. You can then display the content and bind everything as required.
Handling the events and tasks
Our UI has been set up for now, since the camera has not yet been bound to the display and other stuff like that, it is of no use to display the entire application view. The only thing that is shown to the user until the back-end code runs is the command bar that we just made using the AppBar!
Now in this section, I will show you how you can bind the camera to your application, make changes to the state of the application, run functions for the MediaCapture object to start capturing photos and videos or stop capturing. All of them are to be considered as required ones to make our application fully functional! A few things I won't be using here, but you may consider using them for your own applications.
1. ThermalStatus property not used
I won't be using the
ThermalStatus property of the namespace since for the sake of this guide, there is no need to use it. Plus I am not sure whether my camera supports it or not, but in your cases for your Windows Store applications, you must always consider using that object to determine whether your device should continue capturing the data or does it need some break, to protect it from blowing itself to kingdom come!
Plus, you also get to use the ThermalStatusChanged event in your application to determine whether the camera gets too hot or is it ready for use again. Using these will provide a better UX for your application and a good review too. Although they are not required, blow on the camera by the user when it has been heating and not turning if off, no problem. But, I will personally recommend you do use them for any incidental cases.
2. Facial recognition is provided!
For those of you wanting to recognize someone at your door with your webcam, here is good news. The Windows Runtime natively supports facial recognition and you can use those libraries and objects in your applications to make it even better! The
Windows.Media.FacialAnalysis namespace provides the objects that you will be interested in using to recognize or store the facial patterns when viewing the data from a webcam.
What happens is that you need to pass a video frame to these libraries, they detect if they get to find a human face in those frames of videos. If they do, they will let you know, you also get to track the faces in the frames that are similar to what is being done in Windows 10's native Camera app. Currently, the source code I have uploaded doesn't support this feature. It may in the future.
Setting up the application
That said, now let us consider setting up the application for further processing and function handling in our application. We know that we have an empty control (
CaptureElement) waiting for some content to be passed for rendering. For this, we need to seek the function that executes first. The first function that triggers is the event handler for
OnNavigatedTo(e) for the Page of our application. In that function for the event handler, we can set up things and pass the content to the CaptureElement control in our Page, so that when the application starts the user is able to use his camera as if he started the camera application.
The hierarchy is, that we need to call the
InitializeAsync() function before we can do anything to the MediaCapture object. This function needs to be called, because internally the Windows Runtime will set up most of the stuff for us, if we don't, we will start capturing the exceptions rather than media content. So we first call this function, then right after that call we need to associate the capturing object to control that renders the content before we can start previewing the content being captured. This hierarchy needs to be followed by you to capture the content and preview it on the screen. Have a look at the following code, I will explain the purpose below.
- private async void init() {
- await capture.InitializeAsync(); // (1)
-
- capturecaptureElement.Source = capture; // (2)
- await capture.StartPreviewAsync(); // (3)
-
- #region Error handling
- MediaCaptureFailedEventHandler handler = (sender, e) = > {
- System.Threading.Tasks.Task task = System.Threading.Tasks.Task.Run(async() = > {
- await new MessageDialog("There was an error capturing the video from camera.", "Error").ShowAsync();
- });
- };
-
- capture.Failed += handler;#endregion
- }
Now, understand the following list to understand the hierarchy being called.
- First of all the InitializeAsync() function initializes the components and creates the instance (note that it, not the same as calling new MediaCapture() in your application) so that you can now use it for rendering purposes in your applications. This is called to determine the user settings also, to determine whether or not the user has allowed your application to use the resources. Read more in the MSDN.
- You bind the capture object to the XAML captureElement control. This then renders the incoming stream of content on screen for the user!
- This activates the streams to be passed to the view for the user to view them.
All of these functions are asynchronous in calls, allowing you to have responsiveness in your applications.
Tip
I have added a handler to the code, in case anything went wrong when capturing the content, it shows you an error message.
Handling the events and tasks Jr.
Sorry for the same heading, in this section, I will show the code that actually does everything, in the preceding XAML code if you pay attention you will see that every button was attached to the same handler for the Click event. I used it to remove the redundancy since the same thing would be done based on the icon the user used. I wrote the handler in a way to handle the button, based on the icons (in the code I am using the Name that is not visible in the UI) so that the same codebase can be reused.
- private void button_Click(object sender, RoutedEventArgs e) {
- if ((sender as AppBarButton).Name == "cameraIcon") {
- // Capture the image
- capturePhoto();
- } else if ((sender as AppBarButton).Name == "videoIcon") {
- // Start recording
- alterRecording();
- } else if ((sender as AppBarButton).Name == "rotateCameraIcon") {
- invertCamera();
- } else if ((sender as AppBarButton).Name == "muteIcon") {
- muteUnmute();
- } else if ((sender as AppBarButton).Name == "libraryIcon") {
- App.RootFrame.Navigate(typeof(Library));
-
- cleanResources();
- }
- }
Cleanup needed!
In the previous version of this article, there was no library included. In this version, I have also included the library that renders the data on the screen and does not require your camera. In such cases it is better to disconnect the camera from your application, otherwise, it will continuously send a stream of video frames to your capture element, causing a waste of resources. For that, you should consider cleaning the resources and re-initiating the stuff once your application is active to use the camera again.
- private async void cleanResources() {
- captureElement.Source = null;
- await capture.StopPreviewAsync();
-
- if (isRecording) {
- await capture.StopRecordAsync();
- }
- capture.Dispose(); // Dispose the resource
- }
Plus, there is another change in the application. Rather than having a separate function to load the resources, I have not handled the setting up of resources in the event OnNavigatedTo(e), it allows better performance for the application now.
- protected override void OnNavigatedTo(NavigationEventArgs e) {
- // Page has become active, load the resources.
- capture = new MediaCapture();
- loading.Visibility = Visibility.Visible;
-
- init();
- }
These functions are high-level tasks that our application is intended to perform. In later sections, I will dissect those function blocks to show you how to perform these actions in your application.
The only requirements for further procedures are the understanding of asynchronous programming models in the C# language. Asynchronous programming in the C# language (as we know it today) was introduced as of its 5th version (now it is on the 6th at the time of writing) and it will continue evolving. MSDN is a great resource for C# programming tutorials, samples, and remarks. So, before you move on (although not required) you should consider understanding the
Asynchronous programming in C#.
Capturing the photos
Moving down the button click handler, the first function is the function to capture the images for the users. Well, since the Windows Runtime has us covered, we don't actually need to do anything, we just specify the following two things:
- The location where to store the file
StorageFile is created, you can specify other settings for the file too, such as name collision cases.
- Image encoding format, JPEG, PNG, etc.
These are required to convert the bytes stream from the capture element to your file system. They are then rendered as a valid image in your machine.
- Whether to capture a photo when a recording video
You can try your luck in both cases, in my sample I ignored the capture when the user was capturing a video!
Continuing from this, you can write the function that handles the request to capture a photo and store it somewhere in the file system. Both of these can be written in one line of code using Windows Runtime APIs. But since we need the additional condition, we will be spanning it a bit longer.
- private async void capturePhoto() {
- if (!isRecording) {
- var file = await(await ApplicationData.Current.LocalFolder.CreateFolderAsync("Photos",
- CreationCollisionOption.OpenIfExists)).CreateFileAsync("Photo.jpg",
- CreationCollisionOption.GenerateUniqueName);
-
- await capture.CapturePhotoToStorageFileAsync(ImageEncodingProperties.CreateJpeg(), file);
- } else {
- await new MessageDialog("Application is currently recording your camera, please stop recording and try again.", "Recording").ShowAsync();
- }
- }
The preceding code has two paths, one to be executed if the user is recording a video and the other if the user isn't. One path shows an error message and the other one that interests us creates a new file at the application data folder named "Photo.jpg" and also notices the
CreationCollisionOption.GenerateUniqueName being applied, this enables us to handle what happens if a file already exists. In such cases, the file is given a unique name, such as appending an integer to it.
You can add flickering, audio effects and other stuff depending on your needs! That was a bit of fancy, so I ignored it.
Recording a video
That explained, now the next topic to be covered is the recording of a video. The procedure is similar, all is done by the Windows Runtime in itself is, we don't actually need to write anything at all, just call the function and you're done. But, there are still a few things that we need to consider before actually starting the recording. We still need to pass a few parameters.
- The storage file where we will store the recording.
The same as in the preceding, nothing is different. Oh yeah, the format extension only.
- The encoding in which the video must be recorded.
You see in the previous section we did the same, we created the image based on a format! The same thing is done in this module too, we create a video encoding to be used, MP4 or WMV. We also pass the quality for the video, 1080p, 720p, etc. These are then used to configure the settings for storing the contents on the file system. The Windows Runtime has us covered, do not worry!
- private async void alterRecording() {
- if (isRecording) {
- // Stop recording
- await capture.StopRecordAsync();
- videoIcon.Foreground = new SolidColorBrush(new Windows.UI.Color() {
- A = 255, R = 0, G = 0, B = 0
- }); // Black
- isRecording = false; // Not recording any more
- } else {
- encoding = getVideoEncoding(); // Get the current encoding selection.
-
- // Start recording
- var file = await(await ApplicationData.Current.LocalFolder.CreateFolderAsync("Videos",
- CreationCollisionOption.OpenIfExists)).CreateFileAsync(
- string.Format("Recording_{0}-{1}.{2}",
- myEncoding,
- myQuality, (myEncoding == "MP4") ? "mp4" : "wav"),
- CreationCollisionOption.GenerateUniqueName);
-
- await capture.StartRecordToStorageFileAsync(encoding, file);
-
- videoIcon.Foreground = new SolidColorBrush(new Windows.UI.Color() {
- A = 255, R = 255, G = 0, B = 0
- }); // Red
- isRecording = true; // Capturing the video stream.
- }
- }
The preceding code captures and stops capturing the video stream and saves the buffer on the file system for further usage. The file created must have the name specified and the format extension. The preceding code is flexible enough to change the extension and other settings based on what the user chose when starting the recording event. I would like to share the content of the getVideoEncoding function also, since that is said in the preceding code, not sharing it here will not be sincere.
- private MediaEncodingProfile getVideoEncoding() {
- VideoEncodingQuality quality = VideoEncodingQuality.Auto;
- myQuality = "Auto";
-
- switch (videoQuality.SelectedIndex) {
- case 2:
- quality = VideoEncodingQuality.HD1080p;
- myQuality = "1080p";
- break;
- case 3:
- quality = VideoEncodingQuality.HD720p;
- myQuality = "720p";
- break;
- case 4:
- quality = VideoEncodingQuality.Vga;
- myQuality = "VGA";
- break;
- default:
- break;
- }
-
- myEncoding = (videoType == null || videoType.SelectedIndex == 0) ? "MP4" : "WMV";
-
- return (videoType == null || videoType.SelectedIndex == 0) ? MediaEncodingProfile.CreateMp4(quality) : MediaEncodingProfile.CreateWmv(quality);
- }
This function is executed each time the settings are changed in the UI, please see the command bar and find theComboBox controls that are provided. They are used to change the video encoding and video quality being saved on the machine. Each time the settings are changed, this function is executed to select the current settings for video encodings and quality for the video file being stored.
Also, note that these are not all of the settings. I have only provided a few of the quality types and encoding types provided. Others were audio encodings, that I have not discussed in this code, but they are present and they can be used to create profiles for storing the content on the file system. The quality settings also range down to VGA quality, but in most cases, you will require the Auto setting provided only. That can fit for your video controller and other devices so that you do not stumble upon an error.
Preview mirroring
Usually, when you are building the applications for sharing the view on the network, you will need to share the content in a mirror view, usually, users do not like to view themselves in a way that seems opposite to them, inverted in other words. Adding a mirror effect is the same as rotating the image horizontally to 180° that then previews the content as if you were viewing yourself in a mirror.
Windows Runtime although provides you with a function to set preview mirroring
usingSetPreviewMirroring(true) but that is always recommended, not to be used. Instead, you must always use the
FlowDirection property and set it to the RightToLeft value. This would invert the image as required.
You can do that programmatically too as in the following.
- captureElement.FlowDirection = FlowDirection.RightToLeft;
Mute/Unmute the microphone
Finally, for this guide, I would like to show the code to mute/unmute the microphone when you are recording the video also. The MediaCapture object provides you with read-only members for controllers of audio and video. You can use them to alter the state of these devices, you can mute/unmute the audio controller and similarly you get to work around with the video controller also.
- AudioDeviceController
This member controls the audio controller. In this section, I will be using this member to control the functions of muting and/or unmuting the device.
- CameraStreamState
Gets the current stream state for the camera stream.
- MediaCaptureSettings
The settings for your capture object.
- ThermalStatus
Already discussed previously, it provides you information about the thermal status of your device.
- VideoDeviceController
The object that controls the settings for the video controller. I won't explain it here.
For their documentation and other information, please refer to the MediaCapture properties section in the MSDN. In this section, I will use AudioDeviceController to change the state of the muting or unmuting of the microphone.
- private void muteUnmute() {
- if (muted) {
- // Unmute
- capture.AudioDeviceController.Muted = false;
- muted = false;
- muteIcon.Foreground = new SolidColorBrush(new Windows.UI.Color() {
- A = 255, R = 0, G = 0, B = 0
- });
- } else {
- // Mute
- capture.AudioDeviceController.Muted = true;
- muted = true;
- muteIcon.Foreground = new SolidColorBrush(new Windows.UI.Color() {
- A = 255, R = 255, G = 0, B = 0
- });
- }
- }
The main code that does everything is the alteration in the Muted property of the controller that changes the state and mutes it or unmutes it. The preceding code checks what action to perform based on the current state of the controller.
Building the Gallery Library
Of what good will be the camera application if there is no way to view what you saved, and preview what you recorded. Apart from just being able to create an application that captures and stores the images and videos, I want to share the code to be able to create a gallery for those images and to preview the videos also. Anyways, the gallery (since I am not a good designer) does not contain a very elegant style UI for the users, it is just a ListView that previews the content in the form of a list.
Tip
If you want, you can show the content in a form of GridView also, you can remove the image names and other content and just simply preview the image in an Image control of Windows Runtime APIs.
I created the gallery using a new page control, that has a separate bottom app bar and other details, thus allows us to abstract the camera controls and the library controls from each other. The main idea is that in the library the user must be able to get a list of images that he has captured, a list of videos that he has recorded and to be able to preview. We only need a ListView control or a GridView based on how we want to design everything. We can then bind the list of media files to these lists and show them to the user.
In this section, I will teach you how you can do that so that in your own applications, you can modify the source code and create a separate theme and style for your users or provide them with both the styles (list styled gallery or grid styled gallery). Windows 10 application development is really very easy!
Building the Page
If you have even been developing a dynamic application, you are already familiar with the procedure of Data Binding. It is a technique to bind the controls, the visual elements, to back-end data. The data fills the controls as it is present and as much as it is present. Data binding allows developers to create a single template for their application's layout and then the data fills the template and is provided to the user. I would recommend that you give What is Data Binding (from MSDN) a thorough look before continuing.
In the following code for the application, I am using the same technique, I am creating a template for the controls to be viewed, then I will pass a list of objects (remember, we can also pass a list of single elements or no elements in it, XAML will take care of the rest) and they will be used to create the application's UI based on our data. This way, no matter how many images or videos have been captured, we can display them in the application's UI and the good thing is that we only need to provide the template. XAML will fill in the details itself and will take care of the rendering.
You must, first of all, understand that rendering an image and rendering a video is different and different controls are used to render the images. In the following section, I have created two separate
ListViews for each of them, one of them is used to render the images and the other one for rendering the videos. Thus two templates are being used in the application for the gallery. In the list that renders the images, I used an Image control. That enables us to add the Source property to some image resource from our file system. On the other hand, for the list that renders the videos, I am using
MediaElement to render the videos on the screen. Similarly, it also provides us with the features to alter the Source property, so we can attach it to a video resource from our file system.
- <TextBlock FontSize="20" TextWrapping="WrapWholeWords" Margin="30, 0, 0, 0">This is the area for your application's gallery, images or videos recorded can be viewed in this area.</TextBlock>
- <ListView Name="photos" Visibility="Visible" Margin="0, 100, 0, 0">
- <ListView.ItemTemplate>
- <DataTemplate>
- <Grid Height="100" Margin="10, 2, 10, 2">
- <Grid.ColumnDefinitions>
- <ColumnDefinition />
- <ColumnDefinition />
- </Grid.ColumnDefinitions>
- <Image Grid.Column="0" Source="{Binding Path=Path}" />
- <TextBlock Grid.Column="1" Margin="10, 0, 0, 0" Text="{Binding Path=Name}" />
- </Grid>
- </DataTemplate>
- </ListView.ItemTemplate>
- </ListView>
- <ListView Name="videos" Visibility="Collapsed" Margin="0, 100, 0, 0">
- <ListView.ItemTemplate>
- <DataTemplate>
- <Grid Height="100" Margin="10, 2, 10, 2">
- <Grid.ColumnDefinitions>
- <ColumnDefinition />
- <ColumnDefinition />
- </Grid.ColumnDefinitions>
- <MediaElement Grid.Column="0" Width="100" Source="{Binding Path}" Volume="0" />
- <TextBlock Grid.Column="1" Text="{Binding Name}" Margin="10, 0, 0, 0" />
- </Grid>
- </DataTemplate>
- </ListView.ItemTemplate>
- </ListView>
The preceding XAML code is simply the template that I was talking about previously. This will be filled in with the data that we provide. The ItemTemplate allows us to template the items being added to it. It responds to theItemsSource (or Items; that is often not recommended to be used) property and uses their attributes or properties to fill in the data.
Notice the properties,
Source="{Binding Path=Path}" or the
Text="{Binding Path=Name}". They are the binding properties that I am using, the properties Path or Name will be used in these placeholders and the UI will be built. These are simply the variables holding a reference to the data in that item in the collection.
Twisted words: Why the Source is set in the XAML now?
Previously in the article, I said that we should not consider adding the Source property to the
MediaElement in XAML, and now I am adding the Source property right in the XAML. Such a shameful act, isn't it?
Well not actually, have a look at the preceding. The Source property is bound to the Binding property, not to a resource. That means that although the chances are that the data will be null. if we bind it successfully the source won't be null and the application will be built. Have a look, the XAML is still complaining, but in template-mode, it doesn't matter! Just go ahead.
But once the application loads, the problem no longer exists. Have a look at the snapshots below for the gallery in the list-view!
Binding the data programmatically
As I was saying, we need to bind the object to this template, how are we going to actually capture the object when the data is of separate types? The thing is, we take the common things and use them as members for a custom-object, then we pass that data. Putting it simply, we create a class to hold the properties that we are interested in.
- public class Data
- {
- public string Name { get; set; }
- public Uri Path { get; set; }
- }
Done, now we can have the values that we need. (Plus, you can remove the Name field and use the Path only, then you can get the values for the Name and other stuff later! But that is done in advanced topics.) Now we can also create the lists of the objects we need.
But to be sure that XAML doesn't throw an exception for "Object reference not set an instance of an object." we need to ensure that the source property is applied, we will handle the
OnNavigatedTo(e) event and set everything up. I recommend that you also use this event because it is triggered when the application has loaded the page and is rendering the controls on the screen. To handle it, we override its default behavior and do what we are expecting it to do, have a look.
- protected override void OnNavigatedTo(NavigationEventArgs e)
- {
- getResources();
-
- // Set the resources
- photos.ItemsSource = photosList;
- videos.ItemsSource = videosList;
- }
That finished, now have a look at the getResources function in my application's source code.
- private void getResources()
- {
- System.Threading.Tasks.Task.Run(async () =>
- {
- var photos = await (await ApplicationData.Current.LocalFolder.GetFolderAsync("Photos")).GetFilesAsync();
- var videos = await (await ApplicationData.Current.LocalFolder.GetFolderAsync("Videos")).GetFilesAsync();
-
- // Filter files
- foreach (var photo in photos)
- {
- photosList.Add(
- new Data { Name = photo.Name, Path = new Uri(photo.Path) }
- );
- }
-
- foreach (var video in videos)
- {
- videosList.Add(
- new Data { Name = video.Name, Path = new Uri(video.Path) }
- );
- }
- }).Wait();
- }
I am using a Task to perform this function because if I wouldn't then the following two cases would develop:
- await keyword will continue the previous function from where we came and will apply a null list to the photos and video control. That is not what we want, but that is exactly what awaits does.
- If we ignore the await keyword then we are left with IAsyncResult objects, working with which is again a headache.
Keeping the preceding points in mind, it is better to use the await keyword and let the application's function run asynchronously rather than wait for the task to complete. This allows us to maintain the synchronous calls so that the list applied actually represents the images and videos in the file system. Plus, we don't need to work around with other low-level interfaces for asynchronous function results and so on.
Once the preceding code compiles (press CTRL + SHIFT + B to test) it will provide you with the data that you require from your file system. Also, since we are loading the resources when the user navigates to this page, we also get a +1 feature in which, if we capture new photos or videos, they are also shown in the library; I am calling this gallery a Library!
Tip
Using a GridView instead of ListView
If you are interested in using a GridView instead of a ListView then you can change the content of your XAML page and instead of the ListView control use the GridView. The example of which can be seen below.
- <GridView Name="photosGrid" Visibility="Visible" Margin="0, 100, 0, 0">
- <GridView.ItemTemplate>
- <DataTemplate>
- <Grid Height="100" Margin="10, 2, 10, 2">
- <Grid.ColumnDefinitions>
- <ColumnDefinition />
- <ColumnDefinition />
- </Grid.ColumnDefinitions>
- <Image Grid.Column="0" Source="{Binding Path=Path}" />
- <TextBlock Grid.Column="1" Margin="10, 0, 0, 0" Text="{Binding Path=Name}" />
- </Grid>
- </DataTemplate>
- </GridView.ItemTemplate>
- </GridView>
This would now render the images in a grid rather than stacking every image in a list, vertically.
Usually, for creating the image galleries you would use the grid rather than using the lists.
GridViews are actually designed in a way to stack the objects horizontally, rather than stacking them vertically like
ListView.
Preview of the application sample
The application's camera page looks as in the following, notice the application's bottom bar, it contains the controls for camera functions and also a new control for the library.
The library holds the media that was captured.
Image library
The image library holds the button that can trigger the change in library UI to show the videos or photos.
- <AppBarToggleButton Icon="Video" Click="showVideos_Click" HorizontalAlignment="Right" Name="showVideos" Content="Show Videos" />
Notice the Red rectangle, I just wanted to point out that the Back button still exists.
If the user clicks the button, the button is checked and can be used to change the UI of the application.
Videos library
It displays the videos present in the application's data folders.
Good one, the app's button, and the back buttons are clearly visible now. You can add the function to display the videos in a separate video with other media transport controls that allow users to change the state of media, such as to pause the media or to play it.
Points of Interests
The Windows Runtime provides you with the libraries and tools that you require to build applications that use the device's resources, such as webcams, microphones and other similar media content. Windows 10 applications use the Windows Runtime as the framework for programming. The Windows.Media.Capture namespace provides you with the libraries and objects that you can use to capture the photos and recording the videos in your device. For user privacy and security, the Windows Runtime provides you with capabilities that you must have before accessing those resources.
This article and the sample associated with it provides you with a basic example of such a program. The application is capable of capturing the images, storing videos and also provides other options, such as muting or unmuting the microphone when capturing the recordings. The application's source code also provides a sample for building the library for representing the stored media such as images and videos.
Download the application's source code provided with this article, test it out for other purposes and do comment on what you find in it, vote and share! I would like to hear your feedback to make it even a better guide and sample!
What's next?
I will continue to add more features to the camera app, by actually using it as a consumer for applications. I am sure I will find a few more bugs and I will update the article and source code for the solutions.
Plus, if I have any other ideas about this, I will let you guys know. Do leave your feedback if you have any other ideas.
Summary
In this article, we learned about Building Camera App and Gallery in Windows 10.