我在wpf项目中使用Image和MediaElement,我在文件系统中显示图像和视频。我有几个定时器,它们将文件加载到Image / MediaElement控件。一切都工作4-5小时,但MediaElement视频文件冻结,MediaEnded事件不会发生。我重新启动应用程序,它运行没有任何问题,但几个小时后再次出现此问题。
我的WPF XAML代码:
<Grid Name="MainGrid">
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Name="MainImage" Stretch="Fill" />
<MediaElement MediaEnded="MediaEnded" MediaOpened="MediaOpened" LoadedBehavior="Manual" HorizontalAlignment="Center" Name="VideoControl" VerticalAlignment="Center"
Stretch="Fill" UnloadedBehavior="Manual"/>
</Grid>
C#代码:
public partial class ImageView
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
private static String _advCheckGuid;
private List<String> _FolderNames;
private int _FolderIndex = 0;
private MainWindow _MainWindow;
private List<String> _PathList;
private List<String> _CheckPathList;
private int _Index;
private BitmapImage _BitmapImage;
private volatile bool _Running = true;
private Backend _Backend;
private ApplicationDeployment _UpdateCheck;
// Threads
private Timer _ImageTimer;
private Timer _UpdateTimer;
private Timer _FolderClearTimer;
private Timer _CheckApplicationUpdateTimer;
private Thread _TerminationThread;
public ImageView()
{
InitializeComponent();
_PathList = new List<string>();
_CheckPathList = new List<string>();
_Index = 0;
}
private void ViewPageLoaded(Object sender, EventArgs e)
{
_FolderNames = new List<string> { Constants.AdsFolderFirst,
Constants.AdsFolderSecond };
_Backend = new Backend();
_MainWindow = (MainWindow)Window.GetWindow(this);
_ImageTimer = new Timer(Constants.DefaultImageTimer);
_ImageTimer.Elapsed += ChangeImageSource;
_ImageTimer.Start();
}
private void ChangeImageSource(object sender, System.Timers.ElapsedEventArgs e)
{
Application.Current.Dispatcher.Invoke(
DispatcherPriority.Normal, new Action(
delegate()
{
try
{
if (MainImage != null && MainImage.Source != null)
{
MainImage.Source = null;
}
if (VideoControl != null && VideoControl.Source != null)
{
VideoControl.Stop();
VideoControl.Source = null;
}
if (_Index >= _PathList.Count)
{
_Index = 0;
}
if (_PathList.ElementAt(_Index) != null)
{
Log.Info(String.Format("Start [ChangeImageSource]. Element: {0}, Index: {1}", _PathList.ElementAt(_Index), _Index));
try
{
_ImageTimer.Stop();
String[] checkExt = _PathList.ElementAt(_Index).Split('.');
String ext = checkExt[checkExt.Length - 1];
if (ext.Equals("jpg", StringComparison.CurrentCultureIgnoreCase) ||
ext.Equals("jpeg", StringComparison.CurrentCultureIgnoreCase) ||
ext.Equals("png", StringComparison.CurrentCultureIgnoreCase))
{
_ImageTimer.Interval = Constants.NormalImageTimer;
ShowImage(_PathList.ElementAt(_Index));
}
else if (ext.Equals("mp4", StringComparison.CurrentCultureIgnoreCase) ||
ext.Equals("3gp", StringComparison.CurrentCultureIgnoreCase))
{
_ImageTimer.Interval = Constants.VideoDefaultTimer;
PlayQueue(_PathList.ElementAt(_Index));
}
_ImageTimer.Start();
_Index++;
}
catch (Exception exception)
{
Log.ErrorException(exception.Message, exception);
}
}
}
catch (Exception exception)
{
Log.ErrorException(exception.Message, exception);
}
}));
}
private void ShowImage(String fileName)
{
try
{
if (!String.IsNullOrEmpty(fileName))
{
_BitmapImage = LoadImage(fileName);
MainImage.Source = _BitmapImage;
}
}
catch (Exception e)
{
Log.ErrorException(e.Message, e);
}
}
private void PlayQueue(String fileName)
{
try
{
if (!String.IsNullOrEmpty(fileName))
{
VideoControl.LoadedBehavior = MediaState.Play;
VideoControl.Source = new Uri(fileName, UriKind.Absolute);
}
}
catch (Exception e)
{
Log.ErrorException(e.Message, e);
}
}
private void MediaEnded(object sender, EventArgs e)
{
try
{
if (MainImage != null && MainImage.Source != null)
{
MainImage.Source = null;
}
if (VideoControl != null && VideoControl.Source != null)
{
VideoControl.Stop();
VideoControl.Source = null;
}
if (_Index >= _PathList.Count)
{
_Index = 0;
}
if (_PathList.ElementAt(_Index) != null)
{
Log.Info(String.Format("Start [MediaEnded oper]. Element: {0}, Index: {1}", _PathList.ElementAt(_Index), _Index));
try
{
_ImageTimer.Stop();
String[] checkExt = _PathList.ElementAt(_Index).Split('.');
String ext = checkExt[checkExt.Length - 1];
if (ext.Equals("jpg", StringComparison.CurrentCultureIgnoreCase) ||
ext.Equals("jpeg", StringComparison.CurrentCultureIgnoreCase) ||
ext.Equals("png", StringComparison.CurrentCultureIgnoreCase))
{
_ImageTimer.Interval = Constants.NormalImageTimer;
ShowImage(_PathList.ElementAt(_Index));
}
else if (ext.Equals("mp4", StringComparison.CurrentCultureIgnoreCase) ||
ext.Equals("3gp", StringComparison.CurrentCultureIgnoreCase))
{
_ImageTimer.Interval = Constants.VideoDefaultTimer;
PlayQueue(_PathList.ElementAt(_Index));
}
_ImageTimer.Start();
_Index++;
}
catch (Exception exception)
{
Log.ErrorException(exception.Message, exception);
}
}
}
catch (Exception exception)
{
Log.ErrorException(exception.Message, exception);
}
}
private void MediaOpened(object sender, EventArgs e)
{
}
private BitmapImage LoadImage(string myImageFile)
{
BitmapImage myRetVal = null;
if (!String.IsNullOrEmpty(myImageFile))
{
var image = new BitmapImage();
try
{
using (FileStream stream = File.OpenRead(myImageFile))
{
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = stream;
image.EndInit();
}
}
catch (Exception exception)
{
Log.ErrorException(exception.Message, exception);
}
myRetVal = image;
}
return myRetVal;
}
答案 0 :(得分:4)
我用Google搜索,发现这是与软件渲染相关的WPF图形问题。通过将这段代码添加到 ViewPageLoaded 方法中来解决该问题。
try
{
var hwndSource = PresentationSource.FromVisual(this) as HwndSource;
var hwndTarget = hwndSource.CompositionTarget;
hwndTarget.RenderMode = RenderMode.SoftwareOnly;
}
catch (Exception ex)
{
Log.ErrorException(ex.Message, ex);
}
帮我解决了这个问题。希望它也会对你有所帮助。
从here得到答案。感谢@detale提供的解决方案
答案 1 :(得分:4)
这是一个复杂的问题..我会尝试深入解释它。 (是的,我有一个解决方案)
让我们从 MediaElement应该做什么开始? no ..真的!
它的通配符对吗?这意味着你要扔的东西 - 需要播放:视频,图片,GIF动画,音乐......好的..
现在..每个类别都有多种格式(或标准).. Gif,Png .. Wmv,Mp4 ...
因此,我们使用的每个文件都是由其他编辑器创建的
(有一个可以在里面实现它的玩家 - 这肯定是......)
似乎大多数公司都削减了开支 - 他们并不总是(通常就是......)全面实施标准..所以我们得到的结果文件并不总是标准的1:1。
那么对于一个玩家来说什么是完美的文件格式可以被认为对另一个玩家来说太过腐败。
虽然商业/高级玩家的目的是容忍腐败和口味&#34;用一些标准编写的文件 - MediaElement - 嗯..更简单,也许它比你可能投入的游戏过于简单。
所以,当它陷入这种类型的问题时 - 是的......它可能会冻结而不会报告 - 这是我可以完全归咎于微软的事情 - 为什么?因为它是一个可以接受的冻结缺陷,但忽略它是不可接受的(并且极其不负责任!)并且不通知程序使用MediaElement它冻结或遇到严重的演示错误..
但正如我所说,这是微软的问题,绝对不是你的错。
那么解决方案是什么?
你可能会试着对自己说'#罚款 - 我只是得到另一个组件来播放视频或使用第三方插件......&#34;,但没有我的朋友,那样做不会真正解决你的问题,因为你不知道你要替换的东西是否会受到完全相同的问题..
因此,您唯一的选择就是创建自己的&#34; custom&#34;标准 - 放松,我并不是说你需要制定一个新的标准 - 我只是意味着你需要创建一个标准的策略来确保你将在MediaElement上投掷的内容将被播放而不会冻结..
因此,如果您的应用程序要播放用作资源的视频 - 您可能希望使用最新版本的AnyVideoConverter将所有视频转换为mp4。对我来说它运作得相当好,视频在wmv中被冻结转换为mp4,现在MediaElement可以非常顺利地容忍。这不是MP4的伎俩,而是转换本身 - 我相信ANV创造了一个现代化的&#34;您可能用于文件的任何标准的视频文件。
但是,如果您的视频在运行时期间是动态的/上传到您的应用程序或类似的东西 - 您必须确保通过您的应用程序的任何视频,以通过您选择的#34;标准化程序&#34;在你真正把它们扔到MediaElement之前。
顺便说一下,浏览器偶尔会遇到同样的问题。
我希望所有这些可能会让遇到它的其他人解决问题。
答案 2 :(得分:2)
您正在创建大量的BitmapImage实例,BitmapImage类中存在内存泄漏,BitmapImage保留对源流的引用(可能是因为您可以随时读取StreamSource属性),因此它使MemoryStream对象保持活动状态。这导致内存异常。阅读this,他为流创建了一个很好的包装器,它对我有用。
他在wrapperclass中创建了一个实例流,当你调用wrapper的dispose方法和BitmapImage时,它会被释放.Source只有空的包装类,它没有对原始流的任何引用。
答案 3 :(得分:1)
我建议您注册MediaElement.MediaFailed活动。看看它是否会给你带来任何回报。
然而,正如其他人所说,这听起来像是一个记忆问题。您可以使用WPF Performance Suite甚至只使用任务管理器来确认这一点。注意内存使用量的逐渐增加。
正如Shivam cv所提到的,可能是BitmapImage是漏洞。尝试从解决方案中对其进行评论,看看是否能解决问题。