В настоящее время я пишу небольшое приложение, которое показывает предварительный просмотр с камеры телефона с использованием пакета спрайтов 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.