forked from microsoft/WinUI-Gallery
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added a "Capture element / camera preview" page in the Media section. (…
…microsoft#1357) ## Description `CaptureElement` from UWP XAML does not exist in WinAppSDK, but `MediaPlayerElement` can be used in its place. The change adds a new sample page to demonstrate how this can be done. Note: Currently this page just reuses the same icon as the MediaPlayerElement page. Ideally at some point we'll get a camera icon which could be used here instead. ## Motivation and Context Demonstrate the couple of calls to get from a `MediaCapture` to an `IMediaPlaybackSource` necessary to display the capture in a MediaPlayerElement. This also demonstrates basic creation of a `MediaCapture` to provide an end-to-end sample. This sample should help address questions in microsoft/microsoft-ui-xaml#4710 and microsoft/microsoft-ui-xaml#8214. ## How Has This Been Tested? Ad-hoc testing and testing with Accessibility Insights for Windows tool. ## Types of changes - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change)
- Loading branch information
Showing
6 changed files
with
241 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<Page x:Class="AppUIBasics.ControlPages.CaptureElementPreviewPage" | ||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:AppUIBasics" | ||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | ||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> | ||
<StackPanel> | ||
<local:ControlExample x:Name="Example1" HeaderText="A MediaCapture preview displayed via a MediaPlayerElement." XamlSource="Media/CaptureElementPreviewSample_xaml.txt" CSharpSource="Media/CaptureElementPreviewSample_cs.txt"> | ||
<local:ControlExample.Example> | ||
<Grid RowDefinitions="Auto,*" ColumnDefinitions="*,100" MinWidth="400" MinHeight="300" RowSpacing="10" ColumnSpacing="4"> | ||
<TextBlock x:Name="frameSourceName" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center"/> | ||
<MediaPlayerElement x:Name="captureElement" Grid.Row="1" Grid.Column="0" Stretch="Uniform" AutoPlay="True" /> | ||
<TextBlock x:Name="capturedText" Visibility="Collapsed" Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Text="Captured:" /> | ||
<Grid x:Name="captureContainer" Grid.Row="1" Grid.Column="1"> | ||
<ScrollViewer VerticalScrollMode="Enabled"> | ||
<StackPanel x:Name="snapshots" Spacing="2"/> | ||
</ScrollViewer> | ||
</Grid> | ||
</Grid> | ||
</local:ControlExample.Example> | ||
<local:ControlExample.Options> | ||
<StackPanel> | ||
<ToggleSwitch x:Name="mirrorSwitch" Header="Mirror preview" IsOn="False" Toggled="MirrorToggleSwitch_Toggled" ToolTipService.ToolTip="Mirrors only the preview, not captured photos"/> | ||
<Button x:Name="captureButton" Content="Capture Photo" Click="CapturePhoto_Click" /> | ||
</StackPanel> | ||
</local:ControlExample.Options> | ||
<local:ControlExample.Substitutions> | ||
<local:ControlExampleSubstitution Key="MirrorPreview" Value="{x:Bind MirrorTextReplacement, Mode=OneWay}"/> | ||
</local:ControlExample.Substitutions> | ||
</local:ControlExample> | ||
</StackPanel> | ||
</Page> |
130 changes: 130 additions & 0 deletions
130
WinUIGallery/ControlPages/CaptureElementPreviewPage.xaml.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Runtime.InteropServices.WindowsRuntime; | ||
using Windows.Foundation; | ||
using Windows.Foundation.Collections; | ||
using Microsoft.UI.Xaml; | ||
using Microsoft.UI.Xaml.Controls; | ||
using Microsoft.UI.Xaml.Controls.Primitives; | ||
using Microsoft.UI.Xaml.Data; | ||
using Microsoft.UI.Xaml.Input; | ||
using Microsoft.UI.Xaml.Media; | ||
using Microsoft.UI.Xaml.Navigation; | ||
using Windows.Media.Capture.Frames; | ||
using Windows.Media.Capture; | ||
using Microsoft.UI.Xaml.Media.Imaging; | ||
using Windows.Media.MediaProperties; | ||
using Windows.Storage.Streams; | ||
using System.ComponentModel; | ||
using AppUIBasics.Helper; | ||
|
||
namespace AppUIBasics.ControlPages | ||
{ | ||
public sealed partial class CaptureElementPreviewPage : Page, INotifyPropertyChanged | ||
{ | ||
public CaptureElementPreviewPage() | ||
{ | ||
this.InitializeComponent(); | ||
|
||
StartCaptureElement(); | ||
|
||
// Move the ScrollViewer from the captureContainer under an ExpandToFillContainer. | ||
// This will allow the snapshots column to use all available height without | ||
// influencing the height. | ||
var expandToFillContainer = new ExpandToFillContainer(); | ||
var sv = captureContainer.Children[0]; | ||
captureContainer.Children.Remove(sv); | ||
captureContainer.Children.Add(expandToFillContainer); | ||
expandToFillContainer.Children.Add(sv); | ||
} | ||
|
||
private MediaFrameSourceGroup mediaFrameSourceGroup; | ||
private MediaCapture mediaCapture; | ||
|
||
async private void StartCaptureElement() | ||
{ | ||
var groups = await MediaFrameSourceGroup.FindAllAsync(); | ||
if (groups.Count == 0) | ||
{ | ||
frameSourceName.Text = "No camera devices found."; | ||
return; | ||
} | ||
mediaFrameSourceGroup = groups.First(); | ||
|
||
frameSourceName.Text = "Viewing: " + mediaFrameSourceGroup.DisplayName; | ||
mediaCapture = new MediaCapture(); | ||
var mediaCaptureInitializationSettings = new MediaCaptureInitializationSettings() | ||
{ | ||
SourceGroup = this.mediaFrameSourceGroup, | ||
SharingMode = MediaCaptureSharingMode.SharedReadOnly, | ||
StreamingCaptureMode = StreamingCaptureMode.Video, | ||
MemoryPreference = MediaCaptureMemoryPreference.Cpu | ||
}; | ||
await mediaCapture.InitializeAsync(mediaCaptureInitializationSettings); | ||
|
||
// Set the MediaPlayerElement's Source property to the MediaSource for the mediaCapture. | ||
var frameSource = mediaCapture.FrameSources[this.mediaFrameSourceGroup.SourceInfos[0].Id]; | ||
captureElement.Source = Windows.Media.Core.MediaSource.CreateFromMediaFrameSource(frameSource); | ||
} | ||
|
||
public string MirrorTextReplacement = ""; // starts not mirrored, so no text in that case | ||
|
||
public event PropertyChangedEventHandler PropertyChanged; | ||
|
||
public void OnPropertyChanged(string PropertyName) | ||
{ | ||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName)); | ||
} | ||
|
||
private void MirrorToggleSwitch_Toggled(object sender, RoutedEventArgs e) | ||
{ | ||
if (mirrorSwitch.IsOn) | ||
{ | ||
captureElement.RenderTransform = new ScaleTransform() { ScaleX = -1 }; | ||
captureElement.RenderTransformOrigin = new Point(0.5, 0.5); | ||
MirrorTextReplacement = | ||
"\n" + | ||
" // Mirror the preview\n" + | ||
" captureElement.RenderTransform = new ScaleTransform() { ScaleX = -1 };\n" + | ||
" captureElement.RenderTransformOrigin = new Point(0.5, 0.5);\n"; | ||
} | ||
else | ||
{ | ||
captureElement.RenderTransform = null; | ||
MirrorTextReplacement = ""; | ||
} | ||
OnPropertyChanged("MirrorTextReplacement"); | ||
} | ||
|
||
async private void CapturePhoto_Click(object sender, RoutedEventArgs e) | ||
{ | ||
// Capture a photo to a stream | ||
var imgFormat = ImageEncodingProperties.CreateJpeg(); | ||
var stream = new InMemoryRandomAccessStream(); | ||
await mediaCapture.CapturePhotoToStreamAsync(imgFormat, stream); | ||
stream.Seek(0); | ||
|
||
// Show the photo in an Image element | ||
BitmapImage bmpImage = new BitmapImage(); | ||
await bmpImage.SetSourceAsync(stream); | ||
var image = new Image() { Source = bmpImage }; | ||
snapshots.Children.Insert(0, image); | ||
|
||
capturedText.Visibility = Visibility.Visible; | ||
|
||
UIHelper.AnnounceActionForAccessibility(captureButton, "Photo successfully captured.", "CameraPreviewSampleCaptureNotificationId"); | ||
} | ||
} | ||
|
||
class ExpandToFillContainer : Grid | ||
{ | ||
protected override Size MeasureOverride(Size availableSize) | ||
{ | ||
// Measure with the minimum height so it will just expand to whatever space is available. | ||
var desiredSize = base.MeasureOverride(new Size(availableSize.Width, 100)); | ||
return desiredSize; | ||
} | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
WinUIGallery/ControlPagesSampleCode/Media/CaptureElementPreviewSample_cs.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using Windows.Media.Capture.Frames; | ||
using Windows.Media.Capture; | ||
|
||
private MediaFrameSourceGroup mediaFrameSourceGroup; | ||
private MediaCapture mediaCapture; | ||
|
||
async private void StartCaptureElement() | ||
{ | ||
var groups = await MediaFrameSourceGroup.FindAllAsync(); | ||
if (groups.Count == 0) | ||
{ | ||
frameSourceName.Text = "No camera devices found."; | ||
return; | ||
} | ||
mediaFrameSourceGroup = groups.First(); | ||
|
||
frameSourceName.Text = "Viewing: " + mediaFrameSourceGroup.DisplayName; | ||
mediaCapture = new MediaCapture(); | ||
var mediaCaptureInitializationSettings = new MediaCaptureInitializationSettings() | ||
{ | ||
SourceGroup = this.mediaFrameSourceGroup, | ||
SharingMode = MediaCaptureSharingMode.SharedReadOnly, | ||
StreamingCaptureMode = StreamingCaptureMode.Video, | ||
MemoryPreference = MediaCaptureMemoryPreference.Cpu | ||
}; | ||
await mediaCapture.InitializeAsync(mediaCaptureInitializationSettings); | ||
|
||
// Set the MediaPlayerElement's Source property to the MediaSource for the mediaCapture. | ||
var frameSource = mediaCapture.FrameSources[this.mediaFrameSourceGroup.SourceInfos[0].Id]; | ||
captureElement.Source = Windows.Media.Core.MediaSource.CreateFromMediaFrameSource(frameSource); | ||
$(MirrorPreview) } | ||
|
||
async private void CapturePhoto_Click(object sender, RoutedEventArgs e) | ||
{ | ||
// Capture a photo to a stream | ||
var imgFormat = ImageEncodingProperties.CreateJpeg(); | ||
var stream = new InMemoryRandomAccessStream(); | ||
await mediaCapture.CapturePhotoToStreamAsync(imgFormat, stream); | ||
stream.Seek(0); | ||
|
||
// Show the photo in an Image element | ||
BitmapImage bmpImage = new BitmapImage(); | ||
await bmpImage.SetSourceAsync(stream); | ||
var image = new Image() { Source = bmpImage }; | ||
snapshots.Children.Insert(0, image); | ||
|
||
capturedText.Visibility = Visibility.Visible; | ||
} |
10 changes: 10 additions & 0 deletions
10
WinUIGallery/ControlPagesSampleCode/Media/CaptureElementPreviewSample_xaml.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<Grid RowDefinitions="Auto,*" ColumnDefinitions="*,100" MinWidth="400" MinHeight="300" RowSpacing="10" ColumnSpacing="4"> | ||
<TextBlock x:Name="frameSourceName" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center"/> | ||
<MediaPlayerElement x:Name="captureElement" Grid.Row="1" Grid.Column="0" Stretch="Uniform" AutoPlay="True" /> | ||
<TextBlock x:Name="capturedText" Visibility="Collapsed" Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Text="Captured:" /> | ||
<Grid x:Name="captureContainer" Grid.Row="1" Grid.Column="1"> | ||
<ScrollViewer VerticalScrollMode="Enabled"> | ||
<StackPanel x:Name="snapshots" Spacing="2"/> | ||
</ScrollViewer> | ||
</Grid> | ||
</Grid> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters