Android多媒体详解

先看一下效果图


1、     MediaPlayer播放音频

2、     SoundPool播放音频

3、     VideoView播放视频

4、     通过Intent意图调用自带视频播放器

5、     MediaPlayerSurfaceView播放视频

1MediaPlayer播放音频

MediaPlayer是用于播放音频视频的,来看一下MediaPlayer类控制音频的常用方法

setDataSource()

设置要播放的音频文件的位置

prepare()

在播放之前调用这个方法完成准备工作

start()

开始或继续播放音频

pause()

暂停播放音频

reset()

将MediaPlayer对象重置到刚刚创建的状态

seekTo()

从指定位置开始播放音频

stop()

停止播放音频

relase()

释放掉与MediaPlayer对象相关的资源

isPlaying()

判断当前MediaPlayer是否正在播放音频

getDurtion()

获取载入的音频文件的时长

接下来看一下MediaPlayer的具体使用步骤:

1、创建MediaPlayer

MediaPlayer mediaPlayer=new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManger.STREAM_MUSIC);//设置声音流的类型

MediaPlayer接收的声音类型有如下几种:

l  AudioManger.STREAM_MUSIC:音乐

l  AudioManger.STREAM_RING:铃声

l  AudioManger.STREAM_ALARM:闹钟

l  AudioManger.STREAM_NOTIFICTION:提示音

2、设置数据源

设置数据源的方式有三种,分别是设置播放应用自带的音频文件、设置播放SD卡中的音频文件、设置播放网络音频文件。具体代码如下:

//播放应用res/raw目录下的自带的音频文件
mediaPlayer.create(this,R.raw.xxx);
//播放SD卡中的音频文件
mediaPlayer.setDataSource(“mnt/sdcard/xxx.mp3”);
//播放网络音频文件
mediaPlayer.setDataSourse(“http://www.xxx.mp3”);

3、播放音乐

播放本地音乐文件与播放网络文件有所不同,当播放本地文件时使用的是prepare();方法通知底层框架准备播放音乐,而准备播放网络音频文件使用prepareAsync()方法。具体代码如下:

//播放本地文件
mediaPlayer.prepare();
mediaPlayer.start();
//播放网络文件
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(newOnPreparedListener() {
                   
                    @Override
                    public void onPrepared(MediaPlayermediaPlayer) {
                             // TODO 自动生成的方法存根
                             mediaPlayer.start();
                    }
           });

注意:当播放网络中的文件时,需要添加网络访问权限

<uses-permission android:name="android.permission.INTERNET"/>


Prepare()与PreoareAsync()的区别:

l  Prepare()是同步操作,在主线程中执行,它会对音频文件进行解码,当prepare()执行完毕之后才会继续向下执行。

l  prepareAsync()是子线程中执行的异步操作,不管它有没有执行完成都不音响主线程的执行操作。但是,如果音频文件没有解码完毕就执行start()方法会播放失败。因此这里这里要监听音频准备好的监听器OnPreparedListener()。当音频解码完成可以播放时会执行OnPreparedListener()中的onPrepared()方法,在该方法中执行播放音乐的操作即可。

2SoundPool播放音频

在游戏开发中经常需要播放一些游戏音效(比如爆炸声、物体撞击声等),这些音效的共同特点就是短促、密集、延迟程度小。在这种情况下可以使用SoundPool代替MediaPlayer来播放这些音效。下面分步骤讲解如何使用SoundPool播放音效:

1、创建SoundPool对象

在创建SoundPool对象时可以使用它的构造方法,该方法有三个参数

SoundPool soundPool=new SoundPool(int maxStreams, int streamType,int srcQuality);


maxStreams:同时播放的流的最大数量。

streamType:流的类型,一般为AudioManger.STREAM_MUSIC:音乐。

srcQuality采样转化率质量,当前无效可以使用0作为默认值。

2、将多个声音添加到Map

创建好SoundPool对象后需要添加音乐文件,音乐文件素材放在res/raw目录下或assets目录下。一般多个声音添加到一个Map中,具体代码如下:

SoundPoolsoundPool=new SoundPool(maxStreams, streamType,srcQuality);
        Map<Integer, Integer> map=new HashMap<Integer, Integer>();
        map.put(0, soundPool.load(this, R.raw.dingdong, 1));
     map.put(1,soundPool.load(this, R.raw.bang, 1));


soundPool.load()方法是为soundPool对象添加音乐文件,其中第三个参数表示文件加载的优先级。

3VideoView播放视频

播放视频文件与播放音频文件类似,只是,视频的播放需要视觉组件将影像显示出来。在Android中主要使用VideoView和SurfaceVIew播放视频,其中VIdeoVIew组件播放视频最为简单,它将视频的显示和控件集于一身,由于VideoView的用法和MediaPlayer类似,其中提供的常用方法就不一一介绍了,其中setVideoPath():设置要播放的视频文件的位置需要知道。

具体步骤如下:

1、  创建VideoView

不同于音乐播放器,视频播放器需要在界面上显示,因此首先要在布局文件中创建VideoView控件

     <VideoView
        android:id="@+id/videoView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />


2、  视频播放

使用VideoView播放视频和音频一样,既可以本地播放,也可以播放网络中的视频,具体代码如下:

VideoViewvideoView=(VideoView) findViewById(R.id.videoView1);
    //播放本地视频
    videoView.setVideoPath("mnt/sdcard/b.avi");
    //加载网络视频
    videoView.setVideoURI("http://www.xxx.avi");
videoView.start();


注意:播放网络视频时需要添加网络访问权限

<uses-permission android:name="android.permission.INTERNET"/>

这里上传一下代码:

import android.app.Activity;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.widget.MediaController;
import android.widget.VideoView;

public class Video extends Activity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.video);
		
		VideoView vv = (VideoView) findViewById(R.id.videoView1);
		
		MediaController mc=new MediaController(this);//设置默认控制器,里面自带暂停,快进,播放
		mc.setBackgroundColor(Color.YELLOW);
		vv.setMediaController(mc);//讲控制器添加到VideoView中去
		
		Uri data=Uri.parse(Environment.getExternalStorageDirectory().getAbsolutePath()+"/auqi.3gp");
		vv.setVideoURI(data);
		
		vv.start();
	}
}


3、  VideoView添加控制器

使用VideoView播放视频时可以为他添加一个控制器或媒体播放器MediaController,它是一个包含媒体播放器(MediaPlayer)控件的视图。它自带播放按钮,如播放、暂停、倒带、快进与进度滑动器

MediaController controller=new MediaController(context);
videoView.setMediaController(controller);//为VideoView绑定控制器

4通过Intent意图调用自带视频播放器

利用Intent只是调用系统自带的视频播放器

Intent intent=new Intent(android.content.Intent.ACTION_VIEW);
			Uri uri=Uri.parse(Environment.getExternalStorageDirectory().getAbsolutePath()+"/auqi.3gp");
			intent.setDataAndType(uri, "video/3gp");//注意这个Type是由文件类型(video)和播放的格式(3gp)所组成
			startActivity(intent);


5MediaPlayerSurfaceView播放视频


当开发者需要根据需求自定义视频播放器的时候,使用VideoVIew就会很麻烦。为此,Android系统中还提供另一种播放视频的方式,就是MediaPlayer和Surface结合使用。MediaPlayer可以播放视频,只不过它在播放视频时没有图像输出注意这句话),因此需要使用SurfaceVIew组件。

SurfaceVIew是继承自View用于显示图像的组件。SurfaceVIew最大的特点就是它的双缓冲技术,所谓的双缓冲就是在它的内部有两个线程,例如A线程和B线程。当线程A更新界面时,线程B进行后台技术操作,当两个线程都完成各自的任务时,它们会互相交换,两个线程就这样无限循环交替更新和计算。由于SurfaceVIew这种特性可以避免画图任务繁重而造成的主线程的阻塞,从而提高了程序的反应速度,因此在游戏开发中多用SurfaceVIew,例如游戏中的背景、人物、动画等

1、创建SurfaceVIew控件

SurfaceVIew是一个控件,使用时需要在布局文件中定义

<SurfaceView
        android:id="@+id/surfaceView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />


2、获取界面显示容器并设置类型

布局创建好之后,在代码中找到控件并得到SurfaceVIew的容器SurfaceHolder

具体代码如下:

SurfaceView view = (SurfaceView)findViewById(R.id.surfaceView1);
        SurfaceHolder holder=view.getHolder();
     holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);


是一个接口类型,就是一个容器,通过SurfaceHolder对象控制SurfaceView的大小和像素格式,监控控件中的内容格式

  在这里添加SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS参数为的是不让SurfaceView自己维护双缓冲区,而是交给MediaPlayer底层去管理。虽然该API已经过时了,但是在Android4.0版本以下的系统中必须添加该参数

注意播放视频是MediaPlayer框架

3SurfaceView添加回调

如果onCreate()方法执行时,SurfaceView还没有完全创建好。这时候播放视频会出现异常,因此,需要添加SurfaceHolder的回调函数CallBack,在SurfaceCreated()方法中执行视频的播放

CallBack接口一共有三个回调方法:

l  surfaceChanged():SurfaceView的大小发生变化
l  surfaceCreated():SurfaceView的holder被创建
l surfaceDestroyed():SurfaceView的holder被销毁


4、创建MediaPlayer并与SurfaceViewholder被创建

MediaPlayer mediaPlayer = new MediaPlayer();
        mediaPlayer.setDataSource("SD卡的路径");
        mediaPlayer.setDisplay(holder);
     mediaPlayer. prepareAsync ();
mediaPlayer.start();


 这里使用mediaPlayer.setDisplay(holder);将播放的视频显示在SurfaceView的容器holder中。并且视频一般很大,因此都需要使用prepareAsync()异步准备

 先看一下代码:

import java.io.IOException;

import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.LinearLayout;

public class ThreeKindsVideoActivity extends Activity implements SurfaceHolder.Callback,OnPreparedListener{
    /** Called when the activity is first created. */
	SurfaceHolder surfaceHolder;
    SurfaceView surfaceView;
	MediaPlayer mediaPlayer;
	Display current;
	int videoHeight;
	int videoWidth;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
		current = getWindowManager().getDefaultDisplay();//获取设备的尺寸  
		SurfaceHolder surfaceHolder = surfaceView.getHolder();// 找到容器SurfaceHolder		
		surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// 创建一个缓冲区,为了看视频不卡顿
		surfaceHolder.addCallback(this);// 添加SurfaceHolder的回调函数,类似于监听,所以需要添加实现接口的方法SurfaceHolder.Callback
    }
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO 自动生成的方法存根
		
	}
	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		// TODO 自动生成的方法存根
		String path = Environment.getExternalStorageDirectory()
				.getAbsolutePath() + "/auqi.3gp";
		@Override
	public void onPrepared(MediaPlayer mp) {
		// TODO 自动生成的方法存根
	/*	// 在播放之前,设置surface的大小与视频尺寸大小匹配
		// 首先获取视频的尺度
		videoHeight = mediaPlayer.getVideoHeight();
		videoWidth = mediaPlayer.getVideoWidth();
		// 如果视频的宽度或高度大于显示器的高度,找一个合理的比例进行缩放
		if (videoHeight > current.getHeight()
				|| videoWidth > current.getWidth()) {
			// 获取视频与显示器的比例
			float heightRatio =(float)videoHeight/(float) current.getHeight();
			float widthRatio = (float) videoWidth / (float) current.getWidth();
			// 我们按较大的尺寸缩放,主要保证视频的尺寸在显示范围内
			if (heightRatio > 1 || widthRatio > 1) {
				if (widthRatio > heightRatio) {
					videoWidth = (int) Math.ceil((float)videoWidth / (float)widthRatio);
					videoHeight = (int) Math.ceil((float)videoHeight / (float)widthRatio);
				}else {
					videoWidth = (int) Math.ceil((float)videoWidth / (float)heightRatio);
					videoHeight = (int) Math.ceil((float)videoHeight / (float)heightRatio);
				}
			}
			
		}//videoWidth,videoHeight是缩放后的尺寸,根据这个尺寸来制作显示Surface的大小
		surfaceView.setLayoutParams(new LinearLayout.LayoutParams(videoWidth, videoHeight));*/
		mediaPlayer.start();
	}
Log.i("mwijfd没撒扩大 萨达萨达", "mwijfd没撒扩大 萨达萨达");
		try {
			mediaPlayer=new MediaPlayer();
			mediaPlayer.setDataSource(path);
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			//finish();// 此次有异常最好finish一下
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Log.i("mwijfd没撒扩大 萨达萨达", "mwijfd没撒扩大 萨达萨达");
		mediaPlayer.setDisplay(surfaceHolder);// 通过容器将SurfaceView与MediaPlayer进行关联
		mediaPlayer.prepareAsync();
		//将播放的视频显示在SurfaceView的容器holder中。并且视频一般很大,因此都需要使用prepareAsync()异步准备
	}
	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		// TODO 自动生成的方法存根
		
	}
       @Override
	public void onPrepared(MediaPlayer mp) {
		// TODO 自动生成的方法存根
	<span style="color:#ff0000;">/*	// 在播放之前,设置surface的大小与视频尺寸大小匹配
		// 首先获取视频的尺度
		videoHeight = mediaPlayer.getVideoHeight();
		videoWidth = mediaPlayer.getVideoWidth();
		// 如果视频的宽度或高度大于显示器的高度,找一个合理的比例进行缩放
		if (videoHeight > current.getHeight()
				|| videoWidth > current.getWidth()) {
			// 获取视频与显示器的比例
			float heightRatio =(float)videoHeight/(float) current.getHeight();
			float widthRatio = (float) videoWidth / (float) current.getWidth();
			// 我们按较大的尺寸缩放,主要保证视频的尺寸在显示范围内
			if (heightRatio > 1 || widthRatio > 1) {
				if (widthRatio > heightRatio) {
					videoWidth = (int) Math.ceil((float)videoWidth / (float)widthRatio);
					videoHeight = (int) Math.ceil((float)videoHeight / (float)widthRatio);
				}else {
					videoWidth = (int) Math.ceil((float)videoWidth / (float)heightRatio);
					videoHeight = (int) Math.ceil((float)videoHeight / (float)heightRatio);
				}
			}
			
		}//videoWidth,videoHeight是缩放后的尺寸,根据这个尺寸来制作显示Surface的大小
		surfaceView.setLayoutParams(new LinearLayout.LayoutParams(videoWidth, videoHeight));*/</span>
		mediaPlayer.start();
	}
}
注意部分onPrepared()中的内容 如果不是正规用途就没必要写,因为这部分是为了调整视频的大小和播放器的大小相匹配而写的代码









猜你喜欢

转载自blog.csdn.net/mxcsdn/article/details/51137031