我有一个 VideoRenderer 类,它继承了一个 Image 控件,一个 MyVideo 类,它有一个 VideoRenderer 实例,以及 MainWindow 代码隐藏中的一个 RenderFrames 方法
我附上了这些类的相关部分,以及下面的 RenderFrames 方法和一些 MainWindow 代码隐藏构造函数。
VideoRenderer 接收外部视频并将视频帧生成为位图对象,存储在“位图”字段中。在每个完成的过程之后,我将位图的副本存储在“bitmapCopy”字段中。
MyVideo 控制 VideoRenderer 实例“sharedVideoRenderer”何时开始和停止接收和发送帧到 MainWindow RenderFrames 方法,使用 ThreadPool.QueueUserWorkItem 将 VideoRenderer 实例作为对象参数传递。
RenderFrames 循环,直到 MyVideo 说通过更改其布尔“我们正在渲染”属性中的任何一个来停止,并且它从 Bitmap -> BitmapImage -> Image.Source 进行转换,然后使用 MainWindow Dispatcher 将 VideoContentControl.Content 设置为图像.
一切正常,视频被渲染,但 GUI 控制基本上被冻结,其他按钮和东西不起作用,因为将整个操作分派到 MainWindow 线程并不断循环正在占用线程。
我的问题是:我可以尝试哪些其他方法将位图帧从“sharedVideoRenderer”传输到 VideoContentControl,并使用新图像不断更新它,而不冻结 GUI?
任何帮助,将不胜感激。
相关代码:
视频渲染器.cs:
internal void DrawBitmap()
{
lock (bitmapLock)
{
bitmapCopy = (Bitmap)bitmap.Clone();
}
}
我的视频.cs:
public static void RenderVideoPreview()
{
sharedVideoRenderer.VideoObject = videoPreview;
sharedVideoRenderer.Start();
videoPreviewIsRendering = true;
ThreadPool.QueueUserWorkItem((Application.Current.MainWindow as MainWindow).RenderFrames, sharedVideoRenderer);
}
MainWindow.xaml.cs:
Dispatcher mainWindowDispatcher;
public MainWindow()
{
InitializeComponent();
mainWindowDispatcher = this.Dispatcher;
...
public void RenderFrames(object videoRenderer)
{
while (MyVideo.VideoPreviewIsRendering || MyVideo.LiveSessionParticipantVideoIsRendering)
{
mainWindowDispatcher.Invoke(new Action(() =>
{
try
{
System.Drawing.Bitmap bitmap;
bitmap = (videoRenderer as VideoRenderer).BitmapCopy;
using (MemoryStream memory = new MemoryStream())
{
BitmapImage bitmapImage = new BitmapImage();
ImageSource imageSource;
Image image;
image = new Image();
bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Bmp);
memory.Position = 0;
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
imageSource = bitmapImage;
image.Source = imageSource;
VideoContentControl.Content = image;
memory.Close();
}
}
catch (Exception)
{
}
}));
}
mainWindowDispatcher.Invoke(new Action(() =>
{
VideoContentControl.ClearValue(ContentProperty);
VideoContentControl.InvalidateVisual();
}));
}