1

我正在尝试编写一个应用程序,它首先将视频合并到 XNA 游戏引擎中,添加一些增强现实内容,然后将渲染的内容流式传输给另一个用户。所有这些都需要实时或近乎实时地发生。本质上,系统看起来像这样:

Video -> XNA(Game) -> (???) -> Expression Engine -> Live Stream -> Network -> Client

干净而优雅的方法是将 XNA 的渲染输出视为 LiveDeviceSource 并将其直接馈送到 Expression Engine 流作业中。是否可以编写自定义 LiveDeviceSource 或类似的东西?基本上有人知道如何为表达式引擎创建自定义源,我可以将渲染的 XNA 缓冲区直接推送到编码器吗?将缓冲区转储到文件并让表达式引擎对其进行编码是相当容易的,但我担心写入磁盘会导致太多延迟,因为写入磁盘需要时间。

另一种快速而肮脏的技巧是让表达式引擎对输出窗口进行屏幕捕获,然后让它流式传输。我可以让 Expression Engine 捕捉屏幕截图,但我无法让它直播。有人可以建议如何同时做这两件事吗?

提前为这个问题道歉,因为我仍然熟悉表达式引擎 SDK。作为参考,我正在使用 XNA 4、MS Expression Engine 4 和 Visual Studio 2010。我们的目标是最终将这项技术与即将发布的 Goblin XNA 集成。

我也愿意接受有关直接从 XNA 流式传输实时视频的其他方法的建议。我们没有与 Expression Engine 结婚,它似乎是迄今为止我们遇到的最好的流媒体解决方案(我们遇到了 ffmpeg 的问题)。

4

1 回答 1

0

您需要实现一个 AVStream miindriver 以通过创建一个被识别为实时源的驱动程序来完成管道(在此处查找详细信息http://msdn.microsoft.com/en-us/library/ff554228(v=VS. 85).aspx ) 另一种解决方案是使用 DirectShowFilter 或 MFT 过滤器编写,但在这个部门我帮不了你太多。

我已经使用过表达式编码器 sdk,但我还没有遇到您所要求的解决方案。但是,您可以非常轻松地将图像数据传输到 Expression Encoder。一种方法是从渲染目标中检索字节并使用您喜欢的任何方式将它们传输到表达式编码器(WCF 是一个不错的选择)并将数据重建为位图以用于流式传输。

我将我的源用于从 Texture2D(以及因此的 RenderTarget2D)中检索字节数据,然后从中构造一个 Bitmap 对象。

    public static Bitmap ToBitmap(this Microsoft.Xna.Framework.Graphics.Texture2D rd, int Width, int Height)
    {
        var Bmp = new Bitmap(Width, Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

        byte[] data = ToBytes(rd);

        var bmpData = Bmp.LockBits(new Rectangle(0, 0, rd.Width, rd.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

        System.Runtime.InteropServices.Marshal.Copy(data, 0, bmpData.Scan0, data.Length);

        Bmp.UnlockBits(bmpData);

        return Bmp;
    }

    public static byte[] ToBytes(this Microsoft.Xna.Framework.Graphics.Texture2D rd, byte[] data = null)
    {
        if (data == null || data.Length != 4 * rd.Height * rd.Width)
            data = new byte[4 * rd.Height * rd.Width];

        rd.GetData<byte>(data);

        SwapBytes(data);

        return data;
    }

    private static void SwapBytes(byte[] data)
    {
        System.Threading.Tasks.ParallelOptions po = new System.Threading.Tasks.ParallelOptions();
        po.MaxDegreeOfParallelism = -1;

        System.Threading.Tasks.Parallel.For(0, data.Length / 4, po, t =>
        {
            int bi = t * 4;
            byte temp = data[bi];
            data[bi] = data[bi + 2];
            data[bi + 2] = temp;
        });
    }

    public static void FromBytes(this Texture2D texture, byte[] bytes)
    {
        SwapBytes(bytes);

        texture.SetData<byte>(bytes);
    }

我希望我有所帮助。

于 2011-06-15T16:54:03.857 回答