Introduction and Background
This one is another article about Windows 10 application programming, in this article I will discuss a few of the media elements in Windows Runtime programming and how can we 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 Windows Runtime since quite a long time as I was Insider for Windows, and after a while I have found a few things that I hate about Windows Runtime and a few things that I love about it. I will talk about the top most of both sides,
- Good thing is: Since entire framework is written keeping asynchronous programming in mind, it is a lot easier to maintain the responsiveness of user applications. you can any time write the function with
async
keyword to it and use the rest of the functions of API with await, well a lot of background threads may throttle the memory but, for smaller applications the framework it great! In my opinion, it is better in performance. Windows Runtime was written right on top of native code, Win32 was used as a base, so it makes it a lot better and easier to write efficient codes in Windows Runtime, plus .NET framework is also support (not entire .NET framework, just a few). - Bad thing is: 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, OS will prompt you with an "Access is denied"exception. Plus, the currently added capabilities in the applicatio manifest are so less in number that you cannot even utilitize the entire machine power, you just, design an application. To do something useful you will have to get support from another framework, such as Win32, Native programming in C/C++ or you will have to use .NET framework itself, there is indeed some support for .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 coming 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, source code contains the sample that I made for the sake of this article, it can 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 about these frameworks and how you should use them when you try to build your own applications that makes use of media capturing and recording facilities provided in Windows Runtime.
Windows 10 — Capabilities of application
In a Windows Runtime application you must first of all define all of the capabilities that your application has, before OS would let it perform any action. It is similar to declaring the uses-feature
or uses-permission
in the Android programming; if you ever did Android programming. It would notify the user about your application, plus it would allow 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 have to make sure that the application has access to a resources, say, camera. User can always revoke access to the camera from the settings, you cannot alter the settings yourself. User would have 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 Webcam as well as Microphone. The function, StartRecordAsync
of the MediaCapture
object (discussed later) requires you to allow Microphone also, well you can turn off the mic but still the permission is required. If you do not allow these permissions. There will be an exception raised!
Every application needs a package manifest; same as Android applications, the manifest file contains the information required by the Store to process the applciation 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 which gets executed.
Description for the application. - Visual Assets
The logo and splashscreen 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 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, Visual Assets are used to preview the application 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 camera and microphone resources, in a coming section.
Further in the article, you will find out that Windows Runtime uses these capabilities to find out whether your application is authorized to use that resource or not. It provides users with a layer of privacy, which abstracts the applications to use resources without letting the user know. In settings application, users can manage what applications have a permission to and which permission they must be denied to access. For example, you can deny Internet access request to an application which you don't want to access internet, same applies to other permissions. You can deny request of accessing the camera, microphone and file system resources. In my opinion, it is a great feature in Windows Runtime.
Most of the media related APIs and namespace are present in the 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, microphone are all present under these namespaces. Separated for their own sake of categorization. You can reference them all in your application if you need to.
In this article, I am going to reference and talk about the 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 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.
Windows.Media.Capture
namespace actually provides the classes, enums, structures and other stuff to communicate or work around with the media devices, such as camera and microphone and other sensors installed to them. For example, Windows.Media.Capture
namespace's MediaCapture
object holds a definition for ThermalStatus
field, which provides you with the thermal status of the device. Capturing the data may cause the device to heat, if device has feature to expose the thermal status such as a secondary device installed, it will allow you to capture the thermal status and turn off capturing the photos or videos. Plus, there is an event included which can be used to determine when the thermal status falls 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 two values for this enum,
- Normal (0; zero)
- Overheated (1)
Hopefully, these are the only objects required. You can however dive into much more advanced topics in this namespace, or in the Windows.Media
namespace collection. 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. Where as 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 up 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 in order to write the software for Windows 10.
Tip: If you are not having Windows 10 or Visual Studio 2015, you can still use the code to write applications for Windows 8, 8.1 or Windows Phone 8, 8.1 applications! So, keep reading, and provide your feedback at the end in case of Windows 8, 8.1 application!
Writing the application
Let us head toward the main topic of this article post, writing the source code for the application. This section will be divided in two main sections, one for writing the UI code and 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 screen. Plus, capturing and storing the content on your application's data folder!
As this section continues, I will show you the steps to performs in order 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
First step in this guide is to build the XAML, 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. CaptureElement
control allows you to bind the Source
property to a media device, such as camera (webcam). Windows Runtime provides the content from camera, microphone and other media devices to this control, which 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 Windows Runtime will manage how to transfer and render on the screen for user. Good thing for us is that the syntax to create this control is single line (unless you want to add other functionality to the control also),
<CaptureElement Height="650" Name="captureElement" />
That is enough!
Now, as 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, so we need to build them up for our use. XAML provides a lot of 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, 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 etc. 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 make use of 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
While 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 make sure user isn't capturing the photos when 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 while 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 application, which enables us to provide the controls in a form of tray to the user which 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 a lot of more great resources in MSDN documentation for Symbol
and AppBar
. Furthermore, mostly I created the buttons and commands using the AppBarButto
n (which inherits from Button
object and thus provides us with all of the events, functions and members that Button
object had, we are interested in the Click
event of 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 above code acts as the command bar for our application, thus enabling us to interact with the UI of the application to initiate different commands and functions in the application.
The above bar is what is displayed to the user. I would like to say that Windows team has put a great effort in building great fonts for Windows UI and UX. All of these icons (camera, video and others) are in real, characters (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 have 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 screen to the user which he can interacts with and capture and store on his machine.
Why not set the Source
property in XAML?
No matter what, this will bug you if you are beginner, why didn't I set the property of Source in 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 inital stages until we call explicitly capture.InitializeAsync()
function in the coming code, our capture object is also null which will further more cause a trouble in our application start up — to the XAML, it will cause an exception to be raised, generally of NullReferenceException
type. See below, it was declared that this is caused as a trouble!
For this sake, we leave all of such settings for later, we can set up the environment and other stuff in the contructor asynchronously. Then, once everything is ready, we can intialize 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 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, as 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 go on 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 camera got too hot or is it back ready to be used again. Using these will provide a better UX for your application, and a good review too. Although they are not required, blow the camera user has by heating it and not turning if off, no problem. But, I will personally recommend you do use them for any incidental cases. :-)
2. Facial recognision is provided!
For those of you, wanting to recognise someone at your door with your webcam, here is a good news. Windows Runtime natively supports facial recognision, and you can use those libraries and objects in your applications to make it even better! Windows.Media.FacialAnalysis
namespace provides the objects that you would be interested in using to recognise or store the facial patterns when viewing the data from a webcam.
What happens is that you have 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 which is 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; in future it may.
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 event handler, we can set up things and pass the content to the CaptureElement
control in our Page, so that when the application starts user is able to use his camera as if he started the camera application.
The hierarchy is, that we have to call the InitializeAsync()
function before we can do anything to the MediaCapture object. This function needs to be called, because underground 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, first of all we call this function, then right after this call we have to associate the capturing object to a control that renders the content before we can start previewing the content being captured. This hierarchy needs to be followed by you in order 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();
captureElement.Source = capture;
await capture.StartPreviewAsync();
#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 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 user has allowed your application to use the resources or not. Read more on 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 application.
Tip: I have added a handler to the code, in case anything went wrong while 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 above XAML code if you pay attention you will see that every button was attached to the same handler for Click event. I used it to remove the redundancy, since the same thing was going to be performed based on the icon the user used. I wrote the handler in a way to handle the button, based on the icons (in code I am using the Name
; which is not visible in the UI) so that same code base can be reused. :)
private void button_Click(object sender, RoutedEventArgs e)
{
if((sender as AppBarButton).Name == "cameraIcon")
{
capturePhoto();
} else if((sender as AppBarButton).Name == "videoIcon")
{
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 which renders the data on screen and does not require your camera. In such cases it is better to disconnect the camera from your application otherwise it will continously send 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();
}
Plus, there is another change in the application. Rather than having a separate function to load the resources, I have not handled setting up resources in the event OnNavigatedTo(e)
, it allows better performance for the application now.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
capture = new MediaCapture();
loading.Visibility = Visibility.Visible;
init();
}
These functions are high-level tasks that our application is intended to perform. In coming sections, I will dissect those function blocks to show you how perform these actions in your application.
The only requirements for the further procedures are understandings of asynchronous programming models in C# language. Asynchronous programming in C# language (as we know it today) was introduced as of its 5th version (now it is on 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, but) 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 Windows Runtime has got us covered we don't actually have to do anything, we just specify two things:
- 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 while recording video?
You can try your luck in both cases, in my sample I ignore the capture while 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 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 above code has two paths, one to be executed if the user is recording a video and other if user isn't. One path shows an error message, and other one which interests us creates a new file at the application data folder named "Photo.jpg" and also notice 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 as per your need! That was a bit of a fancy, so I ignored.
Recording a video
That discussed now the next topic to be covered is the recording of a video. The procedure is similar, all is done by Windows Runtime in itself, we don't actually have 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 have to pass a few parameters,
- The storage file where we will store the recording.
Same as above, nothing 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! Same thing being 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 content on the file system. Windows Runtime has us covered, do not worry! :)
private async void alterRecording()
{
if(isRecording)
{
await capture.StopRecordAsync();
videoIcon.Foreground = new SolidColorBrush(new Windows.UI.Color() { A = 255, R = 0, G = 0, B = 0 });
isRecording = false;
} else
{
encoding = getVideoEncoding();
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 });
isRecording = true;
}
}
The above 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 above code is fluid enough to change the extension and other settings based on what user chose while starting the recording event. I would like to share the content of the getVideoEncoding function also, since that is mentioned in the above 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 chaned in the UI, please see the command bar and find the ComboBox
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 any error.
Preview mirroring
Mostly, when you are building the applications for sharing the view on network, you will have to share the content in a mirror view, mostly users do not like to view themselves in a way that seems opposite to them, inverted in other words. Adding a mirror effect is same as rotating the image horizontally to 180° which 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 using SetPreviewMirroring(true)
but that is always recommended, not to be used. Instead you must always use the FlowDirection
property and set it to RightToLeft value. This would invert the image as required.
You can do that programmatically too,
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. MediaCapture
object provides you with read-only members for controllers of audio, 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 is used to control 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 above, it provides you information about the thermal status of your device. VideoDeviceController
The object that controls the settings for video controller — Won't discuss it here.
For their documentation and other information, please refer to the MediaCapture
properties section on MSDN.
In this section, I will use AudioDeviceController to change the state of muting or unmuting of the microphone.
private void muteUnmute()
{
if(muted)
{
capture.AudioDeviceController.Muted = false;
muted = false;
muteIcon.Foreground = new SolidColorBrush(new Windows.UI.Color() { A = 255, R = 0, G = 0, B = 0 });
} else
{
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, which changes the state and mutes it on unmutes it. The above code checks what action to perform based on current state of the controller.
Building the Gallery — Library
Of what good would be the camera application if there is no way to view what you saved, and preview what you recored. 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 gallery for those images and to preview the videos also. Anyways the gallery (as 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 a 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, which 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 user must be able to get a list of images that he has captured, list of videos that he has recorded and to be able to preview them. 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 a 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 fill 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 of things) and they will be used to create the application's UI based on our data. This way, no matter how much images or videos have been captured, we can display them in the application's UI and the good thing is that we only have to provide the template. XAML will fill in the details itself and will take care of 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 ListView
s for each of them, one of them is used to render the images and other one for rendering the videos. Thus two templates are being used in the application for gallery. In the list that renders the images, I have used Image
control. Which 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 above XAML code is simply the template that I was talking about previously. This will be filled with the data that we provide it. The ItemTemplate
allows us to template the items being added to it. It responds to the ItemsSource
(or Items
; which 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 would be built. These are simply the variables holding a reference to the data in that item in the collection.
Twisted words: Why have you set the Source
in XAML now?
Above 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 above. The Source property is bound to Binding property, not to a resource. Which means that although chances are that the data will be null but if we bind it successfully the source won't be null and the application will be built. Have a look, 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 list-view!
Binding the data programmatically
As I was saying that we need to bind the object to this template, how are we going to capture the object in real, 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 Name and other stuff later! But that is done in advanced topics) and now we can create lists of objects that we need.
But to make sure that XAML doesn't throw exception for "Object reference not set an instance of object." we need to make sure that the source property is applied, we will handle the OnNavigatedTo(e)
event and set up everything. I recommend that you also use this event because it gets triggered when application has loaded the page and is now rendering the controls on 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();
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();
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 two cases would arise:
await
keyword will continue the previous function from where we came, and will apply a null list to the photos
and videos
control. Which is not what we want, but that is exactly what await does. - If we ignore the await keyword then we are left with
IAsyncResult
objects, working with which is again a headache.
Keeping the above points in mind, it is better to use the await keyword and let the application's function run asynchronously then by waiting 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 have to work around with other low-level interfaces for asynchronous function results and so on.
Once the above 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 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 ListView 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. GridView
s 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 like the following, notice the application's bottom bar, it contains the controls for camera functions and also a new control for the library.
The libary 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" />
Mind the red rectangle, just wanted to point out that Back button still exists. :sigh:
If user clicks on the button, the button is checked and can be used to change the UI of 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
Windows Runtime provides you with the libraries and tools that you require to build applications that use the devices' resources such as webcams, microphones and other similar media content. Windows 10 applications use Windows Runtime as the framework for programming. 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, 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 while 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 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 application, I am sure I will find a few more bug and I will update the article and source code for the solutions.
Plus, if I have any other idea about this, I will let you guys know. :-) Do leave your feedback if you have any other ideas.
History
Tracking the changes:
- First version of the article and source code.
- Added the library section for the camera