如何从WinRT(8.1)中的MediaElement捕获当前帧? [英] How do you capture current frame from a MediaElement in WinRT (8.1)?

查看:906
本文介绍了如何从WinRT(8.1)中的MediaElement捕获当前帧?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在WinRT应用程序中实现截图功能,通过MediaElement显示视频。我有以下代码,它保存了一个截图,这是MediaElement的大小,但图像是空的(完全黑色)。试用各种类型的媒体文件。如果我在Surface RT上做Win Key + Vol Down,屏幕快照包括媒体框架内容,但如果我使用下面的代码,它是黑色的:(

  private async任务SaveCurrentFrame()
{
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(Player);
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
MultimediaItem currentItem =(MultimediaItem)this.DefaultViewModel [Group];
StorageFolder currentFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
var saveFile = await currentFolder.CreateFileAsync(currentItem.UniqueId +.png,CreationCollisionOption.ReplaceExisting);
if(saveFile == null)
return;
//将图像编码为所选文件在磁盘
使用(var fileStream = await saveFile.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId,fileStream);

encoding.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
DisplayInformation.GetForCurrentView()。LogicalDpi,
DisplayInformation.GetForCurrentView()。LogicalDpi,
pixelBuffer.ToArray());

await encoder.FlushAsync();
}
}


$ b $ p这里MultimediaItem是我的View Model类,具有为字符串的UniqueId属性。



Player是媒体元素的名称。



有什么错误的代码或这种方法是错误的,我要进入C ++的壕沟?



PS我只对WinRT API感兴趣。



更新1 看起来像RenderTargetBitmap不支持这个,MSDN文档澄清它 http://msdn.microsoft.com/ en-us / library / windows / apps / windows.ui.xaml.media.imaging.rendertargetbitmap
我将欣赏任何关于如何使用DirectX C ++做的指针。这是我的一个主要任务,所以我会破解这种方式或其他,并报告回解决方案。

解决方案

OK我已经设法从按钮按下MediaElement的快照工作。



我使用SetMediaStreamSource方法将MediaStreamSource对象传递给MediaElement。 MediaStreamSource具有事件SampleRequested,它在每次绘制新帧时基本上被触发。然后使用布尔值控制何时创建位图

  private async void MediaStream_SampleRequested(MediaStreamSource sender,MediaStreamSourceSampleRequestedEventArgs args)
{
if(!takeSnapshot)
{
return;
}

takeSnapshot = false;
Task.Run(()=> DecodeAndSaveVideoFrame(args.Request.Sample));
}

之后剩下的就是解压缩图像并将其转换为WriteableBitmap。图像是(或至少是在我的情况下)在YUV fromat。你可以使用

获取字节数组。

  byte [] yvuArray = sample.Buffer.ToArray 

,然后从此数组获取数据并将其转换为RGB。不幸的是,我不能发布整个代码,但我会给你一些更多的提示:



YUV到RGB维基这里你有wiki描述YUV到RGB转换的工作原理。



这里我找到了python项目我已经改编(和工作完美)的解决方案。要更精确地你必须分析方法NV12Converter的工作原理。



最后一件事是在按钮或做其他活动后将takeSnapshot boolean更改为true。)。 p>

I am trying to implement a screenshot functionality in a WinRT app that shows Video via a MediaElement. I have the following code, it saves a screenshot that's the size of the MediaElement but the image is empty (completely black). Tried with various types of Media files. If I do a Win Key + Vol Down on Surface RT, the screen shot includes the Media frame content, but if I use the following code, it's blackness all around :(

private async Task SaveCurrentFrame()
{
 RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
 await renderTargetBitmap.RenderAsync(Player);
 var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
 MultimediaItem currentItem = (MultimediaItem)this.DefaultViewModel["Group"];
 StorageFolder currentFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
 var saveFile = await currentFolder.CreateFileAsync(currentItem.UniqueId + ".png", CreationCollisionOption.ReplaceExisting);
 if (saveFile == null)
    return;
 // Encode the image to the selected file on disk
 using (var fileStream = await saveFile.OpenAsync(FileAccessMode.ReadWrite))
 {
    var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, fileStream);

    encoder.SetPixelData(
        BitmapPixelFormat.Bgra8,
        BitmapAlphaMode.Ignore,
        (uint)renderTargetBitmap.PixelWidth,
        (uint)renderTargetBitmap.PixelHeight,
        DisplayInformation.GetForCurrentView().LogicalDpi,
        DisplayInformation.GetForCurrentView().LogicalDpi,
        pixelBuffer.ToArray());

    await encoder.FlushAsync();
 }
}

Here MultimediaItem is my View Model class that among other things has a UniqueId property that's a string.

'Player' is the name of the Media Element.

Is there anything wrong with the code or this approach is wrong and I've to get in the trenches with C++?

P.S. I am interested in the WinRT API only.

Update 1 Looks like RenderTargetBitmap doesn't support this, the MSDN documentation clarifies it http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.imaging.rendertargetbitmap . I'll appreciate any pointers on how to do it using DirectX C++. This is a major task for me so I'll crack this one way or the other and report back with the solution.

解决方案

Ok I have managed to get making snapshot from MediaElement on button press to work.

I am passing MediaStreamSource object to MediaElement using SetMediaStreamSource method. MediaStreamSource has event SampleRequested which is fired basicly everytime new frame is drawn. Then using boolean I control when to create bitmap

private async void MediaStream_SampleRequested(MediaStreamSource sender, MediaStreamSourceSampleRequestedEventArgs args)
{
    if (!takeSnapshot)
    {
        return;
    }

    takeSnapshot = false;
    Task.Run(() => DecodeAndSaveVideoFrame(args.Request.Sample));
}

After that what is left is to decode compressed image and convert it to WriteableBitmap. The image is (or at least was in my case) in YUV fromat. You can get the byte array using

byte[] yvuArray = sample.Buffer.ToArray();

and then get data from this array and convert it to RGB. Unfortunetly I cannot post entire code but I'm gonna give you a few more hints:

YUV to RGB wiki here you have wiki describing how does YUV to RGB conversion works.

Here I found python project which solution I have adapted (and works perfectly). To be more precise you have to analize how method NV12Converter works.

The last thing is to change takeSnapshot boolean to true after pressing button or doing other activity :).

这篇关于如何从WinRT(8.1)中的MediaElement捕获当前帧?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆