Android开发笔记(五十七)录像录音与播放

媒体录制MediaRecorder

MediaRecorder是Android自带的录制工具,通过操纵摄像头和麦克风完成媒体录制,既可录制视频,也可单独录制音频。其中对摄像头Camera的介绍参见《 Android开发笔记(五十六)摄像头拍照》。
下面是MediaRecorder的常用方法:

reset : 重置录制资源
prepare : 准备录制
start : 开始录制
stop : 结束录制
release : 释放录制资源
以上方法用于控制录像/录音操作。

setCamera : 设置摄像头对象
setPreviewDisplay : 设置预览界面。一般使用SurfaceHolder.getSurface
setOrientationHint : 设置预览的角度。跟拍照一样一般设置90度
以上三个方法用于录制视频,如果仅是录音则不需要这三个方法。
setOnErrorListener : 设置错误监听器。可监听服务器异常以及未知错误的事件。
setOnInfoListener : 设置信息监听器。可监听录制结束事件,包括达到录制时长或者达到录制大小。
以上方法用于关联录像工具和事件。

setAudioSource : 设置音频来源。一般使用麦克风AudioSource.MIC。
setAudioEncoder : 设置音频编码器。AudioEncoder.AMR_NB表示窄带编码,AudioEncoder.AMR_WB表示宽带编码,AudioEncoder.AAC表示低复杂度编码,AudioEncoder.HE_AAC表示高效率编码,AudioEncoder.AAC_ELD表示增强型低延迟编码。
注意:setAudioEncoder应在setOutputFormat之后执行,否则会出现“setAudioEncoder called in an invalid state(2)”的异常。
setAudioSamplingRate : 设置音频的采样率,单位赫兹(Hz)。该方法为可选
setAudioChannels : 设置音频的声道数。1表示单声道,2表示双声道。该方法为可选
setAudioEncodingBitRate : 设置音频每秒录制的字节数。越大则音频越清晰。该方法为可选
以上五个方法用于录制音频。
setVideoSource : 设置视频来源。一般使用摄像头VideoSource.CAMERA。
setVideoEncoder : 设置视频编码器。VideoEncoder.MPEG_4_SP表示MPEG4编码,H263表示h263编码,H264表示h264编码。
setVideoSize : 设置视频的分辨率。
setVideoEncodingBitRate : 设置视频每秒录制的字节数。越大则视频越清晰。该方法为可选
setVideoFrameRate : 设置视频每秒录制的帧数。越大则视频越连贯,当然大小也越大。该方法为可选
以上五个方法用于录制视频,如果仅是录音则不需要这五个方法。
setMaxDuration : 设置录制时长。
setMaxFileSize : 设置录制的媒体大小。
setOutputFormat : 设置媒体输出格式。OutputFormat.MPEG_4表示MPEG4格式,OutputFormat.THREE_GPP表示3GP格式。
setOutputFile : 设置输出文件的路径。
以上方法用于设置录像/录音参数。


媒体播放MediaPlayer

MediaPlayer是Android自带的播放器,可用于播放视频与音频。下面是MediaPlayer的常用方法:
reset : 重置播放器
prepare : 准备播放
start : 开始播放
pause : 暂停播放
stop : 停止播放
以上方法用于控制播放操作。

setOnPreparedListener : 设置准备播放监听器。
setOnCompletionListener : 设置结束播放监听器。
setOnSeekCompleteListener : 设置播放拖动监听器。
setOnVideoSizeChangedListener : 设置视频缩放监听器。
以上方法用于关联播放事件。

create : 创建指定Uri的播放器。
setDataSource : 设置播放数据来源。create与setDataSource只需设置其一。
setVolume : 设置音量。第一个参数是左声道,第二个参数是右声道。
setAudioStreamType : 设置音频流的类型。AudioManager.STREAM_MUSIC表示音乐,AudioManager.STREAM_RING表示铃声,AudioManager.STREAM_ALARM表示闹钟,AudioManager.STREAM_NOTIFICATION表示通知。
setDisplay : 设置播放界面,参数为SurfaceHolder类型。该方法为视频播放专用,播放音频不需要该方法。
setSurface : 设置播放表层,一般使用SurfaceHolder.getSurface。setDisplay与setSurface只需设置其一。
setLooping : 设置是否循环播放。
isPlaying : 判断是否正在播放。
seekTo : 拖动播放进度到指定位置。
getCurrentPosition : 获取当前播放进度所在的位置。
getDuration : 获取播放时长。
以上方法用于设置播放参数。


录制/播放事件

下面是几个媒体录制/播放用到的回调事件接口:

录制异常事件
监听器类名 : MediaRecorder.OnErrorListener
设置监听器的方法 : MediaRecorder.setOnErrorListener
监听器需要重写的方法 : onError

录制完毕事件
监听器类名 : MediaRecorder.OnInfoListener
设置监听器的方法 : MediaRecorder.setOnInfoListener
监听器需要重写的方法 : onInfo,其中what值为MEDIA_RECORDER_INFO_MAX_DURATION_REACHED表示达到录制时长,为MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED表示达到录制大小。

准备播放事件
监听器类名 : MediaPlayer.OnPreparedListener
设置监听器的方法 : MediaPlayer.setOnPreparedListener
监听器需要重写的方法 : onPrepared

播放结束事件
监听器类名 : MediaPlayer.OnCompletionListener
设置监听器的方法 : MediaPlayer.setOnCompletionListener
监听器需要重写的方法 : onCompletion

拖动播放事件
监听器类名 : MediaPlayer.OnSeekCompleteListener
设置监听器的方法 : MediaPlayer.setOnSeekCompleteListener
监听器需要重写的方法 : onSeekComplete

视频缩放事件
监听器类名 : MediaPlayer.OnVideoSizeChangedListener
设置监听器的方法 : MediaPlayer.setOnVideoSizeChangedListener
监听器需要重写的方法 : onVideoSizeChanged


录像与录音需要在AndroidManifest.xml中加上如下权限(录制操作通常要操作SD卡,所以也要加上SD卡的权限):
    <!-- 录像/录音 -->
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_VIDEO"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <!-- SD卡 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />



代码示例

下面是录像视图VideoRecorderView的代码示例:
import java.io.File;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import com.example.exmcamera.R;

import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.media.MediaRecorder;
import android.media.MediaRecorder.AudioEncoder;
import android.media.MediaRecorder.AudioSource;
import android.media.MediaRecorder.OnErrorListener;
import android.media.MediaRecorder.OnInfoListener;
import android.media.MediaRecorder.OutputFormat;
import android.media.MediaRecorder.VideoEncoder;
import android.media.MediaRecorder.VideoSource;
import android.os.Environment;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;

public class VideoRecorderView extends LinearLayout implements OnErrorListener,OnInfoListener {
	private static final String TAG = "VideoRecorderView";
    private SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder;
    private ProgressBar mProgressBar;
 
    private MediaRecorder mMediaRecorder;
    private Camera mCamera;
    private Timer mTimer;  //计时器
    private OnRecordFinishListener mOnRecordFinishListener;  //录制完成回调接口
 
    private int mWidth;  //视频分辨率宽度
    private int mHeight;  //视频分辨率高度
    private int mRecordMaxTime = 10;  //一次拍摄最长时间
    private int mTimeCount;  //时间计数
    private File mRecordFile = null;  //文件
 
    public VideoRecorderView(Context context) {
        this(context, null);
    }
 
    public VideoRecorderView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
 
	public VideoRecorderView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mWidth = (int) context.getResources().getDimension(R.dimen.video_height);
        mHeight = (int) context.getResources().getDimension(R.dimen.video_width);
 
        LayoutInflater.from(context).inflate(R.layout.movie_recorder_view, this);
        mSurfaceView = (SurfaceView) findViewById(R.id.surfaceview);
        mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
        mProgressBar.setMax(mRecordMaxTime);  //设置进度条最大量
 
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(new CustomCallBack());
    }

    //开始录制视频
    public void record(final OnRecordFinishListener onRecordFinishListener) {
        mOnRecordFinishListener = onRecordFinishListener;
        createRecordDir();
        try {
            initCamera();
            initRecord();
            mTimeCount = 0;  //时间计数器重新赋值
            mTimer = new Timer();
            mTimer.schedule(new TimerTask() {
                @Override
                public void run() {
                    mProgressBar.setProgress(mTimeCount++);  //设置进度条
                }
            }, 0, 1000);  //每隔1000毫秒就重复执行run函数
        } catch (Exception e) {
			Log.d(TAG, "record error: " + e.getMessage());
        }
    }

    //停止拍摄
    public void stop() {
        stopRecord();
        releaseRecord();
        freeCameraResource();
    }
 
    public File getRecordFile() {
        return mRecordFile;
    }
 
    private class CustomCallBack implements Callback {
 
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            try {
                initCamera();
            } catch (IOException e) {
                Log.d(TAG, "surfaceCreated error: "+e.getMessage());
            }
        }
 
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        }
 
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            freeCameraResource();
        }
    }
 
    private void initCamera() throws IOException {
        if (mCamera != null) {
            freeCameraResource();
        }
        try {
            mCamera = Camera.open();
        } catch (Exception e) {
            Log.d(TAG, "Camera.open() error: "+e.getMessage());
            freeCameraResource();
        }
        if (mCamera == null) {
            return;
        }
 
        setCameraParams();
        mCamera.setDisplayOrientation(90);
        mCamera.setPreviewDisplay(mSurfaceHolder);
        mCamera.startPreview();
        mCamera.unlock();
    }
 
    //设置摄像头为竖屏
    private void setCameraParams() {
        if (mCamera != null) {
            Parameters params = mCamera.getParameters();
            params.set("orientation", "portrait");
            mCamera.setParameters(params);
        }
    }

    private void freeCameraResource() {
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.lock();
            mCamera.release();
            mCamera = null;
        }
    }

	private void createRecordDir() {
		File sampleDir = new File(Environment.getExternalStorageDirectory()
				+ File.separator + "RecordVideo/");
		if (!sampleDir.exists()) {
			sampleDir.mkdirs();
		}
		File recordDir = sampleDir;
		try {
			mRecordFile = File.createTempFile("recording", ".mp4", recordDir);
			Log.d(TAG, mRecordFile.getAbsolutePath());
		} catch (Exception e) {
			Log.d(TAG, "createTempFile error: " + e.getMessage());
		}
	}

    private void initRecord() {
        mMediaRecorder = new MediaRecorder();
        mMediaRecorder.reset();
        if (mCamera != null) {
            mMediaRecorder.setCamera(mCamera);
        }
        mMediaRecorder.setOnErrorListener(this);
        mMediaRecorder.setOnInfoListener(this);
        mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
        mMediaRecorder.setVideoSource(VideoSource.CAMERA);  //视频源
        mMediaRecorder.setAudioSource(AudioSource.MIC);  //音频源
        mMediaRecorder.setOutputFormat(OutputFormat.MPEG_4);  //视频输出格式
        mMediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB);  //音频格式
        mMediaRecorder.setVideoSize(mWidth, mHeight);  //设置分辨率:
        //mMediaRecorder.setVideoFrameRate(16);  //setVideoFrameRate与setVideoEncodingBitRate设置其一即可
        mMediaRecorder.setVideoEncodingBitRate(1 * 1024 * 512);  //设置帧频率,然后就清晰了
        mMediaRecorder.setOrientationHint(90);  //输出旋转90度,保持竖屏录制
        mMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);  //视频录制格式
        mMediaRecorder.setMaxDuration(mRecordMaxTime * 1000);  //设置录制时长
        //mMediaRecorder.setMaxFileSize(1024*1024*10);  //setMaxFileSize与setMaxDuration设置其一即可
        mMediaRecorder.setOutputFile(mRecordFile.getAbsolutePath());
        try {
            mMediaRecorder.prepare();
            mMediaRecorder.start();
        } catch (Exception e) {
			Log.d(TAG, "MediaRecorder.start error: " + e.getMessage());
        }
    }

    private void stopRecord() {
        mProgressBar.setProgress(0);
        if (mTimer != null) {
            mTimer.cancel();
        }
        if (mMediaRecorder != null) {
            mMediaRecorder.setOnErrorListener(null);
            mMediaRecorder.setPreviewDisplay(null);
            try {
                mMediaRecorder.stop();
            } catch (Exception e) {
    			Log.d(TAG, "MediaRecorder.stop error: " + e.getMessage());
            }
        }
    }

    private void releaseRecord() {
        if (mMediaRecorder != null) {
            mMediaRecorder.setOnErrorListener(null);
            mMediaRecorder.release();
            mMediaRecorder = null;
        }
    }
 
    //录制完成回调接口
    public interface OnRecordFinishListener {
        public void onRecordFinish();
    }
 
    @Override
    public void onError(MediaRecorder mr, int what, int extra) {
        if (mr != null) {
            mr.reset();
        }
    }

	@Override
	public void onInfo(MediaRecorder mr, int what, int extra) {
		if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED
				|| what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
	        stop();
	        if (mOnRecordFinishListener != null) {
	            mOnRecordFinishListener.onRecordFinish();
	        }
		}
	}
}


下面是录制与播放页面VideoActivity的代码示例:
import com.example.exmcamera.R;
import com.example.exmcamera.widget.VideoRecorderView;

import android.app.Activity;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.View.OnClickListener;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.widget.Button;

public class VideoActivity extends Activity implements OnClickListener {
	private static final String TAG = "VideoActivity";
    private VideoRecorderView mVideoView;
    private Button start_btn;
    private Button stop_btn;
    private Button play_btn;
    private Button pause_btn;

    private SurfaceView mSurfaceView;
    private MediaPlayer mMediaPlayer;
    private int mPosition;
    private boolean bFirstPlay = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_video);

		mVideoView = (VideoRecorderView) findViewById(R.id.moive_rv);
		start_btn = (Button) findViewById(R.id.start_btn);
		stop_btn = (Button) findViewById(R.id.stop_btn);
		play_btn = (Button) findViewById(R.id.play_btn);
		pause_btn = (Button) findViewById(R.id.pause_btn);

		start_btn.setOnClickListener(this);
		stop_btn.setOnClickListener(this);
		play_btn.setOnClickListener(this);
		pause_btn.setOnClickListener(this);
		start_btn.setEnabled(true);
		stop_btn.setEnabled(false);
		play_btn.setEnabled(false);
		pause_btn.setEnabled(false);
        init();
    }
    
	private void init() {
        mMediaPlayer = new MediaPlayer();
        mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
        		play_btn.setEnabled(true);
        		pause_btn.setEnabled(false);
        		bFirstPlay = true;
            }
        });
        mSurfaceView = (SurfaceView) this.findViewById(R.id.play_surfaceV);
        mSurfaceView.getHolder().addCallback(new Callback() {
        	
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
            }

            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                if (mPosition > 0) {
                    try {
                        play();
                        mMediaPlayer.seekTo(mPosition);
                        mPosition = 0;
                    } catch (Exception e) {
                        Log.d(TAG, "surfaceCreated error: "+e.getMessage());
                    }
                }
            }
            
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            }
        });
    }
    
	@Override
	protected void onPause() {
		// 先判断是否正在播放
		if (mMediaPlayer.isPlaying()) {
			// 如果正在播放我们就先保存这个播放位置
			mPosition = mMediaPlayer.getCurrentPosition();
			mMediaPlayer.stop();
		}
		super.onPause();
	}
	
	private void preplay() {
		try {
			mMediaPlayer.reset();
			mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
			// 设置需要播放的视频
			String path = mVideoView.getRecordFile().getAbsolutePath();
			mMediaPlayer.setDataSource(path);
			Log.d(TAG, "video path = "+path);
			// 把视频画面输出到SurfaceView
			mMediaPlayer.setDisplay(mSurfaceView.getHolder());
			mMediaPlayer.prepare();
		} catch (Exception e) {
            Log.d(TAG, "mMediaPlayer.prepare error: "+e.getMessage());
		}
	}
    
    private void play() {
        try {
        	preplay();
            //播放
            mMediaPlayer.start();
        } catch (Exception e) {
            Log.d(TAG, "mMediaPlayer.start error: "+e.getMessage());
        }
    }
    
    private void stopRecord() {
		start_btn.setEnabled(true);
		stop_btn.setEnabled(false);
		play_btn.setEnabled(true);
    	preplay();
    }

	@Override
	public void onClick(View v) {
		int resid = v.getId();
		if (resid == R.id.start_btn) {
            mVideoView.record(new VideoRecorderView.OnRecordFinishListener() {
                @Override
                public void onRecordFinish() {
                	stopRecord();
                }
            });
    		start_btn.setEnabled(false);
    		stop_btn.setEnabled(true);
		} else if (resid == R.id.stop_btn) {
            mVideoView.stop();
            stopRecord();
		} else if (resid == R.id.play_btn) {
			if (bFirstPlay == true) {
	            play();
	            bFirstPlay = false;
			} else {
	            mMediaPlayer.start();
			}
    		play_btn.setEnabled(false);
    		pause_btn.setEnabled(true);
		} else if (resid == R.id.pause_btn) {
            mMediaPlayer.pause();
    		play_btn.setEnabled(true);
    		pause_btn.setEnabled(false);
		}
	}
}





点此查看Android开发笔记的完整目录

你可能感兴趣的:(android,MediaRecorder,mediaplayer,播放,录像)