各WPFMediaElementフレームをキャプチャする方法はありますか?レンダリングされた各フレームで発生し、それにアクセスできるようにするイベントのように。MediaElementがそのような機能を提供しない場合、どのように実装できますか、または他にどのようなコントロールを使用できますか?ちなみに、フレームキャプチャを使用したメディアクリップのオフスクリーン高速レンダリングを可能にするような制御または方法はありますか?(フレームをできるだけ速く処理できるように)
4 に答える
WPFMediaKitプロジェクトを試してみてください。メディアを使用してWPFでほとんどすべてのことを実行できます。MediaDetector.csを試してみてください。これにより、メディア内のいつからでもフレームを抽出できます。私はそれに多くの時間を費やしたことがないので、それは少しバグがありますが、あなたが必要とするもののために働くはずです。
組み込みのWPFの方法はありません。
- MediaElementにはこの機能はありません。
- BitmapDecoderにはこれを要求するAPIがありますが、BitmapDecoderを使用して任意のメディアからフレームを抽出することは実装されていません。.gifなどのいくつかのアニメーションビットマップ形式からのみフレームを抽出できます。
DirectShowを使用して、.mpg、.wmv、.mov、.flv、.aviなどのムービー形式からフレーム画像を取得できました。DirectShowのCOMグラフビルダーインターフェイスを使用してフィルターグラフを作成しました。結果のフィルターグラフは、ムービーをデコードし、C#で記述されたカスタムレンダラーフィルターに接続しました。私のカスタムフィルターはフレームデータを受け取り、BitmapSource.Createを使用して表示するためにそれをBitmapSourceオブジェクトに変換しました。
DirectShowソリューションは非常にうまく機能し、マネージドからアンマネージドへの移行は大した問題ではありませんでしたが、DirectShowグラフ構築の詳細を理解するのに時間がかかりました。
あなたがあなたの想像力を使うならば、おそらくこのスニペットはあなたにいくつかのアイデアを与えることができます:
MediaPlayer player = new MediaPlayer();
player.Open(new Uri(_inputFilename));
player.ScrubbingEnabled = true;
DrawingVisual dv = new DrawingVisual();
for (int i = 0; i < session.FramesList.Count; i++)
{
Frame f = session.FramesList[i];
player.Position = new TimeSpan((long)(f.Time * 10000000));
using (DrawingContext dc = dv.RenderOpen())
{
dc.DrawVideo(player, new Rect(0, 0, 1024, 576));
}
RenderTargetBitmap bmp = new RenderTargetBitmap(1024, 576, 96, 96, PixelFormats.Pbgra32);
bmp.Render(dv);
f.Thumbnail = bmp.GetAsFrozen() as ImageSource;
framesListView.Dispatcher.Invoke(() => FramesList.Add(f));
}
このメソッドを試して、WPFのMediaElementを含む任意のUI要素を出力できます。
public static void ConvertUiElementToBitmap(UIElement elt, string path)
{
double h = elt.RenderSize.Height;
double w = elt.RenderSize.Width;
if (h > 0)
{
PresentationSource source = PresentationSource.FromVisual(elt);
RenderTargetBitmap rtb = new RenderTargetBitmap((int)w, (int)h, 96, 96, PixelFormats.Default);
VisualBrush sourceBrush = new VisualBrush(elt);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
using (drawingContext)
{
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0),
new Point(w, h)));
}
rtb.Render(drawingVisual);
// return rtb;
var encoder = new PngBitmapEncoder();
var outputFrame = BitmapFrame.Create(rtb);
encoder.Frames.Add(outputFrame);
using (var file = System.IO.File.OpenWrite(path))
{
encoder.Save(file);
}
}
}