Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Camera helper WIP #1980

Merged
merged 71 commits into from
May 23, 2018
Merged
Show file tree
Hide file tree
Changes from 64 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
2a6b3d6
Initial checkin- adding camera helper class for capturing frames, Add…
Apr 10, 2018
0c75302
Cleaning up resources, adding logic to update source and capture video
Apr 10, 2018
b32d3c5
- Added MediaPlayer and hooking it to the frame source
Apr 11, 2018
eb73681
- Added CameraResult class to return status of Camera Helper Capture …
Apr 13, 2018
7acdac2
Updating error message for debugging
Apr 13, 2018
add873f
- Updated CameraPreviewCode.bind class to check for result from camer…
Apr 13, 2018
e4db028
Merge pull request #1 from Microsoft/master
skommireddi Apr 13, 2018
f60fbf4
Merge branch 'master' into CameraHelper
Apr 16, 2018
d3468a3
Added copyright header for source files
skommireddi Apr 16, 2018
803dcd2
Renaming Async methods with Async keyword
skommireddi Apr 17, 2018
d5a0300
Added new custom CameraVideoPreview xaml control
skommireddi Apr 19, 2018
97e00b0
Addressing code review comment: changing to auto property initializers
skommireddi Apr 19, 2018
ef8a6cf
Removing Debug statements per code review comment
skommireddi Apr 20, 2018
a472edf
Added sample page, code bind file and documentation for Camera Previe…
skommireddi Apr 20, 2018
929233b
Merge pull request #2 from Microsoft/master
skommireddi Apr 20, 2018
93aad10
Merge branch 'master' into CameraHelper
skommireddi Apr 20, 2018
bee2fb1
Changing icons for CameraPreview and CameraHelper sample pages
skommireddi Apr 23, 2018
09fcc25
Addressing code review comments from PR.
skommireddi Apr 26, 2018
aa357e7
Addressing more code review comments -Disposing software bitmap after…
skommireddi Apr 26, 2018
5110904
Addressing PR review comments - Updated docs, added PreviewFailed eve…
skommireddi Apr 27, 2018
1777b7b
Merge pull request #3 from Microsoft/master
skommireddi Apr 27, 2018
741c414
Merge branch 'master' into CameraHelper
skommireddi Apr 27, 2018
815321d
Adding headers to code files, fixing out of range exception when clic…
skommireddi Apr 27, 2018
9d0b9b8
Renamed filename to match type name
skommireddi Apr 27, 2018
7c60361
Changing camera icon to show on top left corner inside MediaPlayerEle…
skommireddi Apr 30, 2018
7fa67e0
PR review changes - Updated docs per template
skommireddi Apr 30, 2018
5fa587a
Adding code to handle exception when user denies camera access, fixin…
skommireddi Apr 30, 2018
ecf7e42
Added FrameSourceGroupButton Visibility dependency property
skommireddi May 1, 2018
ea3b77b
Removed comment
skommireddi May 1, 2018
89271cc
Addressing PR review comments
skommireddi May 2, 2018
6410612
Adding IsFrameSourceGroupButtonAvailable dependency property for Came…
skommireddi May 3, 2018
781f73c
Removed Software Bitmap from FrameEventArgs, Fixed a bug causing Vide…
skommireddi May 3, 2018
85ecafb
Merge branch 'master' into CameraHelper
nmetulev May 4, 2018
20a8f7f
Removing duplicate frame sources
skommireddi May 5, 2018
99b66c0
exposing filtered available format on the source and selecting a defa…
LPBourret May 10, 2018
3fcae45
correcting lower fps threshold filtered on for frame format and corre…
LPBourret May 10, 2018
73f9039
Making CleanUp method async, so that Camera controls are disposed bef…
skommireddi May 11, 2018
4a9990a
Exposing FrameSourceGroup property setter so user can set a camera so…
skommireddi May 12, 2018
72276f3
Removing app suspend and resume event handles from camera control and…
skommireddi May 14, 2018
22a7bd3
addressing comments
LPBourret May 14, 2018
131e2d1
Merge branch 'CameraHelper' into lobourre/CameraHelper_update
LPBourret May 15, 2018
4612c55
adding example of SetFormatAsync on the CameraHelper.FrameSource
LPBourret May 15, 2018
033a77b
Merge pull request #4 from skommireddi/lobourre/CameraHelper_update
LPBourret May 15, 2018
e6da67f
Changing namespace from Microsoft.Toolkit.Uwp.Helpers.CameraHelper to…
skommireddi May 15, 2018
aef4b6b
Renaming FrameSource to PreviewFrameSource as you could have a differ…
skommireddi May 16, 2018
8a04de9
Per review comments :Renamed SetCameraHelperAsync() to StartAsync() f…
skommireddi May 16, 2018
67e8d98
fixed merge conflicts
nmetulev May 17, 2018
8dc39dd
CameraHelper FrameArrived event returns a copy of the VideoFrame
nmetulev May 17, 2018
b9da02d
Added missing docs
nmetulev May 17, 2018
3cd8a8c
Fixing suspend and adding app resume event handlers on Camera Helper …
skommireddi May 17, 2018
6653e7f
updated EventArgs to lazy copy the VideoFrame
nmetulev May 18, 2018
19d3e5a
Merge pull request #5 from Microsoft/nmetulev/camera
nmetulev May 18, 2018
f965d6d
Fixing multiple issues: 1. In Camera Preview control toggle button wa…
skommireddi May 18, 2018
0547ab6
Merge branch 'CameraHelper' of https://github.com/skommireddi/UWPComm…
skommireddi May 18, 2018
884d075
Adding thread safety to Camera Helper logic. Modified logic in Camera…
skommireddi May 19, 2018
4d37ee1
Fixing an issue with toggle button not finding the correct group
skommireddi May 19, 2018
c904aa3
Merge branch 'master' into CameraHelper
nmetulev May 20, 2018
d3652a7
unregistered lifecycle events to prevent memory leak
nmetulev May 20, 2018
f11291b
updated docs
nmetulev May 21, 2018
9ef5c71
cleanup
nmetulev May 21, 2018
718064c
Updating docs, adding thread safe code for cleaning up CameraHelper r…
skommireddi May 22, 2018
da47ee0
Added webcam capability link in docs.
skommireddi May 22, 2018
1a81de7
Addressing Michael's comments: Changed logic to find previe control b…
skommireddi May 23, 2018
6ca4963
Merge branch 'master' into CameraHelper
nmetulev May 23, 2018
294f05a
Merge branch 'master' into CameraHelper
nmetulev May 23, 2018
a764de3
Addressing comments: adding constants to refer to Template Part Names
skommireddi May 23, 2018
2cd0448
Addressing comments
skommireddi May 23, 2018
d06a3b0
Merge branch 'CameraHelper' of https://github.com/skommireddi/UWPComm…
skommireddi May 23, 2018
97487ee
Removing unnecessary usings
skommireddi May 23, 2018
12e387e
Updating docs with Dispose() method
skommireddi May 23, 2018
e2f556f
Merge branch 'master' into CameraHelper
nmetulev May 23, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,8 @@
<Content Include="SamplePages\BluetoothLEHelper\BluetoothLEHelper.png" />
<Content Include="SamplePages\BackdropBlurBrush\BackdropBlurBrush.png" />
<Content Include="SamplePages\Blur\BlurBehavior.png" />
<Content Include="SamplePages\CameraPreview\CameraPreview.png" />
<Content Include="SamplePages\CameraHelper\CameraHelper.png" />
<Content Include="SamplePages\Connected Animations\ConnectedAnimations.png" />
<Content Include="SamplePages\DispatcherHelper\DispatchHelper.png" />
<Content Include="SamplePages\DockPanel\DockPanel.png" />
Expand Down Expand Up @@ -496,13 +498,16 @@
<Content Include="SamplePages\RadialGradientBrush\RadialGradientBrushXaml.bind">
<SubType>Designer</SubType>
</Content>
<Content Include="SamplePages\CameraPreview\CameraPreviewCode.bind" />
<Content Include="SamplePages\CameraHelper\CameraHelperCode.bind" />
<Content Include="SamplePages\LayoutTransformControl\LayoutTransformControlXaml.bind" />
<Content Include="SamplePages\GazeTracing\GazeTracingXaml.bind">
<SubType>Designer</SubType>
</Content>
<Content Include="SamplePages\PrintHelper\PrintHelperXaml.bind">
<SubType>Designer</SubType>
</Content>
<Content Include="SamplePages\CameraPreview\CameraPreviewXaml.bind" />
<Content Include="SamplePages\GazeInteraction\GazeInteractionXaml.bind">
<SubType>Designer</SubType>
</Content>
Expand Down Expand Up @@ -562,6 +567,12 @@
<DependentUpon>BluetoothLEHelperPage.xaml</DependentUpon>
</Compile>
<Compile Include="Common\IXamlRenderListener.cs" />
<Compile Include="SamplePages\CameraPreview\CameraPreviewPage.xaml.cs">
<DependentUpon>CameraPreviewPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\CameraHelper\CameraHelperPage.xaml.cs">
<DependentUpon>CameraHelperPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\Connected Animations\ConnectedAnimationsPage.xaml.cs">
<DependentUpon>ConnectedAnimationsPage.xaml</DependentUpon>
</Compile>
Expand Down Expand Up @@ -895,6 +906,14 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="SamplePages\CameraPreview\CameraPreviewPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="SamplePages\CameraHelper\CameraHelperPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="SamplePages\UniformGrid\UniformGridPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
Expand Down
1 change: 1 addition & 0 deletions Microsoft.Toolkit.Uwp.SampleApp/Package.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
<Capability Name="privateNetworkClientServer" />
<DeviceCapability Name="location" />
<DeviceCapability Name="bluetooth" />
<DeviceCapability Name="webcam" />
<DeviceCapability Name="gazeInput" />
</Capabilities>
</Package>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Creates a Camera Helper and subscribes to frames from an available frame source.
// Make sure you have the capability webcam enabled for your app to access the device's camera.

using Microsoft.Toolkit.Uwp.Helpers;

CameraHelper cameraHelper = new CameraHelper();
var result = await _cameraHelper.InitializeAndStartCaptureAsync();

if(result == CameraHelperResult.Success)
{
// Subscribe to get frames as they arrive
cameraHelper.FrameArrived += CameraHelper_FrameArrived;
}
else
{
// Get error information
var errorMessage = result.ToString();
}

private void CameraHelper_FrameArrived(object sender, FrameEventArgs e)
{
// Gets the current video frame
VideoFrame currentVideoFrame = e.VideoFrame;

// Gets the software bitmap image
SoftwareBitmap softwareBitmap = currentVideoFrame.SoftwareBitmap;
}

private async void Application_Suspending(object sender, SuspendingEventArgs e)
{
if (Frame.CurrentSourcePageType == typeof(CameraHelperPage))
{
var deferral = e.SuspendingOperation.GetDeferral();
await CleanUpAsync();
deferral.Complete();
}
}

private async Task CleanUpAsync()
{
// You may want to unsubscribe from any events and call CameraHelper CleanUpAsync() method
// to free up camera helper resources on App suspending, Page OnNavigatedFrom events when appropriate.
// Note: You would need to re-initialize the CameraHelper and rehook events on App resuming, OnNavigatedTo events.
if (_cameraHelper != null)
{
_cameraHelper.FrameArrived -= CameraHelper_FrameArrived;
await _cameraHelper.CleanUpAsync();
_cameraHelper = null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Page
x:Class="Microsoft.Toolkit.Uwp.SampleApp.SamplePages.CameraHelperPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Microsoft.Toolkit.Uwp.SampleApp.SamplePages"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<Style x:Name="ErrorMessageStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="Red"/>
</Style>
</Page.Resources>
<StackPanel Orientation="Vertical" Margin="20">
<ComboBox x:Name="FrameSourceGroupCombo" Header="Frame Source Group" HorizontalAlignment="Left" Width="Auto">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}"></TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock x:Name="CameraErrorTextBlock" Style="{StaticResource ErrorMessageStyle}" Margin="0,0,0,10" Visibility="Collapsed"></TextBlock>
<Button x:Name="CaptureButton" Content="Capture Video Frame" Margin="0,10" Click="CaptureButton_Click"></Button>
<Image x:Name="CurrentFrameImage" MinWidth="300" Width="400" HorizontalAlignment="Left"></Image>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of using an Image, you can use a MediaPlayerElement XAML control and hook it to your source directly (like in my email) so you don't have to orchestrate rendering of the frames as they come in

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would save you most of the code in your page below

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a different example of using the Video Frames and displaying in an image using the Camera Helper directly. The CameraPreview sample page demonstrates what you mentioned and it uses the xaml control encapsulating the MediaPlayerElement. Does that make sense?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep ok

</StackPanel>
</Page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************

using System;
using System.Threading.Tasks;
using Microsoft.Toolkit.Uwp.Helpers;
using Windows.ApplicationModel;
using Windows.Graphics.Imaging;
using Windows.Media;
using Windows.Media.Capture.Frames;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;

namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
{
/// <summary>
/// Sample page for Camera Helper
/// </summary>
public sealed partial class CameraHelperPage : Page
{
private CameraHelper _cameraHelper;
private VideoFrame _currentVideoFrame;
private SoftwareBitmapSource _softwareBitmapSource;

public CameraHelperPage()
{
this.InitializeComponent();
}

protected override async void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
_softwareBitmapSource = new SoftwareBitmapSource();
CurrentFrameImage.Source = _softwareBitmapSource;

Application.Current.Suspending += Application_Suspending;
Application.Current.Resuming += Application_Resuming;

await InitializeAsync();
}

protected async override void OnNavigatedFrom(NavigationEventArgs e)
{
Application.Current.Suspending -= Application_Suspending;
Application.Current.Resuming -= Application_Resuming;
await CleanUpAsync();
}

private async void Application_Suspending(object sender, SuspendingEventArgs e)
{
if (Frame.CurrentSourcePageType == typeof(CameraHelperPage))
{
var deferral = e.SuspendingOperation.GetDeferral();
await CleanUpAsync();
deferral.Complete();
}
}

private async void Application_Resuming(object sender, object e)
{
await InitializeAsync();
}

private void CameraHelper_FrameArrived(object sender, FrameEventArgs e)
{
_currentVideoFrame = e.VideoFrame;
}

private async Task InitializeAsync()
{
var frameSourceGroups = await CameraHelper.GetFrameSourceGroupsAsync();
if (_cameraHelper == null)
{
_cameraHelper = new CameraHelper();
}

var result = await _cameraHelper.InitializeAndStartCaptureAsync();
if (result == CameraHelperResult.Success)
{
// Subscribe to the video frame as they arrive
_cameraHelper.FrameArrived += CameraHelper_FrameArrived;
FrameSourceGroupCombo.ItemsSource = frameSourceGroups;
FrameSourceGroupCombo.SelectionChanged += FrameSourceGroupCombo_SelectionChanged;
FrameSourceGroupCombo.SelectedIndex = 0;
}

SetUIControls(result);
}

private async void FrameSourceGroupCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (FrameSourceGroupCombo.SelectedItem is MediaFrameSourceGroup selectedGroup)
{
_cameraHelper.FrameSourceGroup = selectedGroup;
var result = await _cameraHelper.InitializeAndStartCaptureAsync();
SetUIControls(result);
}
}

private void SetUIControls(CameraHelperResult result)
{
var success = result == CameraHelperResult.Success;
if (!success)
{
_currentVideoFrame = null;
}

CameraErrorTextBlock.Text = result.ToString();
CameraErrorTextBlock.Visibility = success ? Visibility.Collapsed : Visibility.Visible;

CaptureButton.IsEnabled = success;
CurrentFrameImage.Opacity = success ? 1 : 0.5;
}

private async void CaptureButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
var softwareBitmap = _currentVideoFrame.SoftwareBitmap;

if (softwareBitmap != null)
{
if (softwareBitmap.BitmapPixelFormat != BitmapPixelFormat.Bgra8 || softwareBitmap.BitmapAlphaMode == BitmapAlphaMode.Straight)
{
softwareBitmap = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
}

await _softwareBitmapSource.SetBitmapAsync(softwareBitmap);
}
}

private async Task CleanUpAsync()
{
if (FrameSourceGroupCombo != null)
{
FrameSourceGroupCombo.SelectionChanged -= FrameSourceGroupCombo_SelectionChanged;
}

if (_cameraHelper != null)
{
_cameraHelper.FrameArrived -= CameraHelper_FrameArrived;
await _cameraHelper.CleanUpAsync();
_cameraHelper = null;
}
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Make sure you have the capability webcam enabled for your app to access the device's camera.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d">
<StackPanel Orientation="Vertical" Margin="20">
<controls:CameraPreview x:Name="CameraPreviewControl">
</controls:CameraPreview>
<TextBlock x:Name="ErrorMessage"></TextBlock>
<Image x:Name="CurrentFrameImage" MinWidth="300" Width="400" HorizontalAlignment="Left"></Image>
</StackPanel>
</Page>

// Create and associate the camera helper instance with the camera preview control
var cameraHelper = new CameraHelper();
await _cameraPreviewControl.StartAsync(cameraHelper);
_cameraPreviewControl.CameraHelper.FrameArrived += CameraPreviewControl_FrameArrived;
_cameraPreviewControl.PreviewFailed += CameraPreviewControl_PreviewFailed;


// Create a software bitmap source and set it to the Xaml Image control source.
var softwareBitmapSource = new SoftwareBitmapSource();
CurrentFrameImage.Source = softwareBitmapSource;

// Register for FrameArrived to get real time video frames, software bitmaps.
private void CameraPreviewControl_FrameArrived(object sender, FrameEventArgs e)
{
var videoFrame = e.VideoFrame;
var softwareBitmap = e.VideoFrame.SoftwareBitmap;
var targetSoftwareBitmap = softwareBitmap;

if (softwareBitmap != null)
{
if (softwareBitmap.BitmapPixelFormat != BitmapPixelFormat.Bgra8 || softwareBitmap.BitmapAlphaMode == BitmapAlphaMode.Straight)
{
targetSoftwareBitmap = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
}

await softwareBitmapSource.SetBitmapAsync(targetSoftwareBitmap);
}
}

// Register for PreviewFailed to get failure error information.
private void CameraPreviewControl_PreviewFailed(object sender, PreviewFailedEventArgs e)
{
ErrorMessage.Text = e.Error;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Page
x:Class="Microsoft.Toolkit.Uwp.SampleApp.SamplePages.CameraPreviewPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Microsoft.Toolkit.Uwp.SampleApp.SamplePages"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
</Page>
Loading