GLSurfaceView 和 SurfaceView 是 Android 中用于顯示圖像的兩個視圖類,它們在實現(xiàn)方式和使用場景上有一些區(qū)別。
- 實現(xiàn)方式:GLSurfaceView 基于 OpenGL ES 技術實現(xiàn),可以通過 OpenGL ES 渲染圖像。而 SurfaceView 則是通過基于線程的繪制方式,可以在獨立的線程中進行繪制操作。
- 性能:由于 GLSurfaceView 使用了 OpenGL ES 技術,可以充分利用 GPU 進行圖像渲染,因此在處理復雜圖像和動畫時通常具有更好的性能。相比之下,SurfaceView 使用 CPU 進行圖像繪制,性能可能相對較低。
- 使用場景:如果你需要進行復雜的圖形繪制、圖像處理或者動畫,那么 GLSurfaceView 是一個更好的選擇,因為它提供了強大的 OpenGL ES 功能支持。另外,GLSurfaceView 還可以與其他 OpenGL ES 相關的庫和工具進行集成。而 SurfaceView 在一些簡單的圖像展示場景中更常見,例如顯示圖片、播放視頻等。
- 使用復雜度:由于 GLSurfaceView 使用了 OpenGL ES,因此它需要編寫著色器程序來進行圖像渲染,并且需要處理 OpenGL ES 相關的上下文管理。相對而言,SurfaceView 的使用相對簡單,只需繼承 SurfaceView 類并實現(xiàn)自定義的繪制邏輯即可。
需要注意的是,由于 GLSurfaceView 使用了 OpenGL ES 技術,它對開發(fā)者的要求更高,需要熟悉 OpenGL ES 相關的知識和編程技術。而 SurfaceView 在一些簡單的場景中更易于使用和理解。
總之,GLSurfaceView 適用于需要進行復雜圖形渲染和動畫的場景,而 SurfaceView 適用于一般的圖像展示和簡單的繪制需求。選擇哪個類取決于你的具體需求和技術能力。
-
在 AndroidManifest.xml 文件中添加相機權限:
<uses-permission android:name="android.permission.CAMERA" />
-
創(chuàng)建相機預覽的布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".CameraActivity"> <android.opengl.GLSurfaceView android:id="@+id/glsurfaceview" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>
-
創(chuàng)建相機預覽的 Activity,用于管理相機預覽和 OpenGL 繪制、
package com.test.jnitest import android.Manifest import android.content.Context import android.content.pm.PackageManager import android.graphics.SurfaceTexture import android.hardware.camera2.CameraCaptureSession import android.hardware.camera2.CameraDevice import android.hardware.camera2.CameraManager import android.hardware.camera2.CaptureRequest import android.opengl.GLSurfaceView import android.os.Bundle import android.util.Size import android.view.Surface import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import com.test.jnitest.databinding.ActivityCameraBinding import java.util.* class CameraActivity : AppCompatActivity() { var mGLSurfaceView:GLSurfaceView?=null var mRenderer:CameraRenderer?=null var cameraManager:CameraManager?=null var mCameraDevice:CameraDevice?=null var mCaptureSession:CameraCaptureSession?=null var mRequestBuild:CaptureRequest.Builder?=null var size = Size(1920,1080) lateinit var mContext:Context lateinit var binding:ActivityCameraBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityCameraBinding.inflate(layoutInflater) setContentView(binding.root) // 設置狀態(tài)欄透明 window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) //設置導航欄透明 window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) mContext = this mGLSurfaceView = binding.glsurfaceview mGLSurfaceView?.setEGLContextClientVersion(2) // 創(chuàng)建并設置相機渲染器 mRenderer = CameraRenderer(mGLSurfaceView!!) mGLSurfaceView?.setRenderer(mRenderer) mGLSurfaceView?.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); // 獲取攝像頭管理器 cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { this.requestPermissions(mutableListOf<String>(Manifest.permission.CAMERA).toTypedArray(),200) return } cameraManager?.openCamera("5",mCameraStateCallback,null) } override fun onResume() { super.onResume() mGLSurfaceView?.onResume() } override fun onDestroy() { super.onDestroy() closeCamera() } // 相機狀態(tài)回調 var mCameraStateCallback = object : CameraDevice.StateCallback() { override fun onOpened(p0: CameraDevice) { mCameraDevice = p0 // 創(chuàng)建預覽會話 var surfaceTexture = mRenderer?.mSurfaceTexture surfaceTexture?.setDefaultBufferSize(size.width,size.height) var surface = Surface(surfaceTexture) mRequestBuild = mCameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) mRequestBuild?.addTarget(surface) val surfaces = Arrays.asList(surface) mCameraDevice?.createCaptureSession(surfaces,mCaptureCallback,null) } override fun onDisconnected(p0: CameraDevice) { p0.close() } override fun onError(p0: CameraDevice, p1: Int) { p0.close() } } // 捕獲會話狀態(tài)回調 var mCaptureCallback = object : CameraCaptureSession.StateCallback() { override fun onConfigured(p0: CameraCaptureSession) { mCaptureSession = p0 mRequestBuild?.build()?.let { mCaptureSession?.setRepeatingRequest(it,null,null) } } override fun onConfigureFailed(p0: CameraCaptureSession) { p0.close() mCaptureSession = null } } // 關閉相機 private fun closeCamera() { mCaptureSession?.close() mCaptureSession = null mCameraDevice?.close() mCameraDevice = null } }
-
創(chuàng)建相機渲染器,創(chuàng)建一個繼承自 GLSurfaceView.Renderer 的類,用于實現(xiàn) OpenGL 繪制和與相機交互的邏輯文章來源:http://www.zghlxwxcb.cn/news/detail-704347.html
package com.test.jnitest import android.content.Context import android.graphics.SurfaceTexture import android.graphics.SurfaceTexture.OnFrameAvailableListener import android.opengl.GLES11Ext import android.opengl.GLES20 import android.opengl.GLSurfaceView import java.nio.ByteBuffer import java.nio.ByteOrder import java.nio.FloatBuffer import javax.microedition.khronos.egl.EGLConfig import javax.microedition.khronos.opengles.GL10 class CameraRenderer(var mGLSurfaceView: GLSurfaceView):GLSurfaceView.Renderer,OnFrameAvailableListener { //攝像頭圖像的紋理ID var textureId:Int = 0 var mSurfaceTexture:SurfaceTexture?=null private val COORDS_PER_VERTEX = 2 private val TEXTURE_COORDS_PER_VERTEX = 2 //頂點著色器 var vertexShaderCode = """attribute vec4 a_position; attribute vec2 a_textureCoord; varying vec2 v_textureCoord; void main() { gl_Position = a_position; v_textureCoord = a_textureCoord; } """ // 片段著色器 var fragmentShaderCode = """#extension GL_OES_EGL_image_external : require precision mediump float; uniform samplerExternalOES u_texture; varying vec2 v_textureCoord; void main() { gl_FragColor = texture2D(u_texture, v_textureCoord); } """ //頂點坐標數(shù)據(jù),表示預覽圖像的位置和大小。 private val VERTEX_COORDS = floatArrayOf( -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f ) //紋理坐標數(shù)據(jù),表示攝像頭圖像在預覽區(qū)域的映射關系。 private val TEXTURE_COORDS = floatArrayOf( 0f, 1f, 1f, 1f, 0f, 0f, 1f, 0f ) //著色器程序的ID private var programId = 0 //頂點屬性的句柄 private var positionHandle = 0 private var textureCoordHandle = 0 init { textureId = createTexture() mSurfaceTexture = SurfaceTexture(textureId) mSurfaceTexture?.setOnFrameAvailableListener(this) } /** * 初始化OpenGL,并加載頂點著色器和片段著色器。通過編譯和鏈接著色器,創(chuàng)建著色器程序,并獲取頂點屬性的句柄。 */ override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) { // 在此進行 OpenGL 環(huán)境初始化,如創(chuàng)建紋理、著色器程序等 // 設置清空顏色緩沖區(qū)時的顏色值為黑色 GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f) // 加載頂點著色器和片段著色器 val vertexShader: Int = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode) val fragmentShader: Int = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode) // 創(chuàng)建著色器程序并將頂點著色器和片段著色器綁定到該程序上 programId = GLES20.glCreateProgram() GLES20.glAttachShader(programId, vertexShader) GLES20.glAttachShader(programId, fragmentShader) // 鏈接著色器程序并檢查是否鏈接成功 GLES20.glLinkProgram(programId) // 獲取頂點坐標屬性和紋理坐標屬性的位置 positionHandle = GLES20.glGetAttribLocation(programId, "a_position") textureCoordHandle = GLES20.glGetAttribLocation(programId, "a_textureCoord") // 使用著色器程序 GLES20.glUseProgram(programId) } override fun onSurfaceChanged(p0: GL10?, p1: Int, p2: Int) { // 在此響應 GLSurfaceView 尺寸變化,如更新視口大小等 GLES20.glViewport(0, 0, p1, p2); } /** * 繪制每一幀,在此進行實際的繪制操作,如清屏、繪制紋理等 */ override fun onDrawFrame(p0: GL10?) { // 更新紋理圖像 mSurfaceTexture?.updateTexImage(); // 清空顏色緩沖區(qū) GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); // 設置頂點坐標屬性并啟用 GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, floatBufferFromArray(VERTEX_COORDS)); GLES20.glEnableVertexAttribArray(positionHandle); // 設置紋理坐標屬性并啟用 GLES20.glVertexAttribPointer(textureCoordHandle, TEXTURE_COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, floatBufferFromArray(TEXTURE_COORDS)); GLES20.glEnableVertexAttribArray(textureCoordHandle); // 激活紋理單元0,并將當前紋理綁定到外部OES紋理目標 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId); // 繪制三角帶的圖元 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, VERTEX_COORDS.size / COORDS_PER_VERTEX); } /** * 創(chuàng)建攝像頭紋理 */ private fun createTexture(): Int { // 創(chuàng)建一個用于存儲紋理ID的數(shù)組 val textureIds = IntArray(1) // 生成一個紋理對象,并將紋理ID存儲到數(shù)組中 GLES20.glGenTextures(1, textureIds, 0) // 將當前紋理綁定到OpenGL ES的紋理目標(外部OES紋理) GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureIds[0]) // 設置紋理S軸的包裹模式為GL_CLAMP_TO_EDGE,即超出邊界的紋理坐標會被截取到邊界上的紋素 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE) // 設置紋理T軸的包裹模式為GL_CLAMP_TO_EDGE GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE) // 設置紋理縮小過濾器為GL_NEAREST,即使用最近鄰采樣的方式進行紋理縮小 GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST) // 設置紋理放大過濾器為GL_NEAREST GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST) return textureIds[0] } /** * 加載著色器,接受著色器類型和著色器代碼作為參數(shù),并將編譯后的著色器對象的ID返回 * @param type 著色器類型,如GLES20.GL_VERTEX_SHADER或GLES20.GL_FRAGMENT_SHADER * @param shaderCode 著色器代碼 * @return 著色器的ID */ private fun loadShader(type: Int, shaderCode: String): Int { // 創(chuàng)建一個新的著色器對象 val shader = GLES20.glCreateShader(type) // 將著色器代碼加載到著色器對象中 GLES20.glShaderSource(shader, shaderCode) // 編譯著色器 GLES20.glCompileShader(shader) return shader } private fun floatBufferFromArray(array: FloatArray): FloatBuffer? { val byteBuffer: ByteBuffer = ByteBuffer.allocateDirect(array.size * 4) byteBuffer.order(ByteOrder.nativeOrder()) val floatBuffer: FloatBuffer = byteBuffer.asFloatBuffer() floatBuffer.put(array) floatBuffer.position(0) return floatBuffer } override fun onFrameAvailable(p0: SurfaceTexture?) { // 當相機有新的幀可用時回調,可以在這里進行一些處理 mGLSurfaceView.requestRender() } }
通過以上步驟,你可以實現(xiàn)使用 Camera2 API 和 GLSurfaceView 預覽相機的功能。在 CameraActivity 中,我們通過 Camera2 API 打開相機并創(chuàng)建相機預覽會話,然后將相機預覽的 SurfaceTexture 傳遞給 CameraRenderer,在 CameraRenderer 的 onDrawFrame() 方法中繪制相機預覽幀的紋理內容。文章來源地址http://www.zghlxwxcb.cn/news/detail-704347.html
到了這里,關于Android 使用Camera2 API 和 GLSurfaceView實現(xiàn)相機預覽的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!