关键词:
在Andrioid 5.0之前如果要自己创建相机应用,那么需要使用android.hardware.Camera类,但是在Android 5.0中引入了android.hardware.camera2包用于替代原有的类构建相机应用。本文主要讲述利用camera2包构建应用,如果想了解在Android 5.0之前构建应用的话,可以到官网文档查看。
一、android.hardware.camera2概述
在官方文档中这样写道:android.hardware.camera2包在Android设备和个人相机设备之间提供接口,替代过时的Camera类。该包将相机设备抽象成管道,输入为捕获单个一帧的请求或单个图片的请求,输出为一个捕获结果的元数据包,附带一些请求的输出图片缓存信息。请求按照顺序处理,并且可以同时发送多个请求。
二、使用步骤
1. 获取指定摄像头并设置参数
为了获得可用的相机设备,需要首先获取CameraManager对象。获取代码如下:
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
每一个CameraDevices提供了一系列描述硬件设备、设置和输出参数的静态属性。这些属性通过CameraCharacteristics对象,CameraCharacteristic对象则通过CameraManager的getCameraCharacteristicis(String)方法获得。现在很多Android设备都有两个摄像头,一个前置,一个后置。下面的代码就是获取后置摄像头的代码:
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try
for (String cameraId : cameraManager.getCameraIdList())
CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
Integer facing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT)
continue;
//TODO 后置设置头
catch (CameraAccessException e)
e.printStackTrace();
CameraCharacteristics的LENS_FACING参数描述的是摄像头相对于屏幕的方向,可能值为FRONT、BACK、EXTERNAL。在获取到指定摄像头后,保存对应的cameraId,该cameraId就代表了某一摄像头。
当获得了cameraId后,就调用CameraManager的openCamera方法打开指定摄像头,方法声明如下:
void openCamera (String cameraId,
CameraDevice.StateCallback callback,
Handler handler)
其中callback是相机一旦开启后使用的回调,handler是回调所使用的。如果handler为空,那么就使用当前线程的Looper。也就是说Handler取决于Callback在哪个线程中运行。其中StataCallback的声明如下:
public abstact CameraDevice.StateCallback
@Override
public abstract void onOpened(@NonNull CameraDevice cameraDevice);
@Override
public abstract void onDisconnected(@NonNull CameraDevice cameraDevice);
@Override
public abstract void onError(@NonNull CameraDevice cameraDevice, int error);
一旦相机打开,就可以获得CameraDevice对象,一般在onOpened方法中创建相机会话,在onDisconnected和onError中释放相机资源。
2. 设置预览界面
为了拍照或录像,应用需要首先用一系列输出Surface装进相机捕获绘画。每一个Surface需要首先配置好恰当的尺寸和格式。Surface可以从多种方式获得,包括SurfaceView、SurfaceTexture。一般地,相机预览图片被发送到SurfaceView或TexttureView。在这里我们简单实用TextureView。SurfaceView创建预览的例子可以参考这里。实用TextureView很简单,只需要获得SurfaceTexture对象即可。SurfaceTexture用于渲染内容。在开发中我们需要设置TextureView的SurfaceTextureListener监听器,该监听器用于监听SurfaceTexture的获得、尺寸改变、更新和销毁事件。
3. 创建相机会话
在第一步中获取到CameraDevice和第二步设置了预览界面后,下面需要利用CameraDevice和预览界面创建相机会话。应用需要创建CaptureRequest对象,该对象定义了摄像头捕获一帧需要的所有参数。CaptureRequest需要列出配置好的Surface作为输出结果的Surface。一旦CaptureRequest对象创建,可以被提交给活动着的会话用于拍一张图片或多张图片。创建会话需要使用CameraDevice的createCaptureSession方法,下面是方法的声明
void createCaptureSession (List<Surface> outputs,
CameraCaptureSession.StateCallback callback,
Handler handler)
createCaptureSession方法使用提供的一系列Surface创建新的会话。callback是会话状态的回调,Handler是回调发消息所使用的,如果为null,那么使用当前线程的Looper创建Handler。CameraCaptureSession.StateCallback是一个抽象类,有两个抽象方法,onConfigured和onConfigureFailed。在onConfigured中可以处理CaptureRequest。下面是一段示例,
try
SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
surfaceTexture.setDefaultBufferSize(textureView.getWidth(), textureView.getHeight());
Surface surface = new Surface(surfaceTexture);
priviewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
priviewRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(Arrays.asList(surface, imageReader.getSurface()), new CameraCaptureSession.StateCallback()
@Override
public void onConfigured(CameraCaptureSession session)
try
if (null == cameraDevice)
return;
cameraCaptureSession = session;
//预览时,需要设置自动聚焦模式
priviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
previewRequest = priviewRequestBuilder.build();
cameraCaptureSession.setRepeatingRequest(previewRequest, mCaptureCallback, mBackgroundHandler);
catch (CameraAccessException e)
e.printStackTrace();
@Override
public void onConfigureFailed(CameraCaptureSession session)
Toast.makeText(MainActivity.this, "Failed", Toast.LENGTH_SHORT).show();
, null);
catch (Exception e)
e.printStackTrace();
从代码中可以看到,在会话的onConfigured方法中保存会话对象,然后创建预览的CaptureRequest对象,因为是预览,所以使用的是CameraSession的setRepeatingRequest方法。
4. 拍照
上面建立了预览状态,并且在会话创建成功后保存了会话变量,接下来的所有拍照请求都需要提交给CameraSeesion。拍摄单张图片调用capture方法,如下
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
其中mCaptureCallback用于跟踪提交的CaptureRequest的处理进程。CaptureSession.CaptureCallback的定义如下:
public static abstract class CaptureCallback
/**
* This constant is used to indicate that no images were captured for
* the request.
*
* @hide
*/
public static final int NO_FRAMES_CAPTURED = -1;
public void onCaptureStarted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, long timestamp, long frameNumber)
// Temporary trampoline for API change transition
onCaptureStarted(session, request, timestamp);
/**
* Temporary for API change transition
* @hide
*/
public void onCaptureStarted(CameraCaptureSession session,
CaptureRequest request, long timestamp)
// default empty implementation
/**
* @hide
*/
public void onCapturePartial(CameraCaptureSession session,
CaptureRequest request, CaptureResult result)
// default empty implementation
public void onCaptureProgressed(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, @NonNull CaptureResult partialResult)
// default empty implementation
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, @NonNull TotalCaptureResult result)
// default empty implementation
public void onCaptureFailed(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, @NonNull CaptureFailure failure)
// default empty implementation
public void onCaptureSequenceCompleted(@NonNull CameraCaptureSession session,
int sequenceId, long frameNumber)
// default empty implementation
public void onCaptureSequenceAborted(@NonNull CameraCaptureSession session,
int sequenceId)
// default empty implementation
public void onCaptureBufferLost(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, @NonNull Surface target, long frameNumber)
// default empty implementation
可以看到很多方法都是空实现。
5. 保存图片
在用camera2包中,如何保存拍摄的图片呢?这需要使用到ImageReader类,需要创建ImageReader类并设置OnImageAvailableListener接口,OnImageAvailableListener用于处理可获得图片时,我们可以在这里保存图片。还需要在创建CameraCaptureSession时,将ImageReader也作为输出Surface接受拍摄的图片。
6. 完整例子
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class MainActivity extends AppCompatActivity implements ActivityCompat.OnRequestPermissionsResultCallback, View.OnClickListener
public static final String TAG = "MainActivity";
private static final int STATE_PREVIEW = 0;
private static final int STATE_WAITING_LOCK = 1;
private static final int STATE_WAITING_PRECAPTURE = 2;
private static final int STATE_WAITING_NON_PRECAPTURE = 3;
private static final int STATE_PICTURE_TAKEN = 4;
private int mState = STATE_PREVIEW;
private TextureView textureView;
private Button captureBtn;
private CameraCaptureSession cameraCaptureSession;
private String cameraId;
private CameraDevice cameraDevice;
private HandlerThread mBackgroundThread;
private Handler mBackgroundHandler;
private CaptureRequest.Builder priviewRequestBuilder;
private CaptureRequest previewRequest;
private ImageReader imageReader;
private File file;
private TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener()
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)
openCamera();
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface)
return false;
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface)
;
private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback()
@Override
public void onOpened(CameraDevice camera)
cameraDevice = camera;
createCameraPreviewSession();
@Override
public void onDisconnected(CameraDevice camera)
camera.close();
cameraDevice = null;
@Override
public void onError(CameraDevice camera, int error)
camera.close();
cameraDevice = null;
;
private CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback()
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result)
process(result);
@Override
public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult)
process(partialResult);
private void process(CaptureResult result)
switch (mState)
case STATE_PREVIEW:
// We have nothing to do when the camera preview is working normally.
break;
case STATE_WAITING_LOCK:
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
if (afState == null)
captureStillPicture();
else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState)
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED)
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
else
runPrecaptureSequence();
break;
case STATE_WAITING_PRECAPTURE:
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED)
mState = STATE_WAITING_NON_PRECAPTURE;
break;
case STATE_WAITING_NON_PRECAPTURE:
// CONTROL_AE_STATE can be null on some devices
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE)
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
break;
;
private void runPrecaptureSequence()
try
// This is how to tell the camera to trigger.
priviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
// Tell #mCaptureCallback to wait for the precapture sequence to be set.
mState = STATE_WAITING_PRECAPTURE;
cameraCaptureSession.capture(priviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
catch (CameraAccessException e)
e.printStackTrace();
private void captureStillPicture()
try
CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
builder.addTarget(imageReader.getSurface());
builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
CameraCaptureSession.CaptureCallback callback = new CameraCaptureSession.CaptureCallback()
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result)
Toast.makeText(MainActivity.this, "Saved:" + file, Toast.LENGTH_SHORT).show();
unlockFocus();
;
cameraCaptureSession.stopRepeating();
cameraCaptureSession.capture(builder.build(), callback, null);
catch (CameraAccessException e)
e.printStackTrace();
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textureView = (TextureView) findViewById(R.id.surface);
captureBtn = (Button) findViewById(R.id.capture);
captureBtn.setOnClickListener(this);
file = new File(getExternalFilesDir(null), "test.jpg");
@Override
protected void onResume()
super.onResume();
mBackgroundThread = new HandlerThread("camera");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
if (textureView.isAvailable())
openCamera();
else
textureView.setSurfaceTextureListener(mSurfaceTextureListener);
private void openCamera()
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(this, new String[]Manifest.permission.CAMERA,
1);
return;
//获取相机对象
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try
for (String id : cameraManager.getCameraIdList())
CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(id);
Integer facing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT)
continue;
cameraId = id;
imageReader = ImageReader.newInstance(textureView.getWidth(), textureView.getHeight(), ImageFormat.JPEG, 2);
imageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);
break;
catch (CameraAccessException e)
e.printStackTrace();
try
cameraManager.openCamera(cameraId, mStateCallback, mBackgroundHandler);
catch (CameraAccessException e)
e.printStackTrace();
/**
* 创建预览会话
*/
private void createCameraPreviewSession()
try
SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
surfaceTexture.setDefaultBufferSize(textureView.getWidth(), textureView.getHeight());
Surface surface = new Surface(surfaceTexture);
priviewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
priviewRequestBuilder.addTarget(surface);
cameraDevice.createCaptureSession(Arrays.asList(surface, imageReader.getSurface()), new CameraCaptureSession.StateCallback()
@Override
public void onConfigured(CameraCaptureSession session)
try
if (null == cameraDevice)
return;
cameraCaptureSession = session;
//预览时,需要设置自动聚焦模式
priviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
previewRequest = priviewRequestBuilder.build();
cameraCaptureSession.setRepeatingRequest(previewRequest, mCaptureCallback, mBackgroundHandler);
catch (CameraAccessException e)
e.printStackTrace();
@Override
public void onConfigureFailed(CameraCaptureSession session)
Toast.makeText(MainActivity.this, "Failed", Toast.LENGTH_SHORT).show();
, null);
catch (Exception e)
e.printStackTrace();
@Override
public void onClick(View v)
//拍照
takePic();
private void takePic()
lockFocus();
//锁住焦点
private void lockFocus()
try
priviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
mState = STATE_WAITING_LOCK;
cameraCaptureSession.capture(priviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
catch (CameraAccessException e)
e.printStackTrace();
//解决焦点
private void unlockFocus()
try
priviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
cameraCaptureSession.capture(priviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
mState = STATE_PREVIEW;
cameraCaptureSession.setRepeatingRequest(previewRequest, mCaptureCallback,
mBackgroundHandler);
catch (CameraAccessException e)
e.printStackTrace();
private ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener()
@Override
public void onImageAvailable(ImageReader reader)
//保存图片
mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), file));
;
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults)
if (requestCode == 1)
if (grantResults.length != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED)
//TODO 不同意
else
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
openCamera();
/**
*保存图片
*/
private static class ImageSaver implements Runnable
private Image mImage;
private File mFile;
public ImageSaver(Image mImage, File mFile)
this.mImage = mImage;
this.mFile = mFile;
@Override
public void run()
ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
FileOutputStream output = null;
try
output = new FileOutputStream(mFile);
output.write(bytes);
catch (IOException e)
e.printStackTrace();
finally
mImage.close();
if (null != output)
try
output.close();
catch (IOException e)
e.printStackTrace();
说明
上述代码示例,参考google官方示例。
本文代码可以到我的Github地址查看。
只有一个带有 Camera2 和旧相机 API 的 APK
】只有一个带有Camera2和旧相机API的APK【英文标题】:OnlyoneAPKwithCamera2andoldcameraAPI【发布时间】:2017-04-2922:21:29【问题描述】:我有一个使用camera2API和旧相机版本的应用。问题是我需要使用minSdkVersion16生成单个APK,并且由于显而... 查看详情
Android 10(api 29)camera2 api回归与广角相机
】Android10(api29)camera2api回归与广角相机【英文标题】:Android10(api29)camera2apiregressionwithwide-anglecamera【发布时间】:2020-05-0511:26:57【问题描述】:我在专为GooglePixel3XL设计的相机应用中使用了camera2api。该设备有两个前置摄像头(... 查看详情
android进阶宝典--camerax与camera2的使用比对(代码片段)
...就必须要用到。传统的相机app,一般使用到Camera或者Camera2比较多,但是Google的JectPack框架中引入了CameraX组件作为官方推荐相机架构,既然推出此框架,那么一定是有它自身的优势之处在的,本文将会从CameraX和... 查看详情
调用 Camera2 API onCaptureComplete() 但相机状态仍为 CONTROL_AE_STATE_PRECAPTURE
】调用Camera2APIonCaptureComplete()但相机状态仍为CONTROL_AE_STATE_PRECAPTURE【英文标题】:Camera2APIonCaptureComplete()iscalledbutcamerastateisstillCONTROL_AE_STATE_PRECAPTURE【发布时间】:2016-01-0221:17:20【问题描述】:我正在尝试创建一个应用,该应用使... 查看详情
app使用相机camerax(代码片段)
APP使用相机Android开发者>文档>指南-选择相机库CameraXCamera2Camera(已废弃)CameraX示例应用SampleDescriptionCameraXBasicDemonstrateshowtouseCameraXAPIs.CameraXAdvancedDemonstrateshowtouseCameraXAPIswithTFLiteandothersCameraXVideoDemonstrateshowtouseCameraXVide... 查看详情
Camera2 API OIS 问题
】Camera2APIOIS问题【英文标题】:Camera2APIOISIssue【发布时间】:2021-03-0902:48:40【问题描述】:我有一台华为NovaPlus设备。我启用了带有构建道具编辑的Camera2API,几乎可以正常工作,但ois不起作用。我认为一些库需要进行一些修复... 查看详情
androidcamera2教程·第一章·概览
...考技术A从Android5.0开始,Google引入了一套全新的相机框架Camera2(android.hardware.camera2)并且废弃了旧的相机框架Camera1(android.hardware.Camera)。作为一个专门从事相机应用开发的开发者来说,这一刻我等了太久了,Camera1那寥寥无几... 查看详情
android进阶宝典--camerax与camera2的使用比对(代码片段)
...就必须要用到。传统的相机app,一般使用到Camera或者Camera2比较多,但是Google的JectPack框架中引入了CameraX组件作为官方推荐相机架构,既然推出此框架 查看详情
Android使用camera2复制内置视频录制质量和帧率
】Android使用camera2复制内置视频录制质量和帧率【英文标题】:Androidcopybuilt-invideorecordingqualityandframerateusingcamera2【发布时间】:2019-06-2502:10:20【问题描述】:使用camera2API获得的图像质量和帧速率与我使用相机应用手动将视频录... 查看详情
Android中Camera和Camera2的区别
】Android中Camera和Camera2的区别【英文标题】:DifferenceBetweenCameraandCamera2inAndroid【发布时间】:2017-09-1200:10:08【问题描述】:我正在构建一个类似于社交媒体的应用程序,人们可以在其中分享照片和视频,例如Instagram。这就是相机... 查看详情
Camera2 API Android min SDK [重复]
】Camera2APIAndroidminSDK[重复]【英文标题】:Camera2APIAndroidminSDK[duplicate]【发布时间】:2016-12-2821:42:26【问题描述】:您好,我正在尝试开发一个使用自定义相机的应用程序,当我尝试使用相机类时,它已被弃用,因此我使用了android... 查看详情
androidcameraapi/camera2api相机预览及滤镜贴纸等处理(代码片段)
AndroidLollipop增加了Camera2API,并将原来的CameraAPI标记为废弃了。相对原来的CameraAPI来说,Camera2是重新定义的相机API,也重构了相机API的架构。初看之下,可能会感觉Camera2使用起来比Camera要复杂,然而使用过后... 查看详情
Android:Camera2错误参数传递给相机服务
】Android:Camera2错误参数传递给相机服务【英文标题】:Android:Camera2Badargumentpassedtocameraservice【发布时间】:2015-12-0714:32:37【问题描述】:有人知道我做错了什么吗...我想使用SurfaceView捕获具有预览屏幕的图像。我能够在表面视图... 查看详情
android多媒体功能开发(14)——camera2框架(代码片段)
从Android5.0开始,引入了一套Camera2框架控制相机实现拍照和录像等功能,相关的类定义在android.hardware.camera2包中。原有的android.hardware包中的Camera类降级使用,因为其功能少,灵活性差,满足不了日益复杂的相... 查看详情
EGL 错误:0x3003,相机设备遇到严重错误(Camera2 Api)
】EGL错误:0x3003,相机设备遇到严重错误(Camera2Api)【英文标题】:EGLerror:0x3003,Thecameradevicehasencounteredaseriouserror(Camera2Api)【发布时间】:2019-01-0500:47:39【问题描述】:我正在编写一个应用程序控制闪光灯相机手机,我可以控制... 查看详情
横向模式下的预览方向使用 Camera2 api 顺时针旋转
】横向模式下的预览方向使用Camera2api顺时针旋转【英文标题】:PrevieworientationinlandscapemodeisrotatedclockwisewithCamera2api\'s【发布时间】:2015-09-2915:25:55【问题描述】:我使用Camera2api编写了一个相机应用程序。但是当我以横向模式打... 查看详情
使用previewview来展示相机预览
...美实现这个却并非易事。原因是,在某些特别极端情况下camera2API的使用会变得很复杂,而且在不同设备上的行为还会有所不同。还好,JetpackCameraX库的PreviewView可以帮助您解决这一问题。通过在各种Android设备上提供开发者友好、... 查看详情
支持 Android Camera Api 和 Camera2 Api 的问题
】支持AndroidCameraApi和Camera2Api的问题【英文标题】:ProblemssupportingAndroidCameraApiandCamera2Api【发布时间】:2016-02-1414:56:14【问题描述】:我正在帮助开发一个应用程序,该应用程序需要支持所有Android版本的相机使用,而不使用任何... 查看详情