android平臺下OpenGL ES 3.0使用TextureView對相機Camera預覽實時處理
OpenGL ES 3.0學習實踐
- android平臺下OpenGL ES 3.0從零開始
- android平臺下OpenGL ES 3.0繪製純色背景
- android平臺下OpenGL ES 3.0繪製圓點、直線和三角形
- android平臺下OpenGL ES 3.0繪製彩色三角形
- android平臺下OpenGL ES 3.0從矩形中看矩陣和正交投影
- android平臺下OpenGL ES 3.0著色語言基礎知識(上)
- android平臺下OpenGL ES 3.0著色語言基礎知識(下)
- android平臺下OpenGL ES 3.0例項詳解頂點屬性、頂點陣列
- android平臺下OpenGL ES 3.0例項詳解頂點緩衝區物件(VBO)和頂點陣列物件(VAO)
- android平臺下OpenGL ES 3.0繪製立方體的幾種方式
- android平臺下OpenGL ES 3.0實現2D紋理貼圖顯示bitmap
- android平臺下OpenGL ES 3.0基於GLSurfaceView對相機Camera預覽實時處理
- android平臺下OpenGL ES 3.0基於TextureView對相機Camera預覽實時處理
GLSurfaceView和TextureView對比
相信接觸過直播或者視訊播放的朋友,對這兩個控制元件應該很熟悉,這個兩個控制元件都可以用來渲染視訊用的,下面來看下他們的區別:
- GLSurfaceView:
前面的一些部落格都是基於
GLSurfaceView
來實現渲染的,因為它內部自帶了EGL的管理以及渲染執行緒。另外它定義了使用者需要實現的Render介面,其中EglHelper
和GLThread
分別實現了上面提到的管理EGL環境
和渲染執行緒
的工作。
缺點
:GLSurfaceView將OpenGL繫結到一起,換言之,GLSurfaceView一但銷燬,伴隨的OpenGL也一起銷燬了,一個OpenGL只能渲染一個GLSurfaceView
。
- TextureView:
這個控制元件是在在android 4.0中引入的,和SurfaceView不同,它不會在WMS中單獨建立視窗,而是作為一個普通View,因此可以和其它普通View一樣進行移動,旋轉,縮放,動畫等變化。值得注意的是TextureView必須在
硬體加速的視窗
中。
缺點
:使用這個控制元件需要自己來實現EGL管理和渲染執行緒,當然了,雖然麻煩了一點,但是也更為靈活
。
注意:
TextureView本身內建了一個SurfaceTexture
,用來配合EGL來將影象顯示到螢幕上,而我們自定義的SurfaceTexture用來接收Camera的預覽影象來做二次處理。
開始實踐
我們現在就可以仿照GLSurfaceView
的實現原理,基於HandlerThread
來自己實現渲染執行緒和EGL環境管理
:
回到之後的專案工程,新建TextureEGLHelper
在啟動的CameraTextureActivity中初始化如下程式碼
:
private void setupView() {
mTextureView = new TextureView(this);
setContentView(mTextureView);
//例項化相機採集類
mCameraPick = new CameraV1Pick();
mCameraPick.bindTextureView(mTextureView);
}
因為這裡使用的都是CameraV1版本的相機
,所以新建一個CameraV1Pick相機採集類
:
public class CameraV1Pick implements TextureView.SurfaceTextureListener {
private static final String TAG = "CameraV1Pick";
private TextureView mTextureView;
private int mCameraId;
private ICamera mCamera;
private TextureEGLHelper mTextureEglHelper;
public void bindTextureView(TextureView textureView) {
this.mTextureView = textureView;
mTextureEglHelper = new TextureEGLHelper();
mTextureView.setSurfaceTextureListener(this);
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
//載入OES紋理ID
final int textureId = TextureUtils.loadOESTexture();
//初始化操作
mTextureEglHelper.initEgl(mTextureView, textureId);
//自定義的SurfaceTexture
SurfaceTexture surfaceTexture = mTextureEglHelper.loadOESTexture();
//前置攝像頭
mCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
mCamera = new CameraV1((Activity) mTextureView.getContext());
if (mCamera.openCamera(mCameraId)) {
mCamera.setPreviewTexture(surfaceTexture);
mCamera.enablePreview(true);
} else {
Log.e(TAG, "openCamera failed");
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
mTextureEglHelper.onSurfaceChanged(width, height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
if (mCamera != null) {
mCamera.enablePreview(false);
mCamera.closeCamera();
mCamera = null;
}
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
public void onDestroy() {
if (mTextureEglHelper != null) {
mTextureEglHelper.onDestroy();
}
}
}
上面的註釋比較清楚了,在onSurfaceTextureAvailable
的回撥中,首先通過TextureUtils.loadOESTexture
方法載入外部紋理textureId
,然後通過mTextureEglHelper
這個例項初始化EGL環境
,接著建立一個基於textureId
的自定義SurfaceTexture(它對影象流的處理並不直接顯示,而是轉為GL外部紋理,因此可用於影象流資料的二次處理(如Camera濾鏡,桌面特效等)
,最後開啟相機,將剛才自定義的SurfaceTexture
設定到相機中。
其中載入外部紋理ID的loadOESTexture
的方法實現如下:
/**
* 載入OES Texture
*
* @return
*/
public static int loadOESTexture() {
int[] textureIds = new int[1];
GLES20.glGenTextures(1, textureIds, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureIds[0]);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
return textureIds[0];
}
封裝EGL環境管理和執行緒渲染類
EGL主要需要四個物件,一個EGLDisplay描述EGL顯示屏,一個EGLConfig,一個EGLContext,一個EGLSurface描述
接下來就是筆者剛剛說到的EGL環境管理和執行緒渲染
類,主要用來初始化EGL環境
和線上程中渲染。
public class TextureEGLHelper extends HandlerThread implements SurfaceTexture.OnFrameAvailableListener {
private static final String TAG = "TextureEGLHelper";
@IntDef({EGLMessage.MSG_INIT, EGLMessage.MSG_RENDER, EGLMessage.MSG_DESTROY})
@Retention(RetentionPolicy.SOURCE)
public @interface EGLMessage {
int MSG_INIT = 100;
int MSG_RENDER = 200;
int MSG_DESTROY = 300;
}
private HandlerThread mHandlerThread;
private Handler mHandler;
private TextureView mTextureView;
private int mOESTextureId;
/**
* 顯示裝置
*/
private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;
/**
* EGL上下文
*/
private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT;
/**
* 描述幀緩衝區配置引數
*/
private EGLConfig[] configs = new EGLConfig[1];
/**
* EGL繪圖表面
*/
private EGLSurface mEglSurface;
/**
* 自定義的SurfaceTexture
* 用來接受Camera資料作二次處理
*/
private SurfaceTexture mOESSurfaceTexture;
private CameraTextureRenderer mTextureRenderer;
private final class TextureHandler extends Handler {
public TextureHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case EGLMessage.MSG_INIT:
//筆者使用的是OpenGL ES 3.0
initEGLContext(3);
return;
case EGLMessage.MSG_RENDER:
//開始渲染
drawFrame();
return;
case EGLMessage.MSG_DESTROY:
//銷燬
return;
default:
return;
}
}
}
public TextureEGLHelper() {
super("TextureEGLHelper");
}
public void initEgl(TextureView textureView, int textureId) {
mTextureView = textureView;
mOESTextureId = textureId;
//啟動執行緒
mHandlerThread = new HandlerThread("Renderer Thread");
mHandlerThread.start();
mHandler = new TextureHandler(mHandlerThread.getLooper());
//執行緒中初始化
mHandler.sendEmptyMessage(EGLMessage.MSG_INIT);
}
/**
* 初始化EGL環境
*
* @param clientVersion
*/
private void initEGLContext(int clientVersion) {
//獲取預設顯示裝置
mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {
throw new RuntimeException("eglGetDisplay error: " + EGL14.eglGetError());
}
//存放EGL版本號
int[] version = new int[2];
version[0] = 3;
if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) {
throw new RuntimeException("eglInitialize error: " + EGL14.eglGetError());
}
//配置列表
int[] attributes = {
EGL14.EGL_BUFFER_SIZE, 32,
EGL14.EGL_RED_SIZE, 8,
EGL14.EGL_GREEN_SIZE, 8,
EGL14.EGL_BLUE_SIZE, 8,
EGL14.EGL_ALPHA_SIZE, 8,
EGL14.EGL_RENDERABLE_TYPE, 4,
EGL14.EGL_SURFACE_TYPE, EGL14.EGL_WINDOW_BIT,
EGL14.EGL_NONE
};
int[] numConfigs = new int[1];
//EGL選擇配置
if (!EGL14.eglChooseConfig(mEGLDisplay, attributes, 0, configs, 0, configs.length, numConfigs, 0)) {
throw new RuntimeException("eglChooseConfig error: " + EGL14.eglGetError());
}
//獲取TextureView內建的SurfaceTexture作為EGL的繪圖表面,也就是跟系統螢幕打交道
SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
if (surfaceTexture == null) {
throw new RuntimeException("surfaceTexture is null");
}
//建立EGL顯示視窗
final int[] surfaceAttributes = {EGL14.EGL_NONE};
mEglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, configs[0], surfaceTexture, surfaceAttributes, 0);
//建立上下文環境
int[] contextAttributes = {
EGL14.EGL_CONTEXT_CLIENT_VERSION, clientVersion,
EGL14.EGL_NONE
};
mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT, contextAttributes, 0);
if (mEGLDisplay == EGL14.EGL_NO_DISPLAY || mEGLContext == EGL14.EGL_NO_CONTEXT) {
throw new RuntimeException("eglCreateContext fail error: " + EGL14.eglGetError());
}
if (!EGL14.eglMakeCurrent(mEGLDisplay, mEglSurface, mEglSurface, mEGLContext)) {
throw new RuntimeException("eglMakeCurrent error: " + EGL14.eglGetError());
}
//載入渲染器
mTextureRenderer = new CameraTextureRenderer(mOESTextureId);
mTextureRenderer.onSurfaceCreated();
}
public void onSurfaceChanged(int width, int height) {
//設定視口
mTextureRenderer.onSurfaceChanged(width, height);
}
private void drawFrame() {
if (mTextureRenderer != null) {
//指定mEGLContext為當前系統的EGL上下文
EGL14.eglMakeCurrent(mEGLDisplay, mEglSurface, mEglSurface, mEGLContext);
//呼叫渲染器繪製
mTextureRenderer.onDrawFrame(mOESSurfaceTexture);
//交換緩衝區,android使用雙緩衝機制,所以我們繪製的都是在後臺緩衝區,通過交換將後臺緩衝區變為前臺顯示區,下一幀的繪製仍然在後臺緩衝區
EGL14.eglSwapBuffers(mEGLDisplay, mEglSurface);
}
}
@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
if (mHandler != null) {
//通知子執行緒渲染
mHandler.sendEmptyMessage(EGLMessage.MSG_RENDER);
}
}
public SurfaceTexture loadOESTexture() {
//載入自定義的SurfaceTexture傳遞給相機
mOESSurfaceTexture = new SurfaceTexture(mOESTextureId);
mOESSurfaceTexture.setOnFrameAvailableListener(this);
return mOESSurfaceTexture;
}
/**
* 銷燬
* 釋放
*/
public void onDestroy() {
if (mHandlerThread != null) {
mHandlerThread.quitSafely();
}
if (mHandler != null) {
mHandler.removeCallbacksAndMessages(null);
}
}
}
相機操作封裝
ICamera程式碼就不貼了
,本身是抽象的一個相機的操作介面類。
public class CameraV1 implements ICamera {
private Activity mActivity;
private int mCameraId;
private Camera mCamera;
public CameraV1(Activity activity) {
mActivity = activity;
}
/**
* 開啟相機
*
* @param cameraId
* @return
*/
public boolean openCamera(int cameraId) {
try {
mCameraId = cameraId;
mCamera = Camera.open(mCameraId);
setCameraDisplayOrientation(mActivity, mCameraId, mCamera);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 釋放開啟預覽
*
* @param enable
*/
@Override
public void enablePreview(boolean enable) {
if (mCamera != null) {
if (enable) {
mCamera.startPreview();
} else {
mCamera.stopPreview();
}
}
}
/**
* 設定相機的旋轉角度
* 前置相機旋轉270度
* 後置相機旋轉90度
*
* @param activity
* @param cameraId
* @param camera
*/
private void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) {
Camera.CameraInfo info =
new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
public void setPreviewTexture(SurfaceTexture surfaceTexture) {
if (mCamera != null) {
try {
mCamera.setPreviewTexture(surfaceTexture);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 關閉相機釋放資源
*/
@Override
public void closeCamera() {
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
mActivity = null;
}
}
實現自定義的渲染器
最後是渲染器程式碼
,當然了,筆者這裡是仿照GLSurfaceView
的Renderer介面
實現的,你也可以根據這個介面自定義實現一個渲染器
,主要用來將相機的資料繪製到我們自定義的SurfaceTexture
上去,這裡的紋理座標
不再細說,可以對照之前的部落格 android平臺下OpenGL ES 3.0使用GLSurfaceView對相機Camera預覽實時處理。
/**
* @anchor: andy
* @date: 2018-11-11
* @description: 基於相機
*/
public class CameraTextureRenderer implements ITextureRenderer
相關推薦
android平臺下OpenGL ES 3.0使用GLSurfaceView對相機Camera預覽實時處理
OpenGL ES 3.0學習實踐
android平臺下OpenGL ES 3.0從零開始
android平臺下OpenGL ES 3.0繪製純色背景
android平臺下OpenGL ES 3.0繪製圓點、直線和三角形
android平臺下OpenGL E
android平臺下OpenGL ES 3.0使用TextureView對相機Camera預覽實時處理
OpenGL ES 3.0學習實踐
android平臺下OpenGL ES 3.0從零開始
android平臺下OpenGL ES 3.0繪製純色背景
android平臺下OpenGL ES 3.0繪製圓點、直線和三角形
android平臺下OpenGL E
android平臺下OpenGL ES 3.0從零開始
OpenGL ES 3.0學習實踐
android平臺下OpenGL ES 3.0從零開始
android平臺下OpenGL ES 3.0繪製純色背景
android平臺下OpenGL ES 3.0繪製圓點、直線和三角形
android平臺下OpenGL E
android平臺下OpenGL ES 3.0繪製純色背景
OpenGL ES 3.0學習實踐
android平臺下OpenGL ES 3.0從零開始
android平臺下OpenGL ES 3.0繪製純色背景
android平臺下OpenGL ES 3.0繪製圓點、直線和三角形
android平臺下OpenGL E
android平臺下OpenGL ES 3.0從矩形中看矩陣和座標系
OpenGL ES 3.0學習實踐
android平臺下OpenGL ES 3.0從零開始
android平臺下OpenGL ES 3.0繪製純色背景
android平臺下OpenGL ES 3.0繪製圓點、直線和三角形
android平臺下OpenGL E
android平臺下OpenGL ES 3.0繪製彩色三角形
OpenGL ES 3.0學習實踐
android平臺下OpenGL ES 3.0從零開始
android平臺下OpenGL ES 3.0繪製純色背景
android平臺下OpenGL ES 3.0繪製圓點、直線和三角形
android平臺下OpenGL E
android平臺下OpenGL ES 3.0繪製圓點、直線和三角形
OpenGL ES 3.0學習實踐
android平臺下OpenGL ES 3.0從零開始
android平臺下OpenGL ES 3.0繪製純色背景
android平臺下OpenGL ES 3.0繪製圓點、直線和三角形
android平臺下OpenGL E
android平臺下OpenGL ES 3.0著色語言基礎知識(下)
OpenGL ES 3.0學習實踐
android平臺下OpenGL ES 3.0從零開始
android平臺下OpenGL ES 3.0繪製純色背景
android平臺下OpenGL ES 3.0繪製圓點、直線和三角形
android平臺下OpenGL E
android平臺下OpenGL ES 3.0例項詳解頂點屬性、頂點陣列
OpenGL ES 3.0學習實踐
android平臺下OpenGL ES 3.0從零開始
android平臺下OpenGL ES 3.0繪製純色背景
android平臺下OpenGL ES 3.0繪製圓點、直線和三角形
android平臺下OpenGL E
android平臺下OpenGL ES 3.0例項詳解頂點緩衝區物件(VBO)和頂點陣列物件(VAO)
OpenGL ES 3.0學習實踐
android平臺下OpenGL ES 3.0從零開始
android平臺下OpenGL ES 3.0繪製純色背景
android平臺下OpenGL ES 3.0繪製圓點、直線和三角形
android平臺下OpenGL E
android平臺下OpenGL ES 3.0繪製立方體的幾種方式
OpenGL ES 3.0學習實踐
android平臺下OpenGL ES 3.0從零開始
android平臺下OpenGL ES 3.0繪製純色背景
android平臺下OpenGL ES 3.0繪製圓點、直線和三角形
android平臺下OpenGL E
android平臺下OpenGL ES 3.0實現2D紋理貼圖顯示bitmap
OpenGL ES 3.0學習實踐
android平臺下OpenGL ES 3.0從零開始
android平臺下OpenGL ES 3.0繪製純色背景
android平臺下OpenGL ES 3.0繪製圓點、直線和三角形
android平臺下OpenGL E
android平臺下OpenGL ES 3.0從矩形中看矩陣和正交投影
OpenGL ES 3.0學習實踐
目錄
繪製矩形
新建一個矩形渲染器:
public class RectangleRenderer implements GLSurfaceView.Renderer
定義頂點著色器:
#version 300 es
l
Android平臺下OpenGL圖形編程
alloc arch jsb config ble _array itl conf graphics http://blog.csdn.net/jason0539/article/details/9164885
https://developer.android.com/
Android 平臺下OpenGL繪製立方體(2)
圖形類 ——本文用所引法繪製
構造方中初始化資料 和渲染器
private void initData() {
//獲得 頂點 顏色 和 索引的緩衝資料
//頂點
verBuffer = getFloa
Android平臺下OpenGL初步
轉自網上,網上沒找到出處,只看到一些論壇中有這篇文章,組織的有點混亂,這篇文章感覺講的挺好的。本文只關注於如何一步步實現在Android平臺下運用OpenGl。 1、GLSurfaceViewGLSurfaceView是Android應用程式中實現OpenGl畫圖的重要組成部
Android 平臺下OpenGL繪製立方體(1)
寫在文前的話
回顧Opengl繪製圖形的開發步驟
1.新建自己的View 實現 GLSurfaceView
2.初始化著色器Render
1)設定Opengl 版本 非必需
2)設定著色器
3)設定渲染模式
4)實現 onSurfaceCr
Android 為例編寫一個 OpenGL ES 3.0 例項,Native & Java 兩種實現
一、簡介
通過這個 Sample,你將瞭解到 Android 中是怎麼使用 OpenGL ES
通過繪製一個簡單的靜態三角形,來簡單入門和了解它大致的流程(類似於 HelloWorld 工程)
介紹使用 Native 層 和 Java 層 兩種方式來分別實現
一個簡單的OpenGL ES 3.0 示例 (Android NDK jni)
OpenGL ES 3.0 上的一個三角形例子,網上可以下載到android skd 版(java)和 android ndk (c&c++版)
為了瞭解一下JNI,於是寫了如下小程式。
這個例子是使用jni, java中呼叫c中的程式碼完成三角形的渲染, 其中sh
android studio | openGL es 3.0增強現實(AR)開發 (1) 建立一個openGL es 3.0開發環境
1.什麼是NDK,什麼是JNI?
NDK:Native Development Kit(原生開發工具包), NDK允許使用者使用類似C / C++之類的原生程式碼語言執行部分程式。它包括下面的部分(1)從C / C++生成原生程式碼庫所需要的工具和buil