Skip to content

Commit

Permalink
windows support
Browse files Browse the repository at this point in the history
  • Loading branch information
afriscic committed Jun 2, 2024
1 parent 98e2fa8 commit 03b41c0
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 1 deletion.
15 changes: 14 additions & 1 deletion BarcodeScanning.Native.Maui/BarcodeScanning.Native.Maui.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

<PropertyGroup>
<TargetFrameworks>net8.0;net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>

<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
Expand All @@ -17,7 +19,9 @@
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">24.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.1</SupportedOSPlatformVersion>
</PropertyGroup>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
</PropertyGroup>

<ItemGroup Condition="$(TargetFramework.StartsWith('net8.0-android')) != true">
<Compile Remove="**\Android\**\*.cs" />
Expand All @@ -29,6 +33,11 @@
<None Include="**\MaciOS\**\*.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>

<ItemGroup Condition="$(TargetFramework.StartsWith('net8.0-windows')) != true">
<Compile Remove="**\Windows\**\*.cs" />
<None Include="**\Windows\**\*.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>

<ItemGroup Condition="!($(TargetFramework.StartsWith('net')) == true AND $(TargetFramework.EndsWith('.0')) == true AND $(TargetFramework.Contains('-')) != true)">
<Compile Remove="**\NET\**\*.cs" />
<None Include="**\NET\**\*.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
Expand All @@ -47,6 +56,10 @@
<PackageReference Include="Xamarin.AndroidX.Collection.Ktx" Version="1.4.0.1" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net8.0-windows'">
<PackageReference Include="ZXingCpp" Version="0.2.1-alpha" />
</ItemGroup>

<ItemGroup>
<None Include="..\README.md">
<Pack>True</Pack>
Expand Down
5 changes: 5 additions & 0 deletions BarcodeScanning.Native.Maui/Platform/Android/CameraManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,12 @@ internal void Stop()
if (_cameraController is not null)
{
if ((int)_cameraController.TorchState.Value == TorchState.On)
{
_cameraController.EnableTorch(false);

if (_cameraView is not null)
_cameraView.TorchOn = false;
}

if (_cameraRunning)
_cameraController.Unbind();
Expand Down
5 changes: 5 additions & 0 deletions BarcodeScanning.Native.Maui/Platform/MaciOS/CameraManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,13 @@ internal void Stop()
if (_captureSession is not null)
{
if (_captureDevice is not null && _captureDevice.TorchActive)
{
CaptureDeviceLock(() => _captureDevice.TorchMode = AVCaptureTorchMode.Off);

if (_cameraView is not null)
_cameraView.TorchOn = false;
}

if (_captureSession.Running)
_captureSession.StopRunning();
}
Expand Down
7 changes: 7 additions & 0 deletions BarcodeScanning.Native.Maui/Platform/Windows/BarcodeView.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using Grid = Microsoft.UI.Xaml.Controls.Grid;

namespace BarcodeScanning;

public class BarcodeView : Grid
{
}
230 changes: 230 additions & 0 deletions BarcodeScanning.Native.Maui/Platform/Windows/CameraManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
using Microsoft.UI.Xaml.Controls;
using Windows.Media.Capture;
using Windows.Media.Capture.Frames;
using Windows.Media.Core;
using Windows.Media.Devices;
using Windows.Media.MediaProperties;

using Border = Microsoft.UI.Xaml.Controls.Border;
using SolidColorBrush = Microsoft.UI.Xaml.Media.SolidColorBrush;

namespace BarcodeScanning;

internal class CameraManager : IDisposable
{
internal BarcodeView BarcodeView { get => _barcodeView; }

private readonly BarcodeView _barcodeView;
private readonly Border _aimDot;
private readonly CameraView _cameraView;
private MediaCapture _mediaCapture;
private MediaFrameSourceInfo _selectedCamera;
private MediaFrameReader _mediaFrameReader;
private readonly MediaPlayerElement _mediaPlayerElement;
private readonly SemaphoreSlim _mediaCaptureLock;

private const int aimDotRadius = 20;

internal CameraManager(CameraView cameraView)
{
_cameraView = cameraView;
_mediaCaptureLock = new SemaphoreSlim(1);

_barcodeView = new BarcodeView();

_mediaPlayerElement = new MediaPlayerElement()
{
HorizontalAlignment = Microsoft.UI.Xaml.HorizontalAlignment.Center,
VerticalAlignment = Microsoft.UI.Xaml.VerticalAlignment.Center,
Stretch = Microsoft.UI.Xaml.Media.Stretch.UniformToFill
};
_aimDot = new Border()
{
Background = new SolidColorBrush(Windows.UI.Color.FromArgb(156, 255, 0, 0)),
HorizontalAlignment = Microsoft.UI.Xaml.HorizontalAlignment.Center,
VerticalAlignment = Microsoft.UI.Xaml.VerticalAlignment.Center,
Width = aimDotRadius,
Height = aimDotRadius,
CornerRadius = new Microsoft.UI.Xaml.CornerRadius(aimDotRadius / 2)
};

_barcodeView.Children.Add(_mediaPlayerElement);
}

internal void Start()
{
MainThread.BeginInvokeOnMainThread(async () =>
{
if (_selectedCamera is null)
UpdateCamera();
if (_mediaCapture is null)
{
_mediaCapture = new MediaCapture();
await _mediaCapture.InitializeAsync(new MediaCaptureInitializationSettings()
{
SourceGroup = await MediaFrameSourceGroup.FromIdAsync(_selectedCamera.Id),
SharingMode = MediaCaptureSharingMode.ExclusiveControl,
StreamingCaptureMode = StreamingCaptureMode.Video,
MemoryPreference = MediaCaptureMemoryPreference.Cpu
});
UpdateResolution();
_mediaPlayerElement.Source = MediaSource.CreateFromMediaFrameSource(_mediaCapture?.FrameSources[_selectedCamera?.Id]);
}
if (_mediaFrameReader is null)
{
_mediaFrameReader = await _mediaCapture.CreateFrameReaderAsync(_mediaCapture?.FrameSources[_selectedCamera?.Id], MediaEncodingSubtypes.Argb32);
_mediaFrameReader.AcquisitionMode = MediaFrameReaderAcquisitionMode.Realtime;
//_mediaFrameReader.FrameArrived += ColorFrameReader_FrameArrived;
}
await _mediaFrameReader.StartAsync();
});
}

internal void Stop()
{
MainThread.BeginInvokeOnMainThread(async () =>
{
if (_mediaCapture?.VideoDeviceController?.TorchControl?.Enabled ?? false)
{
_mediaCapture.VideoDeviceController.TorchControl.Enabled = false;
if (_cameraView is not null)
_cameraView.TorchOn = false;
}
if (_mediaFrameReader is not null)
await _mediaFrameReader.StopAsync();
});
}

internal void UpdateCamera()
{
MainThread.BeginInvokeOnMainThread(async () =>
{
var mediaFrameSourceGroups = await MediaFrameSourceGroup.FindAllAsync();
MediaFrameSourceInfo newCamera = null;
if (_cameraView?.CameraFacing == CameraFacing.Front)
{
newCamera = mediaFrameSourceGroups
.SelectMany(s => s.SourceInfos)
.Where(w => w.MediaStreamType == MediaStreamType.VideoRecord && w.DeviceInformation?.EnclosureLocation?.Panel == Windows.Devices.Enumeration.Panel.Front)
.FirstOrDefault();
}
newCamera ??= mediaFrameSourceGroups
.SelectMany(s => s.SourceInfos)
.Where(w => w.MediaStreamType == MediaStreamType.VideoRecord)
.FirstOrDefault();
if (newCamera is null)
return;
if (_selectedCamera != newCamera && _mediaCapture is not null)
{
if (_mediaCapture.CameraStreamState == CameraStreamState.Streaming)
await _mediaFrameReader?.StopAsync();
//_mediaFrameReader.FrameArrived -= ColorFrameReader_FrameArrived;
_mediaFrameReader.Dispose();
_mediaCapture.Dispose();
_selectedCamera = newCamera;
ReportZoomFactors();
}
});
}

internal void UpdateTorch()
{
if (_mediaCapture?.VideoDeviceController?.TorchControl?.Supported ?? false)
_mediaCapture.VideoDeviceController.TorchControl.Enabled = _cameraView?.TorchOn ?? false;
}

internal void UpdateZoomFactor()
{
if (_mediaCapture?.VideoDeviceController?.ZoomControl?.Supported ?? false)
{
var factor = _cameraView?.RequestZoomFactor ?? -1;

if (factor < 0)
return;

var minValue = _cameraView?.MinZoomFactor ?? -1;
var maxValue = _cameraView?.MaxZoomFactor ?? -1;

if (factor < minValue)
factor = minValue;
if (factor > maxValue)
factor = maxValue;

if (factor > 0)
_mediaCapture.VideoDeviceController.ZoomControl.Value = factor;
}

ReportZoomFactors();
}

internal void UpdateResolution()
{
if (_selectedCamera is null)
return;
//TODO resolution translator
MainThread.BeginInvokeOnMainThread(async () =>
{
var frameSource = _mediaCapture?.FrameSources[_selectedCamera?.Id];
var preferredFormat = frameSource.SupportedFormats
.Where(w => w.VideoFormat.Width == 1280 && w.VideoFormat.Height == 720)
.OrderByDescending(o => (decimal)o.FrameRate.Numerator / (decimal)o.FrameRate.Denominator)
.FirstOrDefault();
if (preferredFormat is not null)
await frameSource.SetFormatAsync(preferredFormat);
});
}

internal void HandleCameraEnabled()
{
if (_cameraView?.CameraEnabled ?? false)
Start();
else
Stop();
}

internal void HandleAimMode()
{
if (_cameraView?.AimMode ?? false)
_barcodeView?.Children.Add(_aimDot);
else
_barcodeView?.Children.Remove(_aimDot);
}

private void ReportZoomFactors()
{
if (_cameraView is not null && (_mediaCapture?.VideoDeviceController?.ZoomControl?.Supported ?? false))
{
_cameraView.CurrentZoomFactor = _mediaCapture.VideoDeviceController.ZoomControl.Value;
_cameraView.MinZoomFactor = _mediaCapture.VideoDeviceController.ZoomControl.Min;
_cameraView.MaxZoomFactor = _mediaCapture.VideoDeviceController.ZoomControl.Max;
}
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{

}
}
}
10 changes: 10 additions & 0 deletions BarcodeScanning.Native.Maui/Platform/Windows/CameraViewHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace BarcodeScanning;

public partial class CameraViewHandler
{
protected override BarcodeView CreatePlatformView()
{
_cameraManager = new CameraManager(VirtualView);
return _cameraManager.BarcodeView;
}
}

0 comments on commit 03b41c0

Please sign in to comment.