Android 錄視頻可切換攝像頭,記錄時間,一分鐘小於5M,

本demo自定義控件實現視頻錄製,可切換攝像頭,記錄錄製時間,測試錄製一分鐘小於5M。
完整demo下載地址:http://download.csdn.net/detail/bnm52007/9594709

自定義MovieRecorder

package record.lip.com.videoDemo;

import java.io.File;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
/**
* 視頻錄製控件
*
* @author lip
* @date 2015-3-16
*/
public class MovieRecorderView extends LinearLayout implements OnErrorListener {

private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private ProgressBar mProgressBar;
private MediaRecorder mMediaRecorder;
private Camera mCamera;
private Timer mTimer;// 計時器
private OnRecordFinishListener mOnRecordFinishListener;// 錄製完成回調接口

private int mWidth;// 視頻分辨率寬度
private int mHeight;// 視頻分辨率高度
private boolean isOpenCamera;// 是否一開始就打開攝像頭
private int mRecordMaxTime;// 一次拍攝最長時間
private int mTimeCount;// 時間計數
private File mVecordFile = null;// 文件
public int mark = Camera.CameraInfo.CAMERA_FACING_BACK;
private TextView timer;
//記錄錄製時間
Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        if (1 == msg.what) {
            mTimeCount = (int) msg.obj;
            if (mTimeCount > 9) {
                timer.setText("00:" + mTimeCount);
            } else {
                timer.setText("00:0" + mTimeCount);
            }
        }
    }
};

public MovieRecorderView(Context context) {
    this(context, null);
}

public MovieRecorderView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}


@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public MovieRecorderView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    mWidth = 1280;
    mHeight = 720;
    isOpenCamera = true;
    mRecordMaxTime = 60;

    LayoutInflater.from(context).inflate(R.layout.moive_recorder_view, this);
    mSurfaceView = (SurfaceView) findViewById(R.id.surfaceview);
    mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
    timer = (TextView) findViewById(R.id.timer);
    mProgressBar.setMax(mRecordMaxTime);// 設置進度條最大量
    mSurfaceHolder = mSurfaceView.getHolder();
    mSurfaceHolder.addCallback(new CustomCallBack());
    mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

/**
 * @date 2015-2-5
 */
private class CustomCallBack implements Callback {

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (!isOpenCamera){
            return;
        }
        try {
            initCamera(mark);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (!isOpenCamera)
            return;
        freeCameraResource();
    }

}

/**
 * 初始化攝像頭
 *
 * @throws IOException
 * @author lip
 * @date 2015-3-16
 */
private void initCamera(int mark) throws IOException {
    if (mCamera != null) {
        freeCameraResource();
    }
    try {
        mCamera = Camera.open(mark);
    } catch (Exception e) {
        e.printStackTrace();
        freeCameraResource();
    }
    if (mCamera == null) {
        return;
    }
    setCameraParams();
    mCamera.setDisplayOrientation(90);
    mCamera.setPreviewDisplay(mSurfaceHolder);
    mCamera.startPreview();
    mCamera.unlock();
}

/**
 * 設置攝像頭爲豎屏
 *
 * @author lip
 * @date 2015-3-16
 */
private void setCameraParams() {
    if (mCamera != null) {
        Parameters params = mCamera.getParameters();
        params.set("orientation", "portrait");
        mCamera.setParameters(params);
    }
}

/**
 * 釋放攝像頭資源
 *
 * @date 2015-2-5
 */
private void freeCameraResource() {
    if (mCamera != null) {
        mCamera.setPreviewCallback(null);
        mCamera.stopPreview();
        mCamera.lock();
        mCamera.release();
        mCamera = null;
    }
}

private void createRecordDir() {
    // File sampleDir = new File(Environment.getExternalStorageDirectory() + File.separator + "im/video/");
    File sampleDir = new File(Environment.getExternalStorageDirectory() + File.separator + "RecordVideo/");
    //File sampleDir = new File("/video/");
    if (!sampleDir.exists()) {
        sampleDir.mkdirs();
    }
    File vecordDir = sampleDir;
    // 創建文件
    try {
        mVecordFile = File.createTempFile("recording", ".mp4", vecordDir);//mp4格式
        //LogUtils.i(mVecordFile.getAbsolutePath());
        Log.d("Path:", mVecordFile.getAbsolutePath());
    } catch (IOException e) {
    }
}

/**
 * 初始化
 *
 * @throws IOException
 * @author lip
 * @date 2015-3-16
 */
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
private void initRecord() throws IOException {
    mMediaRecorder = new MediaRecorder();
    mMediaRecorder.reset();
    if (mCamera != null)
        mMediaRecorder.setCamera(mCamera);
    mMediaRecorder.setOnErrorListener(this);
    mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
    mMediaRecorder.setVideoSource(VideoSource.CAMERA);// 視頻源
    mMediaRecorder.setAudioSource(AudioSource.MIC);// 音頻源
    mMediaRecorder.setOutputFormat(OutputFormat.MPEG_4);// 視頻輸出格式
    mMediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB);// 音頻格式
    mMediaRecorder.setVideoSize(mWidth, mHeight);// 設置分辨率:

// mMediaRecorder.setVideoFrameRate(16);// 這個我把它去掉了,感覺沒什麼用
mMediaRecorder.setVideoEncodingBitRate(1 * 1024 * 512);// 設置幀頻率,然後就清晰了
if (mark == Camera.CameraInfo.CAMERA_FACING_BACK) {
mMediaRecorder.setOrientationHint(90);// 輸出旋轉90度,保持豎屏錄製
} else {
mMediaRecorder.setOrientationHint(270);//前置攝像頭
}
mMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);// 視頻錄製格式
// mediaRecorder.setMaxDuration(Constant.MAXVEDIOTIME * 1000);
mMediaRecorder.setOutputFile(mVecordFile.getAbsolutePath());
mMediaRecorder.prepare();
try {
mMediaRecorder.start();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}

/**
 * 開始錄製視頻
 *
 * @param onRecordFinishListener 達到指定時間之後回調接口
 * @date 2015-2-5
 * //     * @param fileName
 * //     *            視頻儲存位置
 */
public void record(final OnRecordFinishListener onRecordFinishListener, final int mark) {
    this.mOnRecordFinishListener = onRecordFinishListener;
    createRecordDir();
    try {
        if (!isOpenCamera) {
            initCamera(mark); // 如果未打開攝像頭,則打開
        }
        initRecord();
        mTimeCount = 0;// 時間計數器重新賦值
        mTimer = new Timer();
        mTimer.schedule(new TimerTask() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                mTimeCount++;
                Message message = new Message();
                message.what = 1;
                message.obj = mTimeCount;
                handler.sendMessage(message);
                mProgressBar.setProgress(mTimeCount);// 設置進度條
                if (mTimeCount == mRecordMaxTime) {// 達到指定時間,停止拍攝
                    stop();
                    if (mOnRecordFinishListener != null)
                        mOnRecordFinishListener.onRecordFinish();
                }
            }
        }, 0, 1000);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

/**
 * 停止拍攝
 *
 * @date 2015-2-5
 */
public void stop() {
    stopRecord();
    releaseRecord();
    freeCameraResource();
}

/**
 * 停止錄製
 *
 * @date 2015-2-5
 */
public void stopRecord() {
    mProgressBar.setProgress(0);
    if (mTimer != null)
        mTimer.cancel();
    if (mMediaRecorder != null) {
        // 設置後不會崩
        mMediaRecorder.setOnErrorListener(null);
        mMediaRecorder.setPreviewDisplay(null);
        try {
            mMediaRecorder.stop();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (RuntimeException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

/**
 * 釋放資源
 *
 * @date 2015-2-5
 */
private void releaseRecord() {
    if (mMediaRecorder != null) {
        mMediaRecorder.setOnErrorListener(null);
        try {
            mMediaRecorder.release();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    mMediaRecorder = null;
}

public int getTimeCount() {
    return mTimeCount;
}

/**
 * @return the mVecordFile
 */
public File getmVecordFile() {
    return mVecordFile;
}

/**
 * 錄製完成回調接口
 *
 * @author lip
 * @date 2015-3-16
 */
public interface OnRecordFinishListener {
    public void onRecordFinish();
}

@Override
public void onError(MediaRecorder mr, int what, int extra) {
    try {
        if (mr != null)
            mr.reset();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void switchover() {
    stop();
    if (mark == Camera.CameraInfo.CAMERA_FACING_BACK) {
        mark = Camera.CameraInfo.CAMERA_FACING_FRONT;
        try {
            initCamera(mark);
        } catch (IOException e) {
            e.printStackTrace();
        }
    } else {
        mark = Camera.CameraInfo.CAMERA_FACING_BACK;
        try {
            initCamera(mark);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

MainActivity調用
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
initEvents();
init();
}
private void init()
{
player=new MediaPlayer();
}
private void initViews()
{
movieRV=(MovieRecorderView)findViewById(R.id.moive_rv);
//錄製
startBtn=(Button)findViewById(R.id.start_btn);
stopBtn=(Button)findViewById(R.id.stop_btn);
//切換攝像頭
switchover = (Button) findViewById(R.id.switchover);
}

private void initEvents()
{
    //開始錄製
    startBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            movieRV.record(new MovieRecorderView.OnRecordFinishListener() {
                @Override
                public void onRecordFinish() {

                }
            }, Camera.CameraInfo.CAMERA_FACING_BACK);
        }
    });

    //停止錄製
    stopBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            movieRV.stop();
        }
    });

    //切換攝像頭
    switchover.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            movieRV.stop();
            movieRV.switchover();
        }
    });
}

@Override
protected void onStop() {
    super.onStop();
    movieRV.stop();
}

佈局

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章