Отображение предварительного просмотра камеры с использованием DirectX Texture2D вызывает колебания на Windows Phone 8

В настоящее время я пишу небольшое приложение, которое показывает предварительный просмотр с камеры телефона с использованием пакета спрайтов SharpDX. Для тех, у кого есть учетная запись разработчика Nokia, код в основном взят из этой статьи.

Проблема

Иногда кажется, что предыдущие кадры тянутся к скребку («видео» прыгает туда-сюда), на долю секунды, что выглядит как колебание/мерцание.

Я думал о проблеме с многопоточностью (поскольку обработчик события PreviewFrameAvailable вызывается другим потоком, а не методом, отвечающим за рендеринг), но вставка оператора блокировки в оба метода делает код слишком медленным (частота кадров падает ниже 15 кадров в секунду). сек).

Есть ли у кого-нибудь идеи, как решить эту проблему или как выполнить синхронизацию потоков в этом случае без потери производительности?

Код

Во-первых, создаются все ресурсы, тогда как устройство является действительным экземпляром GraphicsDevice:

spriteBatch = new SpriteBatch(device);
photoDevice = await PhotoCaptureDevice.OpenAsync(CameraSensorLocation.Back, captureSize);
photoDevice.FocusRegion = null;

width = (int)photoDevice.PreviewResolution.Width;
height = (int)photoDevice.PreviewResolution.Height;

previewData = new int[width * height];

cameraTexture = Texture2D.New(device, width, height, PixelFormat.B8G8R8A8.UNorm);

photoDevice.PreviewFrameAvailable += photoDevice_PreviewFrameAvailable;

Затем, всякий раз, когда кадр предварительного просмотра изменяется, я устанавливаю данные в текстуру:

void photoDevice_PreviewFrameAvailable(ICameraCaptureDevice sender, object args)
{
    sender.GetPreviewBufferArgb(previewData);
    cameraTexture.SetData(previewData);
}

Наконец, Текстура рисуется с использованием SpriteBatch, тогда как параметры backBufferCenter, textureCenter, textureScaling и Math.Pi/2 используются для центрирования и настройки текстуры в альбомной ориентации:

spriteBatch.Begin();

spriteBatch.Draw(cameraTexture, backBufferCenter, null, Color.White, (float)Math.PI / 2, textureCenter, textureScaling, SpriteEffects.None, 1.0f);

spriteBatch.End();

Метод рендеринга вызывается игровым классом SharpDX, который в основном использует интерфейс IDrawingSurfaceBackgroundContentProvider, который представляет собой вызывается компонентом DrawingSurfaceBackgroundGrid среды выполнения Windows Phone 8.

Решение

В дополнение к решению Olydis (см. ниже) мне также пришлось установить для Game.IsFixedTimeStep значение false из-за ошибки SharpDX (см. ="nofollow">выпуск на GitHub для получения подробной информации).

Кроме того, не вызывать sender.GetPreviewBufferArgb(previewData) внутри обработчика PreviewFrameAvailable из-за доступа между потоками. См. соответствующую тему в разделе сообщество разработчиков Windows Phone.


person Emiswelt    schedule 11.09.2013    source источник


Ответы (1)


Моя догадка

Как вы уже догадались, я также уверен, что это может быть связано с многопоточностью. Я подозреваю, что, например, относительно длинный вызов SetData может быть перехвачен вызовом Draw, что приведет к неожиданному выводу.

Решение

Следующее решение не использует синхронизацию, а вместо этого перемещает «критические» части (доступ к текстурам) в тот же контекст.

Кроме того, давайте выделим два int[] вместо одного, которые мы будем использовать попеременно.

Фрагменты кода

void photoDevice_PreviewFrameAvailable(ICameraCaptureDevice sender, object args)
{
    sender.GetPreviewBufferArgb(previewData2);
    // swap buffers
    var previewDataTemp = previewData1;
    previewData1 = previewData2;
    previewData2 = previewDataTemp;
}

Затем добавьте это к вашему вызову Draw (или аналогичному контексту):

cameraTexture.SetData(previewData1);

Заключение

Это должно практически предотвратить вашу проблему, поскольку отрисовываются только «полностью обновленные» текстуры, и к ним нет параллельного доступа. Использование двух int[] снижает риск одновременного доступа SetData и GetPreviewBufferArgb к одному и тому же массиву, однако не устраняет риск (но не знаю, может ли одновременный доступ к int[] привести к странному поведению в первое место).

person olydis    schedule 12.09.2013