2012-02-03 178 views
1

我想提供一个选项,用于在使用CaptureElement/MediaCapture显示预览的网络摄像头之间进行切换。不幸的是,我尝试了呼叫序列的多种组合,预览只显示了我使用的第一个设备。如何在使用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(),虽然摄像头预览不断刷新)。

其他时候 - 它工作的方式,它显示从第一设备预览,但不为其他一个,当我再回到第一个 - 它再次工作与它的罚款。

错误?

似乎有不是一个处置或未初始化方法的任何地方。这是我看到的性能(这是三星的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

我认为这个问题一定是与开发者预览版本。在Consumer Preview中的3个网络摄像头之间切换时没有问题。

2

我没有平板电脑,和我很少有地铁的经历......但我有很多的异步编程经验。你必须要知道的

的一件事是异步程序不符合国家发挥好。你本身没有竞争条件,但你必须考虑重入性。在这样的例子中,重入可能导致一种单线程“竞态条件”。

如果我是对的,避免重新进入事件的一个简单方法是有一个布尔型“重入守卫”变量(我在下面称之为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,你有更多的组合性的选择。

+0

谢谢你 - 它并没有真正解决我的问题,但这些都是有用的技巧。 – 2012-02-04 03:58:25

0

获得设备的所有列表后,尝试像下面

var rearCamera = devices.FirstOrDefault(item => item.EnclosureLocation != null && 
                 item.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back);