OpenCore为Android用户提供了强大的多媒体开发运用功能,为了简化音频、视频系统的开发和播放,Android提供了一个综合的的MediaPlayer以简化对多媒体的操作。
Android提供了MediaPlayer类来完成对多媒体的播放。通过MediaPlayer类我们可以播放应用程序实现对应用程序资源文件、本地文件、内容提供器或者通过URL获得的流媒体。
MediaPlayer对音频视频播放的流程是用一个状态机来处理的:
![adfgasdg.png adfgasdg.png](http://www.devdiv.com/data/attachment/forum/201207/18/144253elpau66hjkxqpcoe.png)
图13-2 MediaPlayer状态机图
其状态基本转换可以归纳如下:
1、初始化分配播放时所需资源
2、准备播放
3、开始播放
4、暂停播放
5、停止播放
6、播放结束,释放资源
以上状态机图出自android官方的文档,网址如下:http://developer.android.com/reference/android/media/MediaPlayer.html
一、初始化和准备播放
初始化时调用MediaPlayer的Create静态方法,可以有四种方法设置音频的数据源。
1)资源描述符
通过将音频文件添加到资源结构中的res/raw文件夹中。
1 | MediaPlayer player = MediaPlayer.create(getApplicationContext(), R.raw.music); |
2)以file://开头的本地文件URI
1 | MediaPlayer player = MediaPlayer.create(getApplicationContext(), Uri.parse(“file: |
3)以URL为地址的网络文件URI
3 | <p></p><p align= "\"left\"" ></p> |
1 | MediaPlayer player = MediaPlayer.create(getApplicationContext(), Settings.System.DEFAULT_RINGTONE_URI); |
也有另一种初始化方式,使用MediaPlayer的setDataSource成员方法。注意,当调用此方法作为初化方式时,在调用setDataSource之后,应当调用prepare()成员方法。代码如下:
1 | MediaPlayer player = new MediaPlayer(); |
2 | player.setDataSource(“/sdcard/test.3gp”); |
注意:
1、在不合适的状态下调用prepare()和prepareAsync()方法会抛出IllegalStateException异常。
2、当MediaPlayer对象处于Prepared状态的时候,可以调整音频/视频的属性,如音量,播放时是否一直亮屏,循环播放等。
二、播放控制
准备好MediaPlayer后,想要开始播放,必须调用start()方法。当此方法成功返回时,MediaPlayer的对象处于Started状态。
isPlaying()方法可以被调用来测试某个MediaPlayer对象是否在Started状态。而对一个已经处于Started 状态的MediaPlayer对象调用start()方法没有影响。
调用pause()方法并返回时, 播放可以被暂停会使MediaPlayer对象进入Paused状态。调用start()方法会让一个处于Paused状态的MediaPlayer对象从之前暂停的地方恢复播放。当调用start()方法返回的时候,MediaPlayer对象的状态会又变成Started状态。
注意:Started与Paused状态的相互转换在内部的播放引擎中是异步的。所以可能需要一点时间在isPlaying()方法中更新状态,若在播放流内容,这段时间可能会有几秒钟。
调用stop()方法会停止播放,并且还会让一个处于Started,Paused,Prepared或PlaybackCompleted状态的MediaPlayer进入Stopped状态。
调用seekTo()方法可以调整播放的位置。seekTo(int)方法是异步执行的,所以它可以马上返回,但是实际的定位播放操作可能需要一段时间才能完成,尤其是播放流形式的音频/视频。
当实际的定位播放操作完成之后,内部的播放引擎会调用客户端程序员提供的OnSeekComplete.onSeekComplete()回调方法。可以通过setOnSeekCompleteListener(OnSeekCompleteListener)方法注册。
注意:seekTo(int)方法也可以在其它状态下调用,比如Prepared,Paused和PlaybackCompleted状态。此外,目前的播放位置,实际可以调用getCurrentPosition()方法得到,它可以帮助如音乐播放器的应用程序不断更新播放进度。
01 | private void startPlay() { |
04 | private void stopPlay() { |
07 | private void pausePlay() { |
10 | private void goTo( int pos) { |
三、释放播放资源
当播放到流的末尾,播放就完成了。如果调用了setLooping(boolean)方法开启了循环模式,那么这个MediaPlayer对象会重新进入Started状态。
在播放结束时,应调用MediaPlayer的release()方法,释放播放程序所占用的资源。代码如下:
1 | private void release() { |
四、视频播放
视频播放与音频播放在MediaPlayer中基本相同,但与音频不同的是,视频播放必须考虑到MediaPlayer的视频的显示方法。下面简要描述了两种可以用于视频播放显示的方法。
1) 使用VideoView播放显示视频
由于VideoView继承了SurfaceView,并且实现了MediaController.MediaPlayerControl。使得VideoView控件包含了一个视频显示的界面,该界面可以管理MediaPlayer以控制视频的播放,同样的,VideoView也支持对MediaPlayer组件所支持的本地文件或者流式文件播放。
下面以一个简单的VideoView的Demo简单介绍一下VideoView的使用。
布局文件activity_main.xml的内容如下:
03 | android:layout_width = "fill_parent" |
04 | android:layout_height = "fill_parent" > |
05 | < VideoView android:id = "@+id/mvideoview" |
06 | android:layout_width = "fill_parent" |
07 | android:layout_height = "wrap_content" |
MainActivity.java文件的内容如下:
01 | package com.example.videoviewdemo; |
03 | import android.os.Bundle; |
04 | import android.app.Activity; |
05 | import android.view.Menu; |
06 | import android.view.MenuItem; |
07 | import android.widget.MediaController; |
08 | import android.widget.Toast; |
09 | import android.widget.VideoView; |
10 | import android.support.v4.app.NavUtils; |
12 | public class MainActivity extends Activity { |
14 | private String path = "" ; |
15 | private VideoView mVideoView; |
18 | public void onCreate(Bundle savedInstanceState) { |
19 | super .onCreate(savedInstanceState); |
20 | setContentView(R.layout.activity_main); |
22 | path = "/sdcard/abc.3gp" ; |
24 | mVideoView = (VideoView) findViewById(R.id.mvideoview); |
27 | Toast.makeText( this , "Please set the path of your video" , Toast.LENGTH_SHORT).show(); |
29 | mVideoView.setVideoPath(path); |
30 | mVideoView.setMediaController( new MediaController( this )); |
31 | mVideoView.requestFocus(); |
这个Demo内容非常简单,不再做具体分析了。在调试时,本人采用的是真机调试,需要把abc.3gp文件放在SD卡的根目录下。
运行效果如下图所示:
![豌豆荚截图20120718122120.png 豌豆荚截图20120718122120.png](http://www.devdiv.com/data/attachment/forum/201207/18/144254flk6avzposklcpd6.png)
图13-3 Demo运行效果图
2) 使用SurfaceHolder播放显示视频
虽然VideoView可以很容易地播放视频,但播放位置和播放大小并不受控制,因此,需要用SurfaceView来播放视频。
想要使用MediaPlayer播放视频,需要使用SurfaceView控件。对于显示视频内容则需要调用MediaPlayer的setDisplay()方法分配一个SurfaceHolder对象,否则,视频将不会显示。
下面以一个Demo简单演示一下通过SurfaceView播放视频文件。
activity_main.xml布局文件内容如下:
02 | android:orientation = "vertical" |
03 | android:layout_width = "fill_parent" |
04 | android:layout_height = "fill_parent" > |
06 | android:layout_width = "fill_parent" |
07 | android:layout_height = "wrap_content" |
08 | android:text = "@string/app_name" |
10 | android:gravity = "center_horizontal" /> |
11 | < com.example.surfaceviewdemo.VideoSurfaceView |
12 | android:layout_width = "320px" |
13 | android:layout_height = "240px" |
14 | android:layout_gravity = "center" /> |
VideoSurfaceView.java文件的内容如下:
001 | package com.example.surfaceviewdemo; |
003 | import java.io.IOException; |
005 | import android.content.Context; |
006 | import android.media.AudioManager; |
007 | import android.media.MediaPlayer; |
008 | import android.media.MediaPlayer.OnCompletionListener; |
009 | import android.media.MediaPlayer.OnPreparedListener; |
010 | import android.util.AttributeSet; |
011 | import android.util.Log; |
012 | import android.view.SurfaceHolder; |
013 | import android.view.SurfaceHolder.Callback; |
014 | import android.view.SurfaceView; |
016 | public class VideoSurfaceView extends SurfaceView implements Callback, |
017 | OnPreparedListener, OnCompletionListener { |
020 | private MediaPlayer videoPlayer = null ; |
022 | public VideoSurfaceView(Context context, AttributeSet attrs) { |
023 | super (context, attrs); |
025 | this .getHolder().addCallback( this ); |
026 | this .getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); |
031 | private void initVideoPlayer() throws IllegalArgumentException, IllegalStateException, IOException { |
033 | videoPlayer = new MediaPlayer(); |
035 | videoPlayer.setDataSource( "/sdcard/def.3gp" ); |
036 | videoPlayer.setDisplay( this .getHolder() ); |
037 | videoPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); |
040 | videoPlayer.setVolume( 80 , 100 ); |
042 | videoPlayer.setOnPreparedListener( this ); |
044 | videoPlayer.setOnCompletionListener( this ); |
045 | videoPlayer.prepare(); |
047 | Log.d( this .getClass().getSimpleName(), |
048 | "Width=" +videoPlayer.getVideoWidth()+ |
049 | ", height=" +videoPlayer.getVideoHeight() ); |
054 | public void onCompletion(MediaPlayer mp) { |
056 | if (videoPlayer != null ) { |
058 | videoPlayer.release(); |
065 | public void onPrepared(MediaPlayer mp) { |
067 | if (videoPlayer != null ) { |
073 | public void surfaceChanged(SurfaceHolder holder, int format, int width, |
081 | public void surfaceCreated(SurfaceHolder holder) { |
085 | } catch (IllegalArgumentException e) { |
088 | } catch (IllegalStateException e) { |
091 | } catch (IOException e) { |
098 | public void surfaceDestroyed(SurfaceHolder holder) { |
100 | if (videoPlayer != null ) { |
101 | videoPlayer.release(); |
Demo的运行效果如下图所示:
![豌豆荚截图20120718141525.png 豌豆荚截图20120718141525.png](http://www.devdiv.com/data/attachment/forum/201207/18/144254f616t800n3z33xnf.png)
图13-4 Demo运行效果图1
![豌豆荚截图20120718141515.png 豌豆荚截图20120718141515.png](http://www.devdiv.com/data/attachment/forum/201207/18/144254c9w4dt1c9ctb9t9b.png)
图13-5 Demo运行效果图2
五、音频播放
音频播放的操作相对视频播放要简单一些,关于MediaPlayer的使用方法,前文已经做了详细的说明。下面给出两个例子作为参考。
Demo1
该Demo用来播放SD卡上对应路径的音频文件,需要把one.mp3、two.mp3和three.mp3放到SD卡的根目录下。
Demo1的运行效果如下图所示:
![豌豆荚截图20120718142309.png 豌豆荚截图20120718142309.png](http://www.devdiv.com/data/attachment/forum/201207/18/144255kkq3vro56ad66kna.png)
图13-6 Demo运行效果图
分别点击音乐列表中的对应项,会播放不同的歌曲,退出程序,歌曲停止播放。
Demo2
该Demo用来播放res目录下raw文件夹里面的音乐资源,需要把one.mp3放到raw文件夹里面。
初始化的代码如下:
1 | musicMediaPlayer = MediaPlayer.create( this , R.raw.one); |
不需要执行prepare()方法,直接通过start()方法进行播放。如果执行prepare()方法程序会报错。
Demo2运行效果如下图所示:
![豌豆荚截图20120718142319.png 豌豆荚截图20120718142319.png](http://www.devdiv.com/data/attachment/forum/201207/18/144255co8mqo115mosssq4.png)
图13-7 Demo运行效果图