かなり久しぶりに WPF を使って動画からサムネイルを作ってみるコードを書いてみました。
最初は MediaElement を作って、そのまま RenderTargetBitmap にレンダリングすれば良いかなと思ったんですが、それだと MediaElement 自体の描画が行われないみたいなので、DrawingVisual を使ってみたら上手くいきました。
とりあえずコードを一通り載せておきます。
int maxWidth = 640; // キャプチャする動画を読み込んでおく var player = new MediaPlayer { ScrubbingEnabled = true }; // 動画を開いてすぐに一時停止する player.Open(new Uri(@"D:\video.mp4", UriKind.Absolute)); player.Pause(); // 指定位置へシーク player.Position = TimeSpan.FromSeconds(32); // 読み込みが完了するまで待機 while (player.DownloadProgress < 1.0 && player.NaturalVideoWidth == 0) { Thread.Sleep(100); } // リサイズ後のサイズを計算 var ratio = (double)maxWidth / player.NaturalVideoWidth; int width = (int)(player.NaturalVideoWidth * ratio); int height = (int)(player.NaturalVideoHeight * ratio); // 描画用の Visual を用意 var visual = new DrawingVisual(); using (var context = visual.RenderOpen()) { context.DrawVideo(player, new System.Windows.Rect(0, 0, width, height)); } // レンダリングするビットマップを用意 var bitmap = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32); // ビットマップに Visual をレンダリング bitmap.Render(visual); // PNG として保存 var encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmap)); using (var stream = File.OpenWrite(@"D:\sample.png")) { encoder.Save(stream); }
注意点は ScrubbingEnabled を true にしておかないと、Position プロパティを弄ってシークさせた時にサムネイルが更新されないので上手く動きません。テストとして今回はクラウディアさんの動画を使いました。
ちゃんとサムネイルを切り出すことが出来ました。
あと、Azure Web サイトの WebJobs として使いたくて、その前にコンソールアプリケーションを作ってテストしたのですが、残念ながら動きませんでした。デコーダーとかの関係があるのかもしれません。*1
Windows Azureメディア・サービスを利用したアプリケーション開発 - Build Insider
ちなみに Azure Media Services を使うと簡単にサムネイル作れるみたいですね。
*1:ffmpeg とか使ってコマンドラインベースでやるしかないかも