自Android SDK 1.6 开始,录制视频需要将照相机所看到的内容预览到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"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <Button android:id="@+id/initBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Initialize Recorder" android:onClick="doClick" android:enabled="false" /> <Button android:id="@+id/beginBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Begin Recording" android:onClick="doClick" android:enabled="false" /> <Button android:id="@+id/stopBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Stop Recording" android:onClick="doClick" /> <Button android:id="@+id/playRecordingBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Play Recording" android:onClick="doClick" /> <Button android:id="@+id/stopPlayingRecordingBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Stop Playing" android:onClick="doClick" /> </LinearLayout> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/recording" android:text=" " android:textColor="#0000ff" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <VideoView android:id="@+id/videoView" android:layout_width="250dp" android:layout_height="200dp" /> </LinearLayout> </LinearLayout>
布局为一个LinearLayout中包含两个并排的LinearLayout.左侧是应用程序将在演示过程中启用和禁用的5个按钮。右侧是主要的VideoView,在它之上是Recording消息。在清单文件中设置android:screenOrientation="landscape"特性,强制此应用处于横向模式。
package com.example.recordvideo; import java.io.File; import java.io.IOException; import android.app.Activity; import android.hardware.Camera; import android.media.MediaRecorder; import android.media.MediaRecorder.OnErrorListener; import android.media.MediaRecorder.OnInfoListener; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.SurfaceHolder; import android.view.View; import android.widget.Button; import android.widget.MediaController; import android.widget.TextView; import android.widget.Toast; import android.widget.VideoView; public class MainActivity extends Activity implements SurfaceHolder.Callback, OnInfoListener, OnErrorListener{ private static final String TAG = "RecordVideo"; private MediaRecorder mRecorder = null; private SurfaceHolder mHoler = null; private String mOutputFileName; private VideoView mVideoView; private Button mInitBtn = null; private Button mStartBtn = null; private Button mStopBtn = null; private Button mPlayBtn = null; private Button mStopPlayBtn = null; private Camera mCamera = null; private TextView mRecordingMsg = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); InitViews(); } private void InitViews() { mInitBtn = (Button) findViewById(R.id.initBtn); mStartBtn = (Button) findViewById(R.id.beginBtn); mStopBtn = (Button) findViewById(R.id.stopBtn); mPlayBtn = (Button) findViewById(R.id.playRecordingBtn); mStopPlayBtn = (Button) findViewById(R.id.stopPlayingRecordingBtn); mRecordingMsg = (TextView) findViewById(R.id.recording); mVideoView = (VideoView) findViewById(R.id.videoView); } @Override protected void onResume() { Log.v("TAG", "in onResume"); super.onResume(); //设置不可点击 mInitBtn.setEnabled(false); mStartBtn.setEnabled(false); mStopBtn.setEnabled(false); mPlayBtn.setEnabled(false); mStopPlayBtn.setEnabled(false); if(!initCamera()) { finish(); } } @Override protected void onPause() { Log.v("TAG", "in onPause"); super.onPause(); releaseRecorder(); releaseCamera(); } private void releaseCamera() { if(mCamera != null) { try { mCamera.reconnect(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } mCamera.release(); mCamera = null; } } private void releaseRecorder() { if(mRecorder != null) { mRecorder.release(); mRecorder = null; } } private boolean initCamera() { Toast.makeText(MainActivity.this, "初始化中...", Toast.LENGTH_SHORT).show(); try { mCamera = Camera.open(); Camera.Parameters camParams = mCamera.getParameters(); mCamera.lock(); mHoler = mVideoView.getHolder(); mHoler.addCallback(this); mHoler.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } catch (Exception e) { Log.v("TAG", "Could not initialize the Camera"); e.printStackTrace(); return false; } return true; } public void doClick(View v) { switch (v.getId()) { case R.id.initBtn: Toast.makeText(MainActivity.this, "点击初始化按钮了..", Toast.LENGTH_SHORT).show(); initRecorder(); break; case R.id.beginBtn: Toast.makeText(MainActivity.this, "开始录制...", Toast.LENGTH_SHORT).show(); beaginRecording(); break; case R.id.stopBtn: Toast.makeText(MainActivity.this, "停止录制...", Toast.LENGTH_SHORT).show(); stopRecording(); break; case R.id.playRecordingBtn: Toast.makeText(MainActivity.this, "开始播放录制视频..", Toast.LENGTH_SHORT).show(); playRecording(); break; case R.id.stopPlayingRecordingBtn: Toast.makeText(MainActivity.this, "停止播放录制视频..", Toast.LENGTH_SHORT).show(); stopPlayingRecording(); break; } } private void stopPlayingRecording() { mVideoView.stopPlayback(); } private void playRecording() { MediaController mc = new MediaController(this); mVideoView.setMediaController(mc); mVideoView.setVideoPath(mOutputFileName); mVideoView.start(); mStopPlayBtn.setEnabled(true); } private void stopRecording() { if(mRecorder != null) { mRecorder.setOnErrorListener(null); mRecorder.setOnInfoListener(null); try { mRecorder.stop(); } catch (IllegalStateException e) { Log.v("", "在停止录制发生错误..."); e.printStackTrace(); } releaseRecorder(); mRecordingMsg.setText(""); releaseCamera(); mStartBtn.setEnabled(false); mStopBtn.setEnabled(false); mPlayBtn.setEnabled(true); } } private void beaginRecording() { mRecorder.setOnInfoListener(this); mRecorder.setOnErrorListener(this);//以上两个接口是用来被告知是否有任何来自MediaRecorder的消息 mRecorder.start();//开始录制 mRecordingMsg.setText("正在录制中..."); mStartBtn.setEnabled(false); mStopBtn.setEnabled(true); } private void initRecorder() { if(mRecorder != null)return; mOutputFileName = Environment.getExternalStorageDirectory()+"/test.mp4"; File outFile = new File(mOutputFileName); if(outFile.exists()) { outFile.delete(); } try { mCamera.stopPreview(); mCamera.unlock(); mRecorder = new MediaRecorder(); mRecorder.setCamera(mCamera); mRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mRecorder.setVideoSize(176, 144); mRecorder.setVideoFrameRate(15); mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP); mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); mRecorder.setMaxDuration(7000); mRecorder.setPreviewDisplay(mHoler.getSurface()); mRecorder.setOutputFile(mOutputFileName); System.out.println("1"); mRecorder.prepare(); System.out.println("2"); Log.v("TAG", "MediaRecorder initialized"); mInitBtn.setEnabled(false); mStartBtn.setEnabled(true); System.out.println("2"); } catch (Exception e) { Log.v("TAG", "MediaRecorder failed to initialize"); e.printStackTrace(); } } @Override public void onInfo(MediaRecorder mr, int what, int extra) { Log.i("TAG", "得到一个录制事件"); if(what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) { Log.i("TAG", "...max duration reached"); stopRecording(); Toast.makeText(MainActivity.this, "录制时限已经到了,即将停止录制...", Toast.LENGTH_SHORT).show(); } } @Override public void surfaceCreated(SurfaceHolder holder) { Log.v("TAG", "in sufaceCreated"); try { mCamera.setPreviewDisplay(mHoler); mCamera.startPreview(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } mInitBtn.setEnabled(true); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.v("TAG", "surfaceChanged:Width x Height = "+width + "x" +height); } @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.v("TAG", "in surfaceDestroyed"); } @Override public void onError(MediaRecorder mr, int what, int extra) { Log.e("TAG", "录制发生错误.."); stopRecording(); Toast.makeText(MainActivity.this, "录制发生错误...", Toast.LENGTH_SHORT).show(); } }
在onResume()中,我们仅将按钮设置为初始化的状态,然后初始化照相机。在onPause()中,我们需要同时释放MediaRecorder和Camera.这样,任何时候应用程序退出视图,都会停止录制并释放照相机,使另一个应用程序可使用它。如果用户返回到应用程序,应用程序将重新启动,用户将能够再次录制视频。接下来照相机、Surface.Callback回调,以及Camera和MediaRecorder释放方法的初始化方法。
代码链接:http://download.csdn.net/detail/tan313/8831513