Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何在WinRT(8.1)中从MediaElement捕获当前帧?_C++_Windows Runtime_Winrt Xaml_Rendertargetbitmap - Fatal编程技术网

C++ 如何在WinRT(8.1)中从MediaElement捕获当前帧?

C++ 如何在WinRT(8.1)中从MediaElement捕获当前帧?,c++,windows-runtime,winrt-xaml,rendertargetbitmap,C++,Windows Runtime,Winrt Xaml,Rendertargetbitmap,我正在尝试在WinRT应用程序中实现一个屏幕截图功能,该应用程序通过MediaElement显示视频。我有下面的代码,它保存了一个与MediaElement大小相同的屏幕截图,但是图像是空的(完全黑色)。尝试使用各种类型的媒体文件。如果我在Surface RT上使用Win Key+Vol Down,屏幕截图包括媒体帧内容,但如果我使用以下代码,则周围都是黑色:( 这里的MultimediaItem是我的视图模型类,它有一个唯一的属性,即字符串 “Player”是媒体元素的名称 有什么不对吗?或者

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

这里的MultimediaItem是我的视图模型类,它有一个唯一的属性,即字符串

“Player”是媒体元素的名称

<代码>有什么不对吗?或者这种方法是错误的,我必须在C++(?)/P>中进入战壕。 另外,我只对WinRT API感兴趣

更新1看起来RenderTargetBitmap不支持此功能,MSDN文档对此进行了澄清。
我将感谢使用DirectX C++的任何指针。这是我的一项主要任务,所以我将破解这一种或另一种方式,并用解决方案报告。

< >强>是< <强> >,这有可能——有点棘手,但工作得好。

您不使用
mediaElement
,而是使用
StorageFile
本身。 您需要借助名称空间创建
可写位图

适用于UWP(Windows 10)

这是一个完整的例子,包括文件拾取、获取视频分辨率以及将图像保存到图片库

        TimeSpan timeOfFrame = new TimeSpan(0, 0, 1);//one sec

        //pick mp4 file
        var picker = new Windows.Storage.Pickers.FileOpenPicker();
        picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.VideosLibrary;
        picker.FileTypeFilter.Add(".mp4");
        StorageFile pickedFile = await picker.PickSingleFileAsync();
        if (pickedFile == null)
        {
            return;
        }
        ///


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


        //Use Windows.Media.Editing to get ImageStream
        var clip = await MediaClip.CreateFromFileAsync(pickedFile);
        var composition = new MediaComposition();
        composition.Clips.Add(clip);

        var imageStream = await composition.GetThumbnailAsync(timeOfFrame, (int)frameWidth, (int)frameHeight, VideoFramePrecision.NearestFrame);
        ///


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


        //generate some random name for file in PicturesLibrary
        var saveAsTarget = await KnownFolders.PicturesLibrary.CreateFileAsync("IMG" + Guid.NewGuid().ToString().Substring(0, 4) + ".jpg");


        //get stream from bitmap
        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();
            }
        }
TimeSpan timeoffframe=new TimeSpan(0,0,1);//一秒
//选择mp4文件
var picker=new Windows.Storage.Pickers.FileOpenPicker();
picker.SuggestedStartLocation=Windows.Storage.Pickers.PickerLocationId.VideosLibrary;
picker.FileTypeFilter.Add(“.mp4”);
StorageFile pickedFile=Wait picker.PickSingleFileAsync();
if(pickedFile==null)
{
返回;
}
///
//获取视频分辨率
List encodingPropertiesToRetrieve=新列表();
encodingPropertiesToRetrieve.Add(“System.Video.FrameHeight”);
encodingPropertiesToRetrieve.Add(“System.Video.FrameWidth”);
IDictionary encodingProperties=await pickedFile.Properties.RetrievePropertiesAsync(encodingPropertiesToRetrieve);
uint frameHeight=(uint)encodingProperties[“System.Video.frameHeight”];
uint frameWidth=(uint)encodingProperties[“System.Video.frameWidth”];
///
//使用Windows.Media.Editing获取ImageStream
var clip=wait MediaClip.CreateFromFileAsync(pickedFile);
var composition=新的MediaComposition();
合成.剪辑.添加(剪辑);
var imageStream=wait composition.GetThumbnailAsync(timeOfFrame,(int)frameWidth,(int)frameHeight,VideoFramePrecision.NearestFrame);
///
//生成位图
var WriteableBitmap=新的WriteableBitmap((int)frameWidth,(int)frameHeight);
writableBitmap.SetSource(imageStream);
//为PicturesLibrary中的文件生成一些随机名称
var saveAsTarget=await KnownFolders.PicturesLibrary.CreateFileAsync(“IMG”+Guid.NewGuid().ToString().Substring(0,4)+“.jpg”);
//从位图中获取流
Stream=writableBitmap.PixelBuffer.AsStream();
字节[]像素=新字节[(uint)stream.Length];
wait stream.ReadAsync(像素,0,像素,长度);
使用(var writeStream=await saveAsTarget.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder=等待BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId,writeStream);
编码器.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.预乘,
(uint)writableBitmap.PixelWidth,
(uint)writableBitmap.PixelHeight,
96,
96,
像素);
等待编码器。FlushAsync();
使用(var outputStream=writeStream.getOutputstreeamat(0))
{
等待outputStream.FlushAsync();
}
}

是的……我花了很多时间在这上面

好吧,我已经设法从MediaElement通过按键来制作快照

我正在使用SetMediaStreamSource方法将MediaStreamSource对象传递给MediaElement。MediaStreamSource具有事件SampleRequested,基本上每次绘制新帧时都会激发该事件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。不幸的是,我无法发布完整的代码,但我将给您一些提示:

这里有一个wiki,描述了YUV到RGB的转换是如何工作的

我采用了哪种解决方案(并且工作得非常完美)。为了更精确,您必须分析方法NV12Converter的工作原理


最后一件事是在按下按钮或执行其他活动后将takeSnapshot boolean更改为true:)。

我不确定是否可以将MediaElement渲染为位图。您是否在其他类型的元素上尝试过代码?也看看这个:是的,看起来这在目前是不可能的。在我处理它时,也可以保持它对于C++解决方案的一些指针。你可能想使用MediaFoundation。DirectX与MF一起使用也可能有意义。不过,我现在找不到与之配合使用的接口。多亏了菲利普,我一直在想,自定义媒体转换可能会奏效,但它太深了,所以进展很慢。希望这个周末我能抽出一些时间。首先完成其他功能;-)@JakubWisniewski抱歉,我还没有机会深入了解它。由于Windows10UPnP播放被破坏,我的应用程序现在已经停止使用,我几乎没有什么可用的
byte[] yvuArray = sample.Buffer.ToArray();