问题
My CaptureElements are showing strange behavior. When I set a instantiated MediaCapture as the CaptureElements Source and then call MediaCapture.StartPreviewAsync() the CaptureElement doesn't show anything.
I have one Application (main-app) with a functional BarcodeScanner on the LoginPage. -> Works!
Then I wanted to copy the same code to the SettingsPage with small modifications so in case of several attached cameras, the default one can be set. -> Doesn't work
Then I tried to run the main-app with the help of the remote debugger on other windows tablets with same Windows 10 Version as my machine (keep in mind, that the BarcodeScanner on the Login-Screen works on my machine). -> doesn't work
Because of these failures I copied the running code from the main-apps LoginPage to a completely new solution (lets call it test-app) with the same settings as the original one. I even experimented with referencing the same Dlls, implementing the same design pattern etc. -> doesn't work
My Machine: Win 10 Pro Version 1809 Build 17763.652
DevEnv: MS Visual Studio 2019 Pro Vers. 16.1.6
EDIT: As minimum required Windows Version I selected Build 16229 and my target Version is Build 17763 (my systems Win version)
The "Allow apps to access your camera"-Option in the Widows Settings is switched to ON, so all apps are allowed to access the camera.
Xaml
<Page
x:Class="QrCodeTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:QrCodeTest"
xmlns:vm="using:QrCodeTest.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.DataContext>
<vm:TestViewModel x:Name="ViewModel" />
</Page.DataContext>
<ScrollViewer>
<StackPanel>
<Button Content="Start Preview" HorizontalAlignment="Center" Click="Button_Click" Margin="5" />
<CaptureElement x:Name="capturePreview" HorizontalAlignment="Center" Stretch="Uniform" Width="0" Height="0" Margin="10" />
<Button Content="Stop Preview" HorizontalAlignment="Center" Click="Button_Click_1" Margin="5" />
<TextBlock Text="{Binding Etikett, Mode=TwoWay}" HorizontalAlignment="Center" Margin="5" />
</StackPanel>
</ScrollViewer>
</Page>
CodeBehind
private BarcodeScanner scanner { get; set; }
private ClaimedBarcodeScanner claimedScanner { get; set; }
private MediaCapture captureManager { get; set; }
internal async Task StartScannerAsync () {
capturePreview.Visibility = Visibility.Visible;
capturePreview.Width = 400; capturePreview.Height = 300;
scanner = null;
scanner = await DeviceHelpers.GetFirstDeviceAsync(BarcodeScanner.GetDeviceSelector(connectionTypes), async (id) => await BarcodeScanner.FromIdAsync(id));
if (scanner != null) {
captureManager = new MediaCapture();
claimedScanner = await scanner.ClaimScannerAsync();
if (claimedScanner != null) {
claimedScanner.ReleaseDeviceRequested += claimedScanner_ReleaseDeviceRequested;
claimedScanner.DataReceived += claimedScanner_DataReceived;
claimedScanner.IsDecodeDataEnabled = true;
IReadOnlyList<uint> supportedSymbologies = await scanner.GetSupportedSymbologiesAsync();
foreach (uint symbology in supportedSymbologies) {
listOfSymbologies.Add(new SymbologyListEntry(symbology));
}
await claimedScanner.EnableAsync();
MediaCaptureInitializationSettings _captureInitSettings = new MediaCaptureInitializationSettings {
VideoDeviceId = scanner.VideoDeviceId,
StreamingCaptureMode = StreamingCaptureMode.AudioAndVideo,
PhotoCaptureSource = PhotoCaptureSource.VideoPreview
};
await captureManager.InitializeAsync(_captureInitSettings);
capturePreview.Source = captureManager;
try {
// Change to false, in case you wanna compare different methods of doing the same
bool Like_MP_PAT_UWP = false;
if (Like_MP_PAT_UWP) {
await capturePreview.Source.StartPreviewAsync();
await claimedScanner.StartSoftwareTriggerAsync();
} else {
LocalDataContext.Etikett = "await captureManager.StartPreviewAsync();";
await captureManager.StartPreviewAsync();
await claimedScanner.StartSoftwareTriggerAsync();
Thread.Sleep(2000);
await claimedScanner.StopSoftwareTriggerAsync();
await captureManager.StopPreviewAsync();
LocalDataContext.Etikett = "await capturePreview.Source.StartPreviewAsync();";
await capturePreview.Source.StartPreviewAsync();
await claimedScanner.StartSoftwareTriggerAsync();
Thread.Sleep(2000);
await claimedScanner.StopSoftwareTriggerAsync();
await capturePreview.Source.StopPreviewAsync();
LocalDataContext.Etikett = "await claimedScanner.ShowVideoPreviewAsync();";
await claimedScanner.ShowVideoPreviewAsync();
await claimedScanner.StartSoftwareTriggerAsync();
Thread.Sleep(2000);
await claimedScanner.StopSoftwareTriggerAsync();
claimedScanner.HideVideoPreview();
}
} catch (Exception e) {
Exception x = e; displayRequest.RequestRelease();
} finally {
LocalDataContext.Etikett = string.Empty;
}
}
}
}
ViewModel:
public class TestViewModel: INotifyPropertyChanged {
public static TestViewModel Instance { get; set; }
private string _Etikett;
public string Etikett { get { return _Etikett; } set { _Etikett = value; NotifyPropertyChanged(); } }
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged ([CallerMemberName] String propertyName = "") {
//PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
if (PropertyChanged != null) {
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I've wasted already 4 working days just to compare the solutions, the codes etc. The above code was copied from the test-app but it's mostly identical to the one on the main-apps LoginPage (except for the "if (Like_MP_PAT_UWP) {...}".
Every hint is welcome.
Thank you in advance.
回答1:
The Problem was Kaspersky Endpoint Security's "advanced Threat Protection/host intrusion prevention"-setting. It prevented ALL apps outside from our dev-harddrive (i. e. on our tablets or from our network-drive) to access the camera (Dev-Drive = "Trusted Zone").
It was necessary to reconfigure that feature in Kaspersky Endpoint Security for the whole environment (declare necessary locations/clients as a trusted zone).
Hope, this might help someone with a similar problem or at least give a hint to someone.
回答2:
Just spit-balling here, but I'd suggest attempting to reduce your test to just code that controls the MediaCapture object as much as possible, as that seems to be the symptom where you describe the main issue.
After that, try lowering the SharingMode of the camera to just read-only, in case another app is using the camera with exclusive access. Also, you can reduce the pop up consent check to just the camera, and not have the microphone consent. Sometimes if you accidentally don't agree during the consent pop-up, the app will be denied access to the camera until you allow it again from the system settings (Settings -> Privacy -> Camera).
Below is a sub-optimal and boiled down version of what you described above, but all parts included. I tried to segregate your starting a barcode session from disposing things. Using the MS samples as a guide will be far more reliable than this one. Nonetheless, there's lots more trace points to add, but below has a few traces around where the MediaCapture fails, and other points in the barcode scanner enable section. Hope it helps.
using System;
using System.Collections.Generic;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.Devices.PointOfService;
using System.Threading.Tasks;
using Windows.Media.Capture;
using Windows.Devices.Enumeration;
using System.Diagnostics;
using Windows.Storage.Streams;
namespace StackOverflowQrTest
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
if (claimedScanner == null)
{
await StartScannerAsync();
}
}
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
await StopScannerAsync();
}
private BarcodeScanner scanner { get; set; }
private ClaimedBarcodeScanner claimedScanner { get; set; }
private MediaCapture captureManager { get; set; }
internal async Task StartScannerAsync()
{
capturePreview.Visibility = Visibility.Visible;
capturePreview.Width = 400; capturePreview.Height = 300;
scanner = await DeviceHelpers.GetFirstDeviceAsync(BarcodeScanner.GetDeviceSelector(), async (id) => await BarcodeScanner.FromIdAsync(id));
if (scanner != null)
{
claimedScanner = await scanner.ClaimScannerAsync();
if (claimedScanner != null)
{
claimedScanner.ReleaseDeviceRequested += ClaimedScanner_ReleaseDeviceRequested;
claimedScanner.DataReceived += ClaimedScanner_DataReceived;
claimedScanner.IsDecodeDataEnabled = true;
await claimedScanner.EnableAsync();
try
{
bool haveAssociatedCamera = !string.IsNullOrEmpty(scanner.VideoDeviceId);
if (haveAssociatedCamera)
{
captureManager = new MediaCapture();
captureManager.Failed += CaptureManager_Failed;
MediaCaptureInitializationSettings _captureInitSettings = new MediaCaptureInitializationSettings
{
VideoDeviceId = scanner.VideoDeviceId,
SharingMode = MediaCaptureSharingMode.SharedReadOnly, // share
StreamingCaptureMode = StreamingCaptureMode.Video // just video
};
await captureManager.InitializeAsync(_captureInitSettings);
capturePreview.Source = captureManager;
}
UpdateMessage("waiting..." + (!haveAssociatedCamera ? "But scanner not camera type" : ""));
if (captureManager != null) await captureManager.StartPreviewAsync();
await claimedScanner.StartSoftwareTriggerAsync();
}
catch (Exception e)
{
UpdateMessage(e.Message);
Debug.WriteLine("EXCEPTION: " + e.Message);
}
}
else
{
UpdateMessage("Could not claim barcode scanner");
}
}
else
{
UpdateMessage("No barcode scanners found");
}
}
private void CaptureManager_Failed(MediaCapture sender, MediaCaptureFailedEventArgs errorEventArgs)
{
string msg = string.Format("MediaCapture_Failed: (0x{0:X}) {1}", errorEventArgs.Code, errorEventArgs.Message);
UpdateMessage(msg);
}
internal async Task StopScannerAsync()
{
if (captureManager != null)
{
if (captureManager.CameraStreamState == Windows.Media.Devices.CameraStreamState.Streaming)
{
await captureManager.StopPreviewAsync();
}
captureManager.Dispose();
captureManager = null;
}
if (claimedScanner != null)
{
claimedScanner.Dispose();
claimedScanner = null;
}
if (scanner != null)
{
scanner.Dispose();
scanner = null;
}
}
private void ClaimedScanner_DataReceived(ClaimedBarcodeScanner sender, BarcodeScannerDataReceivedEventArgs args)
{
var scanDataLabelReader = DataReader.FromBuffer(args.Report.ScanDataLabel);
string barcode = scanDataLabelReader.ReadString(args.Report.ScanDataLabel.Length);
UpdateMessage(barcode);
}
private void ClaimedScanner_ReleaseDeviceRequested(object sender, ClaimedBarcodeScanner e)
{
UpdateMessage("Another process is requesting barcode scanner device.");
e.RetainDevice();
}
private async void UpdateMessage (string message)
{
await LastBarcodeRead.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
LastBarcodeRead.Text = message;
});
}
}
public partial class DeviceHelpers
{
// We use a DeviceWatcher instead of DeviceInformation.FindAllAsync because
// the DeviceWatcher will let us see the devices as they are discovered,
// whereas FindAllAsync returns results only after discovery is complete.
public static async Task<T> GetFirstDeviceAsync<T>(string selector, Func<string, Task<T>> convertAsync)
where T : class
{
var completionSource = new TaskCompletionSource<T>();
var pendingTasks = new List<Task>();
DeviceWatcher watcher = DeviceInformation.CreateWatcher(selector);
watcher.Added += (DeviceWatcher sender, DeviceInformation device) =>
{
Func<string, Task> lambda = async (id) =>
{
T t = await convertAsync(id);
if (t != null)
{
completionSource.TrySetResult(t);
}
};
pendingTasks.Add(lambda(device.Id));
};
watcher.EnumerationCompleted += async (DeviceWatcher sender, object args) =>
{
// Wait for completion of all the tasks we created in our "Added" event handler.
await Task.WhenAll(pendingTasks);
// This sets the result to "null" if no task was able to produce a device.
completionSource.TrySetResult(null);
};
watcher.Start();
// Wait for enumeration to complete or for a device to be found.
T result = await completionSource.Task;
watcher.Stop();
return result;
}
}
}
Where main xaml is...
<Page
x:Class="StackOverflowQrTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:StackOverflowQrTest"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ScrollViewer>
<StackPanel>
<Button Content="Start Preview" HorizontalAlignment="Center" Click="Button_Click" Margin="5" />
<CaptureElement x:Name="capturePreview" HorizontalAlignment="Center" Stretch="Uniform" Width="0" Height="0" Margin="10" />
<Button Content="Stop Preview" HorizontalAlignment="Center" Click="Button_Click_1" Margin="5" />
<TextBox Header="LastBarcode" Name="LastBarcodeRead" IsReadOnly="True" HorizontalAlignment="Center" Margin="5" />
</StackPanel>
</ScrollViewer>
</Page>
来源:https://stackoverflow.com/questions/57290614/uwp-barcodescanner-preview-captureelement-doesnt-show-any-preview