基于Android平台视频播放器的开发

摘 要

如今,随着基于android的智能手机的兴起,一款具有个性化的视频播放器是消费者的一个主要需求。因此,设计一个基于android手机的视频播放器,具有重要的实际意义。

遵循软件工程规范,文中主要介绍了基于android的视频视频播放器的设计和实现过程,实现了手机中视频文件的过滤读取、存储、播放、收藏等功能。同时简单的实现了实时流协议RTSP(Real Time Streaming Protocol)上视频流的播放功能。选用的开发环境是基于EclipseAndroid ADT 的Java编写代码,使用了具有信息缓冲的surface view控件、美化界面布局的Android Activity和存放数据的数据库SQLite

关键词:Android;视频播放器; 实时流协议

Development of  Video Player Based-on Android

ABSTRACT:

Nowadays, with the development of the smart phone based on android, a personalized player is a major demand of consumers. Therefore, it is of important and practical significance to design a media mobile phone player based on android.

    Following the specification of software engineering , the paper mainly introduces the design and implementation process of the media video player based on android and realizes the cell phone video files in the filtering read, storage, broadcast, collection and other functions.Meanwhile,it simply realizes the function of  playing RTSP online video stream.Under the environment of the Eclipse and Android ADT in JAVA code,it uses the surface view control with the message buffer , Android Activity with landscaping interface layout  and database SQLite to store data.

Keywords: Android; Media Player; Real Time Streaming Protocol 

目录

1.绪论

1.1课题背景

1.2课题目的与意义

2.Android平台概述

2.1什么是Android

2.1.1 Android简介

2.1.2 Android Features特性

2.1.3 Android基本框架(Android Architecture

2.1.4 Android系统的四大组件

2.2搭建Android开发环境

3.程序设计分析及模块设计

3.1需求分析任务

3.2播放器的基本控制需求

3.2.1视频播放器功能模块

3.2.2分析

3.3系统界面需求

3.4系统性能需求

4.系统功能实现

4.1播放器主界面功能实现

4.2播放器的一般控制功能实现

4.2.1播放进度条

4.2.2播放器暂停、播放、停止等功能

4.2.3音量调节

4.2.4视频比例缩放

4.2.5全屏与非全屏切换

4.3获取媒体文件列表

4.4视频文件扫描

4.5 AndroidManifest.xml的配置

4.6使用说明

5.个人总结

参考文献

   

1.绪论

1.1课题背景

当今社会的生活节奏越来越快,人们对手机的要求也越来越高,由于手机市场发展迅速,使得手机操作系统也出现了不同各类,现在市场上主流的手机操作系统有Windows mobile,sysbian,以及谷歌的Android操作系统,其中占有开放源代码有事的Android系统具有广阔的发展前景,已经和国内外诸多手机厂家开展了合作。那么能否在手机上拥有自己编写的个性多媒体播放器呢?答案是肯定的,谷歌Android系统就能做到。本文所介绍的多媒体播放器就是基于谷歌Android手机平台的播放器。

Android操作系统是谷歌于2007年公布的开放式源代码手机系统,它的开放性相对有其它封闭式手机系统拥有明显的优势,任何人都可以根据自己的喜好和需求将Android系统的功能进行改进,在Android平台上开发属于自己的应用软件。这也让更多的人对这一操作系统有了更浓厚的兴趣。我们开发的这款多媒体播放器就是基于Android平台的。

随着计算机的广泛应用,手机市场的迅速发展,各种音频视频资源也在网上广为流传,这些资源看似平常,但已逐渐成为了人们生活中必不可少的一部分了。于是各种手机播放器相继被开发出来,但是很多播放器一味追求外观花俏,功能过于庞大,导致用户手机资源被过度占用,造成资源浪费。比如说CPU,内存等占用率过高,在用户执行多任务操作时经常出现卡机甚至是死机的现象。其实对于大多数普通用户,很多功能都是形同虚设。针对以上各种弊端,选择了开发一种功能实用,用户交互友好的多媒体播放器,将各种性能优化,继承播放器的常用功能,满足一般用户(如听歌,看电影)的需求。

通过对了市场上主流的播放器的观察,了解它们各自的插件及编码方式,分析了各种开发方式的优缺点,从可行性分析出发,找出一条适合自己的开发之路,编写出功能实用,使用方便,占用资源小的播放器。目前已经实现的功能有能播放常见视频文件的功能,如3GP,WMV等,自动获取用户SD卡上的音视频文件,具备一般播放器的功能,如播放、暂停、上一首、下一首、音量调节、全屏切换显示、选择等功能。

1.2课题目的与意义

随着人们生活节奏地加快,物质生活也越来越丰富了,然而许多人精神上的状态都是比较紧张的,偶尔听听歌曲,看看电影也不失为一种好的舒缓压力的方式。本项目的研究目的是开发一款可以播放主流音频和视频文件的多媒体播放器,并且能够控制播放,暂停,停止,上一首,下一首,音量调节,界面清新友好,操作简单。易于用户上手。

本项目是一款基于Android手机平台的多媒体播放器,能将一些个性化设计融入其中。能完成该软件的多线程管理,实现该多媒体播放器的后台播放和后台Service控制。要求软件界面设计应简洁、易于上手,交互设计友好、人性化、个性化,同时作者也获得了开发android程序的第一次经历。


2.Android平台概述

本章主要讲述Android系统的应用背景以及相关技术框架,了解安卓的发展史及相关平台知识,有助于我们更好地掌握Android开发的技巧。

2.1什么是Android?

图2.1 Android Logo(机器人)

2.1.1 Android简介

Android一词的本义指“机器人”,同时也是Google于2007年11月5日宣布的基于Linux平台的开源手机操作系统的名称,该平台由操作系统、中间件、用户界面和应用软件组成,号称是首个为移动终端打造的真正开放和完整的移动软件。

Android是一种以Linux为基础的开放源码操作系统,主要使用于便携设备。目前尚未有统一中文名称,中国大陆地区较多人使用“安卓”或“安致”。Android操作系统最初由Andy Rubin开发,最初主要支持手机。2005年由Google收购注资,并组建开放手机联盟开发改良,逐渐扩展到平板电脑及其他领域上。Android的主要竞争对手是苹果公司的iOS以及RIM的Blackberry OS。2011年第一季度,Android在全球的市场份额首次超过塞班系统,跃居全球第一。 2012年2月数据,Android占据全球智能手机操作系统市场52.5%的份额,中国市场占有率为68.4%。

2.1.2 Android Features特性

Android系统有如下的几大特性:

•应用程序框架 支持组件的重用与替换

•Dalvik虚拟机 专门为移动设备做了优化

•内部集成浏览器 该浏览器基于开源的WebKit引擎

•优化的图形库 包括2D和3D图形库,3D图形库基于OpenGL ES   

•SQLite 用作结构化的数据存储

•多媒体支持 包括常见的音频、视频和静态印象文件格式(如MPEG4, H.264,MP3, AAC, AMR, JPG, PNG, GIF)

•GSM电话(依赖于硬件)

•蓝牙Bluetooth, EDGE, 3G, and WiFi (依赖于硬件)

•照相机,GPS,指南针,和加速度计 (依赖于硬件)

•丰富的开发环境 包括设备模拟器,调试工具,内存及性能分析图表,和Eclipse集成开发环境插件。

2.1.3 Android基本框架(Android Architecture)

图2.2 Android结构

 Applications,Android会同一个核心应用程序包一起发布,该应用程序包包括email客户端,SMS短消息程序,日历,地图,浏览器,联系人管理程序等。所有的应用程序都是用JAVA编写的。

 Application FrameWork ,开发者完全可以访问核心应用程序所使用的API框架。该应用程序架构用来简化组件软件的重用;任何一个应用程序都可以发布它的功能块并且任何其它的应用程序都可以使用其所发布的功能块(不过得遵循框架的安全性限制)。该应用程序重用机制使得组建可以被用户替换。

 所有的应用程序都由一系列的服务和系统组成,包括:可扩展的视图(Views )可以用来建应用程序,包括列表(lists), 网格(grids),文本框(text boxes),按钮(buttons),甚至包括一个可嵌入的web浏览器。

内容管理器(Content Providers )使得应用程序可以访问另一个应用程序的数据(如联系人数据库),或者共享它们自己的数据。

资源管理器(Resource Manager)提供非代码资源的访问,如本地字符串,图形,和分层文件(layout files )。

通知管理器(Notification Manager)使得应用程序可以在状态栏中显示客户通知信息。

活动类管理器(Activity Manager)用来管理应用程序生命周期并提 供常用的导航回退功能。

 LibrariesAndroid 包括一个被 Android 系统中各种不同组件所使用的 C/C++ 库集。该库通过 Android 应用程序框架为开发者提供服务。以下是一些主要的核心库:

  系统 C - 一个从 BSD 继承来的标准 C 系统函数库( libc ),专门为基于 embedded linux 的设备定制。 

媒体库- 基于 PacketVideo OpenCORE;该库支持录放,并且可以录制许多流行的音频视频格式,还有静态印像文件包括MPEG4, H.264, MP3, AAC, AMR, JPG, PNG 

Surface Manager - 对显示子系统的管理,并且为多个应用程序提供2D3D图层的无缝融合。 

LibWebCore - 一个最新的web浏览器引擎用来支持Android浏览器和一个可嵌入的web视图。 

SGL - 一个内置的2D图形引擎 

3D libraries - 基于OpenGL ES 1.0 APIs实现;该库可以使用硬件3D加速(如果可用)或者使用高度优化的3D软加速。 

FreeType - 位图(bitmap)和向量(vector)字体显示。 SQLite 一个对于所有应用程序可用,功能强劲的轻型关系型数据库引擎。

 Android Runtime Android 包括了一个核心库,该核心库提供了JAVA编程语言核心库的大多数功能。

    每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚拟机实例。Dalvik是针对于同时高效地运行多个VMs来实现的。Dalvik虚拟机执行.dexDalvik可执行文件,该格式文件针对最小内存使用做了优化。该虚拟机是基于寄存器的,所有的类都经由JAVA汇编器编译,然后通过SDK中的dx工具转化成.dex格式由虚拟机执行。

Dalvik虚拟机依赖于linux的一些功能,比如线程机制和底层内存管理机制。

 Linux内核,Android 是运行于 Linux kernel之上,但并不是GNU/Linux。因为在一般GNU/Linux 里支持的功能,Android 大都没有支持,包括CairoX11AlsaFFmpegGTKPangoGlibc等都被移除掉了。Android又以bionic 取代Glibc、以Skia 取代Cairo、再以opencore 取代FFmpeg 等等。Android 为了达到商业应用,必须移除被GNU GPL授权证所约束的部份,例如Android将驱动程序移到 userspace,使得Linux driver  Linux kernel彻底分开。bionic/libc/kernel/ 并非标准的kernel header filesAndroid  kernel header 是利用工具由 Linux kernel header 所产生的,这样做是为了保留常数、数据结构与宏。

目前Android  Linux kernel控制包括安全(Security),存储器管理(Memory Management),程序管理(Process Management),网络堆栈(Network Stack),驱动程序模型(Driver Model)等。下载Android源码之前,先要安装其构建工具 Repo来初始化源码。Repo  Android 用来辅助Git工作的一个工具。

2.1.4 Android系统的四大组件

在Android系统中,为我们提供了四大基本组件,每个组件是一个视图,但是有些是可见的,有些是不可见的视图,像Activity,ContentProvider是可见的视图,Service和BroadcastReceiver是不可见的,它们只在系统的后台运行。下面分别介绍四大组件:

Activity 简介,在Android系统中Activity提供可视化的用户界面,一个Android应用通常由多个Activity组成。多个Activity组成了Activity栈(Stack),当前活动的Activity处于栈顶。Activity有自己的生命周期,由Android系统来控制。

Service 简介,顾名思义Service就是运行在后台的一种服务程序,一般很少和用户交互,因此没有可视化界面定义一个Service类比较简单,只要继承Service类,实现其生命周期中的方法就可以了。一个定义好的Service必须在AndroidManifest.xml配置文件注册,通过<service>元素声明才能使用.Service有自己的生命周期,我们可以调用startService()启动一个Service或者bindService()方法来绑定一个存在的Service。

Broadcast Receiver 简介,Broadcast Receiver 顾名思义广播接收器,它和事件处理机制类似,只不过事件处理机制是程序组件级别的(例如,某个按钮的单击事件),而广播事件处理机制是系统级别的。到目前为止我们可以使用Intent来启动一个程序组件,我们还可以通过使用sendBroadcast()方法来发起一个系统级别的事件广播来传递消息。我们可以在你的应用程序中实现Broadcast Receiver来监听和响应这些广播的Intent。

ContentProvider简介,Content Provider 用来保存和检索数据,并且使应用程序之间相互访问数据成为可能。它是跨应用程序共享数据的唯一方法Android 为常用的数据类型(如:音视频、图片和联系方式等)提供了大量的Content Provider。它们被定义在android.provider包下面。通过这样定义好的ContentProvider 我们可以方便的进行数据操作。当然我们必须拥有适当的权限。我们也可以自己来定ContentProvider共享我们的数据,方便用户的访问。

2.2搭建Android开发环境

任何事物要运行,都需要有它自身的环境配置,Android也不例外,下面就来简单讲解一下在Windows7系统环境下Android开发平台的搭建。

搭建开发环境需要的软件有:

1. PC操作系统:Windows7

2. 软件包:Android SDK(Software Development kit)、ADT-16.0.0以上(Android Development Tool)

3. IDE环境:Eclipse IDE+ADT Eclipse3.5以上

4. JDK:(JREJava Runtime Environment虚拟机 (JDK)Java Development kit

安装步骤如下:

安装JDK,SUN官网下载,网址为Oracle Java Technologies | Oracle 到适合自己系统的安装文件jdk-7u1-windows-x64.exe,下载完成后安装。然后在CMD窗口输入java –version检测是否安装成功,如果未能成功则需要自己手动在系统环境变量新建一个“JAVA_HOME”变量,变量值设置为JDK安装目录即可再新建一个,classpa;%.jar;%JAVA_HOME%/lib/tools.jar然后找到PATH变量,在值的最前面加上“%JAVA_HOME%/bin;”(环境变量在我的电脑高级系统设置属性那里设置)。

安装Eclipse,入Eclipse下载页面http://www.eclipse.org/downloads/,选择Eclipse IDE for Java Developers,下载完成后解压缩即可使用。首次打开可选择自己的工作站点。

安装Android SDK,开Android开发者社区网址http://developer.android.com/,转到SDK下 载页面即可下载android-sdk_r17-windows.zip,下载后解压缩,将解压后的tools目录绝对路径添加到系统变量SDK_HOME中,并在PATH系统变量前面加上“%SDK_HOME%\tools;”在CMD窗口中输入测试命令android –h验证是否安装成功。安装ADT,我们不建议联网安装,因为通常都会失败,被屏蔽了。我们可以下去下载ADT包,然后手动导入安装。打开Eclipse→help→Install New Software,单击Add…→Local,将已下载好的ADT包导入,然后选中所有可用插件,安装。安装过程比较慢,需要耐心等待。

开发环境验证及安卓模拟器(AVD)的创建,基本软件安装完毕以后,打开Eclipse依次选择File→New→Project会看见Android项目,创建一个新的项目。至此,我们的开发环境就搭建好了。还有就是创建AVD,可以选择在命令行中创建也可以在Eclipse→Window→AVD Manager中新建模拟器。

3.程序设计分析及模块设计

3.1需求分析任务

认真分析需求分析是在可行性研究的基.础上,将用户对程序的要求,通过开发人员的分析概括,抽象为完整的需求定义,再形成一系列文档的过程。可行性研究旨在评估目标系统是否值得去开发,问题是否能够解决,而需求分析旨在回答"程序做什么"的问题,确保将来开发出来的程序能够真正满足用户的需要。

3.2播放器的基本控制需求

视频播放器顾名思义是用来播放视频用的,所以它应该具有以下功能,能扫描本地视频文件,并形成播放列表。同时,播放视频视一个基本的功能,由于本程序使用的是系统自带解码器,所以它只支持系统默认的视频格式,如3gp,mp4,wmv等。

播放视频时必须的操作包括,播放,暂停,上一部/下一部,全屏切换,音量调节,退出程序。同时,现在绝大部分Android设备上,都采用更为便捷的触摸体验,本程序也完全采用这种做法进行一切操作。流畅的操作是一个程序所必备的。本程序支持在线视频播放,并支持浏览器调用在线播放。

由于Android设备的复杂性,各种分辨率,各种内核繁多,算是众口难调,所以要求程序能尽可能的适应各种屏幕分辨率,尽可能的支持更多的Android系统,本程序采用Android  API1.7编译通过,支持Android1.5,Android1.6,Android2.0,Android2.1。。。

基本功能如下:

         ①程序安装自适应屏幕,最高支持2.1系统,同时向下兼容。

    ②本地视频/在线视频,播放,暂停,上一部/下一部,全屏切换,音量调节,退出程序

3.2.1视频播放器功能模块

将以上的需求分析整理,并且对各个功能,通过关联性,进行集中,分块,按照模块化程序设计的要求,可得到系统的功能模块图。

功能模块图:

图3.1系统功能模块图

通过对程序的功能模块图进行进一步详细解读,可得到更为详细,更明确的播放器的基本操作事件需求

播放器的基本控制需求:

事件,播放:

                      表3.1  “播放”用例说明

事件,暂停:

                      表3.2 “暂停”用例说明     

事件,上一部/下一部:

                      表3.3 “上下部”用例说明

事件,退出:

                  表3.4 “退出”用例说明

全屏切换

                       表3.5 “全屏切换”用例说明

音量调节

                       表3.6 “音量调节”用例说明

功能分析之时序图:

         点击“清单”

                       自动扫描

                       自动生成     点击设置

           点击播放

返回

                                              

                                               播放/暂停

            进                                                                                        上一部/下一部

                                   退出

                                                                                图3.2功能时序图

流程图

                              图3.3系统流程图

3.2.2数据库分析

当用户启动播放器时,从SD卡获取多媒体文件信息,并以列表的形式显示在手机屏幕上,供用户选择播放,文件格式有wma,mp4,3gp,mkv等。

当我们从SD卡里面获取关于mp3/wma详细信息,包括TITLE(标题)、SIZE(大小)、DURATION(持续时间)、DATA(数据)、DISPLAY_NAME(显示名称)等字段,我们可以通过不同的字段来排列,用户可以获得不同的列表,让用户有更多的选择方式,一般情况下是默认名字的先后,排序。

播放器应用程序自行调用Android库函数,SDCard里所有媒体信息都存储在这个类里——android.provider.MediaStore,从而可以轻松获取SD里面的多媒体文件的详细信息,当然前提是SDCard存在。

MediaStore这个类是android系统提供的一个多媒体数据库,android中多媒体信息都可以从这里提取。这个MediaStore包括了多媒体数据库的所有信息,包括音频,视频和图像,android把所有的多媒体数据库接口进行了封装,所有的数据库不用自己进行创建,直接调用利用ContentResolver去掉用那些封装好的接口就可以进行数据库的操作了

3.3系统界面需求

播放器界面要求布局合理,颜色舒适,控制按钮友好,所以我们采用系统自带播放控制按钮和自定义播放模式按钮、音轨、进度条相结合,合理利用资源,如下图为视频播放器界面示例:

  图3.4视频器播放界面

3.4系统性能需求

根据Android手机系统要求无响应时间为5秒,所以就有如下性能要求:

  1. 当点击播放时,程序响应时间最长不能超过5秒
  2. 当点击暂停时,程序响应时间最长不能超过5秒
  3. 当点击第一首/最后一首时,程序响应时间最长不能超过5秒
  4. 当点击上/下一首时,程序响应时间最长不能超过5秒
  5. 当要求退出播放器时,程序响应时间最长不能超过5秒

4.系统功能实现

4.1播放器主界面功能实现

如图所示:

    图4.1播放器主界面

Android的每一个可视化界面,都有其唯一的布局配置文件,该文件里面有各种布局方式,和各种资源文件如图像,文字,颜色的引用,程序在运行时,可以通过代码对各配置文件进行读取。这样就可以形成不同的可视化界面和绚丽的效果。播放器主界面是一个Activity,Android工程在每个activity启动的时候都会首先执行Oncreate()方法,如下代码:

  public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);  

        setContentView(R.layout.main); 该方法主要执行界面的初始化操作,Activity有个设置布局的方法:Content.setContentView(layoutResID),参数为资源ID,该ID在工程目录res/layout下,主界面布局文件名为controler:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:gravity="center"

    android:background="@color/background"

    >

<com.zh_weir.videoplayer.VideoView

android:id="@+id/vv"  

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    />

</LinearLayout>

显然主界面很简单,因为尽量简化界面设计,只是用了一个线性布局<LinearLayout>仅仅是定义了整个界面背景颜色以及其它一些属性。

orientation="vertical"定义界面的方位默认是垂直的

android:gravity="center"。

gravity属性是用来控制 EditText里边文本的位置。

android:layout_width="fill_parent"

android:layout_height="fill_parent"

上面两端代码用来控制控件宽度和高度,又通过布置一个videoview控件,用于播放视频画面,充满屏幕

4.2播放器的一般控制功能实现

4.2.1播放进度条

  播放进度条是一个多媒体播放器所必备的组件,本程序主要调动android系统自带的。

如图

       图4.2播放进度条

代码如下:

<SeekBar

     android:id="@+id/seekbar"

     android:layout_width="wrap_content"

     android:layout_height="wrap_content"

     android:paddingLeft="5dip"

     android:paddingRight="5dip"

     android:layout_marginLeft="10dip"

     android:layout_marginRight="10dip"

     android:layout_weight="1"

/>

此为系统自带的seekbar,播放器最重要的一部分是播放进度条要与播放的视频同步,播放进度条设置了两个TextView用来显示当前视频播放的进度和视频的长度。其中这两个TextView和seekbar内嵌在一个线性布局之中。

   播放进度条SeekBar在视频播放的时候调用方法seekBar.setMax(i);获得视频的总长度,其中定义一个int变量i来接受这个长度,在视频播放的时候 通过seekBar.setProgress(i);来获取当前的播放进度。

  Android的线程的开始是通过Handler类来实现的,handler类是线程与线程之间通信的桥梁,实现Runnable接口会是实现里面的run方法,当线程开始的时候,Runnable中的run方法会向Handler发一个Message消息,这样,Handler类就可以接受到run方法发送过来的不同的消息进行不同的代码处理,这样就可以到达了各线程之间的通信。要启动一个线程调用Handler的方法

i/=1000;

int minute = i/60;

int hour = minute/60;

int second = i%60;

minute %= 60;

playedTextView.setText(String.format("%02d:%02d:%02d",hour,minute,second));

sendEmptyMessageDelayed(PROGRESS_CHANGED, 100);

以上代码意思是让播放视频的线程每隔1000毫秒即每一秒对播放进度条的TextView重新设置时间且让进度条前进1秒的进度。对播放进度条实行刷新,这样就是实现了播放进度与进度条同步的功能,SeekBar有个监听器,该监听器的作用是一直保持着对进度条的监听,当我们用手指向SeekBar的各个位置进行点击时,它会自动监听其位置进行相应的位置显示。这也是进度条上的游标会不停的移动且和播放进度时间会不停变动的原因。

4.2.2播放器暂停、播放、停止等功能

如图:

图4.3播放器控制界面

各按钮水平放置,用的是布局中的线性布局LinearLayout,用方法setOrientation(horizontal);将其设置为水平。LinearLayout中依次放置播放,暂停,停止,上、下一曲按钮属性。配置文件代码结构如下:

<LinearLayout>

       <ImageButton></ImageButton>

       <ImageButton></ImageButton>

       <ImageButton></ImageButton>

       <ImageButton></ImageButton>

</LinearLayout>

Android的媒体播放器远离:android源程序已经为我们封装好了一个接口类,交MediaPlayer.该接口在执行时需要一个数据源,通过如下四个步骤:

第一步:MediaPlayer.reset();复位操作,为以后媒体准备播放作准备。

第二步:传入视频数据源,这里也是一个数据流MediaPlayer.setDataSource(String path);参数需要传一个路径,该接口类在收到路径后将其转化为数据源。

第三步:准备播放数据源,调用方法MediaPlayer.Prepare();

第四步:MediaPlayer.Start();播放数据源,该数据源播放后,不再与程序有关,需要用MediaPlayer.Stop()方法让其停止或MediaPlayer.Start();让其启动;

视频数据源的获取:要获得数据源,需要我们提供接口类一个视频存放路径,而这个路径已经被事先Android系统放到数据库里了,我们无需再从新建立数据库,我们只需要对这个数据库进行操作。将里面的数据的路径取出。这里将调用VideoPlayerActivity中的一个方法query();代码算法如下:

Cursor cursor=getContentResolver().query(videoListUri, new String[]{"_display_name","_data"}, null, null, null);

            int n = cursor.getCount();

            cursor.moveToFirst();

            LinkedList<MovieInfo> playList2 = new LinkedList<MovieInfo>();

  方法getContentResolver是包android.content.ContextWrapper里面的方法,他它会自动的调用ContentProvider中的关联数据库,我们需要用这个方法就可以操作数据库。数据库操作需要一个Uri。Uri类似一个网络连接的Url。Uri是数据库唯一的标识,不同的Uri可以操作不同的数据库表。在查询数据库时需要传入一个当前播放的视频名字,通过视频名字来查询视频的路径。

android的媒体播放原理:android源程序已经为我们封装好了一个接口类,叫MediaPlayer。该接口在执行行需要一个数据源,通过如下四个步骤:

第一步:MediaPlayer.reset();复位操作,为以后的媒体准备播放作准备。     第二步:传入歌曲数据源,这里也是一个数据流 MediaPlayer.setDataSource();参数需要传一个路径,该接口类在收到路径后将其转化为数据源。

第三步:准备播放数据源,调用方法MediaPlayer.Prepare();

第四步:MediaPlayer.Start();播放数据源,该数据源播放后,不再与程序 有关,需要用MediaPlayer.Stop()方法让其停止或MediaPlayer.Start();让其启动;

4.2.3音量调节

如图:

              图4.4声音调节条

在SoundView.java文件中创建AudioManager对象am,通过am调用通过调用mContext的getSystemService()方法并通过setIndex()就可以改变音量了。具体代码:

AudioManager am=(AudioManaer) mContext.getSystemService(Context.AUIO_SERVICE)

setIndex(am.getStreamVolume(AudioManager.STREAM_MUSIC))

4.2.4视频比例缩放

Android系统已经提供videoview视频按比例缩放问题,但是仍然达不到我们想要的效果,但是有时我们需要按照自己的要求规定视频的长宽比例,这就需要我们对videoview做一些改动做出另一个类似videoview的类出来,我们可以很方便的获得videoview的源代码,所以重写videoview的过程其实只是在原基础上进行一些修改而已,VideoView的源码中有这样一段代码:

@Override

   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

      int width = getDefaultSize(mVideoWidth, widthMeasureSpec);

      int height = getDefaultSize(mVideoHeight, heightMeasureSpec);

       if (mVideoWidth > 0 && mVideoHeight > 0) {

          if ( mVideoWidth * height  > width * mVideoHeight ) {             

                height = width * mVideoHeight / mVideoWidth;

           } else if ( mVideoWidth * height  < width * mVideoHeight ) {       

              width = height * mVideoWidth / mVideoHeight;

         }

            }

       }

       setMeasuredDimension(width, height);

    }    

看上面这段代码,我们就知道为什么不能自由地改变长宽比例了,因为在Android系统定义了一个onMeasure方法,对这个长宽比进行了处理。所以我们只需要屏蔽掉这段代码

@Override

  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

   int width = getDefaultSize(mVideoWidth, widthMeasureSpec);

   int height = getDefaultSize(mVideoHeight, heightMeasureSpec);

   setMeasuredDimension(width,height);

   }

这样我们就实现了对比例的自由设定。

4.2.5全屏与非全屏切换

一般一个Activity设置全屏的方法有两种:

一是在OnCreate中:

@Override   

  public void onCreate(Bundle icicle) {   

    super.onCreate(icicle);         

    requestWindowFeature(Window.FEATURE_NO_TITLE);           

    Window win = getWindow();   

    win.setFlags(WindowManager.LayoutParams.NO_STATUS_BAR_FLAG,   WindowManager.LayoutParams.NO_STATUS_BAR_FLAG);   

            setContentView(R.layout.mylayout);  

     二是在AndroidManifest.xml中:

<activity android:name=".MyActivity"

        android:label=""         android:theme="@android:style/Theme.NoTitleBar.Fullscreen">

然而,这两种方法都不能达到我们在视频播放过程中设置全屏与否的目的。因为它们都只能在初始化的时候决定全屏与否。

还有种方法:

1getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

1getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

 这种方法通过调用lgetWindow()的两个方法addFlags(),和clearFlags()就可以在Activity运行过程中,动态地改变全屏与否

4.3获取媒体文件列表

MediaStore这个类是android系统提供的一个多媒体数据库,android中多媒体信息都可以从这里提取。这个MediaStore包括了多媒体数据库的所有信息,包括音频,视频和图像,android把所有的多媒体数据库接口进行了封装,所有的数据库不用自己进行创建,直接调用利用ContentResolver去调用那些封装好的接口就可以进行数据库的操作了。

图4.5文件列表

代码如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent" >

    <LinearLayout

    android:orientation="horizontal"

    android:layout_width="fill_parent"

    android:layout_height="110dip"

    android:gravity="center_vertical">

    <TextView

     android:layout_width="wrap_content"

     android:layout_height="wrap_content"

     android:text="URL:"

     android:textSize="30sp"

     android:textColor="#FFFF0000"

     android:layout_marginLeft="10dip"

     android:layout_gravity="center_vertical"

     />

     <EditText

     android:id="@+id/url_input"

     android:layout_width="wrap_content"

     android:layout_height="wrap_content"

     android:layout_weight="1"

     android:layout_gravity="center_vertical"

     android:layout_marginLeft="20dip"

     android:layout_marginRight="20dip"

     android:inputType="textUri"

     android:imeOptions="actionGo|flagNoExtractUi"

     /> <ImageButton

     android:id="@+id/cancel"

     android:layout_width="wrap_content"

     android:layout_height="wrap_content"

     android:layout_marginRight="10dip"

     android:src="@drawable/del"

     android:background="#0000003D"

     android:layout_gravity="center_vertical"

    />

    </LinearLayout>

    <ListView

     android:id="@+id/list"

     android:layout_width="fill_parent"

     android:layout_height="wrap_content"

     android:layout_gravity="center"

     android:gravity="center"

     android:cacheColorHint="#330000FF"

     android:scrollingCache="false"

    />

    </LinearLayout>

在Android里面,有一个视图ListView,其特点是一个有BaseAdapter的属性,从上到下,或者从左到右的显示方式。系统默认的方式每一行只显示一个TextView,本播放列表目前不能自由设定了,使用系统默认。

  ListView同样有一个监听器

(new OnItemClickListener(){

public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3){}}

我们只要实现这个方法,就可以监听鼠标的点击事件,当鼠标点击到每一行时,可以通过ListView.getItemAtPositon(int positon)得到该行上的信息。这样就可以通过Intent将数据传入到其他的Activity。其中还有textView控件,来接受输入网址。。。

 视频文件列表界面:

    

                        图4.5真机视频文件列表

首先,要得到一个ContentResolver实例,ContentResolver可以这样获取,利用一个Activity或者Service的Context即可。如下所示:

ContentResolver mResolver = ctx.getContentResolver();

上面的那个ctx的就是一个context,Activity.this就是那个Context,这个Context就相当于一个上下文环境。得到这个Context后就可以调用getContentResolver接口获取ContentResolver实例了。

ContentResolver实例获得后,就可以进行各种查询,。

在讲解各种查询之前,我给大家介绍下怎么看android都提供了哪些多媒体表。在adb shell中,找到/data/data/com.android.providers.media/databases/下,然后找到SD卡的数据库文件(一般是一个.db文件),然后输入命令sqlite3加上这个数据库的名字就可以查询android的多媒体数据库了。.table命令可以列出所有多媒体数据库的表,.scheme加上表名可以查询表中的所有列名。这里可以利用SQL语句来查看你想要的数据,记得最后一定要记住每条语句后面都加上分号。那么怎么在这些表上进行增删改查。查询代码如下所示:

Cursor cursor = resolver.query(_uri, prjs, selections, selectArgs, order);

ContentResolver的query方法接受几个参数,参数意义如下:

Uri:这个Uri代表要查询的数据库名称加上表的名称。这个Uri一般都直接从MediaStore里取得,例如我要取所有视频的信息,就必须利用MediaStore.Audio.Media. EXTERNAL _CONTENT_URI这个Uri。

专辑信息要利用MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI这个Uri来查询,其他查询也都类似。

Prjs:这个参数代表要从表中选择的列,用一个String数组来表示。

Selections:相当于SQL语句中的where子句,就是代表你的查询条件。

selectArgs:这个参数是说你的Selections里有?这个符号是,这里可以以实际值代替这个问号。如果Selections这个没有?的话,那么这个String数组可以为null。

Order:说明查询结果按什么来排序。

上面就是各个参数的意义,它返回的查询结果一个Cursor,这个Cursor就相当于数据库查询的中Result,用法和它差不多。

下面的代码是获取SD卡里所有的视频文件信息并返回列表:

getVideoFile(playList, new File("/sdcard/"));

if(android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)){

   Cursor cursor = getContentResolver().query(videoListUri, new String[]{"_display_name","_data"}, null, null, null);

            int n = cursor.getCount();

            cursor.moveToFirst();

            LinkedList<MovieInfo> playList2 = new LinkedList<MovieInfo>();

            for(int i = 0 ; i != n ; ++i){

             MovieInfo mInfo = new MovieInfo();

             mInfo.displayName = cursor.getString(cursor.getColumnIndex("_display_name"));

             mInfo.path = cursor.getString(cursor.getColumnIndex("_data"));

             playList2.add(mInfo);

             cursor.moveToNext();

            }

            if(playList2.size() > playList.size()){

             playList = playList2;

            }

        }

vv.setMySizeChangeLinstener(new MySizeChangeLinstener(){

@Override

public void doMyThings() {

setVideoScale(SCREEN_DEFAULT);

}

         });

        bn1.setAlpha(0xBB);

        bn2.setAlpha(0xBB);  

        bn3.setAlpha(0xBB);

        bn4.setAlpha(0xBB);

        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVIC);

        maxVolume= mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);

        currentVolume= mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);

        bn5.setAlpha(findAlphaFromSound());

4.4视频文件扫描

视频的文件扫描主要有两种方法:

第一种就是直接读取媒体库中的视频文件数据库。当Android启动的时候,系统会自动扫描sdcard,并为媒体文件建立(或者更新)数据库。我们可以通过对应的uRI来访问数据库,从而得到视频文件的列表,这种方法比较高效。具体代码上面介绍时已经提到。

第二种就是最基本的扫描文件系统的方法来扫描视频文件,就是文件系统的遍历:

      private void getVideoFile(final LinkedList<MovieInfo> list,File file){      

       file.listFiles(new FileFilter(){

       @Override

        public boolean accept(File file) {

           String name = file.getName();

           int i = name.indexOf('.');

             if(i != -1){

                  name=name.substring(i);                if(name.equalsIgnoreCase(".mp4")||name.equalsIgnoreCase(".3gp")){                     

                MovieInfo mi = new MovieInfo();

                     mi.displayName = file.getName();

                     mi.path = file.getAbsolutePath();

                      list.add(mi);

                      return true; }

              }else if(file.isDirectory()){

                  getVideoFile(list, file); }

            return false;

          }       }); }

使用这种方法的好处是,以后随着Android平台下的硬件设备越来越多,越来越强大。我们可以想象,它以后将不仅仅支持MP4和3GP格式的视频我呢件,所以我们必须使用两种方式结合的方法来获得最大的视频集合来作为我们的视频列表。

本程序中不需要手动添加播放列表而是程序自动生成,启动程序时有自动判断功能,调用

  for(int i = 0 ; i != n ; ++i){

             MovieInfo mInfo = new MovieInfo();

             mInfo.displayName = cursor.getString(cursor.getColumnIndex("_display_name"));

             mInfo.path = cursor.getString(cursor.getColumnIndex("_data"));

             playList2.add(mInfo);

             cursor.moveToNext();

4.5 AndroidManifest.xml的配置

Android系统的任何一个程序启动都需要AndroidManifest.xml启动程序,任何一个新建的工程目录都会自动生产一个AndroidManifest.xml文件,此配置文件是整个程序能够正常运行的核心,它里面包含了Android SDK版本,程序运行默认的Activity,当程序中的任何一个组件触发事件后,系统都会自动的去AndroidManifest.xml中去寻找标识来做出相应的操作。任何一个AndroidManifest.xml文件的格式都应为:

<?xmlversion="1.0"encoding="utf-8"?>

<manifest>

    <application>

       <activity>

           <intent-filter>

               <action/>

               <category/>

           </intent-filter>

      </activity>

       <activity-alias>

           <intent-filter></intent-filter>

           <meta-data/>

      </activity-alias>

       <service>

           <intent-filter></intent-filter>

           <meta-data/>

       </service>

       <receiver>

           <intent-filter></intent-filter>

           <meta-data/>

       </receiver>

       <provider>

           <grant-uri-permission/>

           <meta-data/>

       </provider>

       <uses-library/>

    </application>

    <uses-permission/>

    <permission/>

    <permission-tree/>

    <permission-group/>

    <instrumentation/>

    <uses-sdk/>

    <uses-configuration/>

    <uses-feature/>

<supports-screens/>

</manifest>

Android系统有一个编码的规定,支持的编码是“utf-8”,当程序中出现乱码时,我们须将其编码格式转换为“utf-8”。在AndroidManifest.xml中会在第一行声明一句:<?xml version="1.0" encoding="utf-8"?>它是该系统支持的版本和编码。在第二行定义了我们需要使用的架构,该架构来自xmlns: <manifest xmlns:android="http://schemas.android.com/apk/res/android".  Xmlns(XML namespace)是一个命名空间它让我们能够找到系统架构,每个配置文件必须有这个xmls,否则程序中使用的所有资源将无法找到。

在application元素我们定了android:icon="@drawable/icon"android:label="@string/app_name">,android:icon是程序在手机中显示的图片,我们运用@drawable/icon表示了对res/drawable目录下的icon.png的引用。@string/app_name表示了对res/value目录下string.xml中定义的app_name参数的引用。

  <activity android:name=".VideoPlayerActivity"  

                  android:label="@string/app_name"

                  android:configChanges="keyboardHidden|orientation"

                  android:theme="@android:style/Theme.NoTitleBar">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

上面的几行代码的意思是系统确定的首先要启动的Activity是VideoPlayerActivity

在intent-filter选项中,有action和category等等属性,我们需要定义action的值为android.intent.action.MAIN,category的值为android.intent.category.LAUNCHER。它们都是系统的值,程序通过解析这些场后属性后,就可以去确定首先要启动的Activity。当我们通过一个组件触发另一个组件时,我们将设定action和category的其他属性值,系统会根据我们设定的属性值去AndroidManifest.Xml的application中寻找标识,任何一个Activity的action和category是唯一的,所以程序的任何时候都能唯一启动一个Activity,这样不同的Activity之间的相互跳转就可以实现了。

在AndroidManifest.Xml中有一个根节点<uses-sdk>,它是我们需要设定的ADT版本,例如我们将其值设定为

<uses-sdk android:minSdkVersion="3"

            android:targetSdkVersion="7"

            android:maxSdkVersion="7" />

则表示我们所用的工程版本为7,程序最高支持7 ,最低支持3.意思是程序能运行在Android1.5,1.6,1.7,2.0,2.1这几个版本之上。

  如果我们需要对网络进行访问,比如打开一个网页,我们还需要设置一个网络访问权限use-permission,将其的值设定为uses-permission android:name="android.permission.INTERNET" />,这样我们就获得了访问网络的权限了,当然,use-permission还有许多其它的权限,例如GPS定位权限,浏览器数据存取权限等等。。

  当程序的任何一个组件要用到时,都必须在AndroidManifest.Xml文件中声明。四大组件要使用前都需要声明,其声明方式如下:

<service></service>

            <provider></provider>

            <activity></activity>

            <receiver></receiver>

其中声明provider时还需要声明其授权authrities.每个组件里面还有很多的属性,应该根据程序的具体使用需求来定义不同的属性。

  过滤器intent-filter有两种启动方式来启动界面:

     1    显示方式

           显示方式是在代码中的直接启动组件,启动时会声明Intent,在他的构造方法Intent(组件1,组件2)中直接指定一个组件的名字,然后调用方法startIntent(intent)以启动指定的组件。

      2    隐式方式

            隐式方式是通过过滤器来过滤完成的,启动的组件必须满足action和category的条件才能够启动该组件。这些属性是在AndroidManifest.Xml文件中声明的。两种启动方式都可以通过程序setAction(ACTION常量)和startActivity(intent)或配置文件两种方式来实现组件的跳转。

4.6使用说明

图4.6 about界面

 在about.xml中采用线性布局内嵌textview,设计了一个简单的使用说明。

5.个人总结

通过对Android手机平台的多媒体播放器软件的开发,使我对Android多媒体播放器系统的整体设计有一个深入的了解,对整个流程也会有一个清晰的认识。开发Android音乐播放器,要抓住开发的核心部分,多媒体播放器大体由播放主界面、播放列表、菜单、播放设置、以及个性化功能五大核心组成,只要掌握了这五部分的开发,播放器就能初具规模。而其它的功能都是在这五个功能的基础上去补充添加的,但是这是功能的确是必不可少的功能,否则就不能算是多媒体播放器了。

多媒体播放器系统实现了播放器的基本功能:播放,暂停、停止、上/下一首、第一首、最后一首、音量调节、屏显切换等功能。运用的系统平台是现今最热门的Android系统,是一个开源的基于Linux系统的手机平台。是以Java语言编写+SQLite数据库支持+SharePreference配置文件的组合方式进行数据管理。实现了多媒体播放器的系统编程。

本次程序设计,采用主要开发工具是Eclipse3.7+Java语言的支持,Android Development Tool的插件,和Android SDK_r17版本的全面结合,同时参考了许多资料,特别是上相关论坛扒资料,看教程。

总之,经过几个月的Android系统技术知识的学习和对播放器的构思与设计,使我对Android系统有了一定的了解,也非常感兴趣,让我对Android系统上的开发流程和开发模式有了深入的了解,这对我以后的Android项目开发有很大的帮助。相信在以后Android项目开发的实践中可以慢慢充实自己,创造更高的个人价值。

                      

参考文献

[1] 李佐彬. Android开发入门与实战体验 [M]. 北京:机械工业出版社,2011:10—28.

[2] 张孝祥. java就业培训教程 [M].北京:清华大学出版社,2007.

[3] 余志龙. Google Android SDK开发范例大全 [M]. 北京:人民邮电出版社,2009.

[4] 张基温. 新概念Java教程 [M]. 北京:中国电力出版社,2010.

[5] 李刚. 疯狂Android讲义 [M]. 北京:电子工业出版社,2011.

  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

等天晴i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值