强制MediaElement在播放后释放流

5

我正在创建一个具有播放功能的音频录制控件。

我使用媒体元素来播放录制的音频,代码如下:

using (var storage = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication())
{
    using (System.IO.Stream stream = new System.IO.IsolatedStorage.IsolatedStorageFileStream(filePath, System.IO.FileMode.Open, storage))
    {
        player.SetSource(stream);
    }
}

我面临的问题是,当我使用媒体元素播放录制的音频时,流被锁定到媒体元素。我无法覆盖文件,甚至不能再次播放它,因为SetSource()方法会抛出异常。
有没有办法强制媒体元素释放流?
4个回答

10

根据@Sheridan的回答,这是我想出来的可行方案。

每当使用Stop()函数停止MediaElement时,请将Source属性设置为null,如下所示:

ResetMediaElement()
{
    mediaElement.Stop();
    mediaElement.Source = null;
}

这将关闭与媒体元素相关联的流,以便相关资源可以在其他地方使用。

2
mediaElement.Stop();
mediaElement.ClearValue(MediaElement.SourceProperty);

2
如果您使用MediaElement,请确保不会遇到以下问题:http://msdn.microsoft.com/en-us/library/cc626563(v=vs.95).aspx ArgumentNullException - mediaStreamSource为空。
调用此方法后,MediaElement.Source返回null。如果调用此方法并设置了MediaElement.Source,则最后的操作将获胜。
如果在UI树中移除了具有打开的MediaStreamSource的MediaElement,则可能会忽略对SetSource的后续调用。为确保featureSetSource调用有效,请在从UI树中分离MediaElement之前将Source属性设置为null。
自然而然地,人们会期望,如果他们只使用SetSource(somestream)来释放资源,则使用SetSource(null)来释放资源。没有,他们认为“更好”,您必须使用Source = null而不是SetSource(null)来释放资源,并且SetSource(null)会引发ArgumentNullException。
这就是我所说的设计错误(违反了“最少预期”行为规则,并导致仅在运行时咬你的错误[除非有人制定了静态分析规则来捕获这种事情 - 当然需要元数据,表明某些参数不能为空,例如在代码合同中])
我昨天在重构ClipFlair Studio的AudioRecorder控件中引入了此错误:-(
请注意,您无法在MediaElement中使用类似Source= stream的东西来打开Stream,因为那是一个Uri属性(不是Object属性,也接受Stream),您必须使用SetSource(stream),所以您也希望能够使用SetSource(null)来释放资源。
更新:在AudioRecorderControl的AudioRecorderView类(使用MVVM模式)中修复了此问题,在Audio属性的“set”访问器中需要以下空值保护模式。
if (mediaStreamSource != null) 
  player.SetSource(mediaStreamSource); 
      //must set the source once, not every time we play the same audio, 
      //else with Mp3MediaSource it will throw DRM error 
else 
   player.Source = null; 

0

我曾经遇到过类似的显示图片问题。在一个带有图像的控件中,每当用户尝试更新图像时,都会出现“文件正在使用”的错误。解决方法是将 BitmapImage.CacheOption 属性设置为 BitmapCacheOption.OnLoad

MSDN 上说:如果要关闭用于创建 BitmapImage 的流,请将 CacheOption 设置为 BitmapCacheOption.OnLoad。默认的 OnDemand 缓存选项保留对流的访问权限,直到需要图像,并由垃圾回收器处理清理。

在寻找可用于您的 MediaElement 的类似属性时,结果发现并没有这样的属性。但是,根据 MSDN 上 chacheoption for mediaelement 帖子上的答案,有一种(冗长的)方法可以实现此目的... 相关答案如下:

我不确定你的MediaElement是否在UserControl中,但无论如何,你都可以将UserControl或Control设置为IsEnabled=false,这将触发事件处理程序IsEnabledChanged。在其中放置必要的代码来停止MediaElement的播放ME.Stop(),然后调用ME.Clear()和ME.Source=null。之后,你应该找不到删除源文件的问题。
ME.Source = new Uri(MediaFilePath);
ME.Play();
...
private void DeleteButton_Click(object sender, RoutedEventArgs e) 
{ 
    ME.IsEnabled = false;   // This will call the Event Handler IsEnabledChanged 
    System.IO.File.Delete(MediaFilePath); 
    // Now after the player was stopped and cleared and source set to null, it 
    // won't object to deleting the file
}

private void ME_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    ME.Stop();
    ME.Clear();
    ME.Source = null;
}

希望这能有所帮助。


一个Media Element上没有'IsEnabled'属性。虽然您建议将源属性设置为null是有效的,另外感谢您提供有关BitmapImage的信息,这对我在应用程序的另一个场景中会很有帮助。 - Jap
很抱歉,您对“IsEnabled”属性的理解是错误的,而MediaElement属性页面上的MSDN也会支持我的看法。但我很高兴这个问题得到了解决。 - Sheridan
我不知道其他平台上的MediaElement,但在Windows Phone 8上没有'IsEnabled'属性。它在MSDN上显示,但如果你在Visual Studio中检查,它就不在那里。 - Jap
哦,抱歉,我没有注意到那个标签。不过很高兴你已经解决了它。 - Sheridan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接