這個是視頻錄制和拍照功能合到一個頁面的初期版本,有助于更好地理解視頻錄制功能,但可能有預覽黑屏和畫面反轉的問題;
TakePicActivity.java:
package com.haier.uhome.appliance.newVersion.module.messageboard;import android.animation.Animator;import android.animation.ObjectAnimator;import android.app.Activity;import android.content.Intent;import android.graphics.PixelFormat;import android.hardware.Camera;import android.media.MediaRecorder;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.KeyEvent;import android.view.MotionEvent;import android.view.Surface;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.view.ViewGroup;import android.view.ViewTreeObserver;import android.view.animation.LinearInterpolator;import android.widget.Button;import android.widget.FrameLayout;import android.widget.ImageView;import android.widget.RelativeLayout;import android.widget.TextView;import android.widget.Toast;import com.haier.uhome.appliance.R;import com.haier.uhome.appliance.newVersion.module.messageboard.view.CirclePRogressView;import com.haier.uhome.common.util.LogUtil;import java.io.File;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Iterator;import java.util.List;import butterknife.BindView;import butterknife.ButterKnife;import butterknife.OnClick;public class TakePicActivity extends AppCompatActivity { private static final String TAG = "TakePicActivity"; SurfaceView surfaceView; SurfaceHolder surfaceHolder; RelativeLayout rl_btn; @BindView(R.id.fl_content) FrameLayout flContent; //進度條 @BindView(R.id.circleProgress) CircleProgressView circleProgress; @BindView(R.id.iv_turn) ImageView ivTurn; private Camera camera; private Camera.Parameters parameters = null; Bundle bundle = null; // 聲明一個Bundle對象,用來存儲數據 Button takepicture; RelativeLayout rl_playPic; int w, h; protected boolean isPreview; private MediaRecorder mMediaRecorder; private boolean isRecording = true; // true表示沒有錄像,點擊開始;false表示正在錄像,點擊暫停 private File mRecVedioPath; private File mRecAudioFile; //錄制視頻時的計時器 private TextView timer; private int hour = 0; private int minute = 0; private int second = 0; private boolean bool; private Animator animator; private boolean isRecordState = false;//是否是視頻錄制狀態 private int progress; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_take_pic); ButterKnife.bind(this); takepicture = (Button) findViewById(R.id.takepicture); surfaceView = (SurfaceView) this .findViewById(R.id.surfaceView); rl_btn = (RelativeLayout) this.findViewById(R.id.buttonLayout); timer = (TextView) this.findViewById(R.id.show_time); // 設置計時器不可見// timer.setVisibility(View.GONE); // 設置緩存路徑 mRecVedioPath = new File(Environment.getExternalStorageDirectory() .getAbsolutePath() + "/hfdatabase/video/temp/"); if (!mRecVedioPath.exists()) { mRecVedioPath.mkdirs(); } //圓形進度條設置 circleProgress.setBgColor(getResources().getColor(R.color.text_white)); circleProgress.setProgressColor(getResources().getColor(R.color.colorPrimaryDark)); ViewTreeObserver observerCircle = circleProgress.getViewTreeObserver(); observerCircle.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { progress = circleProgress.getmProgress(); return true; } }); surfaceView.getHolder() .setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); surfaceView.getHolder().setFixedSize(176, 144); //設置Surface分辨率 surfaceView.getHolder().setKeepScreenOn(true);// 屏幕常亮 surfaceView.getHolder().addCallback(new SurfaceCallback());//為SurfaceView的句柄添加一個回調函數 //長按錄制 takepicture.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { isRecordState = true; if (isRecording) { /* * 點擊開始錄像 */ if (isPreview) { camera.stopPreview(); camera.release(); camera = null; } second = 0; minute = 0; hour = 0; bool = true; if (mMediaRecorder == null) mMediaRecorder = new MediaRecorder(); else mMediaRecorder.reset(); //拍攝視頻時的相機配置 if (camera != null) { freeCameraResource(); } camera = Camera.open(); camera.setDisplayOrientation(90); camera.startPreview(); camera.unlock(); mMediaRecorder.setCamera(camera); mMediaRecorder.setOnErrorListener(null); mMediaRecorder.setPreviewDisplay(surfaceHolder.getSurface()); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); mMediaRecorder.setMaxDuration(60 * 1000); mMediaRecorder.setVideoSize(320, 240); mMediaRecorder.setVideoEncodingBitRate(1 * 1024 * 1024);// 設置幀頻率,然后就清晰了// mMediaRecorder.setVideoFrameRate(15); mMediaRecorder.setOrientationHint(getPreviewDegree(TakePicActivity.this));// 輸出旋轉90度,保持豎屏錄制 try { mRecAudioFile = File.createTempFile("Vedio", ".mp4", mRecVedioPath); } catch (IOException e) { e.printStackTrace(); } mMediaRecorder.setOutputFile(mRecAudioFile.getAbsolutePath()); try { mMediaRecorder.prepare(); timer.setVisibility(View.VISIBLE); handler.postDelayed(task, 1000); mMediaRecorder.start(); } catch (Exception e) { e.printStackTrace(); } showMsg("開始錄制");// scalePic.setBackgroundDrawable(iconStop); isRecording = !isRecording; recordAnimater(); } return false; } }); takepicture.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_UP: Log.d(TAG, "onTouch: takepicture==setOnTouchListener==ACTION_UP"); if(isRecordState){ if(second < 1){// showMsg("錄制時間太短"); Toast.makeText(TakePicActivity.this, "錄制時間太短", Toast.LENGTH_SHORT).show();// animator.cancel(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if(animator.isRunning()){ animator.end(); }// mMediaRecorder.setOnErrorListener(null);// mMediaRecorder.setPreviewDisplay(null);// mMediaRecorder.stop();// mMediaRecorder.reset(); }else{ if(animator.isRunning()){ animator.end(); } } } break; } return false; } }); } protected void onResume() { super.onResume(); timer.setVisibility(View.GONE); circleProgress.setVisibility(View.GONE); isRecordState = false; } /* * 視頻錄制時的進度條動畫 * */ public void recordAnimater() { //設置進度條 startAnimator(); animator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { Log.i("animator", "stop"); /* * 點擊停止 */ try { bool = false;// isRecordState = false; mMediaRecorder.stop(); timer.setText(format(hour) + ":" + format(minute) + ":" + format(second)); mMediaRecorder.release(); mMediaRecorder = null; //錄制完成后播放攝像頭 freeCameraResource(); videoRename(); } catch (Exception e) { e.printStackTrace(); } isRecording = !isRecording;// scalePic.setBackgroundDrawable(iconStart); showMsg("錄制完成,已保存");// Intent backIntent = new Intent();// backIntent.putExtra("path", mrv_wx.mVecordFile.getAbsoluteFile().toString());// setResult(RESULT_OK, backIntent);// finish(); Intent displayIntent = new Intent(TakePicActivity.this, ShowPicActivity.class); bundle = new Bundle(); bundle.putBoolean("isRecord", isRecordState); bundle.putString("video_path", out.getAbsolutePath()); displayIntent.putExtras(bundle); startActivity(displayIntent); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); } @OnClick(R.id.iv_turn) public void onClick() { } private final class SurfaceCallback implements SurfaceHolder.Callback { @Override public void surfaceCreated(SurfaceHolder holder) { try { if (camera != null) { freeCameraResource(); } camera = Camera.open(); // 打開攝像頭 parameters = camera.getParameters(); //加這句小米手機會黑屏// parameters.setPreviewFrameRate(5); // 每秒5幀 parameters.setPictureFormat(PixelFormat.JPEG);// 設置照片的輸出格式 parameters.set("jpeg-quality", 85);// 照片質量 int PreviewWidth = 0; int PreviewHeight = 0; // 選擇合適的預覽尺寸 List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes(); // 如果sizeList只有一個我們也沒有必要做什么了,因為就他一個別無選擇 if (sizeList.size() > 1) { Iterator<Camera.Size> itor = sizeList.iterator(); while (itor.hasNext()) { Camera.Size cur = itor.next(); if (cur.width >= PreviewWidth && cur.height >= PreviewHeight) { PreviewWidth = cur.width; PreviewHeight = cur.height; break; } } } parameters.setPreviewSize(PreviewWidth, PreviewHeight); // 獲得攝像區域的大小 parameters.setPictureSize(PreviewWidth, PreviewHeight); // 獲得保存圖片的大小// parameters.setPreviewSize(320, 240); // 設置預覽大小// parameters.setPictureSize(320,240);// parameters.set("orientation", "portrait"); camera.setParameters(parameters); camera.setPreviewDisplay(holder); // 設置用于顯示拍照影像的SurfaceHolder對象 camera.setDisplayOrientation(getPreviewDegree(TakePicActivity.this)); camera.startPreview(); // 開始預覽 isPreview = true;// camera.autoFocus(null); } catch (Exception e) { e.printStackTrace(); } surfaceHolder = holder; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { surfaceHolder = holder; LogUtil.d(TAG,"surfaceChanged======"); camera.autoFocus(new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) {// camera.setOneShotPreviewCallback(null); initCamera(width, height); camera.cancelAutoFocus();//只有加上了這一句,才會自動對焦。 } }); } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (camera != null) { if (isPreview) { camera.stopPreview(); isPreview = false; } camera.release(); // 釋放照相機 camera = null; } surfaceHolder = null; surfaceView = null; mMediaRecorder = null; } } // 提供一個靜態方法,用于根據手機方向獲得相機預覽畫面旋轉的角度 public static int getPreviewDegree(Activity activity) { // 獲得手機的方向 int rotation = activity.getWindowManager().getDefaultDisplay() .getRotation(); int degree = 0; // 根據手機的方向計算相機預覽畫面應該選擇的角度 switch (rotation) { case Surface.ROTATION_0: degree = 90; break; case Surface.ROTATION_90: degree = 0; break; case Surface.ROTATION_180: degree = 270; break; case Surface.ROTATION_270: degree = 180; break; } return degree; } /** * 按鈕被點擊觸發的事件 * * @param v */ public void btnOnclick(View v) { if (camera != null) { switch (v.getId()) { case R.id.takepicture: // 拍照 camera.takePicture(null, null, new MyPictureCallback()); break; } } } byte[] picData; private final class MyPictureCallback implements Camera.PictureCallback { @Override public void onPictureTaken(byte[] data, Camera camera) { try { bundle = new Bundle(); bundle.putByteArray("bytes", data);//將圖片字節數據保存在bundle中,實現數據交換 picData = data;// saveToSDCard(data);// camera.startPreview();//拍完照后,重新開始預覽 if (bundle == null) { Toast.makeText(getapplicationContext(), "請先拍照", Toast.LENGTH_SHORT).show(); } else { Intent intent = new Intent(); intent.setClass(getApplicationContext(), ShowPicActivity.class); bundle.putBoolean("isRecord", isRecordState); intent.putExtras(bundle); startActivity(intent); } } catch (Exception e) { e.printStackTrace(); } } } public void initCamera(int width, int height) { parameters = camera.getParameters(); // 獲取各項參數 parameters.setPictureFormat(PixelFormat.JPEG); // 設置圖片格式 parameters.setPreviewSize(width, height); // 設置預覽大小// List<Camera.Size> sizes =parameters.getSupportedPreviewSizes();// Camera.Size optimalSize = getOptimalPreviewSize(sizes, 320,240);// parameters.setPreviewSize(optimalSize.width, optimalSize.height); parameters.setPreviewFrameRate(5); //設置每秒顯示4幀 parameters.setPictureSize(width, height); // 設置保存的圖片尺寸 parameters.setJpegQuality(80); // 設置照片質量 parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);//1連續對焦 parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); camera.startPreview(); camera.cancelAutoFocus();// 2如果要實現連續的自動對焦,這一句必須加上 } public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { if (!isRecordState) { camera.autoFocus(new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { if (success) { Log.d("TakePicActivity", "success"); w = (int) event.getX(); h = (int) event.getY();// setLayout(rlFocus,w-50,h-50);// Rect focusRect = calculateTapArea(w,h,100); mHandler.obtainMessage(0).sendToTarget(); initCamera(w, h); camera.cancelAutoFocus();//只有加上了這一句,才會自動對焦。 } } }); } }else if(event.getAction() == MotionEvent.ACTION_UP){ Log.d(TAG, "onTouchEvent: ACTION_UP"); } else if(event.getAction() == MotionEvent.ACTION_MOVE){ Log.d(TAG, "onTouchEvent: ACTION_MOVE"); } return super.onTouchEvent(event); } /* * 覆寫返回鍵監聽 */ @Override public void onBackPressed() { if (mMediaRecorder != null) { mMediaRecorder.stop(); mMediaRecorder.release(); mMediaRecorder = null;// videoRename(); } finish(); } @Override protected void onPause() { super.onPause();// onBackPressed(); if (mMediaRecorder != null) { mMediaRecorder.stop(); mMediaRecorder.release(); mMediaRecorder = null;// videoRename(); } } View view; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 0: flContent.invalidate(); view = new MyView(TakePicActivity.this, w, h); flContent.addView(view); mHandler.sendEmptyMessageDelayed(1, 1000);//使選框停留1秒后消失 break; case 1: flContent.removeView(view); break; } } }; /* * 設置控件所在的位置YY,并且不改變寬高,* XY為絕對位置*/ public void setLayout(View view, int x, int y) { ViewGroup.MarginLayoutParams margin = new ViewGroup.MarginLayoutParams(view.getLayoutParams()); margin.setMargins(x, y, x + margin.width, y + margin.height); RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(margin); view.setLayoutParams(layoutParams); } File out; /* * 生成video文件名字 */ protected void videoRename() { String path = Environment.getExternalStorageDirectory() .getAbsolutePath() + "/hfdatabase/video/0/"; String fileName = new SimpleDateFormat("yyyyMMddHHmmss") .format(new Date()) + ".mp4"; out = new File(path); if (!out.exists()) { out.mkdirs(); } out = new File(path, fileName); if (mRecAudioFile.exists()) mRecAudioFile.renameTo(out); } /* * 消息提示 */ private Toast toast; public void showMsg(String arg) { if (toast == null) { toast = Toast.makeText(this, arg, Toast.LENGTH_SHORT); } else { toast.cancel(); toast.setText(arg); } toast.show(); } /* * 格式化時間 */ public String format(int i) { String s = i + ""; if (s.length() == 1) { s = "0" + s; } return s; } /* * 定時器設置,實現計時 */ private Handler handler = new Handler(); private Runnable task = new Runnable() { public void run() { if (bool) { handler.postDelayed(this, 1000); second++; if (second >= 60) { minute++; second = second % 60; } if (minute >= 60) { hour++; minute = minute % 60; } timer.setText(format(hour) + ":" + format(minute) + ":" + format(second)); } } }; private void startAnimator() { circleProgress.setVisibility(View.VISIBLE); animator = ObjectAnimator.ofInt(circleProgress, "progress", progress); animator.setDuration(60000); animator.setInterpolator(new LinearInterpolator()); animator.start(); } /** * 釋放攝像頭資源 */ private void freeCameraResource() { if (camera != null) { camera.setPreviewCallback(null); camera.stopPreview(); camera.lock(); camera.release(); camera = null; } } @Override protected void onDestroy() { super.onDestroy(); freeCameraResource(); if(mMediaRecorder != null){ mMediaRecorder.release(); mMediaRecorder = null; } }}
新聞熱點
疑難解答