MediaComposition.RenderToFileAsync crashes with many static images

I have a Windows Phone 8.1 Silverlight application that maps .gif files to .mp4 using the Windows.Media.Editing.MediaComposition class.

Some files will randomly break the RenderToFileAsync method. There are at least two different error messages that you can receive indicating insufficient memory.

Does anyone have any ideas for a workaround or some insider knowledge of how this should work?

Repro:

  • Create a new empty C # WP8.1 Silverlight project in VS2013
  • Add Usings and OnNavigatedTo to MainPage.xaml.cs as shown below.
  • Run in a 512 MB emulator. Watch for failure (most of the time). Download with the value i for it to work correctly.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Navigation;
    using Microsoft.Phone.Controls;
    using Microsoft.Phone.Shell;
    using System.Windows.Media.Imaging;
    using System.IO;
    using Windows.Media.Editing;
    using System.Diagnostics;
    
          

-

    protected async override void OnNavigatedTo(NavigationEventArgs e)
    {
    base.OnNavigatedTo(e);
    SystemTray.ProgressIndicator = new ProgressIndicator();
    SystemTray.ProgressIndicator.IsVisible = true;
    SystemTray.ProgressIndicator.IsIndeterminate= true;
    var comp = new MediaComposition();
    var r = new Random();

    for (int i = 0; i < 190; i++)
    {
        var wb = new WriteableBitmap(576, 300);

        for (int iPix = 0; iPix < wb.Pixels.Length; iPix++)
        {
            wb.Pixels[iPix] = r.Next();
        }

        string filename = "file" + i.ToString() + ".jpg";
        var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync(filename, Windows.Storage.CreationCollisionOption.ReplaceExisting);
        using (var curr = await file.OpenStreamForWriteAsync())
        {
            wb.SaveJpeg(curr, wb.PixelWidth, wb.PixelHeight, 0, 95);
        }

        var clip = await MediaClip.CreateFromImageFileAsync(file, TimeSpan.FromMilliseconds(60));
        comp.Clips.Add(clip);
    }

    // Ensure add capability to write to video library AND ID_CAP_MEDIALIB_PHOTO and change below to 
    // Windows.Storage.KnownFolders.VideosLibrary to see output in Videos app
    var destFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
    var destFile = await destFolder.CreateFileAsync("test.mp4", Windows.Storage.CreationCollisionOption.ReplaceExisting);

    Debug.WriteLine("Mem use before render to disk: " + Windows.System.MemoryManager.AppMemoryUsage.ToString("N0"));
    await comp.RenderToFileAsync(destFile);
    Debug.WriteLine("Mem use after render to disk: " + Windows.System.MemoryManager.AppMemoryUsage.ToString("N0"));

    SystemTray.ProgressIndicator.IsVisible = false; 
    MessageBox.Show("Done OK");

    }

      

+3


source to share


2 answers


I ran your code through the Windows Phone Application Analyzer Memory Profiler. I can confirm that your application is running at the system memory limit of around 150MB. The MediaComposition mechanism can be memory intensive, depending on the size of the input and output formats. In your case, you are adding a large number of clips. The number of clips that can be added is limited by the memory available for decoding.

To be honest, MediaComposition was not designed to handle that many clips. The expected average number of clips hovers around five.

Unfortunately I was not able to get the only possible workaround I could think of in order to work. I think this solution might be workable, but unfortunately I cannot spend more time on it. Perhaps you need to create multiple output files using fewer clips. For example, you can create an output file with images from one to twenty. Then you can create a second file with images ranging from twenty one to forty. Then you can join these two files.



I hope this helps,

James

+1


source


I had basically the same problem, and after much trial and error, I finally got rid of the "Value is not in expected range" error that caused many or all of the missing frames.

I added GC.Collect (); right before each MediaClip.CreateFromImageFileAsync. It looks like it doesn't affect performance or cause any problems and I was able to fix it. Hope this helps others.



Here are some of my code so you can see what I am talking about:

foreach (var thisFrame in frames)
{
        GC.Collect();
        try
        {
               MediaClip clip = await MediaClip.CreateFromImageFileAsync(thisFrame, TimeSpan.FromMilliseconds(36 * speed));
               app.mediaComposition.Clips.Add(clip);
        }
        catch (Exception ex)
        {
               Debug.WriteLine(ex.Message + ex.StackTrace);
        }
}

      

+1


source







All Articles