MediaRecorder可以实现录音和录像。
MediaRecorder官方说明:
http://developer.android.com/reference/android/media/MediaRecorder.html
使用MediaRecorder录音录像时需要严格遵守API说明中的函数调用先后顺序,否则不能成功执行。
下面是MediaRecorder实现录像的例子。
此程序在高通MSM7225平台的华为U8500 2.2版本上可以正常录像。但在MTK MT6575平台的联想A750上不能正常运行,无法实现录像。
在展讯8810 2.3.5平台可以实现录像,但播放没有声音,通过mediaInfo查看,已经有视频数据了,但是无法播放,在PC上也不能播放,可能是录制的时候出现了问题。
可见,通过camera录像的程序对平台和硬件的依赖性很强,同样的程序在不同的手机上表现差别很大。
1.Activity类
public class MainActivity extends Activity implements SurfaceHolder.Callback {
private static final String TAG = "MainActivity";
private SurfaceView mSurfaceview;
private Button mBtnStartStop;
private boolean mStartedFlg = false;
private MediaRecorder mRecorder;
private SurfaceHolder mSurfaceHolder;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题栏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);// 设置全屏
// 设置横屏显示
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// 选择支持半透明模式,在有surfaceview的activity中使用。
getWindow().setFormat(PixelFormat.TRANSLUCENT);
setContentView(R.layout.activity_main);
mSurfaceview = (SurfaceView)findViewById(R.id.surfaceview);
mBtnStartStop = (Button)findViewById(R.id.btnStartStop);
mBtnStartStop.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (!mStartedFlg) {
// Start
if (mRecorder == null) {
mRecorder = new MediaRecorder(); // Create MediaRecorder
}
try {
// Set audio and video source and encoder
// 这两项需要放在setOutputFormat之前
mRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// Set output file format
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
// 这两项需要放在setOutputFormat之后
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
mRecorder.setVideoSize(320, 240);
mRecorder.setVideoFrameRate(20);
mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
// Set output file path
String path = getSDPath();
if (path != null) {
File dir = new File(path + "/recordtest");
if (!dir.exists()) {
dir.mkdir();
}
path = dir + "/" + getDate() + ".3gp";
mRecorder.setOutputFile(path);
Log.d(TAG, "bf mRecorder.prepare()");
mRecorder.prepare();
Log.d(TAG, "af mRecorder.prepare()");
Log.d(TAG, "bf mRecorder.start()");
mRecorder.start(); // Recording is now started
Log.d(TAG, "af mRecorder.start()");
mStartedFlg = true;
mBtnStartStop.setText("Stop");
Log.d(TAG, "Start recording ...");
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
// stop
if (mStartedFlg) {
try {
Log.d(TAG, "Stop recording ...");
Log.d(TAG, "bf mRecorder.stop(");
mRecorder.stop();
Log.d(TAG, "af mRecorder.stop(");
mRecorder.reset(); // You can reuse the object by going back to setAudioSource() step
mBtnStartStop.setText("Start");
} catch (Exception e) {
e.printStackTrace();
}
}
mStartedFlg = false; // Set button status flag
}
}
});
SurfaceHolder holder = mSurfaceview.getHolder();// 取得holder
holder.addCallback(this); // holder加入回调接口
// setType必须设置,要不出错.
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
/**
* 获取系统时间
* @return
*/
public static String getDate(){
Calendar ca = Calendar.getInstance();
int year = ca.get(Calendar.YEAR); // 获取年份
int month = ca.get(Calendar.MONTH); // 获取月份
int day = ca.get(Calendar.DATE); // 获取日
int minute = ca.get(Calendar.MINUTE); // 分
int hour = ca.get(Calendar.HOUR); // 小时
int second = ca.get(Calendar.SECOND); // 秒
String date = "" + year + (month + 1 )+ day + hour + minute + second;
Log.d(TAG, "date:" + date);
return date;
}
/**
* 获取SD path
* @return
*/
public String getSDPath(){
File sdDir = null;
boolean sdCardExist = Environment.getExternalStorageState()
.equals(android.os.Environment.MEDIA_MOUNTED); // 判断sd卡是否存在
if (sdCardExist)
{
sdDir = Environment.getExternalStorageDirectory();// 获取跟目录
return sdDir.toString();
}
return null;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
// 将holder,这个holder为开始在onCreate里面取得的holder,将它赋给mSurfaceHolder
mSurfaceHolder = holder;
Log.d(TAG, "surfaceChanged 1");
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
// 将holder,这个holder为开始在onCreate里面取得的holder,将它赋给mSurfaceHolder
mSurfaceHolder = holder;
Log.d(TAG, "surfaceChanged 2");
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
// surfaceDestroyed的时候同时对象设置为null
mSurfaceview = null;
mSurfaceHolder = null;
if (mRecorder != null) {
mRecorder.release(); // Now the object cannot be reused
mRecorder = null;
Log.d(TAG, "surfaceDestroyed release mRecorder");
}
}
}
2. Layout文件
布局文件只有一个Surface用于显示录制的视频和一个按钮用于控制开始和结束。
<LinearLayout 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:orientation="horizontal">
<SurfaceView
android:id="@+id/surfaceview"
android:layout_weight="1"
android:layout_width="0dip"
android:layout_height="fill_parent" />
<Button
android:id="@+id/btnStartStop"
android:layout_width="55dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Start"
tools:context=".MainActivity" />
</LinearLayout>
3.Manifest文件增加权限
需要增加使用Camera,Mic,Sd卡的权限,代码如下:
<uses-permission android:name="android.permission.CAMERA" >
</uses-permission>
<uses-permission android:name="android.permission.RECORD_AUDIO" >
</uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
</uses-permission>