我正在编写一个视频播放器来播放由我们的ASIC捕获的帧。它们采用自定义格式,并且我已经提供了解码ASIC状态的功能。视频可以是640x480到2560x1200(!!!)的任何大小。每个状态周期的输出是16x16像素块,我必须在屏幕上看到一个视频。
每次需要更新屏幕时,我都会收到以下信息:
主要限制:
今天早上我花了一个WriteableBitmap,并将它用作Image的源代码,如下所示:
private WriteableBitmap ImageSource;
public MainWindow()
{
InitializeComponent();
ImageSource = new WriteableBitmap(FrameWidth, FrameHeight, 96, 96, PixelFormats.Bgr32, null);
ImagePanel.Source = ImageSource;
}
private void DrawBox(byte Red, byte Green, byte Blue, int X, int Y)
{
int BoxWidth = 16;
int BoxHeight = 16;
int BytesPerPixel = ImageSource.Format.BitsPerPixel / 8;
byte[] Pixels = new byte[BoxWidth * BoxHeight * BytesPerPixel];
for (int i = 0; i < Pixels.Length; i += 4)
{
Pixels[i + 0] = Blue;
Pixels[i + 1] = Green;
Pixels[i + 2] = Red;
Pixels[i + 3] = 0;
}
int Stride = BoxWidth * BytesPerPixel;
Int32Rect DrawBox = new Int32Rect(X, Y, BoxWidth, BoxHeight);
ImageSource.Lock();
ImageSource.WritePixels(DrawBox, Pixels, Stride, 0);
ImageSource.Unlock();
}
它有效,我的视频在屏幕上播放,但它是sloooooooow。无处接近实时播放速度。有没有更好的方法,除了在程序上生成一系列位图,这样做,我没有看到?我已经阅读了有关D3Dimage的内容,但似乎更多的是将3D场景导出到位图。这里的建议?
答案 0 :(得分:6)
如果我理解正确,您会收到一个16 * 16像素的块作为捕获,在上面的示例中,您将更新每个更新的可写位图。
在每个块上触发渲染时,这看起来很像流失。
不是更好:
通过这种方式,渲染的流失率会大大减少,因为您不会为每个块触发渲染,但仅针对每个帧。
更新1
如果您不使用Alpha通道,我还会考虑使用Bgr24作为像素格式。这样你每个像素就会有3个字节,而不是4个字节,所以开销就大大减少了。
更新2
如果对于较大的帧大小而言仍然太慢,您还可以考虑以下因素,这会增加复杂性。
考虑维护和翻转两个帧缓冲区。通过这种方式,您可以在后台线程上合成帧,然后在UI线程上对完成的帧进行blit。 Whist UI线程正在渲染帧,您可以继续在替代缓冲区上进行合成。
更新3
如果捕获的像素颜色信息数组格式正确,可以尝试使用Buffer.BlockCopy将源像素数组批量复制到帧缓冲区数组中。您必须将位图格式保留为bgr32。这种低级别的阵列复制技术可以带来一些性能提升。