我们正在使用Lib流媒体库开发实时视频流.Lib流媒体库支持旧的Camera api,一切正常但我们需要将Camera2 api集成到Lib流媒体库.一些功能,如使用Camera2 api的视频预览显示,我们集成但我们需要连续获取流的视频帧数据,如何获得它?请提出前进的方向.
在Lib流媒体库中,他们使用下面的帧数据回调方法:
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
// here we get frame by frame data
}
});
Run Code Online (Sandbox Code Playgroud) 我是Android开发中的新手,所以如果我的问题很简单,我会提前道歉.在我的应用程序的一部分,我需要我的后置摄像头的实时预览,所以我创建了一个自定义类,扩展SurfaceView并实现SurfaceHolder.Callback(我基本上遵循了android文档中的说明).
不幸的是,我正在Nexus 5x中测试我的应用程序,我刚刚意识到它已经以相反的方式安装了相机传感器.出于这个原因,在我的Nexus 5x上运行时,我的应用程序的相机预览显示为颠倒,这是我不想要的.
似乎新的android.hardware.camera2 API能够自动处理这个问题.最终我需要使用这个新API更新我的所有代码,但是现在我需要的是使用旧相机API时的快速修复.
所以我在那里读书,我发现了一段代码,我需要在SurfaceChanged方法中引入以解决这个问题.这里是:
Display display = ((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if(display.getRotation() == Surface.ROTATION_0)
{
parameters.setPreviewSize(capHeight, capWidth);
camera.setDisplayOrientation(90);
}
if(display.getRotation() == Surface.ROTATION_90)
{
parameters.setPreviewSize(capWidth, capHeight);
}
if(display.getRotation() == Surface.ROTATION_180)
{
parameters.setPreviewSize(capHeight, capWidth);
}
if(display.getRotation() == Surface.ROTATION_270)
{
parameters.setPreviewSize(capWidth, capHeight);
camera.setDisplayOrientation(180);
}
camera.setParameters(parameters);*/
camera.startPreview();
Run Code Online (Sandbox Code Playgroud)
问题是我没有看到某些事情发生了变化.
有什么想法吗?
我正在使用新的camera2 API构建自定义相机.我的代码是基于谷歌提供的代码示例在这里.
我无法找到一种方法来全屏显示相机.在代码示例中,他们使用比率优化来适应所有屏幕,但它只占屏幕高度的3/4左右.
这是我的代码AutoFitTextureView:
public class AutoFitTextureView extends TextureView {
private int mRatioWidth = 0;
private int mRatioHeight = 0;
public AutoFitTextureView(Context context) {
this(context, null);
}
public AutoFitTextureView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
* calculated from the parameters. Note …Run Code Online (Sandbox Code Playgroud) 我的 OpenGL/Skia Android Camera2 应用程序遇到奇怪的问题。
我的相机将帧渲染为SurfaceTexture,这是GL_TEXTURE_EXTERNAL_OESOpenGL 中的纹理。
然后,我可以使用简单的直通着色器简单地将这个 OpenGL 纹理渲染到所有输出(1920x1080 Preview EGLSurface、4000x2000 Video Recorder )。EGLSurface
Camera --> GL_TEXTURE_EXTERNAL_OES
GL_TEXTURE_EXTERNAL_OES --> PassThroughShader --> Preview Output EGLSurface
GL_TEXTURE_EXTERNAL_OES --> PassThroughShader --> Video Recorder Output EGLSurface
Run Code Online (Sandbox Code Playgroud)
现在我想将 Skia 引入其中,它允许我在将其传递到输出之前渲染到相机框架上(例如,在框架上绘制一个红色框)。由于我无法GL_TEXTURE_EXTERNAL_OES再次直接渲染到相同的对象上,因此我创建了一个单独的离屏纹理 ( GL_TEXTURE_2D) 和一个单独的离屏帧缓冲区 (FBO1) 并附加了它们。
现在,当我渲染到 FBO1 时,屏幕外纹理GL_TEXTURE_2D会更新,然后我想将其传递GL_TEXTURE_2D到我的输出:
Camera --> GL_TEXTURE_EXTERNAL_OES
GL_TEXTURE_EXTERNAL_OES --> Skia to FBO1 + drawing a red box --> GL_TEXTURE_2D
GL_TEXTURE_2D --> PassThroughShader --> Preview Output EGLSurface
GL_TEXTURE_2D …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用camera2 API从相机捕获图像数据.我主要使用的是从android Capture2RAW示例中获取的代码.在完全停止之前,只有少数图像通过(即调用onImageAvailable).我尝试使用不同大小的RAW_SENSOR和JPEG格式捕获相同的结果.我究竟做错了什么?
this.mImageReader = ImageReader.newInstance(width, height, ImageFormat.RAW_SENSOR, /*maxImages*/ 1);
Surface surface = this.mImageReader.getSurface();
final List<Surface> surfaces = Arrays.asList(surface);
this.mCamera.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
// Callback methods here
}, null);
CaptureRequest.Builder captureRequestBuilder;
captureRequestBuilder = this.mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(surface);
this.mCaptureRequest = captureRequestBuilder.build();
this.mCaptureSession.setRepeatingRequest(mCaptureRequest, null, null);
Run Code Online (Sandbox Code Playgroud) 我需要对实时摄像机数据(仅来自Y平面)执行CPU端只读过程,然后在GPU上进行渲染.在处理完成之前不应渲染帧(因此我并不总是希望从摄像机渲染最新帧,只是CPU端已完成处理的最新帧).渲染与相机处理分离,即使相机帧以低于此速率的速度到达,目标也是60 FPS.
在Android上有一个相关但更高级别的问题:最低开销的相机到CPU到GPU的方法
更详细地描述当前设置:我们有一个用于摄像机数据的应用程序端缓冲池,其中缓冲区是"空闲","显示"或"待处理显示".当来自摄像机的新帧到达时,我们获取一个空闲缓冲区,在那里存储帧(或者如果实际数据在某个系统提供的缓冲池中,则对它进行引用),进行处理并将结果存储在缓冲区中,然后设置缓冲区"待处理显示".在渲染器线程中,如果在渲染循环开始处有任何缓冲区"待处理显示",我们将其锁定为"显示"中的一个,渲染相机,并使用从其计算的处理信息渲染其他内容相机框架.
感谢@ fadden对上面链接的问题的回复,我现在明白了android camera2 API的"并行输出"功能在各种输出队列之间共享缓冲区,因此不应该涉及数据上的任何副本,至少在现代android上.
在评论中有一个建议,我可以同时锁定SurfaceTexture和ImageReader输出,只是"坐在缓冲区",直到处理完成.不幸的是,我不认为这适用于我的情况,因为我们仍然希望以60 FPS驱动的解耦渲染,并且仍然需要访问前一帧,同时处理新帧以确保无法获得不同步.
我想到的一个解决方案是拥有多个SurfaceTextures - 我们每个应用程序端缓冲区中都有一个(我们目前使用3个).使用该方案,当我们获得一个新的相机帧时,我们将从我们的应用程序池中获得一个空闲缓冲区.然后我们调用acquireLatestImage()ImageReader获取要处理的数据,并updateTexImage()在空闲缓冲区中调用SurfaceTexture.在渲染时我们只需要确保来自"in display"缓冲区的SufaceTexture是绑定到GL的那个,并且所有内容都应该在大多数时间同步(因为@fadden评论说在调用updateTexImage()和之间存在争用acquireLatestImage()但是时间窗口应该足够小以使其变得罕见,并且无论如何使用缓冲区中的时间戳可能是可行的和可修复的).
我注意到文档updateTexImage()只能在SurfaceTexture绑定到GL上下文时调用,这表明我在相机处理线程中也需要GL上下文,因此相机线程可以updateTexImage()在"免费"缓冲区中的SurfaceTexture上执行而渲染线程仍然能够从"显示"缓冲区中的SurfaceTexture渲染.
所以,对于问题:
这听起来很有希望,我会试一试; 但是,如果有人(基本上是@fadden!)知道任何我忽略的内部细节会让这个想法变得糟糕,那么我觉得值得一试.
可以同时绑定Preview、ImageAnalysis、吗?VideoCapture成对组合时,所有可能的组合(即Preview+ ImageAnalysis、Preview+VideoCapture和ImageAnalysis+ VideoCapture)都工作得很好,但将所有三个组合在一起会引发以下异常。
java.lang.IllegalArgumentException: No supported surface combination is found for camera device - Id : 1. May be attempting to bind too many use cases.
at androidx.camera.camera2.internal.Camera2DeviceSurfaceManager.getSuggestedResolutions(Camera2DeviceSurfaceManager.java:193)
at androidx.camera.core.CameraX.calculateSuggestedResolutions(CameraX.java:943)
at androidx.camera.core.CameraX.bindToLifecycle(CameraX.java:293)
at androidx.camera.lifecycle.ProcessCameraProvider.bindToLifecycle(ProcessCameraProvider.java:229)
Run Code Online (Sandbox Code Playgroud)
是否有任何解决方法可以让我使用ImageAnalysis并同时录制视频?
我已经按照 Google CameraX代码实验室来实现自定义相机。相机预览很好,但是当我在旋转图像捕获图像后拍摄图像时。我正在以纵向模式拍摄图像,但保存的图像是横向的。这是配置相机的方法
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener(Runnable {
// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Preview
val preview = Preview.Builder()
.setTargetRotation(this.windowManager.defaultDisplay.rotation)
.build()
.also {
it.setSurfaceProvider(viewFinder.createSurfaceProvider())
}
imageCapture = ImageCapture.Builder()
.setTargetRotation(this.windowManager.defaultDisplay.rotation)
.build()
val imageAnalyzer = ImageAnalysis.Builder()
.build()
.also {
it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->
Log.d(TAG, "Average luminosity: $luma")
})
}
// Select back camera as a default
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try { …Run Code Online (Sandbox Code Playgroud) android image-rotation android-orientation android-camera2 android-camerax
我正在尝试创建一个CameraCaptureSession具有四个输出的 Camera2:
SurfaceView,最高 1080p)ImageReader,最多 8k 照片)MediaRecorder/ MediaCodec,最多 4k 视频)ImageReader最多 4k 视频帧)不幸的是,Camera2 不支持同时连接所有这四个输出(表面),因此我必须做出妥协。
对我来说最合乎逻辑的妥协是将两个视频捕获管道合并为一个,以便帧处理输出(#4,ImageReader)将帧重定向到视频捕获输出(#3,MediaRecorder)。
如何从 ImageReader 写入图像:
val imageReader = ImageReader.newInstance(4000, 2256, ImageFormat.YUV_420_888, 3)
imageReader.setOnImageAvailableListener({ reader ->
val image = reader.acquireNextImage() ?: return@setOnImageAvailableListener
callback.onVideoFrameCaptured(image)
}, queue.handler)
val captureSession = device.createCaptureSession(.., imageReader.surface)
Run Code Online (Sandbox Code Playgroud)
..进入Surface从MediaRecorder?
val surface = MediaCodec.createPersistentInputSurface()
val recorder = MediaRecorder(context)
..
recorder.setInputSurface(surface)
Run Code Online (Sandbox Code Playgroud)
我想我可能需要一个带有直通着色器的 OpenGL 管道 - 但我不知道如何从ImageReader …
android opengl-es surfaceview android-camera android-camera2
android ×10
android-camera2 ×10
opengl-es ×3
c++ ×2
android-view ×1
camera ×1
camera2 ×1
skia ×1
streaming ×1
surfaceview ×1
video ×1