使用MediaRecorder录制视频,并进行播放

    自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();
	}
}

此类实现了三个接口,第一个接口SurfaceHolder.Callback用于接收表明Surface已准备好显示视频图像的标志。正本程序中,Surface来自VideoView.我们还希望 被告知是否有任何来自MediaRecorder的消息,这正是我们同时实现了OnInfoListener和OnErrorListener的原因。


在onResume()中,我们仅将按钮设置为初始化的状态,然后初始化照相机。在onPause()中,我们需要同时释放MediaRecorder和Camera.这样,任何时候应用程序退出视图,都会停止录制并释放照相机,使另一个应用程序可使用它。如果用户返回到应用程序,应用程序将重新启动,用户将能够再次录制视频。接下来照相机、Surface.Callback回调,以及Camera和MediaRecorder释放方法的初始化方法。


代码链接:http://download.csdn.net/detail/tan313/8831513

你可能感兴趣的:(使用MediaRecorder录制视频,并进行播放)