MediaRecorder之视频录制

来源:互联网 发布:淘宝自主品牌怎么回事 编辑:程序博客网 时间:2024/05/16 18:46

一 前言

   在前面已经介绍过使用MediaRecorder录制音频,那么录制视频呢?很显然录制视频也需要MediaRecorder,同时需要摄像头Camera(相当于摄像机)。Camera用来取景,然后使用SurfaceView显示影像,那么MediaRecorder用来做录制的工作,接下来就是看看视频的录制的过程。
   本篇通过一个示例来认识简单视频的录制的过程,示例说明:通过Camera、MediaRecorder实现视频录制,停止录制后,点击播放按钮使用MediaPlayer来播放视频,示例完整代码最后提供(该实例的完整代码在recodervideomediarecorder的module中 )。

二 视频录制

   视频录制步骤大致如下:
(1)打开Camera(摄像头);
(2)设置摄像机参数(CamcorderProfile),设置摄像头参数;
(3)创建MediaRecorder对象实例,可以通过默认的构造方法进行创建;
(4)设置音频来源、视频来源、录制设备(Camera)、录制信息(CamcorderProfile)、输出文件格式等;
(5)创建SurfaceView(可以直接在布局中使用),并给SurfaceHolder添加callback监听;
(6)通过MediaRecorder对象实例调用setPreviewDisplay方法设置视频预览界面;
(7)调用prepare方法做录制前的准备工作;
(8)调用start、pause、stop方法控制录制过程;
接下来就来看看具体实现过程。

1 打开Camera(摄像头)

public static Camera open(int cameraId) {
//获取摄像头数目
int numCameras = Camera.getNumberOfCameras();
if (numCameras == 0) {
Log.w(TAG, "No cameras!");
return null;
}
// cameraId the hardware camera to access, between 0 and numCameras(摄像头数目) - 1
boolean explicitRequest = cameraId >= 0;

if (!explicitRequest) {
// Select a camera if no explicit camera requested
int index = 0;
while (index < numCameras) {
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(index, cameraInfo);
//判断使用是前置还是后置摄像头 如果是后置摄像头则停止循环
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
break;
}
index++;
}

cameraId = index;
}

Camera camera;
if (cameraId < numCameras) {
printMessage("Opening camera #" + cameraId);
camera = Camera.open(cameraId);
} else {
if (explicitRequest) {
Log.w(TAG, "Requested camera does not exist: " + cameraId);
camera = null;
} else {// cameraId 值 小于 0 且 不存在后置摄像头时,会走这里
printMessage( "No camera facing back; returning camera #0");
camera = Camera.open(0);
}
}

return camera;
}
说明:上述代码的功能主要是通过ID打开摄像头,一般ID为0的是后置摄像头;如果有多个摄像头的ID依次为0,1,2,...。

2 设置摄像机参数(CamcorderProfile)与摄像头参数

(1)设置摄像机参数
public static CamcorderProfile setCamcorderProfile(boolean isHigh ){
//返回后置相机的配置信息的类
CamcorderProfile profile = CamcorderProfile.get(isHigh ? CamcorderProfile.QUALITY_HIGH : CamcorderProfile.QUALITY_LOW);
//设置视频帧的宽度
profile.videoFrameWidth = (int) (profile.videoFrameWidth * VIDEO_SIZE_RATE);
//设置视频帧的高度
profile.videoFrameHeight = (int) (profile.videoFrameHeight * VIDEO_SIZE_RATE);
//设置视频输出比特率 The target video output bit rate in bits per second
profile.videoBitRate = VIDEO_BIT_RATE;
CamcorderProfile highProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
//The video encoder being used for the video track 设置视频编码
profile.videoCodec = highProfile.videoCodec;
//设置音频编码
profile.audioCodec = highProfile.audioCodec;
//The file output format of the camcorder profile 设置输出格式
profile.fileFormat = MediaRecorder.OutputFormat.MPEG_4;
return profile;
}
说明:很显然上方法主要是配置摄像机参数,返回CamcorderProfile即配置文件(在后面会用到)。那么CamcorderProfile是什么鬼?CamcorderProfile是用来保存摄像机配置信息的一个实体类,准确说是保存音视频配置信息,Android系统已经帮我们预定好了这些配置信息,当然你也可以自己设置,这些信息有:
  1. 文件输出格式
  2. 视频编解码格式
  3. 视频比特率,以位/秒为单位
  4. 视频帧速率(以每秒帧数为单位)
  5. 视频帧宽和高度,
  6. 音频编解码格式
  7. 音频比特率,以位/秒为单位,
  8. 音频采样率
  9. 录制的音频通道数。
对应的变量为:
public int fileFormat;  public int videoCodec;  public int videoBitRate;  public int videoFrameRate;  public int videoFrameWidth;  public int videoFrameHeight;  public int audioCodec;  public int audioBitRate;  public int audioSampleRate;  public int audioChannels 
同时它包含了视频的质量信息,获取方法如下:
手机支持的最低分辨率:  
1.直接获取  
CamcorderProfile profile=CamcorderProfile.get(CamcorderProfile.QUALITY_LOW);  
2.按时间流逝,质量变化情况来  
CamcorderProfile profile=CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_LOW);  
3.按高帧数下的质量来  
CamcorderProfile profile=CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH_SPEED_LOW);  
手机支持的最高分辨率:

1.直接获取  
CamcorderProfile profile=CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);  
2.按时间流逝,质量变化情况来  
CamcorderProfile profile=CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH);  
3.按高帧数下的质量来  
CamcorderProfile profile=CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH_SPEED_HIGH);  
因此CamcorderProfile为我们实现视频的录制提供很大的方便。
(2)设置摄像头参数
/**
* 设置摄像头参数,录制视频时使用该方法
* @param camera 摄像头
* @param profile 该参数为摄像机配置文件,里面保存类摄像机的参数
* @param whiteBalance 白平衡 可以为 null
* @param colorEffect 颜色效果 可以为 null
* @return 摄像头参数类 {@link Camera.Parameters } 对象
*/
public static Camera.Parameters setCameraParameters(Camera camera , CamcorderProfile profile , String whiteBalance , String colorEffect){
if (camera == null){
printMessage("camera can not null !");
return null;
}
if (profile == null){
printMessage("profile can not null !");
return null;
}


//因为android不支持竖屏录制,所以需要顺时针转90度,让其游览器显示正常
camera.setDisplayOrientation(90);

Camera.Parameters parameters = camera.getParameters();
//设置预览图片的大小
parameters.setPreviewSize(profile.videoFrameWidth, profile.videoFrameHeight);
//设置预览图片的帧率
parameters.setPreviewFrameRate(profile.videoFrameRate);
//设置获焦模式
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);

if (TextUtils.isEmpty(whiteBalance)){
whiteBalance = "auto";
}
if (TextUtils.isEmpty(colorEffect)){
colorEffect = "none";
}
// 设置白平衡参数。
if (isSupported(whiteBalance, parameters.getSupportedWhiteBalance())) {
parameters.setWhiteBalance(whiteBalance);
}
// 参数设置颜色效果。
if (isSupported(colorEffect, parameters.getSupportedColorEffects())) {
parameters.setColorEffect(colorEffect);
}

camera.setParameters(parameters);
return parameters;
}
说明:上述代码主要通过Camera.Parameters与上面返回的CamcorderProfile设置预览图片的大小,帧的速率等,在这里我使用竖屏拍摄,所以Camera直接旋转了90度。

3 创建MediaRecorder对象实例

MediaRecorder  mediaRecorder = new MediaRecorder();

4 设置音频来源、视频来源、录制设备(Camera)、录制信息(CamcorderProfile)、输出文件格式等;

      //关闭锁,使其他线程可以访问摄像头 在打开摄像头时要打开锁
camera.unlock();
mediaRecorder.setCamera(camera);
// 设置录制视频源为Camera(相机)
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// 设置音频资源
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//Uses the settings from a CamcorderProfile object for recording 根据CamcorderProfile对象设置录制信息
mediaRecorder.setProfile(profile);
//设置视频大小(分辨率)
mediaRecorder.setVideoSize(1280, 720);
// 设置视频一次写多少字节(可调节视频空间大小)
mediaRecorder.setVideoEncodingBitRate(1024 * 1024);
//每秒4帧
mediaRecorder.setVideoFrameRate(4);

//设置视频文件的输出格式 必须在设置声音编码格式、图像编码格式之前设置
// mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
// mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
// mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);

// 最大期限
mediaRecorder.setMaxDuration(35 * 1000);
//视频文件名
String fileName = "VID_" + System.currentTimeMillis() + ".mp4";
file = new File(videoPath, fileName);
// 指定输出文件 , 设置视频文件输出的路径
mediaRecorder.setOutputFile(file.getAbsolutePath());
说明:videoPath为视频本地保存路径,还有一点需要注意的就是打开Camera后,要调用lock方法锁住Camera,在开始录制前避免被其他线程访问Camera(不然老是出现错误,Camera无法使用,我试过了好多次都不行),在开始录制的时候再调用unlock方法开锁,使其线程可以访问

5 创建SurfaceView(可以直接在布局中使用),并给SurfaceHolder添加callback监听

(1)创建SurfaceView
surfaceView = (SurfaceView) findViewById(R.id.sufaceview);
(2)给SurfaceHolder添加callback监听
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (camera != null){
CameraHelpUtil.startPreview(camera,surfaceView.getHolder());
}
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (camera != null){
camera.stopPreview();
}
}
});

6 通过MediaRecorder对象实例调用setPreviewDisplay方法设置视频预览界面

//设置 surface 预览视频
mediaRecorder.setPreviewDisplay(holder.getSurface());
// // 设置保存录像方向
mediaRecorder.setOrientationHint(90);

7 调用prepare方法做录制前的准备工作

try {
mediaRecorder.prepare();
} catch (IOException e) {
Log.d(TAG,e.getMessage());
}

8 开始录制

mediaRecorder.start();
说明:步骤3,4,6,7,8组合在一起形成一个完整的方法如下:
    /**
* 初始化 MediaRecorder 对象实例
* @param camera 摄像头
* @param profile 摄像头配置文件
* @param videoPath 视频保存的位置
* @param holder SurfaceHolder 对象实例
*/
public static MediaRecorder record( Camera camera , CamcorderProfile profile , String videoPath, SurfaceHolder holder){
MediaRecorder mediaRecorder = new MediaRecorder();
//关闭锁,使其他线程可以访问摄像头 在打开摄像头时要打开锁
camera.unlock();
mediaRecorder.setCamera(camera);
// 设置录制视频源为Camera(相机)
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// 设置音频资源
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//Uses the settings from a CamcorderProfile object for recording 根据CamcorderProfile对象设置录制信息
mediaRecorder.setProfile(profile);
//设置视频大小(分辨率)
mediaRecorder.setVideoSize(1280, 720);
// 设置视频一次写多少字节(可调节视频空间大小)
mediaRecorder.setVideoEncodingBitRate(1024 * 1024);
//每秒4帧
mediaRecorder.setVideoFrameRate(4);

//设置视频文件的输出格式 必须在设置声音编码格式、图像编码格式之前设置
// mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
// mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
// mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);

// 最大期限
mediaRecorder.setMaxDuration(35 * 1000);
//视频文件名
String fileName = "VID_" + System.currentTimeMillis() + ".mp4";
file = new File(videoPath, fileName);
// 指定输出文件 , 设置视频文件输出的路径
mediaRecorder.setOutputFile(file.getAbsolutePath());
//设置 surface 预览视频
mediaRecorder.setPreviewDisplay(holder.getSurface());
// // 设置保存录像方向
mediaRecorder.setOrientationHint(90);

mediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {
@Override
public void onError(MediaRecorder mr, int what, int extra) {
// Toast.makeText(RecorderVideoActivity.this, "未知错误", Toast.LENGTH_SHORT).show();
}
});

mediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
@Override
public void onInfo(MediaRecorder mr, int what, int extra) {

}
});

try {
mediaRecorder.prepare();
mediaRecorder.start();
} catch (IOException e) {
Log.d(TAG,e.getMessage());
}

return mediaRecorder;
}
说明:上述代码都是录制视频业务逻辑的实现过程,都写成了工具类,源码中有,播放视频的实现前面有介绍过,这里就不累述了,下面贴出示例的实现代码:

三 示例

1 视频录制界面Activity的实现代码

public class RecorderVideoActivity extends AppCompatActivity {

private String filePath = " ";
private Camera camera;
private CamcorderProfile profile;
private MediaRecorder mediaRecorder;
private SurfaceView surfaceView;
private ImageView img_start;
/** true 正在录制 */
private boolean isRecoding = false;
private TextView txt_play;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recorder_video);
surfaceView = (SurfaceView) findViewById(R.id.sufaceview);
img_start = (ImageView) findViewById(R.id.img_start);
txt_play = (TextView) findViewById(R.id.txt_play);
setListener();
}

/**
* 设置监听
*/
private void setListener() {
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (camera != null){
CameraHelpUtil.startPreview(camera,surfaceView.getHolder());
}
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (camera != null){
camera.stopPreview();
}
}
});

img_start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (camera == null){
return;
}
if (isRecoding){
isRecoding = false;
MediaRecorderHelpUtil.stop(mediaRecorder);
img_start.setImageResource(R.mipmap.icon_voice_transcribe);
}else {
mediaRecorder = MediaRecorderHelpUtil.record(camera,profile,filePath,surfaceView.getHolder());
isRecoding = true;
img_start.setImageResource(R.mipmap.icon_stop_transcribe);
}
}
});

txt_play.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
play();
}
});
}

private void play() {
if (null == MediaRecorderHelpUtil.getFile()){
return;
}
Intent intent = new Intent(this,MediaPlayerSurfaceActivity.class);
intent.putExtra("video_Path",MediaRecorderHelpUtil.getFile().getAbsolutePath());
startActivity(intent);
}


@Override
protected void onResume() {
super.onResume();
isRecoding = false;
}


@Override
protected void onStart() {
super.onStart();
if (camera == null){
checkPermission();
}
}

/**
* 动态检测必要的权限
*/
private void checkPermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M){
initDrives();
return;
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != 0 ||
ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != 0 ||
ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != 0 ||
ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != 0){
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.RECORD_AUDIO,Manifest.permission.CAMERA},0x123);
}else {
initDrives();
}
}

/**
* 初始化摄像头设备
*/
private void initDrives() {
getFilePath();
camera = CameraHelpUtil.open();
//打开锁 ,使其他线程无法访问 摄像头
camera.lock();
if (camera != null){
profile = CameraHelpUtil.setCamcorderProfile(false);
CameraHelpUtil.setCameraParameters(camera,profile,null,null);
}
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 0x123){
if (grantResults[0] == 0 && grantResults[1] == 0 && grantResults[2] == 0 && grantResults[3] == 0){
initDrives();
}else {
Toast.makeText(this, "需要必要的权限,请授权", Toast.LENGTH_SHORT).show();
}
}
}


/**
* 获取文件保存路径
*/
private void getFilePath(){
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath() /*+ File.separator + getPackageName()*/;
}else {
filePath = Environment.getDataDirectory().getAbsolutePath() /*+ File.separator + getPackageName()*/;
}
filePath = filePath + File.separator + "Camera";
File file = new File(filePath);
if (!file.exists()){
file.mkdirs();
}
filePath = file.getAbsolutePath();
}


@Override
protected void onDestroy() {
CameraHelpUtil.releaseCamera(camera);
if (isRecoding){
MediaRecorderHelpUtil.stop(mediaRecorder);
// MediaRecorderHelpUtil.release(mediaRecorder);
}
super.onDestroy();
}
}
其Xml文件如下:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.lzb.video.RecorderVideoActivity">

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

<ImageView
android:id="@+id/img_start"
android:layout_gravity="bottom|center_horizontal"
android:src="@mipmap/icon_voice_transcribe"
android:layout_marginBottom="50dp"
android:scaleType="fitXY"
android:layout_width="60dp"
android:layout_height="60dp" />

<TextView
android:id="@+id/txt_play"
android:text="播放视频"
android:textColor="@android:color/white"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>

2 播放界面代码

public class MediaPlayerSurfaceActivity extends Activity implements View.OnClickListener{

/** 视频播放控件*/
private SurfaceView surfaceView;
private Display currDisplay;
/** 给SurfaceView添加CallBack监听 */
private SurfaceHolder holder;
/** 多媒体*/
private MediaPlayer player;
private int vWidth,vHeight;
/** 视频路径*/
private String videoPath = "";
private Button button;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_surface);

button = (Button) findViewById(R.id.btn_start);
button.setOnClickListener(this);
//获取播放地址
Intent intent = getIntent();
videoPath = intent.getStringExtra("video_Path");

surfaceView = (SurfaceView) findViewById(R.id.surface_surface_view);
//然后,我们取得当前Display对象
currDisplay = this.getWindowManager().getDefaultDisplay();
//下面开始实例化MediaPlayer对象
player = new MediaPlayer();
setPlayerListener();
setHolder();
}

/**
* 将要播放的视频图像输送到surfaceView
*/
private void setHolder() {
//给SurfaceView添加CallBack监听
holder = surfaceView.getHolder();
//为了可以播放视频或者使用Camera预览,我们需要指定其Buffer类型
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(new Callback() {
/**
* Activity进入后台会触发该方法
* @param holder
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Toast.makeText(MediaPlayerSurfaceActivity.this, "Surface被销毁", Toast.LENGTH_SHORT).show();

}

/**
*
* Activity进入前台会触发该方法
*
* 当SurfaceView中的Surface被创建的时候被调用*/
@Override
public void surfaceCreated(SurfaceHolder holder) {
Toast.makeText(MediaPlayerSurfaceActivity.this, "Surface被创建", Toast.LENGTH_SHORT).show();
play();

}
/** 当Surface尺寸等参数改变时触发 */
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {

}
});
}

/**
*
* MediaPlayer中的prepare方法和prepareAsync方法的区别
* prepare方法是将资源同步缓存到内存中,一般加载本地较小的资源可以用这个,
* 如果是较大的资源或者网络资源建议使用prepareAsync方法,异步加载.但如果想让资源启动,即start()起来,
* 因为在异步中,如果不设置监听直接start的话,是拿不到这个资源,如果让线程睡眠一段时间,则可以取得资源,因为这个时候,
* 异步线程已经取得资源,但不可能使用线程睡眠的方式来获取资源啊.所以就需要设置监听事件setOnPreparedListener();
* 来通知MediaPlayer资源已经获取到了,然后实现onPrepared(MediaPlayer mp)方法.在里面启动MediaPlayer
* 参考:http://blog.csdn.net/qq_24223073/article/details/69315856
* 设置监听示例{@link #setPlayerListener}
* 开始播放视频
*/
void play() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
surfaceView.setForeground(null);
}
if (TextUtils.isEmpty(videoPath)){
return;
}
player.reset();
//将要播放的视频图像输送到surfaceView
player.setDisplay(holder);
try {
player.setDataSource(videoPath);
// player.prepare();
player.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
//首先取得video的宽和高
vWidth = player.getVideoWidth();
vHeight = player.getVideoHeight();
if(vWidth > currDisplay.getWidth() || vHeight > currDisplay.getHeight()){
//如果video的宽或者高超出了当前屏幕的大小,则要进行缩放
float wRatio = (float)vWidth/(float)currDisplay.getWidth();
float hRatio = (float)vHeight/(float)currDisplay.getHeight();
//选择大的一个进行缩放
float ratio = Math.max(wRatio, hRatio);
vWidth = (int)Math.ceil((float)vWidth/ratio);
vHeight = (int)Math.ceil((float)vHeight/ratio);
//设置surfaceView的布局参数
surfaceView.setLayoutParams(new LinearLayout.LayoutParams(vWidth, vHeight - 100));
//然后开始播放视频
// player.start();
}
// player.start();

}

/**
*
* 设置播放监听
*
* @version 1.0
* @createTime 2016-1-20,下午3:04:38
* @updateTime 2016-1-20,下午3:04:38
* @createAuthor lzb
* @updateAuthor
* @updateInfo (此处输入修改内容,若无修改可不写.)
*/
@SuppressLint("NewApi") @SuppressWarnings("deprecation")
private void setPlayerListener() {
//设置播放完监听
player.setOnCompletionListener(new OnCompletionListener() {
/** 当MediaPlayer播放完成后触发 */
@Override
public void onCompletion(MediaPlayer mp) {
Toast.makeText(MediaPlayerSurfaceActivity.this, "播放完成", Toast.LENGTH_SHORT).show();
}
});
//播放错误监听
player.setOnErrorListener(new OnErrorListener() {
@TargetApi(Build.VERSION_CODES.CUPCAKE) @Override
public boolean onError(MediaPlayer mp, int what, int extra) {
switch (what) {
//播放器坏了
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
Toast.makeText(MediaPlayerSurfaceActivity.this, "播放器坏了", Toast.LENGTH_SHORT).show();
break;
//未知错误
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
Toast.makeText(MediaPlayerSurfaceActivity.this, "未知错误", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
return false;
}
});
//详细监听
player.setOnInfoListener(new OnInfoListener() {
/** 当一些特定信息出现或者警告时触发 */
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
switch(what){
case MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING: //视频交叉紊乱
Toast.makeText(MediaPlayerSurfaceActivity.this, "视频交叉紊乱", Toast.LENGTH_SHORT).show();
break;
case MediaPlayer.MEDIA_INFO_METADATA_UPDATE: //更新
Toast.makeText(MediaPlayerSurfaceActivity.this, "更新", Toast.LENGTH_SHORT).show();
break;
case MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING: //无法解码
Toast.makeText(MediaPlayerSurfaceActivity.this, "无法解码", Toast.LENGTH_SHORT).show();
break;
case MediaPlayer.MEDIA_INFO_NOT_SEEKABLE: //不能搜索
Toast.makeText(MediaPlayerSurfaceActivity.this, "不能搜索", Toast.LENGTH_SHORT).show();
break;
}
return false;
}
});

//准备监听 如果是使用异步加载的方式必须要设置该监听,在onPrepared方法中调用start()方法
player.setOnPreparedListener(new OnPreparedListener() {
/** 当prepare完成后,该方法触发,在这里我们播放视频*/
@Override
public void onPrepared(MediaPlayer mp) {
player.start();
}
});

player.setOnSeekCompleteListener(new OnSeekCompleteListener() {
/** seek操作完成时触发 */
@Override
public void onSeekComplete(MediaPlayer mp) {

}
});
/** 当video大小改变时触发 这个方法在设置player的source后至少触发一次 */
player.setOnVideoSizeChangedListener(new OnVideoSizeChangedListener() {
@Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {

}
});
}

/**
* 启动其他Activity或者对话框,暂停播放
*/
@Override
protected void onPause() {
if (player != null){
if (player.isPlaying()){
player.stop();
}
}
super.onPause();
}

@Override
protected void onDestroy() {
if (player != null){
if (player.isPlaying()){
player.stop();
}
player.release();
}
super.onDestroy();
}

@Override
public void onClick(View v) {
if (player.isPlaying()){
player.stop();
player.reset();
play();
}else {
play();
}
}
}
其XML文件如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/main_rLayout"
tools:context="com.lzb.video.MediaPlayerSurfaceActivity" >
<SurfaceView
android:id="@+id/surface_surface_view"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<Button
android:id="@+id/btn_start"
android:text="重播"
android:textColor="@android:color/white"
android:background="@android:color/transparent"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="30dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
完整示例代码

四 效果图



原创粉丝点击