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>