我正在尝试使用CaptureElement / MediaCapture提供在用于显示预览的网络摄像头之间切换的选项。不幸的是,我尝试了多种呼叫序列组合,预览只显示我使用的第一个设备。
这就是我一直在努力做的事情:
XAML:
<CaptureElement
x:Name="captureElement"
Stretch="UniformToFill" />
C#:
MediaCapture mediaCapture;
DeviceInformationCollection devices;
int currentDevice = 0;
private async void LayoutRoot_Tapped(object sender, Windows.UI.Xaml.Input.TappedEventArgs e)
{
if (devices != null)
{
currentDevice = (currentDevice + 1) % devices.Count;
InitializeWebCam();
}
}
private async void InitializeWebCam()
{
if (devices == null)
{
devices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
ListDeviceDetails();
}
if (mediaCapture != null)
{
await mediaCapture.StopPreviewAsync();
this.captureElement.Source = null;
}
mediaCapture = new MediaCapture();
await mediaCapture.InitializeAsync(
new MediaCaptureInitializationSettings
{
VideoDeviceId = devices[currentDevice].Id
});
this.captureElement.Source = mediaCapture;
await mediaCapture.StartPreviewAsync();
}
private void ListDeviceDetails()
{
int i = 0;
foreach (var device in devices)
{
Debug.WriteLine("* Device [{0}]", i++);
Debug.WriteLine("EnclosureLocation.InDock: " + device.EnclosureLocation.InDock);
Debug.WriteLine("EnclosureLocation.InLid: " + device.EnclosureLocation.InLid);
Debug.WriteLine("EnclosureLocation.Panel: " + device.EnclosureLocation.Panel);
Debug.WriteLine("Id: " + device.Id);
Debug.WriteLine("IsDefault: " + device.IsDefault);
Debug.WriteLine("IsEnabled: " + device.IsEnabled);
Debug.WriteLine("Name: " + device.Name);
Debug.WriteLine("IsDefault: " + device.IsDefault);
foreach (var property in device.Properties)
{
Debug.WriteLine(property.Key + ": " + property.Value);
}
}
}
似乎可以偶尔切换到第二台相机(低于10%的时间),然后当我回到第一台时,它会全黑。
有时应用程序挂起后我尝试将相机切换一次或两次(它停止响应输入,它停留在App.Run()中,尽管相机预览保持刷新)。
其他时候 - 它的工作方式是它显示第一个设备的预览,但不适用于另一个设备,当我回到第一个设备时 - 它再次正常工作。
错误?
在任何地方似乎都没有Dispose或Uninitialize方法。这些是我看到的属性(它是三星的Build 2011平板电脑):
* Device [0]
EnclosureLocation.InDock: False
EnclosureLocation.InLid: False
EnclosureLocation.Panel: Front
Id: \\?\USB#VID_2232&PID_1021&MI_00#7&2469C269&0&0000#{e5323777-f976-4f5b-9b55-b94699c46e44}\GLOBAL
IsDefault: False
IsEnabled: True
Name: WebCam SC-20FHM11347N
IsDefault: False
System.ItemNameDisplay: WebCam SC-20FHM11347N
System.Devices.DeviceInstanceId: USB\VID_2232&PID_1021&MI_00\7&2469C269&0&0000
System.Devices.Icon: C:\Windows\System32\DDORes.dll,-2068
System.Devices.InterfaceEnabled: True
System.Devices.IsDefault: False
* Device [1]
EnclosureLocation.InDock: False
EnclosureLocation.InLid: False
EnclosureLocation.Panel: Back
Id: \\?\USB#VID_2232&PID_1022&MI_00#7&27072759&0&0000#{e5323777-f976-4f5b-9b55-b94699c46e44}\GLOBAL
IsDefault: False
IsEnabled: True
Name: WebCam SC-30H2L11449N
IsDefault: False
System.ItemNameDisplay: WebCam SC-30H2L11449N
System.Devices.DeviceInstanceId: USB\VID_2232&PID_1022&MI_00\7&27072759&0&0000
System.Devices.Icon: C:\Windows\System32\DDORes.dll,-2068
System.Devices.InterfaceEnabled: True
System.Devices.IsDefault: False
答案 0 :(得分:2)
我没有平板电脑,我的Metro体验很少......但我确实有很多异步编程经验。
您必须注意的一件事是异步程序与状态不匹配。你本身没有竞争条件,但你必须考虑重入。在这样的例子中,重入可能会导致一种单线程的“竞争条件”。
如果我是对的,一种避免事件重入的简单方法是使用布尔“reentrancy guard”变量(我在下面称之为switchingMedia
)。试试这个:
MediaCapture mediaCapture;
DeviceInformationCollection devices;
int currentDevice = 0;
bool switchingMedia = false;
private async void LayoutRoot_Tapped(object sender, Windows.UI.Xaml.Input.TappedEventArgs e)
{
if (devices != null)
{
InitializeWebCam();
}
}
private async void InitializeWebCam()
{
if (switchingMedia)
return;
switchingMedia = true;
if (devices == null)
{
devices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
ListDeviceDetails();
}
else
{
currentDevice = (currentDevice + 1) % devices.Count;
}
if (mediaCapture != null)
{
await mediaCapture.StopPreviewAsync();
this.captureElement.Source = null;
}
mediaCapture = new MediaCapture();
await mediaCapture.InitializeAsync(
new MediaCaptureInitializationSettings
{
VideoDeviceId = devices[currentDevice].Id
});
this.captureElement.Source = mediaCapture;
await mediaCapture.StartPreviewAsync();
switchingMedia = false;
}
我还建议您使用async
方法返回Task
而不是void
(当然,除非它们是事件处理程序)。这允许它们是可组合的。例如,如果InitializeWebCam
返回Task
,那么您可以将重入保护代码放入事件处理程序中:
private async void LayoutRoot_Tapped(object sender, Windows.UI.Xaml.Input.TappedEventArgs e)
{
if (devices != null && !switchingMedia)
{
currentDevice = (currentDevice + 1) % devices.Count;
switchingMedia = true;
await InitializeWebCam();
switchingMedia = false;
}
}
默认情况下,通过定义所有async
方法返回Task
,您可以使用更多可组合性选项。
答案 1 :(得分:1)
尝试如下
var rearCamera = devices.FirstOrDefault(item => item.EnclosureLocation != null &&
item.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back);
答案 2 :(得分:0)
我认为问题一定是开发人员预览版本。我在Consumer Preview one中的3个网络摄像头之间切换没有问题。