android 相机使用(拍照、录像、图片查看、静态人脸识别、延时拍照)
2017-09-08 22:39
603 查看
相机是我们最常用的手机应用之一,这里只是实现几个简单的功能、拍照、延时拍照、录像、图片查看、静态人脸识别等。
1、这里主要使用surfaceView实现,首先打开摄像头实现预览,在surfaceCreated中添加
关于延时拍照只需加个定时器就可以了具体需要延时多久可根据实际需要设置,下面定时器代码,
3、实现简单摄像功能,主要使用mediaRecorder,录像完保存到跟图片同样路径下,代码中有详细注释
相机功能完整代码
完成后添加权限:
<uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
最后实现的效果图
1、这里主要使用surfaceView实现,首先打开摄像头实现预览,在surfaceCreated中添加
/** * 启动预览 */ private void startPreview() { if (mCamera != null || !mIsSurfaceCreated) { return; } mCamera = Camera.open(0); Camera.Parameters parameters = mCamera.getParameters(); int width = getResources().getDisplayMetrics().widthPixels; int height = getResources().getDisplayMetrics().heightPixels; Camera.Size size = getBestPreviewSize(width, height, parameters); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); parameters.setPreviewFrameRate(20); mCamera.setDisplayOrientation(90); mCamera.setParameters(parameters); try { mCamera.setPreviewDisplay(mHolder); } catch (Exception e) { e.printStackTrace(); } mCamera.startPreview(); }2、实现预览后,实现拍照要先实现Camera.PictureCallback接口,然后使用mCamera.takePicture(null, null, null, MainActivity.this);实现拍照,然后保存到手机上
@Override public void onPictureTaken(byte[] data, Camera camera) { FileOutputStream fos = null; try { String fileName = System.currentTimeMillis() + ".png"; fos = new FileOutputStream(new File(filePath + File.separator + fileName)); videoPath = filePath + File.separator + fileName; Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); Matrix matrix = new Matrix(); matrix.setRotate(90); bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); ivPicture.setImageBitmap(bitmap); new FaceThread(bitmap).start(); fos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); } Toast.makeText(getApplication(), "拍照成功", Toast.LENGTH_SHORT).show(); //拍照后重新预览 mCamera.startPreview(); }
关于延时拍照只需加个定时器就可以了具体需要延时多久可根据实际需要设置,下面定时器代码,
Handler handler = new Handler(); Runnable runnable = new Runnable() { @Override public void run() { // TODO Auto-generated method stub //要做的事情 count++; countDown--; btnDelay.setText(countDown + " s"); handler.postDelayed(this, 1000); if (countDown == 0) { mCamera.takePicture(null, null, null, MainActivity.this); btnDelay.setText("3s"); handler.removeCallbacksAndMessages(null); } tvTime.setText(count + " s"); } };启动定时器代码,当点击3s再点击拍照就可以实现延时拍照功能
handler.postDelayed(runnable, 1000);
3、实现简单摄像功能,主要使用mediaRecorder,录像完保存到跟图片同样路径下,代码中有详细注释
/** * 录像 */ private void videotape() { if (isVideoStart) { count = 0; btnDelay.setVisibility(View.GONE); tvTime.setVisibility(View.VISIBLE); handler.postDelayed(runnable, 1000);//每两秒执行一次runnable. btnVideo.setBackgroundResource(R.drawable.video_recoder); isVideoStart = false; mediarecorder = new MediaRecorder(); mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK); if (mCamera != null) { mCamera.setDisplayOrientation(90); mCamera.unlock(); mediarecorder.setCamera(mCamera); } //设置视频源 mediarecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT); //设置音频源 mediarecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); //设置文件输出格式 mediarecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); //设置视频编码方式 mediarecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); //设置音频编码方式 mediarecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); //设置视频高和宽,注意文档的说明: //Must be called after setVideoSource(). //Call this after setOutFormat() but before prepare(). //设置录制的视频帧率,注意文档的说明: //Must be called after setVideoSource(). //Call this after setOutFormat() but before prepare(). mediarecorder.setVideoSize(800, 480); mediarecorder.setVideoFrameRate(20); mediarecorder.setAudioChannels(2); //设置预览画面 mediarecorder.setPreviewDisplay(mHolder.getSurface()); //设置输出路径 // videoPath = Environment.getExternalStorageDirectory() + File.separator + System.currentTimeMillis() + ".mp4"; videoPath = "/mnt/sdcard/DCIM/Camera" + File.separator + System.currentTimeMillis() + ".mp4"; mediarecorder.setOutputFile(videoPath); try { // 准备录制 mediarecorder.prepare(); // 开始录制 mediarecorder.start(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { tvTime.setText(""); btnDelay.setVisibility(View.VISIBLE); btnDelay.setText("3 s"); //ivPicture.setImageURI(Uri.fromFile(new File(videoPath))); ivPicture.setImageBitmap(getVideoThumbnail(videoPath)); Log.e(TAG, "videoPath=" + videoPath); handler.removeCallbacksAndMessages(null); btnVideo.setBackgroundResource(R.drawable.ic_switch_video); isVideoStart = true; if (mediarecorder != null) { // 停止录制 mediarecorder.stop(); // 释放资源 mediarecorder.release(); mediarecorder = null; } if (mCamera != null) { // mCamera.release(); } Toast.makeText(getApplication(), "视频已保存到" + videoPath + "下", Toast.LENGTH_SHORT).show(); } }4、实现切换前后摄像头
/** * 切换前后摄像头 */ private void changeCamera() { int cameraCount = 0; Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); cameraCount = Camera.getNumberOfCameras();//得到摄像头的个数 for (int i = 0; i < cameraCount; i++) { Camera.getCameraInfo(i, cameraInfo);//得到每一个摄像头的信息 if (cameraPosition == 1) { //现在是后置,变更为前置 //代表摄像头的方位,CAMERA_FACING_FRONT 前置 CAMERA_FACING_BACK后置 if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { mCamera.stopPreview();//停掉原来摄像头的预览 mCamera.release();//释放资源 mCamera = null;//取消原来摄像头 mCamera = Camera.open(i);//打开当前选中的摄像头 try { mCamera.setPreviewDisplay(mHolder);//通过surfaceview显示取景画面 mCamera.setDisplayOrientation(90); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } mCamera.startPreview();//开始预览 cameraPosition = 0; break; } } else { if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { mCamera.stopPreview(); mCamera.release(); mCamera = null; mCamera = Camera.open(i); try { mCamera.setPreviewDisplay(mHolder); mCamera.setDisplayOrientation(90); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } mCamera.startPreview(); cameraPosition = 1; break; } } } }5、实现点击屏幕出现方框聚焦功能,首先我们先写一个自定的view来绘制一个正方形
package com.example.apple.camera.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Typeface; import android.util.AttributeSet; import android.view.View; import com.example.apple.camera.R; /** * */ public class MyView extends View { private Paint mPaint; private Canvas mCanvas; private int x; private int y; private Bitmap mBitmap; public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mPaint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); mPaint.setColor(Color.BLUE); mPaint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); this.mCanvas = canvas; // setDrawRect(400,400); if (mBitmap==null){ mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.border); } Bitmap mm = Bitmap.createScaledBitmap(mBitmap,200,200,true); canvas.drawBitmap(mm,x,y,mPaint); } public void setX(int x) { this.x = x; invalidate(); } public void setY(int y) { this.y = y; invalidate(); } public Bitmap getmBitmap() { return mBitmap; } public void setmBitmap(Bitmap mBitmap) { this.mBitmap = mBitmap; invalidate(); } public void setDrawRect(int x, int y) { Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.border); mCanvas.drawBitmap(mBitmap,x,y,mPaint); } }使用的时候就在onTouchEvent中实现,首先要现在布局中隐藏,当要使用的时候显示出来,再设置要显示的位置,显示位置通过触摸屏幕当前位置来获取,然后当聚焦实现后可以通过定时器来延时几秒消失,这里仅实现聚焦完后就隐藏,这就简单实现了点击聚焦功能
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: focusOnTouch(event); myRect.setVisibility(View.VISIBLE); int x = (int) event.getX(); int y = (int) event.getY(); myRect.setX(x - 100); myRect.setY(y - 300); //Log.e(TAG,"x="+x+" y="+y); mCamera.autoFocus(new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { if (success) { Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.border1); myRect.setmBitmap(mBitmap); myRect.setVisibility(View.GONE); } } }); break; } return super.onTouchEvent(event); }6、设置拍照图片大小,先获取手机支持什么那些规格的,然后再设置,否则可能会出错,不同手机可能不一样
List<Camera.Size> pszize = parameters.getSupportedPictureSizes(); if (null != pszize && 0 < pszize.size()) { int height1[] = new int[pszize.size()]; Map<Integer, Integer> map = new HashMap<Integer, Integer>(); for (int i = 0; i < pszize.size(); i++) { Camera.Size size1 = (Camera.Size) pszize.get(i); int sizeheight = size1.height; int sizewidth = size1.width; height1[i] = sizeheight; map.put(sizeheight, sizewidth); //Log.e(TAG,"size.width="+sizewidth + " size.height="+sizeheight); } Arrays.sort(height1); parameters.setPictureSize(map.get(height1[12]), height1[12]);如果报错可以注释掉设置预览图片大小和设置拍照图片大小
parameters.setPreviewSize(size.width, size.height); // parameters.setPictureSize(size.width, size.height);7、关于设置录像的清晰度和帧率可以设置下面参数
mediarecorder.setVideoSize(800, 480); mediarecorder.setVideoFrameRate(20);8、实现简单的人脸识别,这里只能静态识别,动态识别因为预览回调回来的图片太大,无法处理,可对着一张人脸拍照后可以预览到实际效果,照片会存储到手机上
class FaceThread extends Thread { private Bitmap mBitmap; public FaceThread(Bitmap bitmap) { this.mBitmap = bitmap; } @Override public void run() { FaceDetector.Face[] faces = new FaceDetector.Face[5]; //格式必须为RGB_565才可以识别 Bitmap bitmap = mBitmap.copy(Bitmap.Config.RGB_565, true); final int faceCount = new FaceDetector(bitmap.getWidth(), bitmap.getHeight(), 5).findFaces(bitmap, faces); bitmap.recycle(); if (faceCount > 0) { final Bitmap bmp = parseBitmap(faces, faceCount, mBitmap); runOnUiThread(new Runnable() { @Override public void run() { ivPicture.setImageBitmap(bmp); File file = new File(filePath, System.currentTimeMillis() + ".jpg"); if (file.exists()) { file.delete(); } try { FileOutputStream fo = new FileOutputStream(file); bmp.compress(Bitmap.CompressFormat.JPEG, 90, fo); fo.flush(); fo.close(); } catch (IOException e) { e.printStackTrace(); } } }); } } } /** * 在人脸上画矩形 */ private Bitmap parseBitmap(FaceDetector.Face[] faces, int faceCount, Bitmap mFaceBitmap) { Bitmap bitmap = Bitmap.createBitmap(mFaceBitmap.getWidth(), mFaceBitmap.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setAntiAlias(true); mPaint.setColor(Color.YELLOW); mPaint.setStrokeWidth(5); mPaint.setStyle(Paint.Style.STROKE); canvas.drawBitmap(mFaceBitmap, 0, 0, mPaint); for (int i = 0; i < faceCount; i++) { //双眼的中心点 PointF midPoint = new PointF(); faces[i].getMidPoint(midPoint); //双眼的距离 float eyeDistance = faces[i].eyesDistance(); //画矩形 canvas.drawRect(midPoint.x - eyeDistance, midPoint.y - eyeDistance, midPoint.x + eyeDistance, midPoint.y + eyeDistance, mPaint); myRect.setY(midPoint.x + eyeDistance); myRect.setX(midPoint.y + eyeDistance); } return bitmap; }9、关于拍照后的图片和录制的视频的显示,通过路径查找到所有的文件数据保存,然后传入显示,具体可看代码
/** * 查询获取图片文件 * @param path * @return */ private ArrayList<String> queryImage(String path){ ArrayList<String> filePath = new ArrayList<>(); if (!TextUtils.isEmpty(path)){ File file = new File(path); File[] files = file.listFiles(); if (files!=null){ if (!file.exists()) return null; for (File f : files){ if (getFileType(f)==IMAGE || getFileType(f) == VIDEO){ filePath.add(f.getPath()); } } } } return filePath; } public static int getFileType(File f) { int type = -1; String fileName = f.getName(); String ext = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()).toLowerCase(); if (ext.equals("mp3") || ext.equals("amr") || ext.equals("wma") || ext.equals("aac") || ext.equals("m4a") || ext.equals("mid") || ext.equals("xmf") || ext.equals("ogg") || ext.equals("wav") || ext.equals("qcp") || ext.equals("awb")|| ext.equals("3gpp")|| ext.equals("ape")|| ext.equals("flac")||ext.equals("midi")) { type = MUSIC; } else if (ext.equals("3gp") || ext.equals("avi") || ext.equals("mp4") || ext.equals("3g2") || ext.equals("wmv") || ext.equals("divx") || ext.equals("mkv") || ext.equals("webm") || ext.equals("ts") || ext.equals("asf")|| ext.equals("mov")||ext.equals("mpg")||ext.equals("flv") ) { type = VIDEO; } else if (ext.equals("jpg") || ext.equals("jpeg") || ext.equals("gif") || ext.equals("png") || ext.equals("bmp")||ext.equals("wbmp")) { type = IMAGE; } else if (ext.equals("doc") || ext.equals("docx") || ext.equals("xls") || ext.equals("xlsx") || ext.equals("ppt") || ext.equals("pptx") || ext.equals("txt") || ext.equals("text") || ext.equals("pdf")|| ext.equals("html")) { type = DOC; } else if (ext.equals("rar") || ext.equals("zip") || ext.equals("tar") || ext.equals("gz") || ext.equals("iso") || ext.equals("jar") || ext.equals("cab") || ext.equals("7z") || ext.equals("ace")) { type = ZIP; } else if (ext.equals("apk")) { type = APK; } else { type = OTHER; } return type; }完整代码
package com.example.apple.camera.showpicture; import android.app.Activity; import android.os.Bundle; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; import com.example.apple.camera.R; import com.example.apple.camera.view.ZoomImageView; import java.io.File; import java.util.ArrayList; /** * Created by 550211 on 2017/9/7. */ public class ImageShowActivity extends Activity { private ViewPager mViewPager; private TextView tvFileCount; private ImageView ivPlay; public static final int IMAGE = 0; public static final int VIDEO = 4; public static final int MUSIC = 5; public static final int DOC = 6; public static final int ZIP=7; public static final int APK = 8; public static final int OTHER =9; private ArrayList<String> allImageFile = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_image_show); initView(); } private void initView() { allImageFile = queryImage("/mnt/sdcard/DCIM/Camera"); final ImageView[] mImageViews = new ImageView[allImageFile.size()]; tvFileCount = (TextView)findViewById(R.id.tv_file_count); ivPlay = (ImageView)findViewById(R.id.iv_play); mViewPager = (ViewPager) findViewById(R.id.id_viewpager); mViewPager.setAdapter(new PagerAdapter() { @Override public Object instantiateItem(ViewGroup container, int position) { ZoomImageView imageView = new ZoomImageView(getApplicationContext()); File file = new File(allImageFile.get(position)); Glide.with(getApplication()) .load(file) .centerCrop() .into(imageView); container.addView(imageView); tvFileCount.setText(position+"/"+allImageFile.size()); Log.e("ImageShowActivity","position="+file.getPath()); mImageViews[position] = imageView; if (getFileType(file) == VIDEO){ ivPlay.setVisibility(View.VISIBLE); }else { ivPlay.setVisibility(View.GONE); } return imageView; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(mImageViews[position]); } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public int getCount() { return allImageFile.size(); } }); } /** * 查询获取图片文件 * @param path * @return */ private ArrayList<String> queryImage(String path){ ArrayList<String> filePath = new ArrayList<>(); if (!TextUtils.isEmpty(path)){ File file = new File(path); File[] files = file.listFiles(); if (files!=null){ if (!file.exists()) return null; for (File f : files){ if (getFileType(f)==IMAGE || getFileType(f) == VIDEO){ filePath.add(f.getPath()); } } } } return filePath; } public static int getFileType(File f) { int type = -1; String fileName = f.getName(); String ext = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()).toLowerCase(); if (ext.equals("mp3") || ext.equals("amr") || ext.equals("wma") || ext.equals("aac") || ext.equals("m4a") || ext.equals("mid") || ext.equals("xmf") || ext.equals("ogg") || ext.equals("wav") || ext.equals("qcp") || ext.equals("awb")|| ext.equals("3gpp")|| ext.equals("ape")|| ext.equals("flac")||ext.equals("midi")) { type = MUSIC; } else if (ext.equals("3gp") || ext.equals("avi") || ext.equals("mp4") || ext.equals("3g2") || ext.equals("wmv") || ext.equals("divx") || ext.equals("mkv") || ext.equals("webm") || ext.equals("ts") || ext.equals("asf")|| ext.equals("mov")||ext.equals("mpg")||ext.equals("flv") ) { type = VIDEO; } else if (ext.equals("jpg") || ext.equals("jpeg") || ext.equals("gif") || ext.equals("png") || ext.equals("bmp")||ext.equals("wbmp")) { type = IMAGE; } else if (ext.equals("doc") || ext.equals("docx") || ext.equals("xls") || ext.equals("xlsx") || ext.equals("ppt") || ext.equals("pptx") || ext.equals("txt") || ext.equals("text") || ext.equals("pdf")|| ext.equals("html")) { type = DOC; } else if (ext.equals("rar") || ext.equals("zip") || ext.equals("tar") || ext.equals("gz") || ext.equals("iso") || ext.equals("jar") || ext.equals("cab") || ext.equals("7z") || ext.equals("ace")) { type = ZIP; } else if (ext.equals("apk")) { type = APK; } else { type = OTHER; } return type; } @Override protected void onDestroy() { super.onDestroy(); } }布局实现
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tv_file_count" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.view.ViewPager android:id="@+id/id_viewpager" android:layout_width="fill_parent" android:layout_height="fill_parent"></android.support.v4.view.ViewPager> <ImageView android:id="@+id/iv_play" android:visibility="gone" android:layout_centerInParent="true" android:background="@drawable/ic_gallery_play" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout> </LinearLayout>图片显示view代码
package com.example.apple.camera.view; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Matrix; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.ScaleGestureDetector.OnScaleGestureListener; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewTreeObserver; import android.widget.ImageView; public class ZoomImageView extends ImageView implements OnScaleGestureListener, OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener { private static final String TAG = ZoomImageView.class.getSimpleName(); public static final float SCALE_MAX = 4.0f; private static final float SCALE_MID = 2.0f; /** * 初始化时的缩放比例,如果图片宽或高大于屏幕,此值将小于0 */ private float initScale = 1.0f; private boolean once = true; /** * 用于存放矩阵的9个值 */ private final float[] matrixValues = new float[9]; /** * 缩放的手势检测 */ private ScaleGestureDetector mScaleGestureDetector = null; private final Matrix mScaleMatrix = new Matrix(); /** * 用于双击检测 */ private GestureDetector mGestureDetector; private boolean isAutoScale; private int mTouchSlop; private float mLastX; private float mLastY; private boolean isCanDrag; private int lastPointerCount; private boolean isCheckTopAndBottom = true; private boolean isCheckLeftAndRight = true; public ZoomImageView(Context context) { this(context, null); } public ZoomImageView(Context context, AttributeSet attrs) { super(context, attrs); super.setScaleType(ScaleType.MATRIX); mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener() { @Override public boolean onDoubleTap(MotionEvent e) { if (isAutoScale == true) return true; float x = e.getX(); float y = e.getY(); Log.e("DoubleTap", getScale() + " , " + initScale); if (getScale() < SCALE_MID) { ZoomImageView.this.postDelayed(new AutoScaleRunnable(SCALE_MID, x, y), 16); isAutoScale = true; } else if (getScale() >= SCALE_MID && getScale() < SCALE_MAX) { ZoomImageView.this.postDelayed(new AutoScaleRunnable(SCALE_MAX, x, y), 16); isAutoScale = true; } else { ZoomImageView.this.postDelayed(new AutoScaleRunnable(initScale, x, y), 16); isAutoScale = true; } return true; } }); mScaleGestureDetector = new ScaleGestureDetector(context, this); this.setOnTouchListener(this); } /** * 自动缩放的任务 * * @author zhy */ private class AutoScaleRunnable implements Runnable { static final float BIGGER = 1.07f; static final float SMALLER = 0.93f; private float mTargetScale; private float tmpScale; /** * 缩放的中心 */ private float x; private float y; /** * 传入目标缩放值,根据目标值与当前值,判断应该放大还是缩小 * * @param targetScale */ public AutoScaleRunnable(float targetScale, float x, float y) { this.mTargetScale = targetScale; this.x = x; this.y = y; if (getScale() < mTargetScale) { tmpScale = BIGGER; } else { tmpScale = SMALLER; } } @Override public void run() { // 进行缩放 mScaleMatrix.postScale(tmpScale, tmpScale, x, y); checkBorderAndCenterWhenScale(); setImageMatrix(mScaleMatrix); final float currentScale = getScale(); // 如果值在合法范围内,继续缩放 if (((tmpScale > 1f) && (currentScale < mTargetScale)) || ((tmpScale < 1f) && (mTargetScale < currentScale))) { ZoomImageView.this.postDelayed(this, 16); } else // 设置为目标的缩放比例 { final float deltaScale = mTargetScale / currentScale; mScaleMatrix.postScale(deltaScale, deltaScale, x, y); checkBorderAndCenterWhenScale(); setImageMatrix(mScaleMatrix); isAutoScale = false; } } } @SuppressLint("NewApi") @Override public boolean onScale(ScaleGestureDetector detector) { float scale = getScale(); float scaleFactor = detector.getScaleFactor(); if (getDrawable() == null) return true; /** * 缩放的范围控制 */ if ((scale < SCALE_MAX && scaleFactor > 1.0f) || (scale > initScale && scaleFactor < 1.0f)) { /** * 最大值最小值判断 */ if (scaleFactor * scale < initScale) { scaleFactor = initScale / scale; } if (scaleFactor * scale > SCALE_MAX) { scaleFactor = SCALE_MAX / scale; } /** * 设置缩放比例 */ mScaleMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY()); checkBorderAndCenterWhenScale(); setImageMatrix(mScaleMatrix); } return true; } /** * 在缩放时,进行图片显示范围的控制 */ private void checkBorderAndCenterWhenScale() { RectF rect = getMatrixRectF(); float deltaX = 0; float deltaY = 0; int width = getWidth(); int height = getHeight(); // 如果宽或高大于屏幕,则控制范围 if (rect.width() >= width) { if (rect.left > 0) { deltaX = -rect.left; } if (rect.right < width) { deltaX = width - rect.right; } } if (rect.height() >= height) { if (rect.top > 0) { deltaY = -rect.top; } if (rect.bottom < height) { deltaY = height - rect.bottom; } } // 如果宽或高小于屏幕,则让其居中 if (rect.width() < width) { deltaX = width * 0.5f - rect.right + 0.5f * rect.width(); } if (rect.height() < height) { deltaY = height * 0.5f - rect.bottom + 0.5f * rect.height(); } Log.e(TAG, "deltaX = " + deltaX + " , deltaY = " + deltaY); mScaleMatrix.postTranslate(deltaX, deltaY); } /** * 根据当前图片的Matrix获得图片的范围 * * @return */ private RectF getMatrixRectF() { Matrix matrix = mScaleMatrix; RectF rect = new RectF(); Drawable d = getDrawable(); if (null != d) { rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); matrix.mapRect(rect); } return rect; } @Override public boolean onScaleBegin(ScaleGestureDetector detector) { return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) { } @Override public boolean onTouch(View v, MotionEvent event) { if (mGestureDetector.onTouchEvent(event)) return true; mScaleGestureDetector.onTouchEvent(event); float x = 0, y = 0; // 拿到触摸点的个数 final int pointerCount = event.getPointerCount(); // 得到多个触摸点的x与y均值 for (int i = 0; i < pointerCount; i++) { x += event.getX(i); y += event.getY(i); } x = x / pointerCount; y = y / pointerCount; /** * 每当触摸点发生变化时,重置mLasX , mLastY */ if (pointerCount != lastPointerCount) { isCanDrag = false; mLastX = x; mLastY = y; } lastPointerCount = pointerCount; RectF rectF = getMatrixRectF(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (rectF.width() > getWidth() || rectF.height() > getHeight()) { getParent().requestDisallowInterceptTouchEvent(true); } break; case MotionEvent.ACTION_MOVE: if (rectF.width() > getWidth() || rectF.height() > getHeight()) { getParent().requestDisallowInterceptTouchEvent(true); } Log.e(TAG, "ACTION_MOVE"); float dx = x - mLastX; float dy = y - mLastY; if (!isCanDrag) { isCanDrag = isCanDrag(dx, dy); } if (isCanDrag) { if (getDrawable() != null) { // if (getMatrixRectF().left == 0 && dx > 0) // { // getParent().requestDisallowInterceptTouchEvent(false); // } // // if (getMatrixRectF().right == getWidth() && dx < 0) // { // getParent().requestDisallowInterceptTouchEvent(false); // } isCheckLeftAndRight = isCheckTopAndBottom = true; // 如果宽度小于屏幕宽度,则禁止左右移动 if (rectF.width() < getWidth()) { dx = 0; isCheckLeftAndRight = false; } // 如果高度小雨屏幕高度,则禁止上下移动 if (rectF.height() < getHeight()) { dy = 0; isCheckTopAndBottom = false; } mScaleMatrix.postTranslate(dx, dy); checkMatrixBounds(); setImageMatrix(mScaleMatrix); } } mLastX = x; mLastY = y; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: Log.e(TAG, "ACTION_UP"); lastPointerCount = 0; break; } return true; } /** * 获得当前的缩放比例 * * @return */ public final float getScale() { mScaleMatrix.getValues(matrixValues); return matrixValues[Matrix.MSCALE_X]; } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); getViewTreeObserver().addOnGlobalLayoutListener(this); } @SuppressWarnings("deprecation") @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); getViewTreeObserver().removeGlobalOnLayoutListener(this); } @Override public void onGlobalLayout() { if (once) { Drawable d = getDrawable(); if (d == null) return; Log.e(TAG, d.getIntrinsicWidth() + " , " + d.getIntrinsicHeight()); int width = getWidth(); int height = getHeight(); // 拿到图片的宽和高 int dw = d.getIntrinsicWidth(); int dh = d.getIntrinsicHeight(); float scale = 1.0f; // 如果图片的宽或者高大于屏幕,则缩放至屏幕的宽或者高 if (dw > width && dh <= height) { scale = width * 1.0f / dw; } if (dh > height && dw <= width) { scale = height * 1.0f / dh; } // 如果宽和高都大于屏幕,则让其按按比例适应屏幕大小 if (dw > width && dh > height) { scale = Math.min(width * 1.0f / dw, height * 1.0f / dh); } initScale = scale; Log.e(TAG, "initScale = " + initScale); mScaleMatrix.postTranslate((width - dw) / 2, (height - dh) / 2); mScaleMatrix.postScale(scale, scale, getWidth() / 2, getHeight() / 2); // 图片移动至屏幕中心 setImageMatrix(mScaleMatrix); once = false; } } /** * 移动时,进行边界判断,主要判断宽或高大于屏幕的 */ private void checkMatrixBounds() { RectF rect = getMatrixRectF(); float deltaX = 0, deltaY = 0; final float viewWidth = getWidth(); final float viewHeight = getHeight(); // 判断移动或缩放后,图片显示是否超出屏幕边界 if (rect.top > 0 && isCheckTopAndBottom) { deltaY = -rect.top; } if (rect.bottom < viewHeight && isCheckTopAndBottom) { deltaY = viewHeight - rect.bottom; } if (rect.left > 0 && isCheckLeftAndRight) { deltaX = -rect.left; } if (rect.right < viewWidth && isCheckLeftAndRight) { deltaX = viewWidth - rect.right; } mScaleMatrix.postTranslate(deltaX, deltaY); } /** * 是否是推动行为 * * @param dx * @param dy * @return */ private boolean isCanDrag(float dx, float dy) { return Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop; } }相机显示部分布局代码
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:fresco="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black" android:orientation="vertical"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginLeft="50dp" android:layout_marginRight="50dp" android:gravity="center_vertical" android:orientation="horizontal"> <Button android:id="@+id/btn_delay" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentRight="true" android:background="@android:color/transparent" android:padding="10dp" android:text="3s" android:textColor="@android:color/white" /> <Button android:id="@+id/btn_hdr" android:layout_width="30dp" android:layout_height="30dp" android:layout_marginLeft="10dp" android:background="@drawable/ic_flash_off_indicator" android:padding="10dp" /> <Button android:id="@+id/btn_camera_change" android:layout_width="30dp" android:layout_height="30dp" android:layout_marginLeft="10dp" android:background="@drawable/ic_menu_revert_holo_dark" android:padding="10dp" /> <Button android:id="@+id/btn_setting" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginLeft="10dp" android:background="@drawable/ic_settings_normal" android:padding="10dp" /> </LinearLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <SurfaceView android:id="@+id/surface_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" /> <com.example.apple.camera.view.MyView android:id="@+id/my_rect" android:visibility="gone" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout> <TextView android:id="@+id/tv_time" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:textColor="@android:color/holo_red_dark" /> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginBottom="10dp" android:gravity="center_vertical"> <ImageView android:layout_width="55dp" android:layout_height="55dp" android:layout_centerVertical="true" android:layout_marginLeft="16dp" android:background="@mipmap/focus_ring_touch_outer" /> <Button android:id="@+id/btn_video" android:layout_width="50dp" android:layout_height="50dp" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:background="@mipmap/ic_switch_video" /> <ImageView android:layout_width="55dp" android:layout_height="55dp" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:background="@mipmap/focus_ring_touch_outer" /> <Button android:id="@+id/btn_take_photo" android:layout_width="51dp" android:layout_height="50dp" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:background="@mipmap/ic_video" /> <com.facebook.drawee.view.SimpleDraweeView android:id="@+id/iv_picture" android:layout_width="55dp" android:layout_height="55dp" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="20dp" android:background="@mipmap/focus_ring_touch_outer" android:scaleType="centerCrop" fresco:actualImageScaleType="centerInside" /> </RelativeLayout> </LinearLayout>
相机功能完整代码
package com.example.apple.camera;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.hardware.Camera;
import android.media.FaceDetector;
import android.media.MediaMetadataRetriever;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.example.apple.camera.showpicture.ImageShowActivity;
import com.example.apple.camera.view.MyView;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static android.content.ContentValues.TAG;
public class MainActivity extends Activity implements View.OnClickListener, SurfaceHolder.Callback, Camera.PictureCallback {
private Button btnVideo;
private Button btnTakePhoto;
private ImageView ivPicture;
private SurfaceView mySurfaceView;
private TextView tvTime;
private Button btnDelay;
private Button btnHdr;
private Button btnCameraChange;
private Button btnSetting;
private MyView myRect = null;
private String filePath = "/mnt/sdcard/DCIM/Camera";
private Camera mCamera;
private SurfaceHolder mHolder;
private boolean mIsSurfaceCreated = false;
private boolean isVideoStart = true;
private String videoPath = "";
private MediaRecorder mediarecorder;// 录制视频的类
private int count = 5;
private int countDown = 0;
private boolean startDelayPicture = false;
private int cameraPosition = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
btnVideo = (Button) findViewById(R.id.btn_video);
btnVideo.setOnClickListener(this);
btnTakePhoto = (Button) findViewById(R.id.btn_take_photo);
btnTakePhoto.setOnClickListener(this);
ivPicture = (ImageView) findViewById(R.id.iv_picture);
ivPicture.setOnClickListener(this);
btnDelay = (Button) findViewById(R.id.btn_delay);
btnDelay.setOnClickListener(this);
btnHdr = (Button) findViewById(R.id.btn_hdr);
btnHdr.setOnClickListener(this);
btnCameraChange = (Button) findViewById(R.id.btn_camera_change);
btnCameraChange.setOnClickListener(this);
btnSetting = (Button) findViewById(R.id.btn_setting);
btnSetting.setOnClickListener(this);
myRect = (MyView) findViewById(R.id.my_rect);
tvTime = (TextView) findViewById(R.id.tv_time);
mySurfaceView = (SurfaceView) findViewById(R.id.surface_view);
mHolder = mySurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_camera_change:
changeCamera();
break;
case R.id.btn_video:
videotape();
break;
case R.id.btn_take_photo:
if (startDelayPicture) {
handler.postDelayed(runnable, 1000);//每两秒执行一次runnable.
startDelayPicture = false;
} else {
mCamera.takePicture(null, null, null, MainActivity.this);
}
break;
case R.id.iv_picture:
// Intent intent = new Intent(Intent.ACTION_VIEW);
// String bpath = "file://" + videoPath;
// intent.setDataAndType(Uri.parse(bpath), "video/*");
// startActivity(intent);
Intent intent = new Intent(MainActivity.this, ImageShowActivity.class);
startActivity(intent);
break;
case R.id.btn_delay:
countDown = 3;
startDelayPicture = true;
tvTime.setVisibility(View.GONE);
break;
case R.id.btn_setting:
Intent intentSetting = new Intent(MainActivity.this, SettingActivity.class);
startActivity(intentSetting);
break;
case R.id.btn_hdr:
break;
}
}
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: focusOnTouch(event); myRect.setVisibility(View.VISIBLE); int x = (int) event.getX(); int y = (int) event.getY(); myRect.setX(x - 100); myRect.setY(y - 300); //Log.e(TAG,"x="+x+" y="+y); mCamera.autoFocus(new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { if (success) { Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.border1); myRect.setmBitmap(mBitmap); myRect.setVisibility(View.GONE); } } }); break; } return super.onTouchEvent(event); }
@Override public void onPictureTaken(byte[] data, Camera camera) { FileOutputStream fos = null; try { String fileName = System.currentTimeMillis() + ".png"; fos = new FileOutputStream(new File(filePath + File.separator + fileName)); videoPath = filePath + File.separator + fileName; Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); Matrix matrix = new Matrix(); matrix.setRotate(90); bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); ivPicture.setImageBitmap(bitmap); new FaceThread(bitmap).start(); fos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); } Toast.makeText(getApplication(), "拍照成功", Toast.LENGTH_SHORT).show(); //拍照后重新预览 mCamera.startPreview(); }
@Override
public void surfaceCreated(SurfaceHolder holder) {
mIsSurfaceCreated = true;
startPreview();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, final int width, final int height) {
// mCamera.setPreviewCallback(new Camera.PreviewCallback() {
// @Override
// public void onPreviewFrame(byte[] data, Camera camera) {
// YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, width, height, null);
// ByteArrayOutputStream os = new ByteArrayOutputStream(data.length);
// yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, os);
// byte[] tmp = os.toByteArray();
// Bitmap bmp = BitmapFactory.decodeByteArray(tmp, 0,tmp.length);
// // Bitmap bitmap = BitmapFactory.decodeByteArray(data,width,height,null);
// Matrix matrix = new Matrix();
// matrix.setRotate(90);
// ivPicture.setImageBitmap(bmp);
// new FaceThread(bmp).start();
// }
// });
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsSurfaceCreated = false;
stopPreview();
}
/**
* 启动预览
*/
private void startPreview() {
if (mCamera != null || !mIsSurfaceCreated) {
return;
}
mCamera = Camera.open(0);
Camera.Parameters parameters = mCamera.getParameters();
int width = getResources().getDisplayMetrics().widthPixels;
int height = getResources().getDisplayMetrics().heightPixels;
Camera.Size size = getBestPreviewSize(width, height, parameters);
/**
* 该参数不一定所有手机都合适
*/
// if (size != null) {
// parameters.setPreviewSize(size.width, size.height); // parameters.setPictureSize(size.width, size.height);
// }
List<Camera.Size> pszize = parameters.getSupportedPictureSizes();
if (null != pszize && 0 < pszize.size()) {
int height1[] = new int[pszize.size()];
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < pszize.size(); i++) {
Camera.Size size1 = (Camera.Size) pszize.get(i);
int sizeheight = size1.height;
int sizewidth = size1.width;
height1[i] = sizeheight;
map.put(sizeheight, sizewidth);
//Log.e(TAG,"size.width="+sizewidth + " size.height="+sizeheight);
}
Arrays.sort(height1);
parameters.setPictureSize(map.get(height1[12]), height1[12]);
// if (Utils.getPictureSize(getApplication())!=0){
// parameters.setPictureSize(map.get(height1[Utils.getPictureSize(getApplication())]), height1[Utils.getPictureSize(getApplication())]);
// Log.e(TAG,"size.width="+map.get(height1[Utils.getPictureSize(getApplication())]) + " size.height="+height1[Utils.getPictureSize(getApplication())]);
// }else {
// parameters.setPictureSize(size.width, size.height);
// }
}
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
parameters.setPreviewFrameRate(20);
mCamera.setDisplayOrientation(90);
mCamera.setParameters(parameters);
try {
mCamera.setPreviewDisplay(mHolder);
} catch (Exception e) {
e.printStackTrace();
}
mCamera.startPreview();
}
/**
* 关闭预览
*/
private void stopPreview() {
if (mCamera != null) {
try {
mCamera.setPreviewDisplay(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
}
private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return result;
}
/**
* 触摸聚焦
*
* @param event
*/
public void focusOnTouch(MotionEvent event) {
int[] location = new int[2];
mySurfaceView.getLocationOnScreen(location);
Rect focusRect = calculateTapArea(100, 100, 1f, event.getRawX(), event.getRawY(),
location[0], location[0] + mySurfaceView.getWidth(), location[1], location[1] + mySurfaceView.getHeight());
Rect meteringRect = calculateTapArea(200, 200, 1.5f, event.getRawX(), event.getRawY(),
location[0], location[0] + mySurfaceView.getWidth(), location[1], location[1] + mySurfaceView.getHeight());
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
if (parameters.getMaxNumFocusAreas() > 0) {
List<Camera.Area> focusAreas = new ArrayList<Camera.Area>();
focusAreas.add(new Camera.Area(focusRect, 1000));
parameters.setFocusAreas(focusAreas);
}
if (parameters.getMaxNumMeteringAreas() > 0) {
List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
meteringAreas.add(new Camera.Area(meteringRect, 1000));
parameters.setMeteringAreas(meteringAreas);
}
try {
mCamera.setParameters(parameters);
} catch (Exception e) {
}
mCamera.autoFocus(null);
}
public Rect calculateTapArea(int focusWidth, int focusHeight, float areaMultiple,
float x, float y, int previewleft, int previewRight, int previewTop, int previewBottom) {
int areaWidth = (int) (focusWidth * areaMultiple);
int areaHeight = (int) (focusHeight * areaMultiple);
int centerX = (previewleft + previewRight) / 2;
int centerY = (previewTop + previewBottom) / 2;
double unitx = ((double) previewRight - (double) previewleft) / 2000;
double unity = ((double) previewBottom - (double) previewTop) / 2000;
int left = clamp((int) (((x - areaWidth / 2) - centerX) / unitx), -1000, 1000);
int top = clamp((int) (((y - areaHeight / 2) - centerY) / unity), -1000, 1000);
int right = clamp((int) (left + areaWidth / unitx), -1000, 1000);
int bottom = clamp((int) (top + areaHeight / unity), -1000, 1000);
return new Rect(left, top, right, bottom);
}
public int clamp(int x, int min, int max) {
if (x > max)
return max;
if (x < min)
return min;
return x;
}
/** * 录像 */ private void videotape() { if (isVideoStart) { count = 0; btnDelay.setVisibility(View.GONE); tvTime.setVisibility(View.VISIBLE); handler.postDelayed(runnable, 1000);//每两秒执行一次runnable. btnVideo.setBackgroundResource(R.drawable.video_recoder); isVideoStart = false; mediarecorder = new MediaRecorder(); mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK); if (mCamera != null) { mCamera.setDisplayOrientation(90); mCamera.unlock(); mediarecorder.setCamera(mCamera); } //设置视频源 mediarecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT); //设置音频源 mediarecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); //设置文件输出格式 mediarecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); //设置视频编码方式 mediarecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); //设置音频编码方式 mediarecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); //设置视频高和宽,注意文档的说明: //Must be called after setVideoSource(). //Call this after setOutFormat() but before prepare(). //设置录制的视频帧率,注意文档的说明: //Must be called after setVideoSource(). //Call this after setOutFormat() but before prepare(). mediarecorder.setVideoSize(800, 480); mediarecorder.setVideoFrameRate(20); mediarecorder.setAudioChannels(2); //设置预览画面 mediarecorder.setPreviewDisplay(mHolder.getSurface()); //设置输出路径 // videoPath = Environment.getExternalStorageDirectory() + File.separator + System.currentTimeMillis() + ".mp4"; videoPath = "/mnt/sdcard/DCIM/Camera" + File.separator + System.currentTimeMillis() + ".mp4"; mediarecorder.setOutputFile(videoPath); try { // 准备录制 mediarecorder.prepare(); // 开始录制 mediarecorder.start(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { tvTime.setText(""); btnDelay.setVisibility(View.VISIBLE); btnDelay.setText("3 s"); //ivPicture.setImageURI(Uri.fromFile(new File(videoPath))); ivPicture.setImageBitmap(getVideoThumbnail(videoPath)); Log.e(TAG, "videoPath=" + videoPath); handler.removeCallbacksAndMessages(null); btnVideo.setBackgroundResource(R.drawable.ic_switch_video); isVideoStart = true; if (mediarecorder != null) { // 停止录制 mediarecorder.stop(); // 释放资源 mediarecorder.release(); mediarecorder = null; } if (mCamera != null) { // mCamera.release(); } Toast.makeText(getApplication(), "视频已保存到" + videoPath + "下", Toast.LENGTH_SHORT).show(); } }
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;
}
Handler handler = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//要做的事情
count++;
countDown--;
btnDelay.setText(countDown + " s");
handler.postDelayed(this, 1000);
if (countDown == 0) {
mCamera.takePicture(null, null, null, MainActivity.this);
btnDelay.setText("3s");
handler.removeCallbacksAndMessages(null);
}
tvTime.setText(count + " s");
}
};
/**
* 切换前后摄像头
*/
private void changeCamera() {
int cameraCount = 0;
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
cameraCount = Camera.getNumberOfCameras();//得到摄像头的个数
for (int i = 0; i < cameraCount; i++) {
Camera.getCameraInfo(i, cameraInfo);//得到每一个摄像头的信息
if (cameraPosition == 1) {
//现在是后置,变更为前置
//代表摄像头的方位,CAMERA_FACING_FRONT 前置 CAMERA_FACING_BACK后置
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
mCamera.stopPreview();//停掉原来摄像头的预览
mCamera.release();//释放资源
mCamera = null;//取消原来摄像头
mCamera = Camera.open(i);//打开当前选中的摄像头
try {
mCamera.setPreviewDisplay(mHolder);//通过surfaceview显示取景画面
mCamera.setDisplayOrientation(90);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mCamera.startPreview();//开始预览
cameraPosition = 0;
break;
}
} else {
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
mCamera = Camera.open(i);
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.setDisplayOrientation(90);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mCamera.startPreview();
cameraPosition = 1;
break;
}
}
}
}
class FaceThread extends Thread { private Bitmap mBitmap; public FaceThread(Bitmap bitmap) { this.mBitmap = bitmap; } @Override public void run() { FaceDetector.Face[] faces = new FaceDetector.Face[5]; //格式必须为RGB_565才可以识别 Bitmap bitmap = mBitmap.copy(Bitmap.Config.RGB_565, true); final int faceCount = new FaceDetector(bitmap.getWidth(), bitmap.getHeight(), 5).findFaces(bitmap, faces); bitmap.recycle(); if (faceCount > 0) { final Bitmap bmp = parseBitmap(faces, faceCount, mBitmap); runOnUiThread(new Runnable() { @Override public void run() { ivPicture.setImageBitmap(bmp); File file = new File(filePath, System.currentTimeMillis() + ".jpg"); if (file.exists()) { file.delete(); } try { FileOutputStream fo = new FileOutputStream(file); bmp.compress(Bitmap.CompressFormat.JPEG, 90, fo); fo.flush(); fo.close(); } catch (IOException e) { e.printStackTrace(); } } }); } } } /** * 在人脸上画矩形 */ private Bitmap parseBitmap(FaceDetector.Face[] faces, int faceCount, Bitmap mFaceBitmap) { Bitmap bitmap = Bitmap.createBitmap(mFaceBitmap.getWidth(), mFaceBitmap.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setAntiAlias(true); mPaint.setColor(Color.YELLOW); mPaint.setStrokeWidth(5); mPaint.setStyle(Paint.Style.STROKE); canvas.drawBitmap(mFaceBitmap, 0, 0, mPaint); for (int i = 0; i < faceCount; i++) { //双眼的中心点 PointF midPoint = new PointF(); faces[i].getMidPoint(midPoint); //双眼的距离 float eyeDistance = faces[i].eyesDistance(); //画矩形 canvas.drawRect(midPoint.x - eyeDistance, midPoint.y - eyeDistance, midPoint.x + eyeDistance, midPoint.y + eyeDistance, mPaint); myRect.setY(midPoint.x + eyeDistance); myRect.setX(midPoint.y + eyeDistance); } return bitmap; }
@Override
protected void onDestroy() {
super.onDestroy();
if (handler != null) {
handler.removeCallbacksAndMessages(null);
handler = null;
}
}
}
完成后添加权限:
<uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
最后实现的效果图
相关文章推荐
- Android中级第十讲--相机录像和查看系统相册图片
- android 使用相机拍照,并存储到手机sd卡上,并利用系统录像录像并播放
- Android相机开发(一)之预览拍照查看图片基本功能的实现
- Android 调用系统相机进行拍照 使用自带的图片选择器和裁剪工具
- Android静态图片人脸识别的完整demo(附完整源码)
- Android中级第十讲--相机录像和查看系统相册图片
- 快速使用Android静态人脸识别(附源码)
- 微信小程序-从相册获取图片,视频 使用相机拍照,录像上传+服务器(nodejs版)接收
- Android静态图片人脸识别的完整demo(附完整源码)
- Android相机开发(一)之预览拍照查看图片基本功能的实现
- Android静态图片人脸识别的完整demo(附完整源码)
- Android中级第十讲--相机录像和查看系统相册图片
- 小程序从本地相册选择图片或使用相机拍照wx.chooseImage上传后预览并可以识别图中二维码
- 调用android系统相机拍照并保存图片
- HTML5拍照上传图片&Phonegap封装HTML5调用Android相机拍照上传到PHP端
- android系统相机的使用、及解决拍照闪退的问题
- Android调用系统相机拍照并保存图片文件
- Android WebView 上传各种文件(包括拍照 录像 录音 文件 音乐 等,用到图片或拍照的,可以参考下)
- android 图片压缩,自动旋转保存,查看照片信息,拍照设备类型等
- 使用face++接口实现在Android设备上的人脸识别