65.9K
CodeProject 正在变化。 阅读更多。
Home

使用嵌入式 Microsoft 媒体播放器的有声读物播放器

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.64/5 (7投票s)

2010 年 3 月 7 日

CPOL

4分钟阅读

viewsIcon

90648

downloadIcon

12279

使用嵌入式 Microsoft 媒体播放器的有声读物播放器

引言

这个项目源于我对 Microsoft Mediaplayer 和 Itunes 的极度不满。我需要的是一个简单的有声读物播放器,它可以记住最后一个播放的位置(文件索引和播放进度)。

我的一些有声读物是由多个 MP3 文件组成的(并非所有文件都包含完整的元信息)。因此,如果未提供封面,能够显示封面图像,并能猜测作者和标题将会很有用。该应用程序是一个业余项目,并非商业级应用程序。所以不要指望任何单元测试或其他保证,它在我自己的机器(一台 Windows 7 64 位笔记本电脑)上运行良好。将其发布到 CodeProject 是为了回馈那些在该网站上发表精彩文章的各位。希望您觉得该应用程序有趣或代码有用。它包含了完整的源代码和一个可执行文件的安装程序项目。

应用程序要求

记住播放位置

只有一个播放列表(当前播放列表)。它将在应用程序关闭时写入应用程序数据目录,并在应用程序启动时读取。播放列表(类AudiobookList.cs)包含文件名、封面图像和当前播放位置。

轻松创建新播放列表

支持拖放。所有拖放到应用程序上的文件都将构成一个新的播放列表并开始播放。文件也可以作为命令行启动参数添加。

读取元信息

使用 taglib 库读取媒体文件的元信息。

根据文件名猜测元信息

使用 Amazon 网上商店来检查艺术家和标题,并获取封面图像。您需要提供自己的帐户密钥。此密钥可从 Amazon(http://aws.amazon.com/)免费获得。

实现细节

UI

该应用程序使用 WPF 构建,并且是一个无边框的应用程序。可以通过在窗口声明中添加以下内容来隐藏边框

<window ResizeMode="NoResize" WindowStyle="None" AllowsTransparency="True"
Background="Transparent">

添加左键按下事件处理程序后,当按住鼠标左键并移动鼠标时,即可支持在屏幕上移动窗口。

private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    if (sender == this)
    {
        DragMove();
    }
}

主窗口仍然命名为Window1,因为我有点懒。 ;-) 代码很简单,没有任何技巧,除了对位图进行一些透明度更改。

播放列表

播放列表存储为AudiobookList类的实例。该类本身包含创建、加载和存储列表所需的所有代码。可以基于文件列表或目录创建新实例。目录将被递归扫描,如果文件是音频文件,则会被添加。这是通过根据文件扩展名从注册表中获取 MIME 类型来完成的。如果它以“audio”开头,我们则假定它是一个音频文件。
文件名根据文件和包含目录中的数字进行排序。每个数字都会被添加,每找到一个数字,总数就乘以 1000。

public static FileType DetermineFileType( string filename )
{
    string mime = MimeType(filename);
    if (mime.StartsWith("image"))
    {
        return FileType.Image;
    }
    else if (mime.StartsWith("audio"))
    {
        return FileType.Audio;
    }
    return FileType.Other;
}

private static string MimeType(string filename)
{
    string mime = "application/octetstream";
    string ext = System.IO.Path.GetExtension(filename).ToLower();
    Microsoft.Win32.RegistryKey rk = 
	Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
    if (rk != null && rk.GetValue("Content Type") != null)
    {
        mime = rk.GetValue("Content Type").ToString();
    }
    return mime;
} 

元信息

DetectMediaInfo类将检索文件的元信息。它将首先尝试使用开源TagLib库读取 MP3 标签。如果元信息中未提供任何信息,我们将尝试从文件名中提取作者和标题。我们使用 Amazon 网上商店来检查它们。Amazon 的参数将添加到 URL 中,并使用访问密钥和秘密密钥(未提供)进行哈希处理。访问密钥和秘密密钥可以通过配置页面输入,并会存储在应用程序的配置文件中。Amazon WS 的参数将被哈希处理并添加到 URL 中。响应是纯 XML。代码本身由 Amazon 提供。我唯一添加的是使用 LINQ 处理生成的 XML。

public void FindBookByTitle(string searchTitle, string searchAuthor, 
	out string bookTitle, out string bookArtist, out string imageUrl) 
{ 
    bookTitle = string.Empty; 
    bookArtist = string.Empty; 
    imageUrl = string.Empty; 
    string url = BuildRequestSearchBookTitle(searchTitle, searchAuthor); 
    string xml = CallAmazonWS(url); 
    ProcessXmlBookResult(xml, ref bookTitle, ref bookArtist, ref imageUrl); 
} 

private string BuildRequestSearchBookTitle(string searchTitle, 
					string searchAuthor) 
{ 
    IDictionary parameters = new Dictionary(); 
    parameters["Service"] = "AWSECommerceService"; 
    parameters["Version"] = "2009-03-31"; 
    parameters["Operation"] = "ItemSearch"; 
    parameters["SearchIndex"] = "Books"; 
    parameters["Title"] = searchTitle; 
    if (string.IsNullOrEmpty(searchAuthor) == false) 
    { 
        parameters["AuthorName"] = searchAuthor; 
    } 
    parameters["ResponseGroup"] = "ItemAttributes,Images"; 
    string requestUrl = Sign(parameters); 
    return requestUrl; 
} 

private static string CallAmazonWS(string url) 
{ 
    WebRequest request = HttpWebRequest.Create(url); 
    WebResponse response = request.GetResponse(); 
    StreamReader reader = new StreamReader( response.GetResponseStream( ) ); 
    return reader.ReadToEnd( ); 
}

private static void ProcessXmlBookResult(string xml, ref string bookTitle, 
			ref string bookArtist, ref string imageUrl) 
{ 
    XNamespace ns = "http://webservices.amazon.com/AWSECommerceService/2009-03-31"; 
    XElement root = XElement.Parse( xml ); 
    bool isValid = RequestIsValid(root, ns); 
    int resultCount = GetResultCount(root, ns); 
    if ( isValid && (resultCount > 0)) 
    { 
        XElement item = GetFirstItem(root, ns); 
        GetAuthorAndTitle(item, ns, ref bookTitle, ref bookArtist); 
        imageUrl = GetItemImage( item, ns ); 
    } 
} 

玩家

播放器是 Microsoft Mediaplayer 的 COM 接口,因此需要WMPLIB互操作库。MyPlayer类是对 COM 实例的抽象。我们将接口强制转换为WindowsMediaPlayerClass实例。这使我们能够接收PlayStateChange事件并将Autostart属性设置为false。无需进行任何复杂的操作。UI 有一个每秒运行一次的后台计时器。它会检查播放器是否正在播放,然后将当前时长打印为string。如果 Mediaplayer 尚未播放,则会提供一个时长string,否则则为空string

改进应用程序的想法

  • 该应用程序假设所有文件只有一个作者和标题。如果您向列表中添加不同的标题,则只会显示第一个。
  • Amazon 的 XML 结果只处理第一个项目。也许其他项目也可能包含有效结果。
  • 添加更多检查并提高健壮性。目前只捕获了异常的最小处理部分,使用了try/catch
  • 添加对 MP3 以外格式的支持。这可能会起作用,但并未经过测试。
  • 使用云作为音频文件和AudiobookList的存储。这样,在使用的任何计算机上都可以继续播放。

玩得开心!!

历史

  • 2010 年 3 月 7 日:初次发布
© . All rights reserved.