多媒体应用开发

Android作为手机和平板电脑的一个操作系统,对于多媒体应用也提供了良好的支持。它不仅支持音频和视频的播放,而且还支持 音频录制和摄像头拍照。

播放音频与视频

Android提供了对常用音频和视频格式的支持,它所支持的音频格式有MP3(.mp3)、3GPP(.3gp)、Ogg(.ogg)和WAVE(.ave)等,支持的视频格式有3GPP(.3gp)和MPEG-4(.mp4)等。通过Android API提供的相关方法,在Android中可以实现音频与视频的播放。

使用MediaPlayer播放音频

在Android中,提供了MediaPlayer类来播放音频。使用MediaPlayer类播放音频比较简单,只需要创建该类的对象,并为其指定要播放的音频文件,然后调用该类的start()方法即可

  1. 创建MediaPlayer对象,并装载音频文件
    创建MediaPlayer对象并装载音频文件,可以使用MediaPayer类提供的静态方法create()来实现,也可以通过其无参构造方法来创建并实例化该类的对象来实现。 MediaPlayer类的静态方法create()常用的语法格式有以下两种。

[√]create(Contextcontext, int resid) 用于从资源ID所对应的资源文件中装载音频,并返回新创建的MediaPlayer对象。例如,要创建装载音频资源(res/raw/d.wav)的MediaPlayer对象,可以使用下面的代码:

MediaPlayer player=MediaPlayer.create(this, R.raw.d);

[√]create(Contextcontext, Uri uri)
用于根据指定的URI来装载音频,并返回新创建的MediaPlayer对象。例如,要创建装载了音频文件(URI地址为http://www.baidu.com/sound/bg.mp3)的MediaPlayer对象,可以使用下面的代码:

MediaPlayer player=MediaPlayer.create(this, Uri.parse("http://www.baidu.com/sound/bg.mp3"));

说明:在访问网络中的资源时,要在AndroidManifest.xml文件中授予该程序访问网络的权限,具体的授权代码如下:

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

在通过MediaPlayer类的静态方法create()来创建MediaPlayer对象时,已经装载了要播放的音频,而使用无参的构造方法来创建MediaPlayer对象时,需要单独指定要装载的资源,这可以使用 MediaPlayer类的setDataSource()方法实现。

在使用setDataSource()方法装载音频文件后,实际上MediaPlayer并未真正装载该音频文件,还需要调用MediaPlayer的prepare()方法去真正装载音频文件。使用无参的构造方法来创建MediaPlayer 对象并装载指定的音频文件,可以使用下面的代码:

MediaPlayer player=new MediaPlayer(); 
try {
	player.setDataSource("/sdcard/s.wav"); //指定要装的音频文件 
} catch (IllegalArgumentException e1) { 
	e1.printStackTrace(); 
} catch (SecurityException e1) { 
	e1.printStackTrace(); 
} catch (IllegalStateException e1) { 
	e1.printStackTrace(); 
} catch (IOException e1) { 
	e1.printStackTrace(); 
}
	
try { 
	player.prepare(); //预加载音频
} catch (IllegalStateException e) { 
	e.printStackTrace(); 
} catch (IOException e) { 
	e.printStackTrace(); 
}
  1. 开始或恢复播放

在获取到MediaPlayer对象后,就可以使用MediaPlayer类提供的start()方法来开始播放或恢复已经暂停的音频的播放。例如,已经创建了一个名称为player的对象,并且装载了要播放的音频,可 以使用下面的代码播放该音频:

player.start(); //开始播放
  1. 停止播放
    使用MediaPlayer类提供的stop()方法可以停止正在播放的音频。例如,已经创建了一个名称为player的对象,并且已经开始播放装载的音频,可以使用下面的代码停止播放该音频:
player.stop(); //停止播放
  1. 暂停播放
    使用MediaPlayer类提供的pause()方法可以暂停正在播放的音频。例如,已经创建了一个名称为player的对象,并且已经开始播放装载的音频,可以使用下面的代码暂停播放该音频:
player.pause(); //暂停播放

使用SoundPool播放音频

由于MediaPlayer占用资源较多,且不支持同时播放多个音频,所以Android还提供了另一个播放音频的类——SoundPool。SoundPool即音频池,可以同时播放多个短小的音频,而且占用的资源 较少。SoundPool适合在应用程序中播放按键音或者消息提示音等,在游戏中播放密集而短暂的声音,如多个飞机的爆炸声等。使用SoundPool播放音频,首先需要创建SoundPool对象,然后加载所 要播放的音频,最后调用play()方法播放音频,下面进行详细介绍。

  1. 创建SoundPool对象
    SoundPool类提供了一个构造方法,用来创建SoundPool对象,该构造方法的语法格式如下:
SoundPool (int maxStreams, int streamType, int srcQuality)

中,参数maxStreams用于指定可以容纳多少个音频;参数streamType用于指定声音类型,可以通过AudioManager类提供的常量进行指定,通常使用STREAM_MUSIC;参数srcQuality用于指定音 频的品质,默认值为0。

例如,创建一个可以容纳10个

SoundPool soundpool = new SoundPool(10, AudioManager.STREAM_SYSTEM, 0); //创建一个SoundPool对象,该对象可以容纳10个音频流
  1. 加载所要播放的的音频

创建SoundPool对象后,可以调用load()方法来加载要播放的音频。load()方法的语法格式有以下4种。
[√]publicint load (Contextcontext, int resId, int priority):用于通过指定的资源ID来加载音频。
[√]publicint load (String path, int priority):用于通过音频文件的路径来加载音频。
[√]publicint load (AssetFileDescriptorafd, int priority):用于从AssetFileDescriptor所对应的文件中加载音频。
[√]publicint load (FileDescriptor fd, long offset, long length, int priority):用于加载FileDescriptor对象中从offset开始,长度为length的音频。

例如,要通过资源ID来加载音频文件ding.wav,可以使用下面的代码:

soundpool.load(this, R.raw.ding , 1);

说明: 为了更好地管理所加载的每个音频,一般使用HashMap<Integer, Integer>对象来管理这些音频。这时可以先创建一个HashMap<Integer, Integer>对象,然后应用该对象的put()方法将加载的音 频保存到该对象中。例如,创建一个HashMap<Integer, Integer>对象,并应用put()方法添加一个音频,可以使用下面的代码:

HashMap<Integer, Integer> soundmap = new HashMap<Integer, Integer>(); //创建一个HashMap对象 
soundmap.put(1, soundpool.load(this, R.raw.chimes, 1));
  1. 播放音频
    调用SoundPool对象的play()方法可播放指定的音频。play()方法的语法格式如下:
play (int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)

play()方法各参数的说明

参数 描述
soundID 用于指定要播放的音频,该音频为通过load()方法返回的音频
leftVolume 用于指定左声道的音量,取值范例为0.0~1.0
rightVolume 用于指定右声道的音量,取值范例为0.0~1.0
priority 用于指定播放音频的优先级,数值越大,优先级越高
loop 用于指定循环次数,0为不循环,-1为循环
rate 用于指定速率,正常为1,最低为0.5,最高为2

使用VideoView播放视频

在Android中,提供了VideoView组件用于播放视频文件。要想使用VideoView组件播放视频,首先需要在布局文件中创建该组件,然后在Activity中获取该组件,并应用其setVideoPath()方法或 setVideoURI()方法加载要播放的视频,最后调用start()方法来播放视频。另外,VideoView组件还提供了stop()和pause()方法,用于停止或暂停视频的播放。

在布局文件中创建VideoView组件的基本语法格式如下:

<VideoView 属性列表> </VideoView>

VideoView组件支持的XML属性
XML属性 描述
android:id 用于设置组件的ID
android:background 用于设置背景,可以设置背景图片,也可以设置背景颜色
android:layout_gravity 用于设置对齐方式
android:layout_width 用于设置宽度
android:layout_height 用于设置高度

在Android中还提供了一个可以与VideoView组件结合使用的MediaController组件。MediaController组件用于通过图形控制界面来控制视频的播放。

下面通过一个具体的实例来说明如何使用VideoView和MediaController来播放视频。

<VideoView android:id="@+id/video" 
	android:background="@drawable/mpbackground" 
	android:layout_width="match_parent" 
	android:layout_height="wrap_content" 
	android:layout_gravity="center" />

(2)打开默认添加的MainActivity,在该类中,声明一个VideoView对象,具体代码如下:

private VideoView video; //声明VideoView对象

(3)在onCreate()方法中,首先获取布局管理器中添加的VideoView组件,并创建一个要播放视频所对应的File对象,然后创建一个MediaController对象,用于控制视频的播放,最后判断要播放的 视频文件是否存在,如果存在,使用VideoView播放该视频,否则弹出消息提示框显示提示信息,具体代码如下:

video=(VideoView) findViewById(R.id.video); //获取VideoView组件 
File file=new File("/sdcard/bell.mp4"); //获取SD卡上要播放的文件 
MediaController mc=new MediaController(MainActivity.this); 
if(file.exists()){ //判断要播放的视频文件是否存在 
	video.setVideoPath(file.getAbsolutePath()); //指定要播放的视频 
	video.setMediaController(mc); //设置VideoView与MediaController相关联 
	video.requestFocus(); //让VideoView获得焦点 
	
	try {
		video.start(); //开始播放视频 
	} catch (Exception e) { 
		e.printStackTrace(); //输出异常信息 
	}
	
	//为VideoView添加完成事件监听器 
	video.setOnCompletionListener(new OnCompletionListener() { 
		@Override
		public void onCompletion(MediaPlayer mp) { 
			//弹出消息提示框显示播放完毕 
			Toast.makeText(MainActivity.this, "视频播放完毕!", Toast.LENGTH_SHORT).show(); 
		} 
	}); 
}else{ 
	//弹出消息提示框提示文件不存在 
	Toast.makeText(this, "要播放的视频文件不存在", Toast.LENGTH_SHORT).show(); 
}

说明:由于本实例是在模拟器上运行的,所以并没有显示视频画面,而在屏幕中间显示的图片是为VideoView设置的背景图片。如果将该程序发布到真机上运行,就可以看到视频画面了。

使用MediaPlayer和SurfaceView播放视频

使用MediaPlayer除可以播放音频外,还可以播放视频文件,只不过使用MediaPlayer播放视频时,没有提供图像输出界面。这时,可以使用SurfaceView组件来显示视频图像。使用MediaPlayer和 SurfaceView来播放视频,大致可以分为以下4个步骤。

(1)定义SurfaceView组件。定义SurfaceView组件可以在布局管理器中实现,也可以直接在Java代码中创建,不过推荐在布局管理器中定义SurfaceView组件,其基本语法格式如下:

<SurfaceView android:id="@+id/ID号"
	android:background="背景" 
	android:keepScreenOn="true|false" 
	android:layout_width="宽度" 
	android:layout_height="高度"/>

在上面的语法中,android:keepScreenOn属性用于指定在播放视频时,是否打开屏幕。

例如,在布局管理器中,添加一个ID号为surfaceView1、设置了背景的SurfaceView组件,可以使用下面的代码:

<SurfaceView android:id="@+id/surfaceView1" 
	android:background="@drawable/bg" 
	android:keepScreenOn="true" 
	android:layout_width="576px" 
	android:layout_height="432px"/>

(2)创建MediaPlayer对象,并为其加载要播放的视频。与播放音频时创建MediaPlayer对象一样,也可以使用MediaPlayer类的静态方法create()和无参的构造方法两种方式创建MediaPlayer对象。

(3)将所播放的视频画面输出到SurfaceView。使用MediaPlayer对象的setDisplay()方法,可以将所播放的视频画面输出到SurfaceView。setDisplay()方法的语法格式如下:

setDisplay(SurfaceHolder sh)

参数sh用于指定SurfaceHolder对象,可以通过SurfaceView对象的getHolder()方法获得。例如,为MediaPlayer对象指定输出视频画面的SurfaceView,可以使用下面的代码:

mediaplayer.setDisplay(surfaceview.getHolder()); //设置将视频画面输出到SurfaceView

(4)调用MediaPlayer对象的相应方法控制视频的播放。使用MediaPlayer对象提供的play()、pause()和stop()方法,可以控制视频的播放、暂停和停止。

控制相机拍照

现在的手机和平板电脑一般都会提供相机功能,而且相机功能的应用越来越广泛。在Android中提供了专门用于处理相机相关事件的类,即android.hardware包中的Camera类。Camera类没有构造 方法,可以通过其提供的open()方法打开相机。打开相机后,可以通过Camera.Parameters类处理相机的拍照参数。拍照参数设置完成后,可以调用startPreview()方法预览拍照画面,也可以调用 takePicture()方法进行拍照。结束程序时,可以调用Camera类的stopPreview()方法结束预览,并调用release()方法释放相机资源。Camera类常用的方法如表所示。

方法 描述
getParameters() 用于获取相机参数
Camera.open() 用于打开相机
release() 用于释放相机资源
setParameters(Camera.Parameters params) 用于设置相机的拍照参数
setPreviewDisplay(SurfaceHolder holder) 用于为相机指定一个用来显示相机预览画面的SurfaceView
startPreview() 用于开始预览画面
takePicture(Camera.ShutterCallback shutter, Camera.PictureCallback raw, Camera.PictureCallback jpeg) 用于进行拍照
stopPreview() 用于停止预览

实现控制相机拍照功能。
(1)新建项目的res\layout目录下的布局文件main35.xml,将默认添加的TextView组件删除,并将默认添加的垂直线性布局管理器修改为水平线性布局管理器,然后在该布局管理器中添加一个 垂直线性布局管理器(用于放置控制按钮)和一个SurfaceView组件(用于显示相机预览画面),再在这个垂直线性布局管理器中添加两个按钮:一个是“预览”按钮,id为preview;另一个是“拍照”按 钮,id为takephoto。关键代码如下:

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

(2)打开默认添加的MainActivity,在该类中,声明程序中所需的成员变量,具体代码如下:

private Camera camera; //相机对象 
private boolean isPreview = false; //是否为预览模式

(3)设置程序为全屏运行。这里需要将下面的代码添加到onCreate()方法中默认添加的setContentView(R.layout.main35);语句之前,否则不能应用全屏的效果。

requestWindowFeature(Window.FEATURE_NO_TITLE); //设置全屏显示

(4)在onCreate()方法中,首先判断是否安装SD卡,因为拍摄的图片需要保存到SD卡上,然后获取用于显示相机预览画面的SurfaceView组件,最后通过SurfaceView对象获取SurfaceHolder对象, 并设置该SurfaceHolder不维护缓冲,具体代码如下:

/****************** 判断是否安装SD卡 *********************************/ 
if (!android.os.Environment.getExternalStorageState().equals( android.os.Environment.MEDIA_MOUNTED)) { 
	Toast.makeText(this, "请安装SD卡!", Toast.LENGTH_SHORT).show(); //弹出消息提示框显示提示信息
}
/******************************************************************/ 
SurfaceView sv = (SurfaceView) findViewById(R.id.surfaceView1); //获取SurfaceView组件,用于显示相机预览 
final SurfaceHolder sh = sv.getHolder(); //获取SurfaceHolder对象 
sh.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); //设置该SurfaceHolder不维护缓冲

(5)获取布局管理器中添加的“预览”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,首先判断相机是否为预览模式,如果不是,则打开相机,然后为相机设置显示预览画面的 SurfaceView,并设置相机参数,最后开始预览并设置自动对焦,具体代码如下:

Button preview = (Button) findViewById(R.id.preview); //获取“预览”按钮 
preview.setOnClickListener(new View.OnClickListener() { 
	@Override 
	public void onClick(View v) { 
		//如果相机为非预览模式,则打开相机 
		if (!isPreview) { 
			camera=Camera.open(); //打开相机 
		}
		
		try {
			camera.setPreviewDisplay(sh); //设置用于显示预览的SurfaceView 
			Camera.Parameters parameters = camera.getParameters(); //获取相机参数 
			parameters.setPictureSize(640, 480); //设置预览画面的尺寸 
			parameters.setPictureFormat(PixelFormat.JPEG); //指定图片为JPEG格式 
			parameters.set("jpeg-quality", 80); //设置图片的质量 
			parameters.setPictureSize(640, 480); //设置拍摄图片的尺寸 
			camera.setParameters(parameters); //重新设置相机参数 
			camera.startPreview(); //开始预览 
			camera.autoFocus(null); //设置自动对焦 
		} catch (IOException e) { 
			e.printStackTrace(); 
		} 
	} 
});

(6)获取布局管理器中添加的“拍照”按钮,并为其设置单击事件监听器,在重写的onClick()方法中,如果相机对象不为空,则调用takePicture()方法进行拍照,具体代码如下:

Button takePhoto = (Button) findViewById(R.id.takephoto); //获取“拍照”按钮 
takePhoto.setOnClickListener(new View.OnClickListener() { 
	@Override 
	public void onClick(View v) { 
		if(camera!=null){ 
			camera.takePicture(null, null, jpeg); //进行拍照 
		} 
	} 
});

(7)实现拍照的回调接口,在重写的onPictureTaken()方法中,首先根据拍照所得的数据创建位图,然后实现一个带“保存”和“取消”按钮的对话框,用于保存所拍图片,具体代码如下:

final PictureCallback jpeg = new PictureCallback() { 
	@Override 
	public void onPictureTaken(byte[] data, Camera camera) { 
		//根据拍照所得的数据创建位图 
		final Bitmap bm = BitmapFactory.decodeByteArray(data, 0,data.length);
		//加载layout/save.xml文件对应的布局资源 、
		View saveView = getLayoutInflater().inflate(R.layout.save, null); 
		final EditText photoName = (EditText) saveView.findViewById(R.id.phone_name); 
		//获取对话框上的ImageView组件 
		ImageView show = (ImageView) saveView.findViewById(R.id.show); 
		show.setImageBitmap(bm); //显示刚刚拍得的照片 
		camera.stopPreview(); //停止预览 
		isPreview = false; //使用对话框显示saveDialog组件 
		
		new AlertDialog.Builder(MainActivity.this).setView(saveView) 
			.setPositiveButton("保存", new DialogInterface.OnClickListener() { 
				@Override 
				public void onClick(DialogInterface dialog, int which) { 
					File file = new File("/sdcard/pictures/" + photoName .getText().toString() + ".jpg"); //创建文件对象 
					
					try { 
						file.createNewFile(); //创建一个新文件 //创建一个文件输出流对象 
						FileOutputStream fileOS = new FileOutputStream(file); //将图片内容压缩为JPEG格式输出到输出流对象中 bm.compress(Bitmap.CompressFormat.JPEG, 100, fileOS); 
						fileOS.flush(); //将缓冲区中的数据全部写出到输出流中 
						fileOS.close(); //关闭文件输出流对象 
						isPreview = true; 
						resetCamera(); 
					} catch (IOException e) { 
						e.printStackTrace(); 
					} 
				} 
			}).setNegativeButton("取消", new DialogInterface.OnClickListener() { 
				public void onClick(DialogInterface dialog, int which) { 
					isPreview = true; resetCamera(); //重新预览 
				} 
			}).show(); 
		} 
	};

(8)编写保存对话框所需要的布局文件,名称为save.xml,在该文件中,添加一个垂直线性布局管理器,并在该布局管理器中添加一个水平线性布局管理器(用于添加输入相片名称的文本框和 编辑框)和一个ImageView组件(用于显示相片预览),具体代码请参见光盘。

(9)编写实现重新预览的方法resetCamera(),在该方法中,当isPreview变量的值为真时,调用相机的startPreview()方法开启预览,具体代码如下:

private void resetCamera(){ 
	if(isPreview){ 
		camera.startPreview(); //开启预览 
	} 
}

(10)重写Activity的onPause()方法,用于当暂停Activity时,停止预览并释放相机资源,具体代码如下:

@Override 
protected void onPause() { 
	if(camera!=null){ 
		camera.stopPreview(); //停止预览 
		camera.release(); //释放资源 
	}
	
	super.onPause(); 
}

(11)由于本程序需要访问SD卡和控制相机,所以需要在AndroidManifest.xml文件中赋予程序访问SD卡和控制相机的权限,关键代码如下:

<!-- 授予程序可以向SD卡中保存文件的权限 --> 
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
<!-- 授予程序使用摄像头的权限 --> 
<uses-permission android:name="android.permission.CAMERA" /> 
<uses-feature android:name="android.hardware.camera" /> 
<uses-feature android:name="android.hardware.camera.autofocus" />
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值