首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android开发笔记(五十七)录像录音与播放

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

作者头像
aqi00
发布2019-01-18 11:09:10
2.9K0
发布2019-01-18 11:09:10
举报
文章被收录于专栏:老欧说安卓老欧说安卓

媒体录制MediaRecorder

MediaRecorder是Android自带的录制工具,通过操纵摄像头和麦克风完成媒体录制,既可录制视频,也可单独录制音频。其中对摄像头Camera的介绍参见《Android开发笔记(五十六)摄像头拍照》。 下面是MediaRecorder的常用方法: reset : 重置录制资源 prepare : 准备录制 start : 开始录制 stop : 结束录制 release : 释放录制资源 以上方法用于控制录像/录音操作。 setCamera : 设置摄像头对象 setPreviewDisplay : 设置预览界面。一般使用SurfaceHolder.getSurface setOrientationHint : 设置预览的角度。跟拍照一样一般设置90度 以上三个方法用于录制视频,如果仅是录音则不需要这三个方法。 setOnErrorListener : 设置错误监听器。可监听服务器异常以及未知错误的事件。 setOnInfoListener : 设置信息监听器。可监听录制结束事件,包括达到录制时长或者达到录制大小。 以上方法用于关联录像工具和事件。 setAudioSource : 设置音频来源。一般使用麦克风AudioSource.MIC。 setOutputFormat : 设置媒体输出格式。OutputFormat.AMR_NB表示窄带格式,OutputFormat.AMR_WB表示宽带格式,AAC_ADTS表示高级的音频传输流格式。该方法要在setVideoEncoder之前调用,不然调用setAudioEncoder时会报错“java.lang.IllegalStateException”。 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)。该方法为可选,AMRNB默认8khz,AMRWB默认16khz。 setAudioChannels : 设置音频的声道数。1表示单声道,2表示双声道。该方法为可选 setAudioEncodingBitRate : 设置音频每秒录制的字节数。越大则音频越清晰。该方法为可选 以上六个方法用于录制音频。 setVideoSource : 设置视频来源。一般使用摄像头VideoSource.CAMERA。 setOutputFormat : 设置媒体输出格式。OutputFormat.MPEG_4表示MPEG4格式,OutputFormat.THREE_GPP表示3GP格式。该方法要在setVideoEncoder之前调用。 setVideoEncoder : 设置视频编码器。VideoEncoder.MPEG_4_SP表示MPEG4编码,H263表示h263编码,H264表示h264编码。 setVideoSize : 设置视频的分辨率。 setVideoEncodingBitRate : 设置视频每秒录制的字节数。越大则视频越清晰。该方法为可选 setVideoFrameRate : 设置视频每秒录制的帧数。越大则视频越连贯,当然大小也越大。该方法为可选 以上六个方法用于录制视频,如果仅是录音则不需要这五个方法。 setMaxDuration : 设置录制时长。单位毫秒。 setMaxFileSize : 设置录制的媒体大小。单位字节。 setOutputFile : 设置输出文件的路径。 以上方法用于设置录像/录音参数。

媒体播放MediaPlayer

MediaPlayer是Android自带的播放器,可用于播放视频与音频。下面是MediaPlayer的常用方法: reset : 重置播放器 prepare : 准备播放 start : 开始播放 pause : 暂停播放 stop : 停止播放 以上方法用于控制播放操作。 setOnPreparedListener : 设置准备播放监听器。 setOnCompletionListener : 设置结束播放监听器。 setOnSeekCompleteListener : 设置播放拖动监听器。 setOnVideoSizeChangedListener : 设置视频缩放监听器。 以上方法用于关联播放事件。 create : 创建指定Uri的播放器。 setDataSource : 设置播放数据来源。create与setDataSource只需设置其一。 setVolume : 设置音量。第一个参数是左声道,第二个参数是右声道,取值在0-1之间。 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开发笔记的完整目录

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年02月05日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 媒体录制MediaRecorder
  • 媒体播放MediaPlayer
  • 录制/播放事件
  • 代码示例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档