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() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubif (!mStartedFlg) {// Startif (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 formatmRecorder.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 {// stopif (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; }@Overridepublic 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");}@Overridepublic void surfaceCreated(SurfaceHolder holder) {// TODO Auto-generated method stub// 將holder,這個holder為開始在onCreate裡面取得的holder,將它賦給mSurfaceHolder mSurfaceHolder = holder; Log.d(TAG, "surfaceChanged 2");}@Overridepublic 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>