VideoBrush突然冻结,不知道为什么,wp7

时间:2012-11-19 01:23:27

标签: c# silverlight windows-phone-7 xaml windows-phone-7.1

发现了正在发生的事情 - 同时运行的Accelerometers和VideoBrushes会冻结VideoBrush。要解决此问题,请在启动VideoBrush

之前停止加速度计

使用最少的代码(如下所示),它会在应用程序启动VideoBrush后大约2分15秒时可靠地崩溃。这是在使用c#和Xaml的Windows Phone 7.5应用程序的Windows 7模拟器上。如果VideoBrush拉伸也设置为填充等,则会发生这种情况(此时存在Silverlight 1.0错误)

关于我如何得出这个问题的故事,请查看下面的文字答案:)

为什么会这样?我不知道。也许有内存泄漏或什么?值得注意的是 - 这实际上不会使应用程序本身崩溃。你不会弹出任何异常。

重现问题的代码(制作一个名为PhoneApp1的新应用程序并自行试用!):

Xaml代码:

<phone:PhoneApplicationPage 
    x:Class="PhoneApp1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="False">

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">

            <Rectangle x:Name="viewfinderCanvas" Width="480" Height="800" >
                <Rectangle.Fill>
                    <VideoBrush x:Name="viewfinderBrush"/>
                </Rectangle.Fill>
            </Rectangle>

    </Grid>
</phone:PhoneApplicationPage>

C#代码:

using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Devices;
using Microsoft.Devices.Sensors;

namespace PhoneApp1
{
    public partial class MainPage : PhoneApplicationPage
    {
        private Accelerometer AccelerometerSensor;

        // Constructor
        public MainPage()
        {
            InitializeComponent();
            AccelerometerSensor = new Accelerometer();
            AccelerometerStartup();

            if ((PhotoCamera.IsCameraTypeSupported(CameraType.Primary) == true))
            {
                viewfinderCanvas.Visibility = Visibility.Visible;
                var cam = new Microsoft.Devices.PhotoCamera(CameraType.Primary);

                viewfinderBrush.SetSource(cam);
            }
        }

        #region Accelerometer Startup Function
        private void AccelerometerStartup()
        {
            try
            {
                if (AccelerometerSensor != null)
                {
                    AccelerometerSensor.Start();

                }
            }
            catch (AccelerometerFailedException)
            {
            }
            catch (UnauthorizedAccessException)
            {
            }
        }
        #endregion
    }
}

下面的原始问题: (下面提到的代码已保留,但由于没有附加加速计,因此无法重现问题)

这是一个有趣的,我保证。

我决定在我的wp7.5 app中添加一个矩形,其fill属性是VideoBrush。我使用了从几个网站找到的代码,并认为一切都很好。直到我注意到摄像机的VideoBrush会冻结...运行它的时间为6到40秒。

令人困惑,我以为我的派遣计时器干扰了相机。将它们注释掉以便它们无法运行并不能解决问题。然后我尝试在应用中停用我的广告。也没有解决它。我禁用了可以在整个应用程序中呈现更新的所有内容(计时器,调度计时器,广告轮播,任何循环),并且它仍然冻结。

我做了同样的事情,甚至将我的设备从计算机上拔下来,因为当我使用设备进行调试时,使用zune open连接到计算机可能会中断事情。仍然没有骰子。

我创建了一个新项目并将其粘贴到VideoBrush代码中,并且无需冻结即可正常工作。

XAML代码:

<Rectangle x:Name="viewfinderCanvas" Width="480" Height="800" Visibility="Collapsed" DoubleTap="viewfinderCanvas_DoubleTap">
            <Rectangle.Fill>
                <VideoBrush x:Name="videoBrush">
                <VideoBrush.RelativeTransform>
                    <CompositeTransform x:Name="previewTransform"
                            CenterX=".5"
                            CenterY=".5" />
                </VideoBrush.RelativeTransform>
                </VideoBrush>
            </Rectangle.Fill>
        </Rectangle>

C#代码:

if ((PhotoCamera.IsCameraTypeSupported(CameraType.Primary) == true))
    {
           viewfinderCanvas.Visibility = Visibility.Visible;
           var cam = new Microsoft.Devices.PhotoCamera(CameraType.Primary);

           if (Orientation == PageOrientation.PortraitUp || Orientation ==  
           PageOrientation.PortraitDown || Orientation == PageOrientation.Portrait)
             {
                videoBrush.RelativeTransform =
                new CompositeTransform() { CenterX = 0.5, CenterY = 0.5, Rotation = 90 };
             }

           videoBrush.SetSource(cam);
    }

真的,我不知道是什么导致了VideoBrush显示的冻结。我在每个功能上都设置了断点,没有任何功能。没有错误消息......视频只是冻结。

之前有没有遇到过这个?它发生在我的设备和我编写的计算机上 - 仿真器的白框刚刚停止。

为了清楚起见 - 目的是只显示相机在应用中看到的内容 - 我没有拍照或录制视频。我只是在做这个节目。要关闭窗口,用户将双击矩形以关闭原始视图。

3 个答案:

答案 0 :(得分:1)

我已经知道发生了什么,而且确实是我的代码。

TL:DR:具有活动VideoBrush的活动加速度计会导致VideoBrush最终冻结。

我做了什么来测试这个:

使用我的2000+代码行,我坐在那里开始评论API,引用和我通常认为会导致VideoBrush冻结的东西。每次我拿出一大块代码看我是否有所作为时,我会测试应用程序。我的测试依赖于VideoBrush冻结启动所需的秒数。

有趣的是,在删除任何内容之前,通常在VideoBrush冻结之前约45秒左右。在剪掉我的代码之后,当我突然跳到2分45秒时,我得到了我的第一个主要结果。这是在我删除了一些网格时实现的,这些网格包含一些堆叠面板,文本块和按钮,这些网格都在Blend中进行了动画处理。

在这一点上,我一直认为我的混合物不是从Visibility.Visible到Visibility.Collapsed,因此随着时间的推移积累了一些东西。事实并非如此,因为在调用VideoBrush之前崩溃所有内容的功能在2:45的冻结时间内没有变化。

我取出了所有资产,取出所有计时器,派遣计时器,秒表,日期时间实例,但它仍然没有做任何改变2:45的事情。

然后我遇到了它:我的加速度计。

为了全面了解,我在两个不同页面上的wp7应用程序中使用了加速度计。当用户第一次打开应用程序时,他将进入一个教程页面,其中有一个加速度计来模仿主页面。当完成该教程时,用户将被带到主页面,该主页面也有一个具有相同名称和事件更改通知的加速度计。

作为旁注,在查看我的代码时,我注意到我的编码错误,我没有在任何一页上实际停止/处理我的加速度计。这从未在应用程序中造成崩溃,因此它从未成为一个已实现的问题。

有了这个问题,我注意到在VideoBrush冻结之前,时间会跳到5点左右。进步,但仍然导致这种冻结?

然后我决定在启动VideoBrush之前停止加速度计,然后看看VideoBrush工作而不冻结它的图片。

很抱歉,因为如果不知道什么可以阻止VideoBrush在没有应用程序崩溃的情况下工作,这是一个不可能回答的问题。至少现在有一种已知的方法!

答案 1 :(得分:0)

正如KooKiz的评论中所述,我能够使用绝对最小代码重现VideoBrush冻结。时间可能会有所不同,但是使用下面的代码,VideoBrush可以在2分钟到14秒到2分15秒之间可靠地冻结。 (我通过运行模拟器并打开系统时钟多次计时,注意VideoBrush何时启动以及何时冻结。)

Xaml代码:

<phone:PhoneApplicationPage 
    x:Class="PhoneApp1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="False">

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">

            <Rectangle x:Name="viewfinderCanvas" Width="480" Height="800" >
                <Rectangle.Fill>
                    <VideoBrush x:Name="viewfinderBrush"/>
                </Rectangle.Fill>
            </Rectangle>

    </Grid>
</phone:PhoneApplicationPage>

C#代码:

using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Devices;
using Microsoft.Devices.Sensors;

namespace PhoneApp1
{
    public partial class MainPage : PhoneApplicationPage
    {
        private Accelerometer AccelerometerSensor;

        // Constructor
        public MainPage()
        {
            InitializeComponent();
            AccelerometerSensor = new Accelerometer();
            AccelerometerStartup();

            if ((PhotoCamera.IsCameraTypeSupported(CameraType.Primary) == true))
            {
                viewfinderCanvas.Visibility = Visibility.Visible;
                var cam = new Microsoft.Devices.PhotoCamera(CameraType.Primary);

                viewfinderBrush.SetSource(cam);
            }
        }


        #region Accelerometer Startup Function
        private void AccelerometerStartup()
        {
            try
            {
                if (AccelerometerSensor != null)
                {
                    AccelerometerSensor.Start();

                }
            }
            catch (AccelerometerFailedException)
            {
            }
            catch (UnauthorizedAccessException)
            {
            }
        }
        #endregion
    }
}

答案 2 :(得分:0)

感谢您的代码,我能够重现这个问题,并找到了根本原因。

准备好了,它会成为一个&#34; ......那是什么?&#34;时刻!

基本上,整个问题就在那条线上:

var cam = new Microsoft.Devices.PhotoCamera(CameraType.Primary);

您正在创建一个新的PhotoCamera,但您并未将该引用保留在任何位置。因此,当垃圾收集器启动时,它会处理您的孤立PhotoCamera实例,从而冻结视频。

它很容易重现:只需在页面上添加一个按钮,然后输入点击处理程序:

GC.Collect();

只要按下按钮,视频就会冻结。

现在显而易见的问题是:为什么它只用加速度计冻结?实际上非常简单。当分配的对象总数达到阈值时,将自动触发垃圾回收。当你只有视频时,很少有对象被分配(可能没有),因此垃圾收集器不会在很长时间之前被触发。当打开加速度计时,它会以高速度更新其位置,在过程中分配新对象,因此在几分钟后触发垃圾收集。

如何解决问题?只需将PhotoCamera引用存储在属性中:

private PhotoCamera cam;

public MainPage()
{
    InitializeComponent();

    AccelerometerSensor = new Accelerometer();
    AccelerometerSensor.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<AccelerometerReading>>(AccelerometerSensor_CurrentValueChanged);
    AccelerometerStartup();

    if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary))
    {
        viewfinderCanvas.Visibility = Visibility.Visible;
        cam = new PhotoCamera(CameraType.Primary);

        viewfinderBrush.SetSource(cam);
    }
}