0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WinUI 3のMediaPlayerElementで今表示されている映像を静止画として保存する

Last updated at Posted at 2025-02-20

サンプルプログラムの画面
残したいんですよ。

メディア プレーヤー、ありますよね。
WinUI 3ならMediaPlayerElement クラスです。
それで動画を再生したなら、決定的瞬間を写真に収めたいと思いませんか?私は思います。

やっていきましょうか。

先に結論

サンプル:https://github.com/mifumi323/WinUI3MediaPlayerElementSnapshotSample

画面

MainWindow.xaml
<?xml version="1.0" encoding="utf-8"?>
<Window
    x:Class="WinUI3MediaPlayerElementSnapshotSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WinUI3MediaPlayerElementSnapshotSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="WinUI3MediaPlayerElementSnapshotSample">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <CommandBar HorizontalAlignment="Left" DefaultLabelPosition="Right">
            <AppBarButton Click="PhotoButton_Click" Icon="Camera" Label="写真"/>
        </CommandBar>
        <MediaPlayerElement x:Name="Player" Source="ms-appx:///Assets/sample.mp4" AreTransportControlsEnabled="True" Grid.Row="1" />
    </Grid>
</Window>

サンプルですのでシンプルにメディアプレーヤーとボタンだけです。
MediaPlayerElement.Sourceにファイルを指定すれば簡単に動画を読み込めるわけですね。
本筋とは関係ありませんが、ボタンにはコマンド バーを使っています。

NuGetパッケージのインストール

NuGetの検索画面
先に書いたように、Win2Dが必要になります。
Win2D.uwpのほうが上に表示されますが、名前を見てわかるようにWinUI3じゃなくてUWP用なので、インストールしても使えません。
Microsoft.Graphics.Win2Dのほうをインストールしましょう。

保存するコード

MainWindow.xaml.cs
private async void PhotoButton_Click(object sender, RoutedEventArgs e)
{
    var savePicker = new FileSavePicker();
    savePicker.FileTypeChoices.Add("PNG", [".png"]);

    // このキモいおまじない無くなるといいな(https://qiita.com/hayashida-katsutoshi/items/21b8f99c462c01bb7c6d)
    InitializeWithWindow.Initialize(savePicker, WindowNative.GetWindowHandle(this));

    var file = await savePicker.PickSaveFileAsync();
    if (file != null)
    {
        int naturalVideoWidth = (int)Player.MediaPlayer.PlaybackSession.NaturalVideoWidth;
        int naturalVideoHeight = (int)Player.MediaPlayer.PlaybackSession.NaturalVideoHeight;

        CanvasDevice canvasDevice = CanvasDevice.GetSharedDevice();

        var frameServerDest = new SoftwareBitmap(BitmapPixelFormat.Rgba8, naturalVideoWidth, naturalVideoHeight, BitmapAlphaMode.Ignore);
        using var inputBitmap = CanvasBitmap.CreateFromSoftwareBitmap(canvasDevice, frameServerDest);
        Player.MediaPlayer.CopyFrameToVideoSurface(inputBitmap);

        var photoPath = file.Path;
        await inputBitmap.SaveAsync(photoPath, CanvasBitmapFileFormat.Png);
    }
}

これで画像として保存できます。
まあ、コードに書いた通りです。

コードの前半は保存ダイアログを出しているだけです。
コメントに書いてあるように、メインウィンドウを先に登録してやる必要があります(参考:Windows App SDK, WinUI3, Desktopでファイル選択ダイアログを表示する)。

CanvasDevice以降の保存処理本体は公式ドキュメントのフレーム サーバー モードでの MediaPlayer の使用を参考にしています。
実はフレームサーバーモードじゃなくても普通に保存できるのと、VS2022にお任せで足りないライブラリ入れさせようとするとWin2D.uwp(WinUI3では使えない)を提案してくるあたりが罠でした。
コピー先のビットマップ作るだけで結構回りくどい処理しますね。

環境

Windows 11
Visual Studio 2022 Version 17.13.1

終わりに

WinUI3、DPI Aware PerMonitorV2に最初から対応しているので高解像度モニタできれいに表示されてなかなかいいですよ。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?