如何从UWP中的IBuffer或字节数组创建IDirect3DSurface

时间:2018-06-25 16:19:32

标签: c# uwp com media

我想用UWP中的几个RenderTargetBitmap创建视频。我通过使用MediaClips来做到这一点。 从RenderTargetBitmap我可以得到一个IBuffer或字节数组的像素。 要创建MediaClip,我需要一个图像文件或一个IDirect3DSurface。 仅创建图像来创建剪辑非常昂贵,因此我想到了使用IDirect3DSurface。 我怎样才能做到这一点? 我已经尝试过了:

        RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
        await renderTargetBitmap.RenderAsync(RenderedGrid, 100, 100);

        IBuffer pixels = await renderTargetBitmap.GetPixelsAsync();
        var values = Enum.GetValues(typeof(DirectXPixelFormat));
        CanvasBitmap bitmap=null;

        foreach (DirectXPixelFormat format in values)
        {
            try
            {
                videoClip = new MediaComposition();
                bitmap = CanvasBitmap.CreateFromBytes(myWidget.Device, pixels, renderTargetBitmap.PixelWidth, renderTargetBitmap.PixelHeight, format);
                StorageFile video2 = await storageFolder.CreateFileAsync("video2" + ".mp4", CreationCollisionOption.ReplaceExisting);
                MediaClip d = MediaClip.CreateFromSurface(bitmap, DateTime.Now - previousFrame+new TimeSpan(100));
                videoClip.Clips.Add(d);
                await videoClip.RenderToFileAsync(video2);
                break;
            }
            catch(Exception e)
            {

            }
        }

我尝试了DirectXPixelFormat中的所有格式,但是没有一种方法。

我有一个名为CanvasControl的{​​{1}}是空的。

我从myWidget创建了CanvasBitmapIbuffer实现了CanvasBitmap

IDirect3DSurface创建一个Mediaclip

CanvasBitmap

然后我尝试渲染为视频文件。当我尝试保存到文件时会引发错误

  

System.Runtime.InteropServices.COMException流未处于状态   处理请求。

编辑: 我弄清楚了问题出在哪里,但不知道为什么,也不知道如何解决。

Add it to MediaComposition

现在,使用这三行代码我可以保存视频,但是仅使用第三行它会引发上面的错误。我无法理解。为什么保存和加载可以解决问题?

2 个答案:

答案 0 :(得分:0)

MediaComposition.RenderToFileAsync方法可将合成内容保存到视频文件,该视频文件可使用标准媒体播放器进行播放。从错误信息来看,流内容似乎不是正确的媒体数据,并且无法直接呈现到视频文件中。

因此,要从UWP中的几个RenderTargetBitmaps创建视频,则应选择使用图像文件的方式。使用MediaClip.CreateFromImageFileAsync方法将RenderTargetBitmap保存到文件中,然后使用它来创建视频。

private async void CreateVideoByConvertRenderBitmapToFile()
{
    var folder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("Test", 
        CreationCollisionOption.ReplaceExisting);
    var composition = new MediaComposition();
    for (int i = 0; i < 5; i++)
    {
        RenderTargetBitmap render = new RenderTargetBitmap();
        await render.RenderAsync(RenderGrid);
        MyImage.Source = render;
        var pixel = await render.GetPixelsAsync();
        var file = await folder.CreateFileAsync("test.png", CreationCollisionOption.GenerateUniqueName);
        using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
        {
            var logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
            var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
            encoder.SetPixelData(
                BitmapPixelFormat.Bgra8,
                BitmapAlphaMode.Ignore,
                (uint)render.PixelWidth,
                (uint)render.PixelHeight,
                logicalDpi,
                logicalDpi,
                pixel.ToArray());
            await encoder.FlushAsync();
            stream.Dispose();
            MediaClip clip = await MediaClip.CreateFromImageFileAsync(file, TimeSpan.FromSeconds(3));
            composition.Clips.Add(clip);
            MyText.Text = "First frame >>>" + i;
        }
    }
    var video = await ApplicationData.Current.LocalFolder.CreateFileAsync("test.mp4",
        CreationCollisionOption.ReplaceExisting);
    var action = await composition.RenderToFileAsync(video, MediaTrimmingPreference.Precise);
    await folder.DeleteAsync();
}

答案 1 :(得分:0)

最可能的原因是,CanvasBitmap具有基础的IDirce3DSurface对象以及图像数据,例如byte[]或其他东西,尽管我不确定。

如果是这样,则从CanvasBitmapbyte[]创建IBuffer不会影响基础的IDirect3DSurface,图像部分只会被构造。您可以看到,通过将该映像保存在磁盘上,它不会出错。

但是如果您要跳过将数据保存到磁盘上的话,我认为有一种解决方法

如果对Offscreen Drawing执行CanvasRenderTarget,则可以构造基础IDirect3DSurface

因此,您可以使用CanvasBitmap来构建CanvasRenderTarget,然后使用该CanvasRenderTarget来构造MediaClip

CanvasRenderTarget rendertarget;
using (CanvasBitmap canvas = CanvasBitmap.CreateFromBytes(CanvasDevice.GetSharedDevice(), pixels, renderTargetBitmap.PixelWidth, renderTargetBitmap.PixelHeight, format))
{
     rendertarget = new CanvasRenderTarget(CanvasDevice.GetSharedDevice(), canvas.SizeInPixels.Width, canvas.SizeInPixels.Height, 96);
     using (CanvasDrawingSession ds = rendertarget.CreateDrawingSession())
     {
         ds.Clear(Colors.Black);
         ds.DrawImage(canvas);
     }
}
MediaClip d = MediaClip.CreateFromSurface(renderTarget, TimeSpan.FromMilliseconds(80));
mc.Clips.Add(m);