Naïve Media Player, Part 2

github地址:https://github.com/zhanglinfeng1997/MediaPlayer
这周的任务是对上一周制作的多媒体播放器添加进一步的功能。
主要包括两个,一个添加播放网络资源的功能,二是适当的定位音乐文件夹。除此之外还需要对于上次的交互页面做进一步的修改。


添加网络资源播放的控件

我们需要实现一个,用户输入url,然后播放这个url资源的功能,其中要做出缓冲后播放和一边缓冲一遍播放两种功能。按照我的理解,前者就是直接播放网络上的资源,后者就是先根据url下载资源后,再去播放。不过无论如何,我们需要一个按钮和一个输入框去进行交互。
对此,我修改了上次的代码,从原来的文本介绍中挤出了一块空间,作为这两个空间的位置。

<Grid.RowDefinitions>
                        <RowDefinition Height="*"></RowDefinition>
                        <RowDefinition Height="*"></RowDefinition>
                        <RowDefinition Height="0.5*"></RowDefinition>
                        <RowDefinition Height="0.5*"></RowDefinition>
                        <RowDefinition Height="*"></RowDefinition>
                        <RowDefinition Height="*"></RowDefinition>
                        <RowDefinition Height="*"></RowDefinition>
                        <RowDefinition Height="*"></RowDefinition>
                    </Grid.RowDefinitions>

修改之处是为了排版上的好看,我加入了两行,并且设置其高度为0.5

 <TextBox Name="urlInput" Grid.Row="2" Text="在此处输入URL" FontSize="20px" HorizontalAlignment="Center"></TextBox>
                    <Button Name="urlButton" Grid.Row="3" Content="播放网络资源" HorizontalAlignment="Center" Margin="3" Click="urlButton_Click"></Button>

以上是我添加的两个控件,同时生成了button的点击事件。


将URL转成URI

如果能直接从URL创建一个可播放的文件对象,就再好不过了,于是我做了以下尝试

private void urlButton_Click(object sender, RoutedEventArgs e)
        {
            string url = urlInput.Text;
            MediaPlayer.Source = MediaSource.CreateFromUri(url);
        }

当然,这样是行不通的。MediaSource.CreateFrom的方法有很多,其中两个是我能理解的,一个是FromFileStorage,也就是播放本地文件使用的方法,当然这个不适用我这次的任务,还有一个是FromUri,我在开始的时候把它当成了URL,做出了上面的尝试。
我们只要能将URL转换成URI,就可以生成MediaSource对象了。


【问题一】那么,什么是URL,什么是URI,他们之间有什么不同呢?
作为一个知乎小透明,我首先搜到了这个答案
HTTP 协议中 URI 和 URL 有什么区别?

URI—Uniform Resource Identifier通用资源标志符
Web上可用的每种资源如HTML文档、图像、视频片段、程序等都是一个来URI来定位的
URI一般由三部组成
①访问资源的命名机制
②存放资源的主机名
③资源自身的名称,由路径表示,着重强调于资源。

只看URI的解释有点不太明白,第一反应是常用的网址,比如http://www.uvp.com/index.html。机制应该就是http,https,ftp这样的应用层协议,主机名应该就是www.uvp.com,资源本身的名称就是index.html。
我觉得我的理解是很到位的,那么问题来了,这不就是URL吗?
接下来,看URL的解释

URL—Uniform Resource Location统一资源定位符
URL是Internet上用来描述信息资源的字符串,主要用在各种WWW客户程序和服务器程序上,特别是著名的Mosaic。
采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。
URL一般由三部组成
①协议(或称为服务方式)
②存有该资源的主机IP地址(有时也包括端口号)
③主机资源的具体地址。如目录和文件名等

看完之后还是不是很懂,似乎URL强调了WWW,难道是说URL是URI在万维网上的具体表现吗?继续查阅资料。
维基上是这样说的维基百科URL与URI

URI可被视为定位符(URL),名称(URN)或两者兼备。统一资源名(URN)如同一个人的名称,而统一资源定位符(URL)代表一个人的住址。换言之,URN定义某事物的身份,而URL提供查找该事物的方法。
URL是一种URI,它标识一个互联网资源,并指定对其进行操作或获取该资源的方法。可能通过对主要访问手段的描述,也可能通过网络“位置”进行标识。例如,http://www.wikipedia.org/这个URL,标识一个特定资源(首页)并表示该资源的某种形式(例如以编码字符表示的,首页的HTML代码)是可以通过HTTP协议从http://www.wikipedia.org这个网络主机获得的。URN是基于某命名空间通过名称指定资源的URI。人们可以通过URN来指出某个资源,而无需指出其位置和获得方式。资源无需是基于互联网的。例如,URN urn:isbn:0-395-36341-1 指定标识系统(即国际标准书号ISBN)和某资源在该系统中的唯一表示的URI。它可以允许人们在不指出其位置和获得方式的情况下谈论这本书。

终于明白了,URI实际上是一个更为抽象的概念,URL是带有地址的访问方式,URN是用简单的命名空间,资源名去定位一个资源,但是由于URL的流行,目前使用URI大多都是URL。


【问题二】如何创建URI类呢?
如何从URL创建URI类的,参考了这个网页的demoC#的uri类

private void urlButton_Click(object sender, RoutedEventArgs e)
{
string url = urlInput.Text;
Uri internetSource = new Uri(url);
MediaPlayer.Source = MediaSource.CreateFromUri(internetSource);
}

如此就创建了一个MediaSource类。播放的代码和使用文件播放相同。
这样就完成了第一个功能,直接播放网络资源(边缓存边播放)
这里写图片描述


实现先缓存,再播放的功能

即实现先下载音频文件,然后再播放。
【问题三】如何使用Httpclient下载文件呢?
使用UWP下载文件 这是我找到的一个讲如何实现根据url下载文件的网址。

public async Task<StorageFile> Load()
{
    try
    {
        var httpClient = new HttpClient();
        var buffer = await httpClient.GetBufferAsync(new Uri("http://dx.sc.chinaz.com/Files/DownLoad/sound1/201207/1771.mp3"));
        if (buffer != null && buffer.Length > 0u)
        {
            var file = await ApplicationData.Current.LocalCacheFolder.CreateFileAsync("1771.mp3", CreationCollisionOption.ReplaceExisting);
            using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
            {
                await stream.WriteAsync(buffer);
                await stream.FlushAsync();
            }
            return file;
        }
    }
    catch { }
    return null;
}

主要使用的httpclient这个类,主要步骤是先使用GetBufferAsync下载文件,存储到内存缓冲器中,然后在从缓冲中将信息输出到文件里。根据这段代码,我写出了以下代码

 private async void downloadButton_ClickAsync(object sender, RoutedEventArgs e)
        {
            MediaPlayer.Visibility = Visibility.Visible;
            StorageFile file = await GetFileAsync();
            if (file != null)
            {
                // Application now has read/write access to the picked file  
                MediaPlayer.Source = MediaSource.CreateFromStorageFile(file);
                MediaPlayer.Visibility = Visibility.Visible;


                MediaPlayer.MediaPlayer.MediaEnded += new TypedEventHandler<Windows.Media.Playback.MediaPlayer, object>((player, resource) => {
                    bt.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
                        bt.Visibility = Visibility.Visible;
                        MediaPlayer.Visibility = Visibility.Collapsed;
                    });
                });
            }
        }
public async Task<StorageFile> GetFileAsync()
        {
        describe.Text = "开始下载";
            var httpClient = new Windows.Web.Http.HttpClient();
            var buffer = await httpClient.GetBufferAsync(new Uri("http://www.neu.edu.cn/indexsource/neusong.mp3"));
            if (buffer != null)
            {
                StorageFile File = await KnownFolders.MusicLibrary.CreateFileAsync(
                           "neusong.mp3", CreationCollisionOption.ReplaceExisting);

                using (var stream = await File.OpenAsync(FileAccessMode.ReadWrite))
                {
                    await stream.WriteAsync(buffer);
                    await stream.FlushAsync();
                }
                //  var stream = await File.OpenAsync(FileAccessMode.ReadWrite);
                // await stream.WriteAsync(buffer);
                //await stream.FlushAsync();
                describe.Text = "下载成功";
                return File;
            }
            return null;
        }

但是在运行的过程中,遇到了报错
这里写图片描述
搜索这个报错信息,找到了下面的资料官方文档(unauthorizedaccessException)
里面对于这个异常有这样的解释

The exception that is thrown when the operating system denies access because of an I/O error or a specific type of security error.
Namespace: System
Assembly: mscorlib (in mscorlib.dll)

看起来似乎是操作系统权限的问题,那应该如何解决呢,windows又不能Sudo…
在stackoverflow里找到了类似的问题stackoverflow

Documents Library capability has been a source of confusion for app developers from the first days of Windows Store. This capability can be easily set through App Manifest editor to enable the app to access user’s Documents library through WinRT API. Although it perfectly works during development, enabled Documents Library capability means almost automatic failure of the Store certification process for the affected app, when the app is submitted using non-company account.

stackoverflow的答案提供了这个网站http://lunarfrog.com/blog/documents-library-capability-winrt,根据它说明,做了这样的修改
这里写图片描述
然后再次运行,发现可以使用了,如下

这里写图片描述


music去哪儿

【问题四】如何找到music文件夹呢?
最后还有这样一个问题,我们如何确定用户的音乐文件夹在哪里呢?如果用户修改的话我们该怎么找到呢?
在没有接触这一方面的时候,我的第一反应是,使用bfs在硬盘中搜索“音乐”文件夹,然后将其路径保存到应用程序的数据中,以后每次使用都检查这个文件夹,若用户修改了,就重新搜索,重新确定路径。
不过这么复杂的事情,UWP已经帮我们做好了,我参考了这个网站KnownFolders.MusicLibrary | musicLibrary Property

public static StorageFolder MusicLibrary { get; }

这个网址主要讲的是MusicLibrary的使用方法。根据以上,我写了这样的代码解决了这个问题。

     StorageFile File = await KnownFolders.MusicLibrary.CreateFileAsync(
                           "neusong.mp3", CreationCollisionOption.ReplaceExisting);

通过这次作业,我主要学习了三点
1、URL与URI的区别
2、如何使用httpclient下载文件
3、如何使用KnownFolders获取默认的文件夹(音乐等)

github地址:https://github.com/zhanglinfeng1997/MediaPlayer

阅读更多
个人分类: UVP
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭