[英]How to create a IDirect3DSurface from an IBuffer or byte array in UWP
I want to create a video from a few RenderTargetBitmap
s in UWP. 我想在UWP中从几个RenderTargetBitmap
创建一个视频。 I am doing that by using MediaClips
. 我是通过使用MediaClips
做到这MediaClips
。 From RenderTargetBitmap
i can get an IBuffer
or byte array of pixels. 从RenderTargetBitmap
我可以获得IBuffer
或像素字节数组。 To create a MediaClip
I need either an image file or an IDirect3DSurface
. 要创建MediaClip
我需要一个图像文件或一个IDirect3DSurface
。 Creating an image just to create a clip is very expensive, so I thought of using IDirect3DSurface
. 创建图像只是为了创建一个剪辑是非常昂贵的,所以我想到使用IDirect3DSurface
。 How can I do this? 我怎样才能做到这一点? I have tried this: 我试过这个:
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)
{
}
}
I try all the formats in DirectXPixelFormat
but none works. 我尝试使用DirectXPixelFormat
所有格式,但都DirectXPixelFormat
。
I have a CanvasControl
named myWidget
that is empty. 我有一个CanvasControl
名为myWidget
是空的。
I create a CanvasBitmap
from Ibuffer
( CanvasBitmap
implements IDirect3DSurface
) 我从Ibuffer
创建一个CanvasBitmap
( CanvasBitmap
实现IDirect3DSurface
)
Create a Mediaclip
from CanvasBitmap
创建Mediaclip
从CanvasBitmap
Add it to MediaComposition
. Add it to MediaComposition
。
Then I try to render to video file.When i try to save to a file it throws an error 然后我尝试渲染到视频文件。当我尝试保存到文件时,它会抛出一个错误
System.Runtime.InteropServices.COMException Stream is not in a state to handle the request. System.Runtime.InteropServices.COMException Stream未处于处理请求的状态。
EDIT: I figured out where the problem is, but not why and not how to fix it. 编辑:我想出问题所在,但不是为什么而不是如何解决它。
await videoClip.SaveAsync(video2);
videoClip= await MediaComposition.LoadAsync(video2);
var x=await videoClip.RenderToFileAsync(video2);
Now with these three lines i can save the video, but using only the third line it throws the error above. 现在使用这三行我可以保存视频,但只使用第三行它会抛出上面的错误。 I cannot make sense of it. 我无法理解它。 Why does saving and loading fix the problem?? 为什么保存和加载修复问题?
The MediaComposition.RenderToFileAsync Method saves the composition to a video file that can be played back with standard media players. MediaComposition.RenderToFileAsync方法将合成保存到可以使用标准媒体播放器播放的视频文件中。 From the error info, it seems the stream content is not correct media data and can not be render into a video file directly. 从错误信息来看,似乎流内容不正确的媒体数据,不能直接渲染成视频文件。
So, to create a video from a few RenderTargetBitmaps in UWP, the way to use an image file should be your choice. 因此,要从UWP中的几个RenderTargetBitmaps创建视频,应该选择使用图像文件的方式。 using MediaClip.CreateFromImageFileAsync method by saving the RenderTargetBitmap into a file then using it to create a video. 使用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();
}
Most probable reason is that, CanvasBitmap
has an underlying IDirce3DSurface
object as well as image data like byte[]
or something else , though I am not sure about this. 最可能的原因是, CanvasBitmap
有一个底层的IDirce3DSurface
对象以及像byte[]
或其他东西的图像数据,虽然我不确定这一点。
If that's true, then creating a CanvasBitmap
from byte[]
or IBuffer
won't effect the underlying IDirect3DSurface
, the image part will be constructed only. 如果这是真的,则创建一个CanvasBitmap
从byte[]
或IBuffer
不会影响底层IDirect3DSurface
,图像部分将只构成。 You can see that by saving that image on the disk, it gives no error. 您可以看到,通过将该图像保存在磁盘上,它不会出错。
But I think there's a workaround if you want to skip saving data on the disk : 但是, 如果您想跳过在磁盘上保存数据,我认为有一种解决方法 :
You can contruct the underlying IDirect3DSurface
if you do Offscreen Drawing to a CanvasRenderTarget . 如果对CanvasRenderTarget执行屏幕外 绘制 ,则可以构建基础IDirect3DSurface
。
So, you can use the CanvasBitmap
to construct a CanvasRenderTarget
and then use that CanvasRenderTarget
to contruct a MediaClip
: 因此,您可以使用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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.