我的游戏会在每个游戏循环中截取屏幕截图并存储内存。然后用户可以按“打印屏幕”来触发“SaveScreenshot”(参见下面的代码),将每个屏幕截图存储为PNG,并使用SharpAvi将它们编译成AVI。保存图像工作正常,产生~2秒AVI,但播放时不显示任何视频。它只是占位符VLC播放器图标。我认为这非常接近工作,但我无法确定是什么问题。请参阅下面的代码。如果有人有任何想法,我会非常感激!
private Bitmap GrabScreenshot()
{
try
{
Bitmap bmp = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
System.Drawing.Imaging.BitmapData data =
bmp.LockBits(this.ClientRectangle, System.Drawing.Imaging.ImageLockMode.WriteOnly,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
GL.ReadPixels(0, 0, this.ClientSize.Width, this.ClientSize.Height, PixelFormat.Bgr, PixelType.UnsignedByte,
data.Scan0);
bmp.UnlockBits(data);
bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
return bmp;
} catch(Exception ex)
{
// occasionally getting GDI generic exception when rotating the image... skip that one.
return null;
}
}
private void SaveScreenshots()
{
var directory = "c:\\helioscreenshots\\";
var rootFileName = string.Format("{0}_", DateTime.UtcNow.Ticks);
var writer = new AviWriter(directory + rootFileName + ".avi")
{
FramesPerSecond = 30,
// Emitting AVI v1 index in addition to OpenDML index (AVI v2)
// improves compatibility with some software, including
// standard Windows programs like Media Player and File Explorer
EmitIndex1 = true
};
// returns IAviVideoStream
var aviStream = writer.AddVideoStream();
// set standard VGA resolution
aviStream.Width = this.ClientSize.Width;
aviStream.Height = this.ClientSize.Height;
// class SharpAvi.KnownFourCCs.Codecs contains FOURCCs for several well-known codecs
// Uncompressed is the default value, just set it for clarity
aviStream.Codec = KnownFourCCs.Codecs.Uncompressed;
// Uncompressed format requires to also specify bits per pixel
aviStream.BitsPerPixel = BitsPerPixel.Bpp32;
var index = 0;
while (this.Screenshots.Count > 0)
{
Bitmap screenshot = this.Screenshots.Dequeue();
var screenshotBytes = ImageToBytes(screenshot);
// write data to a frame
aviStream.WriteFrame(true, // is key frame? (many codecs use concept of key frames, for others - all frames are keys)
screenshotBytes, // array with frame data
0, // starting index in the array
screenshotBytes.Length); // length of the data
// save it!
// NOTE: compared jpeg, gif, and png. PNG had smallest file size.
index++;
screenshot.Save(directory + rootFileName + index + ".png", System.Drawing.Imaging.ImageFormat.Png);
}
// save the AVI!
writer.Close();
}
public static byte[] ImageToBytes(Image img)
{
using (var stream = new MemoryStream())
{
img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
return stream.ToArray();
}
}
答案 0 :(得分:0)
据我所知,您提供的是 png 编码的字节数组,但流配置为 KnownFourCCs.Codecs.Uncompressed
。
此外,来自manual:
<块引用>AVI 需要标准 Windows DIB 格式的未压缩数据,即指定位深度的自底向上位图。对于每一帧,将其数据放入字节数组并调用 IAviVideoStream.WriteFrame()
接下来,所有编码器都期望输入特定格式的图像数据。它是 BGR32 自上而下 - 每像素 32 位,蓝色字节在前,不使用 alpha 字节,顶行在前。这是您通常可以从现有图像中获得的格式。 [...] 因此,您只需传递一个未压缩的自上而下的 BGR32
我将按照手册中的说明使用 Bitmap
和 LockBits
直接从 Marshal.Copy
检索字节数组。