1

Found out what was going on -- Accelerometers and VideoBrushes running at the same time will freeze the VideoBrush. To fix this, stop the accelerometer before starting the VideoBrush

With minimal code (noted just below), it will reliably crash at around 2 minutes and 15 seconds after the VideoBrush starts on the app. This is on the Windows 7 emulator for a Windows Phone 7.5 app, using c# and Xaml. It happens if VideoBrush stretch is also set to fill, etc (there was a Silverlight 1.0 bug with this)

For the story of how I derived to this, please check out the wall of text answer below : )

Why does this happen? I do not know. Perhaps there is a memory leak or something? Of note -- this actually does not crash the app itself. You will not get any exception popping up.

Code to reproduce the problem (make a new application titled PhoneApp1 and try it yourself!):

Xaml Code:

<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# code:

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
    }
}

Original Question Below: (code noted below preserved, but will not reproduce problem as no accelerometer is attached)

This is a fun one, I promise.

I decided to put in my wp7.5 app a rectangle with which its fill property is a VideoBrush. I've used the code found from a few websites, and thought everything was all right. THis was until I noticed that the VideoBrush from the camera would freeze... anywhere from 6 - 40 seconds of running it.

Baffled, I thought my dispatch timers were interfering with the camera. Commenting them out so that they could not run did not fix the problem. I then tried disabling my ads in the app. Also didn't fix it. I disabled everything that could render an update throughout the app (timers, dispatch timers, ad rotations, any loops) and it STILL freezes.

I did the same thing and even unplugged my device from the computer as I read debugging with the device while connected to the computer with zune open could disrupt things. Still no dice.

I created a new project and copy pasted just the VideoBrush code in, and it works without freezing.

The XAML code:

<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# code:

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);
    }

So truly, I have no idea what is causing this freezing of the VideoBrush display. I put breakpoints on every function and nothing picked up. No error messages exist... the video just freezes.

Has anyone encountered this before? It happens on both my device and on the computer I code from too -- the emulator's white box just stops.

for clarity -- purpose of this is to just show what the camera sees in the app -- I am not taking photos or recording video. I am merely making this show. To close the window, a user will double tap the rectangle to close the raw view.

2
  • Unfortunately, if you can't reproduce the issue in a minimal project, it will be tough to help you, because it means we lack the piece of code that is actually making the brush freeze. You should try adding the remaining code bit by bit to your test projects until you're able to reproduce the freeze. Commented Nov 19, 2012 at 20:58
  • Found out what was going on -- accelerometers and videobrushes at the same time don't mix.
    – Shaun Doty
    Commented Nov 20, 2012 at 6:46

3 Answers 3

1

I have found out what was going on, and it indeed was something with my code.

TL:DR: An active accelerometer with an active VideoBrush causes the VideoBrush to eventually freeze.

What I did to test this:

Taking my 2000+ some lines of code, I sat there and started commenting out APIs, references, and things that I generally thought would cause the VideoBrush to freeze. I would test the app every time I took out a decent size chunk of code to see if it made a difference. My testing relied on how many seconds it took for the VideoBrush to freeze from being initiated.

Interestingly enough, before removing anything, it was usually around 45 seconds or so before the VideoBrush would freeze. After snipping away at my code, I got my first major result when it suddenly jumped to 2 minutes and 45 seconds. This was achieved when I removed a few grids which contained a couple stackpanels, textblocks, and buttons which were all animated in Blend.

At this point I humored the idea that my things in blend were not going from Visibility.Visible to Visibility.Collapsed, and thus something was building up over time. This was not the case, as a function to collapse everything before calling the VideoBrush yielded no change in the time to freeze of 2:45.

I took out all my assets, took out all timers, dispatch timers, stopwatches, datetime instances and it still didn't do anything to change the 2:45.

Then I came across it: My accelerometer.

For the full picture, I am using an accelerometer in my wp7 application on two different pages. When a user opens the app for the first time, he will be taken to a tutorial page which has an accelerometer to mimic the main page. When that tutorial is done with, the user is taken to the mainpage which also has an accelerometer with the same name and eventchange notification.

As a side note, while going over my code I noticed a coding error of mine where I didn't actually stop/dispose my accelerometers on either page. This never caused a crash in the app, and thus it never became a realized problem.

With that fixed, I noticed that the time would jump up to about 5:00 before the VideoBrush would freeze. Progress, but what was still causing this freezing?

I then decided to stop the accelerometer before initiating the VideoBrush, and lo and behold the VideoBrush works without freezing its picture.

So sorry since this was an impossible question to answer without knowing what could stop the VideoBrush from working without the app crashing. At least there is one known way now!

3
  • Nice work. Are you able to reproduce the issue with a minimal project? I'm just wondering if I could figure out what's happening behind the scene. Commented Nov 20, 2012 at 8:16
  • Hi Kookiz. Yes, I am indeed able to reproduce this with minimal code. I will post it in a new answer below. The time it took to freeze the VideoBrush with minimal code was 2:14. This is with both the accelerometer and VideoBrush running at the same time.
    – Shaun Doty
    Commented Nov 20, 2012 at 17:31
  • The original question has been updated to include the answer I just recently posted.
    – Shaun Doty
    Commented Nov 20, 2012 at 18:25
0

Thanks to your code, I was able to reproduce the issue, and I found the root cause.

Be ready, it's going to be a "... that's it?" moment!

Basically, the whole problem is on that line:

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

Your creating a new PhotoCamera, but you're not keeping the reference anywhere. Therefore, when the garbage collector launches, it disposes your orphan PhotoCamera instance, thus freezing the video.

It's easy to reproduce: just add a button to the page, and put in the click handler:

GC.Collect();

As soon as you press the button, the video will freeze.

Now the obvious question is: why does it freeze only with the accelerometer? Quite simple actually. A garbage collection is automatically triggered when the total number of allocated objects reaches a threshold. When you only have the video, few objects are allocated (maybe none), so the garbage collector won't be triggered before a long time. When turning on the accelerometer, it updates its position at a high pace, allocating new objects in the process, and therefore triggering a garbage collect after a few minutes.

How to fix the issue? Simply store your PhotoCamera reference in a property:

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);
    }
}
3
  • This is pretty fascinating. Would you say this is the best practice -- storing things in the properties outside the function as opposed to using temp properties within the function? Apologies if poorly worded.
    – Shaun Doty
    Commented Nov 20, 2012 at 23:05
  • Well, as long as you need an object, you're supposed to keep a reference to it. So yes, it's definitely the way you should be doing it. Commented Nov 21, 2012 at 6:42
  • Thank you for that insight. I am still learning all the ins and outs of c# coding ;).
    – Shaun Doty
    Commented Nov 22, 2012 at 4:56
0

As noted in the comment with KooKiz, I am able to reproduce the VideoBrush freezing with absolute minimal code. The time may vary, but with the following below code the VideoBrush freezes reliably between 2 minutes and 14 seconds to 2 minutes and 15 seconds. (I timed this multiple times by running the emulator and opening my system clock, noting when the VideoBrush started and when it froze.)

Xaml Code:

<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# code:

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
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.