Android仿微信錄制小視頻
更新時間:2018年05月07日 17:13:42 作者:Anro丶
這篇文章主要為大家詳細介紹了Android仿微信錄制小視頻,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
本文實例為大家分享了Android仿微信錄制小視頻的具體代碼,供大家參考,具體內(nèi)容如下
先上張圖片看看效果

簡單敘述下
- 首先通過Camera類調(diào)用系統(tǒng)相機
- 通過surfaceview繪制出來
- 通過MediaRecorder來錄制視頻
- 閃光燈 和 切換攝像頭 需要重新配置Camera的參數(shù)
- Camera預覽界面畫面拉升的原因是因為Surfaceview的大小與設定的比例不一致的
**本次版本更新了 切換前置攝像頭錄制視頻問題
Android部分手機錄制視頻適配IOS手機問題 (OPPO手機部分不適配 目前啟用的H264格式)**
完整的代碼
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.hardware.Camera;
import android.media.MediaMetadataRetriever;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.tongxun.atongmu.dialog.CommonDialog;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class CircleViedoActivity extends Activity implements View.OnClickListener,MediaRecorder.OnErrorListener {
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private ProgressBar mProgressBar;
private Button shoot_button;
private ImageView circle_light_btn;
private ImageView circle_change_camera_btn;
private TextView circle_camera_time;
private MediaRecorder mMediaRecorder;
private Camera mCamera;
private Timer mTimer;// 計時器
private OnRecordFinishListener mOnRecordFinishListener;// 錄制完成回調(diào)接口
private int mWidth;// 視頻分辨率寬度
private int mHeight;// 視頻分辨率高度
private boolean isOpenCamera;// 是否一開始就打開攝像頭
private int mRecordMaxTime;// 一次拍攝最長時間
private int mTimeCount;// 時間計數(shù)
private int mNumberOfCameras=0;//手機攝像頭的數(shù)量
Bitmap bitmap;//圖片縮略圖
private int screenWidth;
public static File mVecordFile = null;// 文件
private boolean isOpenFlash=false;
private boolean isBackCamera=true;
private int mbackCamera;
private int mfrontCamera;
private CommonDialog commonDialog;
private static final int MOVICE_SUCCESS=1000;//錄制完成
private static final int MOVICE_FILE=1001;//錄制失敗
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_super_video);
init_datas();
init_view();
set_datas();
init_event();
}
private void init_datas() {
isOpenCamera=true;//默認一開始就打開相機
mRecordMaxTime=10;//設置錄制的時間
//獲取手機攝像頭的數(shù)量
Camera.CameraInfo cameraInfo=new Camera.CameraInfo();
mNumberOfCameras=Camera.getNumberOfCameras();
for(int camidx=0;camidx<mNumberOfCameras;camidx++){
Camera.getCameraInfo(camidx, cameraInfo);
if(cameraInfo.facing==Camera.CameraInfo.CAMERA_FACING_BACK){
mbackCamera=camidx;
}else if(cameraInfo.facing==Camera.CameraInfo.CAMERA_FACING_FRONT){
mfrontCamera=camidx;
}
}
}
private void init_view() {
mWidth=640;
mHeight=480;
//獲取屏幕的寬度
screenWidth = getWindowManager().getDefaultDisplay().getWidth();
mSurfaceView = (SurfaceView) findViewById(R.id.surfaceview);//預覽界面
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);//進度條
shoot_button = (Button) findViewById(R.id.shoot_button);//拍攝按鈕
circle_camera_time= (TextView) findViewById(R.id.circle_camera_time);
circle_change_camera_btn= (ImageView) findViewById(R.id.circle_change_camera_btn);//切換攝像頭
circle_light_btn= (ImageView) findViewById(R.id.circle_light_btn);//開啟閃光燈
ViewGroup.LayoutParams params=mSurfaceView.getLayoutParams();
params.height=(screenWidth*4)/3;
params.width=screenWidth;
mSurfaceView.setLayoutParams(params);
top_model2_left_img= (ImageView)findViewById(R.id.top_model2_left_img);
top_model2_left_img.setOnClickListener(this);
top_model2_right_img= (ImageView)findViewById(R.id.top_model2_right_img);
top_model2_right_img.setVisibility(View.INVISIBLE);
top_model2_txt= (TextView)findViewById(R.id.top_model2_txt);
top_model2_txt.setText("視頻錄制");
}
private void set_datas() {
mSurfaceHolder = mSurfaceView.getHolder();
mProgressBar.setMax(mRecordMaxTime);// 設置進度條最大量
mSurfaceHolder.setKeepScreenOn(true);//設置屏幕常亮
mSurfaceHolder.addCallback(new CustomCallBack());
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
circle_camera_time.setText("");
}
private void init_event() {
circle_light_btn.setOnClickListener(this);
circle_change_camera_btn.setOnClickListener(this);
shoot_button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
record(new OnRecordFinishListener() {
@Override
public void onRecordFinish() {
//錄制時間達到最大值
handler.sendEmptyMessage(MOVICE_SUCCESS);
}
});
} else if (event.getAction() == MotionEvent.ACTION_UP) {
if (mTimeCount > 1 && mTimeCount<10) { //防止達到最大值up事件
//錄制時間大于一秒
handler.sendEmptyMessage(MOVICE_SUCCESS);
} else if(mTimeCount<=1) {
//刪除小于一秒的視頻
if (getmVecordFile() != null) {
getmVecordFile().delete();
}
handler.sendEmptyMessage(MOVICE_FILE);
}
}
return true;
}
});
}
@Override
protected void onResume() {
super.onResume();
if(mCamera!=null){
freeCameraResource();
}
try {
initCamera();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// mRecorderView.stop();
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
//停止拍攝
stopRecord();
switch (msg.what){
case MOVICE_SUCCESS:
String msgs = "確認上傳嗎?";
commonDialog = new CommonDialog(CircleViedoActivity.this, new CommonDialog.GoCommonDialog() {
@Override
public void go() {
finishActivity();
commonDialog.dismiss();
}
@Override
public void cancel() {
//刪除沒有上傳的視頻
if (getmVecordFile() != null) {
getmVecordFile().delete();
}
commonDialog.dismiss();
}
}, msgs, "確定", "取消");
commonDialog.show();
break;
case MOVICE_FILE:
Toast.makeText(CircleViedoActivity.this, "視頻錄制時間太短", Toast.LENGTH_SHORT).show();
break;
}
}
};
private void finishActivity() {
stop();
Bitmap bitmap = null;
if (getmVecordFile() != null) {
//得到文件 File類型
File mfile = getmVecordFile();
bitmap = getVideoThumbnail(mfile.toString());
}
/**
* 部分Android手機縮略圖拉不到,找到一種解決辦法不是太滿意 有沒有大神提供思路
*/
// VideoPlayerActivity.startActivity(this, mRecorderView.getVecordFile().toString());
Intent intent = new Intent();
intent.putExtra("bitmap",bitmap);
setResult(RESULT_OK,intent);
finish();
}
@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();
}
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.circle_light_btn:
//開啟關閉閃光燈 默認關閉
if(isOpenFlash){
isOpenFlash=false;
circle_light_btn.setImageResource(R.drawable.camera_light);
}else {
isOpenFlash=true;
circle_light_btn.setImageResource(R.drawable.camera_no_light);
}
try {
initCamera();
} catch (IOException e) {
e.printStackTrace();
}
break;
case R.id.circle_change_camera_btn:
if(isBackCamera){
isBackCamera=false;
}else {
isBackCamera=true;
}
try {
initCamera();
} catch (IOException e) {
e.printStackTrace();
}
break;
case R.id.top_model2_left_img:
stop();
finish();
break;
}
}
private class CustomCallBack implements SurfaceHolder.Callback {
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (!isOpenCamera)
return;
try {
initCamera();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
/**
* 初始化攝像頭
*/
private void initCamera() throws IOException {
if (mCamera != null) {
freeCameraResource();
}
try {
if(isBackCamera){
mCamera = Camera.open(mbackCamera);//打開后攝像頭
setCameraParams(isOpenFlash);
}else {
mCamera=Camera.open(mfrontCamera);//打開前攝像頭
}
} catch (Exception e) {
e.printStackTrace();
freeCameraResource();
}
if (mCamera == null)
return;
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
mCamera.unlock();
}
/**
* 設置攝像頭為豎屏
*/
private void setCameraParams(Boolean isOpenFlash) {
if (mCamera != null) {
Camera.Parameters params = mCamera.getParameters();
//獲取預覽的各種分辨率
List<Camera.Size> supportedPreviewSizes = params.getSupportedPreviewSizes();
params.set("orientation", "portrait");//豎屏錄制
params.setPreviewSize(mWidth, mHeight);//默認640*480
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);//持續(xù)對焦
if(isBackCamera){
if(isOpenFlash){
//開啟閃光燈
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
}else {
//關閉閃光燈
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
}
}else {
}
mCamera.setParameters(params);
}
}
/**
* 釋放攝像頭資源
*/
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 + "ATOMImg/video/");
if (!sampleDir.exists()) {
sampleDir.mkdirs();
}
File vecordDir = sampleDir;
// 創(chuàng)建文件
try {
mVecordFile = File.createTempFile("recording", ".mp4", vecordDir);//mp4格式
} catch (IOException e) {
}
}
/**
* 初始化
*/
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(MediaRecorder.VideoSource.CAMERA);// 視頻源
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 音頻源
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);// 視頻輸出格式
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);// 音頻格式
mMediaRecorder.setVideoSize(mWidth, mHeight);// 設置分辨率:
// mMediaRecorder.setVideoFrameRate(16);// 這個我把它去掉了,感覺沒什么用
mMediaRecorder.setVideoEncodingBitRate(1 * 1024 * 1024);// 設置幀頻率,然后就清晰了
if(isBackCamera) {
mMediaRecorder.setOrientationHint(90);// 輸出旋轉(zhuǎn)90度,保持豎屏錄制
}else {
mMediaRecorder.setOrientationHint(270);
}mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);// 視頻錄制格式
----------
/**
這里是配置攝像頭的重點 因為我們錄制視頻需要適配IOS開發(fā)和Android不同版本的手機 而IOS和Android通配的視頻格式不多 我們這里采用H264格式 它的兼容范圍更廣闊 主要解決的就是部分OPPO手機不適配問題
*/
----------
// 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();
}
}
/**
* 錄制完成回調(diào)接口
*/
public interface OnRecordFinishListener {
public void onRecordFinish();
}
/**
* 錄制
* @param onRecordFinishListener
*/
public void record(final OnRecordFinishListener onRecordFinishListener) {
this.mOnRecordFinishListener = onRecordFinishListener;
createRecordDir();//創(chuàng)建目錄
try {
if (!isOpenCamera)// 如果未打開攝像頭,則打開
initCamera();//初始化攝像頭
initRecord();//初始化錄制參數(shù)
mTimeCount = 0;// 時間計數(shù)器重新賦值
mTimer = new Timer();//創(chuàng)建一個定時器
mTimer.schedule(new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
mTimeCount++;
mProgressBar.setProgress(mTimeCount);// 設置進度條
// handler.sendEmptyMessage(TIME_CHANGW);
runOnUiThread(new Runnable() {
@Override
public void run() {
circle_camera_time.setText(mTimeCount + "″");
}
});
if (mTimeCount == mRecordMaxTime) {// 達到指定時間,停止拍攝
//錄制完成調(diào)用錄制回調(diào)接口
if (mOnRecordFinishListener != null)
mOnRecordFinishListener.onRecordFinish();
}
}
}, 0, 1000);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 停止拍攝
*/
public void stop() {
stopRecord();
releaseRecord();
freeCameraResource();
}
/**
* 停止錄制
*/
public void stopRecord() {
mProgressBar.setProgress(0);
circle_camera_time.setText("");
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();
}
}
}
/**
* 獲取的視頻的位置
* @return
*/
public File getmVecordFile() {
return mVecordFile;
}
/**
* 釋放資源
*/
private void releaseRecord() {
if (mMediaRecorder != null) {
mMediaRecorder.setOnErrorListener(null);
try {
mMediaRecorder.release();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
mMediaRecorder = null;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
stop();
finish();
return false;
}else {
return super.onKeyDown(keyCode, event);
}
}
/**
* 獲取視頻縮略圖
* @param filePath
* @return
*/
public Bitmap getVideoThumbnail(String filePath) {
Bitmap bitmap = null;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
retriever.setDataSource(filePath);
bitmap = retriever.getFrameAtTime();
}
catch(IllegalArgumentException e) {
e.printStackTrace();
}
catch (RuntimeException e) {
e.printStackTrace();
}
finally {
try {
retriever.release();
}
catch (RuntimeException e) {
e.printStackTrace();
}
}
return bitmap;
}
@Override
protected void onDestroy() {
super.onDestroy();
if(bitmap!=null){
try {
bitmap.recycle();
} catch (Exception e) {
e.printStackTrace();
}
bitmap=null;
}
}
}
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
unity3d發(fā)布apk在android虛擬機中運行的詳細步驟(unity3d導出android apk)
這篇文章主要介紹了unity3d發(fā)布apk在android虛擬機中運行的詳細步驟,需要的朋友可以參考下2014-05-05
Android自定義實現(xiàn)循環(huán)滾輪控件WheelView
滾輪布局WheelView大家經(jīng)常使用,比如在選擇生日的時候,風格類似系統(tǒng)提供的DatePickerDialog,這篇文章主要為大家詳細介紹了Android自定義實現(xiàn)循環(huán)滾輪控件WheelView,感興趣的小伙伴們可以參考一下2016-07-07
kotlin android extensions 插件實現(xiàn)示例詳解
這篇文章主要為大家介紹了kotlin android extensions 插件實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10
android自定義popupwindow仿微信右上角彈出菜單效果
這篇文章主要為大家詳細介紹了android自定義popupwindow仿微信右上角彈出菜單效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11

