Question

I am working on a WinRT C# application. I have an event that is raised 15-30 times per second. This event provides me with a byte array parameter (it is actually an image in byte[]):

void FrameArrived(object sender, byte[] pixels)
{
    // 1. Create a bitmap and render it on an <Image> element (UI thread).
    DisplayBitmap(pixels);

    // 2. Pass the byte array to a method for video recording.
    RecordBitmap(pixels);
}

Both DisplayBitmap and RecordBitmap are heavy processes and the UI gets slow.

If I only call one of these methods, everything works fine.

Remember, this event is raised 15-30 times per second.

I need a way to run both methods in parallel. I have tried using Dispatcher, Parallel.Invoke and ThreadPool with no good results.

Thank you in advance.

Was it helpful?

Solution

If you need to record the pixel arrays in order, then you cannot just start a new thread for every call of this function because there is no guarantee that the threads will be run in order. The idea is to push the items into a list as quick as possible and then let another thread process the items at its own rate. This will only help with the recording part of your code, if you are trying to render more images than the UI thread can handle, then that's another issue.

    void FrameArrived(object sender, byte[] pixels)
    {
        //push pixels into list
        lock (_pixelList)
        {
            _pixelList.Add(pixels);
        }
        _waitHandle.Set();


        // 1. Create a bitmap and render it on an <Image> element (UI thread).
        DisplayBitmap(pixels);

        // 2. Pass the byte array to a method for video recording.
        //RecordBitmap(pixels);
    }

    AutoResetEvent _waitHandle = new AutoResetEvent(false);
    List<byte[]> _pixelList = new List<byte[]>();
    bool _stop = false;
    void StartProcessPixelsThread()
    {
        Task.Run(() =>
        {
            while (!_stop)
            {
                _waitHandle.WaitOne();
                while (true)
                {
                    byte[] pixels;

                    lock (_pixelList)
                    {
                        if (_pixelList.Count > 0)
                        {
                            pixels = _pixelList[0];
                            _pixelList.RemoveAt(0);
                        }
                        else
                        {
                            break;
                        }
                    }
                    RecordBitmap(pixels);
                }
            }
        });
    }
    void StopProcessPixelsThread()
    {
        _stop = true;
        _waitHandle.Set();
    }

OTHER TIPS

I finally made it using ConcurrentQueue. It is slightly different to what @Jon proposed. Once again, thank you everyone for your assistance!

// Stores the frames coming from different threads.
ConcurrentQueue<byte[]> _queue = new ConcurrentQueue<byte[]>();

// Begins recording.
public void Start()
{
    if (!IsRecording)
    {
        IsRecording = true;
    }

    Task.Run(() =>
    {
        while (IsRecording || _queue.Count > 0)
        {
            byte[] pixels;

            if (_queue.TryDequeue(out pixels))
            {
                RecordBitmap(pixels);
            }
        }
    });
}

// Stops recording.
public void Stop()
{
    if (IsRecording)
    {
        IsRecording = false;
    }
}

// Updates the frames (called from FrameArrived).
public void Update(byte[] pixels)
{
    _queue.Enqueue(pixels);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top