如何保存媒体元素的当前帧? [英] How to save media element's current frame?

查看:49
本文介绍了如何保存媒体元素的当前帧?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发像vlc这样的媒体播放器.它的功能之一是在回放过程中保存快照.我可以使用以下c#代码使用rendertargetbitmap类成功保存任何元素的快照.

I am developing a media player like vlc. One of it's features is saving snapshot during playback. I am able to successfully save the snapshot of any element using rendertargetbitmap class, using the following c# code.

RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(); 
await renderTargetBitmap.RenderAsync(RenderedGrid, width, height); 
RenderedImage.Source = renderTargetBitmap;

但是它不允许捕获媒体元素.请为我提供解决方法.我不确定,我不确定是否可以通过使用StorageItemThumbnail Class的位置从特定位置提取缩略图来实现.即使是这样,它也将是缩略图而不是当前帧的图像.请有人帮忙.这是我的应用程序的基本功能!

But it does not allow to capture media element. Please help me with a workaround. I guess, I am not sure, may it be possible by extracting a thumbnail from a specific position using position of StorageItemThumbnail Class. If even so, it will be a thumbnail not an image of current frame. Someone help please. It is essential feature of my app!

推荐答案

也有类似的要求.在网上搜索时,我发现由于保护策略的原因,在UWP中您无法直接拍摄媒体元素的屏幕截图(例如,您可以创建一个小型应用程序来捕获没有DRM的视频文件的所有帧)管理).

in a digital signage uwp app that I developed I had also a similar requirement. Searching the web on how I can do I found that in UWP you can't directly take a screenshot of a media element due to a protection policy (for example you could create a small app that captures all the frames of a video file without DRM management).

我想出一种解决方法:我在本地拥有视频文件,因此我可以在某一点提取单个帧并将其保存到与屏幕上呈现的视频尺寸相同的磁盘上(这样,我就拥有了完整的框架的图片,以供日后使用).为此,我编写了以下函数:

I came up with a workaround: I have the video file locally so I can extract a single frame at a certain point and save it to disk with the same dimensions of the video rendered on screen (in this way I had a full image of the frame to use later). To doing this I wrote this function:

private async Task<string> Capture(StorageFile file, TimeSpan timeOfFrame, Size imageDimension)
{
    if (file == null)
{
    return null;
}

//Get FrameWidth & FrameHeight
List<string> encodingPropertiesToRetrieve = new List<string>();
encodingPropertiesToRetrieve.Add("System.Video.FrameHeight");
encodingPropertiesToRetrieve.Add("System.Video.FrameWidth");
IDictionary<string, object> encodingProperties = await file.Properties.RetrievePropertiesAsync(encodingPropertiesToRetrieve);
uint frameHeight = (uint)encodingProperties["System.Video.FrameHeight"];
uint frameWidth = (uint)encodingProperties["System.Video.FrameWidth"];

//Get image stream
var clip = await MediaClip.CreateFromFileAsync(file);
var composition = new MediaComposition();
composition.Clips.Add(clip);
var imageStream = await composition.GetThumbnailAsync(timeOfFrame, (int)frameWidth, (int)frameHeight, VideoFramePrecision.NearestFrame);

//Create BMP
var writableBitmap = new WriteableBitmap((int)frameWidth, (int)frameHeight);
writableBitmap.SetSource(imageStream);

//Get stream from BMP
string mediaCaptureFileName = "IMG" + Guid.NewGuid().ToString().Substring(0, 4) + ".jpg";
var saveAsTarget = await CreateMediaFile(mediaCaptureFileName);
Stream stream = writableBitmap.PixelBuffer.AsStream();
byte[] pixels = new byte[(uint)stream.Length];
await stream.ReadAsync(pixels, 0, pixels.Length);

using (var writeStream = await saveAsTarget.OpenAsync(FileAccessMode.ReadWrite))
{
    var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, writeStream);
    encoder.SetPixelData(
        BitmapPixelFormat.Bgra8,
        BitmapAlphaMode.Premultiplied,
        (uint)writableBitmap.PixelWidth,
        (uint)writableBitmap.PixelHeight,
        96,
        96,
        pixels);
    await encoder.FlushAsync();                
    using (var outputStream = writeStream.GetOutputStreamAt(0))
    {
        await outputStream.FlushAsync();
    }
}
return saveAsTarget.Name;
}

此功能将帧作为图像保存到磁盘并返回其文件名.在我的应用程序中,我有更多的窗口小部件"(其中一些带有图像,一些带有视频),因此我使用此功能获取视频帧,并将新图像放置在具有相同尺寸和更高Canvas Z的媒体元素之上-Index,以便使用 RenderTargetBitmap 拍摄最终的屏幕截图.这不是一个干净的解决方案,但这是 RenderTargetBitmap 不考虑MediaElement的一种解决方法.

This function save the frame to disk as image and return his filename. In my application I had more "widget" (some of those with images, some with video) so I used this function to get the video frames and put a new image on top of the media element with the same dimensions and a higher Canvas Z-Index in order to use RenderTargetBitmap for take the final screenshot. It's not a clean solution but it was a workaround for RenderTargetBitmap not considering MediaElement.

我忘记了在我的应用程序中对内部函数的引用,因此我无法使用前面的代码,而 var file = await _mediaEngine.CreateMediaFile($"{Guid.NewGuid().ToString()}.jpg"); 现在为 var file = await CreateMediaFile($"{Guid.NewGuid().ToString()}.jpg");

异步函数CreateMediaFile(string fileName)只需在磁盘上创建一个新文件:

The async function CreateMediaFile(string fileName) simply create a new file on the disk:

public async Task<StorageFile> CreateMediaFile(string filename)
    {
        StorageFolder _mediaFolder = KnownFolders.PicturesLibrary;
        return await _mediaFolder.CreateFileAsync(filename);
    }

这篇关于如何保存媒体元素的当前帧?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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