2017-09-20 15 views
1

私はvlcのようなメディアプレーヤーを開発しています。 1つは、再生中にスナップショットを保存することです。次のC#コードを使用して、rendertargetbitmapクラスを使用して任意の要素のスナップショットを正常に保存できました。UWP C#では、メディア要素の現在のフレームを保存する方法は?

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

しかし、メディア要素をキャプチャすることはできません。回避策を教えてください。 StorageItemThumbnailクラスの位置を使用して特定の位置からサムネイルを抽出することで可能かもしれません。そうであれば、現在のフレームのイメージではなくサムネイルになります。誰か助けてください。それは私のアプリの不可欠な機能です!

答えて

2

私が開発したデジタルサイネージuwpアプリでも同様の要件がありました。ウェブの検索方法UWPでは、保護ポリシーのためにメディア要素のスクリーンショットを直接取得することはできません(たとえば、DRMなしのビデオファイルのすべてのフレームをキャプチャする小さなアプリケーションを作成することができます管理)。

私は回避策を思いつきました:ビデオファイルをローカルに持っているので、特定のポイントで1つのフレームを抽出し、画面にレンダリングされたビデオと同じサイズのディスクに保存できます(このようにして、後で使用するフレームの完全な画像)。これを行うには、私は、この関数を書いた:

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; 
} 

この関数は、イメージとしてディスクにフレームを保存し、彼の名を返します。 私のアプリケーションでは、より多くの「ウィジェット」(画像付きのもの、ビデオ付きのもの)がありましたので、この関数を使用してビデオフレームを取得し、同じサイズのキャンバスの上に新しい画像を配置しましたZ-インデックスRenderTargetBitmapを使用して最終的なスクリーンショットを撮る。 これはきれいな解決策ではありませんが、RenderTargetBitmap MediaElementを考慮しない場合の回避策でした。

編集:私は自分のアプリケーション内の内部関数への参照を忘れてしまった はので、私は前のコードをcanghedとラインvar file = await _mediaEngine.CreateMediaFile($"{Guid.NewGuid().ToString()}.jpg");は今var file = await CreateMediaFile($"{Guid.NewGuid().ToString()}.jpg");

非同期関数CreateMediaFile(文字列のファイル名)である単に作成ディスク上の新しいファイル:

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

こんにちはAgostini、ありがとうございます。 _mediaEngineが認識されなくなるまで滑らかになります! –

+0

Ops!申し訳ありません...私はその参照を逃す!私は1分で私の答えを編集するつもりです... –

+0

@MgBhadurudeen私は正しいコードで私の答えを更新しました。今は期待どおりに動作するはずです。お知らせ下さい! –

関連する問題