Camera2使用surface支持
surfaceview是运行在子线程,可以为相机提供不断的刷新
public class MainActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); getSupportFragmentManager().beginTransaction().add(R.id.relative, new BlankFragment()).commit(); } }
主activity用于启动一个Fragment在fragment中启动相机
public class BlankFragment extends Fragment { public static final int REQUEST_CAMERA_CODE = 100;
public static final String PACKAGE = "package:"; private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); ///为了使照片竖直显示
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
} private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private ImageView iv_show;
private ImageView mCatture;
private CameraManager mCameraManager;//摄像头管理器
private Handler childHandler, mainHandler;
private String mCameraID;//摄像头Id 0 为后 1 为前
private ImageReader mImageReader;
private CameraCaptureSession mCameraCaptureSession;
private CameraDevice mCameraDevice;
/**
* 摄像头创建监听
*/
private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {//打开摄像头
mCameraDevice = camera;
//开启预览
takePreview();
} @Override
public void onDisconnected(CameraDevice camera) {//关闭摄像头
if (null != mCameraDevice) {
mCameraDevice.close();
mCameraDevice = null;
}
} @Override
public void onError(CameraDevice camera, int error) {//发生错误
Toast.makeText(getContext(), "摄像头开启失败", Toast.LENGTH_SHORT).show();
}
}; public static BlankFragment newInstance() {
return new BlankFragment();
} @Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_blank, container, false);
initVIew(root);
initListener();
return root;
} @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
} @Override
public void onResume() {
super.onResume();
} /**
* 初始化
*/
private void initVIew(View root) {
iv_show = (ImageView) root.findViewById(R.id.iv_show_camera2);
//mSurfaceView
mSurfaceView = (SurfaceView) root.findViewById(R.id.surface_view_camera2);
mCatture = (ImageView) root.findViewById(R.id.capture);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.setKeepScreenOn(true);
// mSurfaceView添加回调
mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) { //SurfaceView创建
// 初始化Camera
initCamera2();
} @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
} @Override
public void surfaceDestroyed(SurfaceHolder holder) { //SurfaceView销毁
// 释放Camera资源
if (null != mCameraDevice) {
mCameraDevice.close();
mCameraDevice = null;
}
}
});
} /**
* 初始化Camera2
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void initCamera2() {
HandlerThread handlerThread = new HandlerThread("Camera2");
handlerThread.start();
childHandler = new Handler(handlerThread.getLooper());
mainHandler = new Handler(getMainLooper());
mCameraID = "" + CameraCharacteristics.LENS_FACING_FRONT;//后摄像头
mImageReader = ImageReader.newInstance(1080, 1920, ImageFormat.JPEG, 1);
mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { //可以在这里处理拍照得到的临时照片 例如,写入本地
@Override
public void onImageAvailable(ImageReader reader) {
//mCameraDevice.close();
// 拿到拍照照片数据
Image image = reader.acquireNextImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);//由缓冲区存入字节数组
final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
if (bitmap != null) {
iv_show.setImageBitmap(bitmap);
}
}
}, mainHandler);
//获取摄像头管理
mCameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
try {
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
//申请WRITE_EXTERNAL_STORAGE权限
requestPermissions(new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_CODE);
//return;
} else {
//打开摄像头
mCameraManager.openCamera(mCameraID, stateCallback, mainHandler); }
} catch (CameraAccessException e) {
e.printStackTrace();
}
} @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CAMERA_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted
try {
mCameraManager.openCamera(mCameraID, stateCallback, mainHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
} else {
// Permission Denied
}
}
} /**
* 开始预览
*/
private void takePreview() {
try {
// 创建预览需要的CaptureRequest.Builder
final CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
// 将SurfaceView的surface作为CaptureRequest.Builder的目标
previewRequestBuilder.addTarget(mSurfaceHolder.getSurface());
// 创建CameraCaptureSession,该对象负责管理处理预览请求和拍照请求
mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface(), mImageReader.getSurface()), new CameraCaptureSession.StateCallback() // ③
{
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
if (null == mCameraDevice) return;
// 当摄像头已经准备好时,开始显示预览
mCameraCaptureSession = cameraCaptureSession;
try {
// 自动对焦
previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// 打开闪光灯
previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
// 显示预览
CaptureRequest previewRequest = previewRequestBuilder.build();
mCameraCaptureSession.setRepeatingRequest(previewRequest, null, childHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
} @Override
public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
Toast.makeText(getContext(), "配置失败", Toast.LENGTH_SHORT).show();
}
}, childHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
} /**
* 拍照
*/
private void takePicture() {
if (mCameraDevice == null) return;
// 创建拍照需要的CaptureRequest.Builder
final CaptureRequest.Builder captureRequestBuilder;
try {
captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
// 将imageReader的surface作为CaptureRequest.Builder的目标
captureRequestBuilder.addTarget(mImageReader.getSurface());
// 自动对焦
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// 自动曝光
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
// 获取手机方向
int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
// 根据设备方向计算设置照片的方向
captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
//拍照
CaptureRequest mCaptureRequest = captureRequestBuilder.build();
mCameraCaptureSession.capture(mCaptureRequest, null, childHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
} private void initListener() {
mCatture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
takePicture();
}
});
} }
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<RelativeLayout 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"
tools:context=".BlankFragment"> <SurfaceView
android:id="@+id/surface_view_camera2"
android:layout_width="match_parent"
android:layout_height="match_parent"/> <ImageView
android:id="@+id/capture"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp"
android:src="@mipmap/ic5"/> <ImageView
android:id="@+id/iv_show_camera2"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="20dp"
android:layout_marginRight="20dp"
android:src="@mipmap/ic_launcher"
android:scaleType="centerCrop"/> </RelativeLayout>
上面是fragment的布局,activity的布局是空的,只有一个id relative
Camera2使用surface支持的更多相关文章
- Camera2使用textureView支持
SurfaceView 绘制会有独立窗口, TextureView 没有独立的窗口,可以像普通的 View 一样,更高效更方便 public class MainActivity extends Ap ...
- linux下编译qt5.6.0静态库——configure配置
linux下编译qt5.6.0静态库 linux下编译qt5.6.0静态库 configure生成makefile 安装选项 Configure选项 第三方库: 附加选项: QNX/Blackberr ...
- Android(java)学习笔记151: SurfaceView使用
1.SurfaceView简介 在一般的情况下,应用程序的View都是在相同的GUI线程(UI主线程)中绘制的.这个主应用程序线程同时也用来处理所有的用户交互(例如,按钮单击或者文本输入) ...
- linux下编译qt5.6.0静态库——configure配置(超详细,有每一个模块的说明)(乌合之众)
linux下编译qt5.6.0静态库 linux下编译qt5.6.0静态库 configure生成makefile 安装选项 Configure选项 第三方库: 附加选项: QNX/Blackberr ...
- Android WebRTC开发入门
在学习 WebRTC 的过程中,学习的一个基本步骤是先通过 JS 学习 WebRTC的整体流程,在熟悉了整体流程之后,再学习其它端如何使用 WebRTC 进行互联互通. 申请权限 Camera 权限 ...
- Flutter 相机定制
Flutter中与硬件相关的部分,一直都挺蛋疼的.方案基本上有两种,自己写,或者等出相关的库. 最近做的一个项目中,需要对相机做定制.有过相关模块开发经验的,就知道这种需求并不简单,况且是这种跨平台解 ...
- Android 4学习(9):用户界面 - THE ANDROID WIDGET TOOLBOX
Android内置了很多View,包括: TextView EditText Chronometer ListView Spinner Button ToggleButton ImageButton ...
- Android(java)学习笔记94: SurfaceView使用
1. SurfaceView简介 在一般的情况下,应用程序的View都是在相同的GUI线程(UI主线程)中绘制的.这个主应用程序线程同时也用来处理所有的用户交互(例如,按钮单击或者文本输入). ...
- linux下编译qt5.6.0静态库(使用./configure --help来看看都有哪些参数。超详细,有每一个模块的说明。如果改变了安装的目录,需要到安装目录下的bin目录下创建文件qt.conf)(乌合之众)good
linux下编译qt5.6.0静态库 linux下编译qt5.6.0静态库 configure生成makefile 安装选项 Configure选项 第三方库: 附加选项: QNX/Blackberr ...
随机推荐
- 计算几何(一):凸包问题(Convex Hull)
引言 首先介绍下什么是凸包?如下图: 在一个二维坐标系中,有若干点杂乱排列着,将最外层的点连接起来构成的凸多边型,它能包含给定的所有的点,这个多边形就是凸包. 实际上可以理解为用一个橡皮筋包含住所有给 ...
- Redis常见的八道面试题
一.memcached与redis的区别? 1.存储方式不同.memcached把数据全部存在内存之中,断电之后会挂掉,而redis虽然也用到了内存,但是会有部分数据存在硬盘中,保证数据持久性. ...
- CVE-2018-8045
Joomla!Core SQL注入漏洞 CVE-2018-8045 受影响版本:joomla!3.5.0-3.8.5 漏洞描述: joomla!3.5.0-3.8.5版本对sql语句内的变量缺少类型转 ...
- 前端性能测试工具之PageSpeed Insights
谷歌开发的一个免费的网页分析工具,在地址栏中输入被分析的网站 url 地址,点击分析 地址:https://developers.google.cn/speed/pagespeed/insights/ ...
- 使用TiDB把自己写分库分表方案推翻了
背景 在日益数据量增长的情况下,影响数据库的读写性能,我们一般会有分库分表的方案和使用newSql方案,newSql如TIDB.那么为什么需要使用TiDB呢?有什么情况下才用TiDB呢?解决传统分库分 ...
- Centos-yum软件包安装-yum
yum 自动安装相关软件依赖,可以同时配置多个yum源,初始启动yum时候首先会缓存资源包到 /var/cache/yum目录下 yum确认 -y yum安装和卸载 install 安装,自动安装软件 ...
- mysql-4-functions
#进阶4:常见函数(单行函数) /* 将一组逻辑语句封装在方法体中,对外暴露方法名 语法: SELECT 函数名() [FROM 表名] 分类: 1.单行函数:concat,length,ifnull ...
- 《kubernetes + .net core 》dev ops部分
目录 1.kubernetes 预备知识 1.1 集群资源 1.1.1 role 1.1.2 namespace 1.1.3 node 1.1.4 persistent volume 1.1.5 st ...
- 山寨一个Spring的@Component注解
1. 前言 我们在上一篇对Mybatis如何将Mapper接口注入Spring IoC进行了分析,有同学问胖哥这个有什么用,这个作用其实挺大的,比如让你实现一个类似@Controller的注解(或者继 ...
- 099 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 02 案例分析及实现 03 编写并测试Student类
099 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 02 案例分析及实现 03 编写并测试Student类 本文知识点:编写并测试Subject类 说明: ...