- * {zh} + + + /** {zh} * 默认构造函数 */ + /** {en} + * Default constructor + */ + public ImageUtil() { } - /** - * {zh} + /** {zh} * 准备帧缓冲区纹理对象 * * @param width 纹理宽度 * @param height 纹理高度 - * @return 纹理ID int
{en} Prepare frame buffer texture object + * @return 纹理ID + */ + /** {en} + * Prepare frame buffer texture object + * + * @param width texture width + * @param height texture height + * @return texture ID */ + public int prepareTexture(int width, int height) { initFrameBufferIfNeed(width, height); return mFrameBufferTextures[0]; } - /** - * {zh} + /** {zh} * 默认的离屏渲染绑定的纹理 - * - * @return 纹理id output texture
{en} Default off-screen rendering bound texture + * @return 纹理id */ + /** {en} + * Default off-screen rendering bound texture + * @return texture id + */ + public int getOutputTexture() { - if (mFrameBufferTextures == null) { - return GlUtil.NO_TEXTURE; - } + if (mFrameBufferTextures == null) return GlUtil.NO_TEXTURE; return mFrameBufferTextures[0]; } - /** - * {zh} + /** {zh} * 初始化帧缓冲区 * * @param width 缓冲的纹理宽度 * @param height 缓冲的纹理高度 */ + /** {en} + * Initialize frame buffer + * + * @param width buffered texture width + * @param height buffered texture height + */ + private void initFrameBufferIfNeed(int width, int height) { boolean need = false; if (null == mFrameBufferShape || mFrameBufferShape.x != width || mFrameBufferShape.y != height) { @@ -120,11 +123,11 @@ private void initFrameBufferIfNeed(int width, int height) { } if (need) { destroyFrameBuffers(); - mFrameBuffers = new int[frameBufferNum]; - mFrameBufferTextures = new int[frameBufferNum]; - GLES20.glGenFramebuffers(frameBufferNum, mFrameBuffers, 0); - GLES20.glGenTextures(frameBufferNum, mFrameBufferTextures, 0); - for (int i = 0; i < frameBufferNum; i++) { + mFrameBuffers = new int[FRAME_BUFFER_NUM]; + mFrameBufferTextures = new int[FRAME_BUFFER_NUM]; + GLES20.glGenFramebuffers(FRAME_BUFFER_NUM, mFrameBuffers, 0); + GLES20.glGenTextures(FRAME_BUFFER_NUM, mFrameBufferTextures, 0); + for (int i = 0; i < FRAME_BUFFER_NUM; i++) { bindFrameBuffer(mFrameBufferTextures[i], mFrameBuffers[i], width, height); } mFrameBufferShape = new Point(width, height); @@ -132,21 +135,35 @@ private void initFrameBufferIfNeed(int width, int height) { } - /** - * {zh} + /** {zh} * 销毁帧缓冲区对象 */ + /** {en} + * Destroy frame buffer objects + */ + private void destroyFrameBuffers() { if (mFrameBufferTextures != null) { - GLES20.glDeleteTextures(frameBufferNum, mFrameBufferTextures, 0); + GLES20.glDeleteTextures(FRAME_BUFFER_NUM, mFrameBufferTextures, 0); mFrameBufferTextures = null; } if (mFrameBuffers != null) { - GLES20.glDeleteFramebuffers(frameBufferNum, mFrameBuffers, 0); + GLES20.glDeleteFramebuffers(FRAME_BUFFER_NUM, mFrameBuffers, 0); mFrameBuffers = null; } } + /** {zh} + * 纹理参数设置+buffer绑定 + * set texture params + * and bind buffer + */ + /** {en} + * Texture parameter setting + buffer binding + * set texture params + * and binding buffer + */ + private void bindFrameBuffer(int textureId, int frameBuffer, int width, int height) { GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, @@ -169,15 +186,14 @@ private void bindFrameBuffer(int textureId, int frameBuffer, int width, int heig } - /** - * {zh} + + /** {zh} * 释放资源,包括帧缓冲区及Program对象 - *
- * {en} + */ + /** {en} * Free resources, including frame buffers and Program objects - * {zh} - * 释放资源,包括帧缓冲区及Program对象 */ + public void release() { destroyFrameBuffers(); if (null != mProgramManager) { @@ -189,18 +205,23 @@ public void release() { } } - /** - * {zh} + /** {zh} * 读取渲染结果的buffer * * @param imageWidth 图像宽度 * @param imageHeight 图像高度 - * @return 渲染结果的像素Buffer 格式RGBA
{en} Read the buffer + * @return 渲染结果的像素Buffer 格式RGBA */ + /** {en} + * Read the buffer + * + * @param imageWidth image width + * @param imageHeight image height + * @return pixel Buffer format of the rendered result RGBA + */ + public ByteBuffer captureRenderResult(int imageWidth, int imageHeight) { - if (mFrameBufferTextures == null) { - return null; - } + if (mFrameBufferTextures == null) return null; int textureId = mFrameBufferTextures[0]; if (null == mFrameBufferTextures || textureId == GlUtil.NO_TEXTURE) { return null; @@ -237,15 +258,21 @@ public ByteBuffer captureRenderResult(int imageWidth, int imageHeight) { return mCaptureBuffer; } - /** - * {zh} + /** {zh} * 读取渲染结果的buffer * - * @param textureId the texture id * @param imageWidth 图像宽度 * @param imageHeight 图像高度 - * @return 渲染结果的像素Buffer 格式RGBA
{en} Read the buffer + * @return 渲染结果的像素Buffer 格式RGBA + */ + /** {en} + * Read the buffer + * + * @param imageWidth image width + * @param imageHeight image height + * @return pixel Buffer format of the rendered result RGBA */ + public ByteBuffer captureRenderResult(int textureId, int imageWidth, int imageHeight) { if (textureId == GlUtil.NO_TEXTURE) { return null; @@ -282,16 +309,25 @@ public ByteBuffer captureRenderResult(int textureId, int imageWidth, int imageHe return mCaptureBuffer; } - /** - * {zh} + /** {zh} * 纹理拷贝 * - * @param srcTexture the src texture - * @param dstTexture the dst texture - * @param width the width - * @param height the height - * @return boolean
{en} Texture copy + * @param srcTexture + * @param dstTexture + * @param width + * @param height + * @return */ + /** {en} + * Texture copy + * + * @param srcTexture + * @param dstTexture + * @param width + * @param height + * @return + */ + public boolean copyTexture(int srcTexture, int dstTexture, int width, int height) { if (srcTexture == GlUtil.NO_TEXTURE || dstTexture == GlUtil.NO_TEXTURE) { return false; @@ -315,133 +351,141 @@ public boolean copyTexture(int srcTexture, int dstTexture, int width, int height int error = GLES20.glGetError(); if (error != GLES20.GL_NO_ERROR) { String msg = "copyTexture glError 0x" + Integer.toHexString(error); - Log.e(TAG, msg); return false; } return true; + + } - /** - * {zh} - * + /** {zh} * @param inputTexture 输入纹理 * @param inputTextureFormat 输入纹理格式,2D/OES * @param outputTextureFormat 输出纹理格式,2D/OES * @param width 输入纹理的宽 * @param height 输入纹理的高 * @param transition 纹理变换方式 - * @return 输出纹理 int + * @return 输出纹理 + * @brief 纹理转纹理 */ - public int transferTextureToTexture(int inputTexture, BytedEffectConstants.TextureFormat inputTextureFormat, - BytedEffectConstants.TextureFormat outputTextureFormat, - int width, int height, Transition transition) { - if (outputTextureFormat != BytedEffectConstants.TextureFormat.Texure2D) { - LogUtils.e(TAG, "the inputTexture is not supported,please use Texure2D as output texture format"); - return GlUtil.NO_TEXTURE; - } + /** {en} + * @param inputTextureFormat input texture format, 2D/OES + * @param outputTextureFormat output texture format, 2D/OES + * @param width input texture width + * @param height input texture height + * @param transition texture transformation mode + * @return output texture + * @brief texture to texture + */ + + public int transferTextureToTexture(int inputTexture, EffectsSDKEffectConstants.TextureFormat inputTextureFormat, + EffectsSDKEffectConstants.TextureFormat outputTextureFormat, + int width, int height, Transition transition) { + if (outputTextureFormat != EffectsSDKEffectConstants.TextureFormat.Texure2D){ + LogUtils.e(TAG, "the inputTexture is not supported,please use Texure2D as output texture format"); + return GlUtil.NO_TEXTURE; + } if (null == mProgramManager) { mProgramManager = new ProgramManager(); } - boolean targetRoated = transition.getAngle() % 180 == 90; - return mProgramManager.getProgram(inputTextureFormat).drawFrameOffScreen(inputTexture, targetRoated ? height : width, targetRoated ? width : height, transition.getMatrix()); + boolean targetRoated = (transition.getAngle()%180 ==90); + return mProgramManager.getProgram(inputTextureFormat).drawFrameOffScreen(inputTexture, targetRoated?height:width, targetRoated?width:height, transition.getMatrix()); } private ProgramTextureYUV mYUVProgram; - - /** - * Transfer yuv to texture int. - * - * @param yBuffer the y buffer - * @param vuBuffer the vu buffer - * @param width the width - * @param height the height - * @param transition the transition - * @return the int - */ public int transferYUVToTexture(ByteBuffer yBuffer, ByteBuffer vuBuffer, int width, int height, Transition transition) { if (mYUVProgram == null) { mYUVProgram = new ProgramTextureYUV(); } int yTexture = GlUtil.createImageTexture(yBuffer, width, height, GLES20.GL_ALPHA); - int vuTexture = GlUtil.createImageTexture(vuBuffer, width / 2, height / 2, GLES20.GL_LUMINANCE_ALPHA); + int vuTexture = GlUtil.createImageTexture(vuBuffer, width/2, height/2, GLES20.GL_LUMINANCE_ALPHA); int rgbaTexture = mYUVProgram.drawFrameOffScreen(yTexture, vuTexture, width, height, transition.getMatrix()); GlUtil.deleteTextureId(new int[]{yTexture, vuTexture}); return rgbaTexture; } - /** - * {zh} - * - * @param texture 纹理 + /** {zh} + * @param texture 纹理 * @param inputTextureFormat 纹理格式,2D/OES - * @param outputFormat 输出 buffer 格式 - * @param width 宽 - * @param height 高 - * @param ratio the ratio + * @param outputFormat 输出 buffer 格式 + * @param width 宽 + * @param height 高 * @return 输出 buffer + * @brief 纹理转 buffer */ - public ByteBuffer transferTextureToBuffer(int texture, BytedEffectConstants.TextureFormat inputTextureFormat, - BytedEffectConstants.PixlFormat outputFormat, int width, int height, float ratio) { - if (outputFormat != BytedEffectConstants.PixlFormat.RGBA8888) { + /** {en} + * @param inputTextureFormat texture format, 2D/OES + * @param outputFormat output buffer format + * @param width width + * @param height height + * @return output buffer + * @brief texture turn buffer + */ + + public ByteBuffer transferTextureToBuffer(int texture, EffectsSDKEffectConstants.TextureFormat inputTextureFormat, + EffectsSDKEffectConstants.PixlFormat outputFormat, int width, int height, float ratio){ + if (outputFormat != EffectsSDKEffectConstants.PixlFormat.RGBA8888){ LogUtils.e(TAG, "the outputFormat is not supported,please use RGBA8888 as output texture format"); - return null; + return null; } if (null == mProgramManager) { mProgramManager = new ProgramManager(); } - return mProgramManager.getProgram(inputTextureFormat).readBuffer(texture, (int) (width * ratio), (int) (height * ratio)); + return mProgramManager.getProgram(inputTextureFormat).readBuffer(texture, (int) (width*ratio), (int)(height*ratio)); + + + } - /** - * Transfer texture to bitmap bitmap. - * - * @param texture the texture - * @param inputTextureFormat the input texture format - * @param width the width - * @param height the height - * @return the bitmap - */ - public Bitmap transferTextureToBitmap(int texture, BytedEffectConstants.TextureFormat inputTextureFormat, + public Bitmap transferTextureToBitmap(int texture, EffectsSDKEffectConstants.TextureFormat inputTextureFormat, int width, int height) { - ByteBuffer buffer = transferTextureToBuffer(texture, inputTextureFormat, BytedEffectConstants.PixlFormat.RGBA8888, + ByteBuffer buffer = transferTextureToBuffer(texture, inputTextureFormat, EffectsSDKEffectConstants.PixlFormat.RGBA8888, width, height, 1); if (buffer == null) { return null; } - return transferBufferToBitmap(buffer, BytedEffectConstants.PixlFormat.RGBA8888, width, height); + return transferBufferToBitmap(buffer, EffectsSDKEffectConstants.PixlFormat.RGBA8888, width, height); } - /** - * {zh} - * + /** {zh} * @param buffer 输入 buffer * @param inputFormat buffer 格式 * @param outputFormat 输出纹理格式 * @param width 宽 * @param height 高 - * @return 输出纹理 int + * @return 输出纹理 + * @brief buffer 转纹理 + */ + /** {en} + * @param inputFormat buffer format + * @param outputFormat output texture format + * @param width width + * @param height height + * @return output texture + * @brief buffer turn texture */ - public int transferBufferToTexture(ByteBuffer buffer, BytedEffectConstants.PixlFormat inputFormat, - BytedEffectConstants.TextureFormat outputFormat, int width, int height) { - if (inputFormat != BytedEffectConstants.PixlFormat.RGBA8888) { + public int transferBufferToTexture(ByteBuffer buffer, EffectsSDKEffectConstants.PixlFormat inputFormat, + EffectsSDKEffectConstants.TextureFormat outputFormat, int width, int height){ + + if (inputFormat != EffectsSDKEffectConstants.PixlFormat.RGBA8888){ LogUtils.e(TAG, "inputFormat support RGBA8888 only"); return GlUtil.NO_TEXTURE; } - if (outputFormat != BytedEffectConstants.TextureFormat.Texure2D) { + if (outputFormat != EffectsSDKEffectConstants.TextureFormat.Texure2D){ LogUtils.e(TAG, "outputFormat support Texure2D only"); return GlUtil.NO_TEXTURE; } - return create2DTexture(buffer, width, height, GL_RGBA); + return create2DTexture(buffer, width,height, GL_RGBA); } @@ -477,33 +521,48 @@ private int create2DTexture(ByteBuffer data, int width, int height, int format) return textureHandle; } - /** - * {zh} - * + /** {zh} * @param buffer 输入 buffer * @param inputFormat 输入 buffer 格式 * @param outputFormat 输出 buffer 格式 * @param width 宽 * @param height 高 * @return 输出 buffer + * @brief buffer 转 buffer + */ + /** {en} + * @param inputFormat input buffer format + * @param outputFormat output buffer format + * @param width width + * @param height height + * @return output buffer + * @brief buffer to buffer */ - public ByteBuffer transferBufferToBuffer(ByteBuffer buffer, BytedEffectConstants.PixlFormat inputFormat, - BytedEffectConstants.PixlFormat outputFormat, int width, int height) { + + public ByteBuffer transferBufferToBuffer(ByteBuffer buffer, EffectsSDKEffectConstants.PixlFormat inputFormat, + EffectsSDKEffectConstants.PixlFormat outputFormat, int width, int height){ return null; } - /** - * {zh} - * + /** {zh} * @param buffer 输入 buffer * @param format 输入 buffer 格式 * @param width 宽 * @param height 高 * @return 输出 bitmap + * @brief buffer 转 bitmap + */ + /** {en} + * @param format input buffer format + * @param width width + * @param height height + * @return output bitmap + * @brief buffer turn bitmap */ - public Bitmap transferBufferToBitmap(ByteBuffer buffer, BytedEffectConstants.PixlFormat format, - int width, int height) { + + public Bitmap transferBufferToBitmap(ByteBuffer buffer, EffectsSDKEffectConstants.PixlFormat format, + int width, int height){ Bitmap mCameraBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); buffer.position(0); @@ -513,17 +572,24 @@ public Bitmap transferBufferToBitmap(ByteBuffer buffer, BytedEffectConstants.Pix } - /** - * {zh} + /** {zh} * 在屏幕上渲染纹理 - * - * @param textureId 纹理ID + * @param textureId 纹理ID * @param srcTetxureFormat 纹理格式 - * @param surfaceWidth 视口宽度 - * @param surfaceHeight 视口高度 - * @param mMVPMatrix 旋转矩阵
{en} Render texture on screen + * @param surfaceWidth 视口宽度 + * @param surfaceHeight 视口高度 + * @param mMVPMatrix 旋转矩阵 + */ + /** {en} + * Render texture on screen + * @param textureId texture ID + * @param srcTetxureFormat texture format + * @param surfaceWidth viewport width + * @param surfaceHeight viewport height + * @param mMVPMatrix rotation matrix */ - public void drawFrameOnScreen(int textureId, BytedEffectConstants.TextureFormat srcTetxureFormat, int surfaceWidth, int surfaceHeight, float[] mMVPMatrix) { + + public void drawFrameOnScreen(int textureId,EffectsSDKEffectConstants.TextureFormat srcTetxureFormat,int surfaceWidth, int surfaceHeight, float[]mMVPMatrix) { if (null == mProgramManager) { mProgramManager = new ProgramManager(); } @@ -533,26 +599,22 @@ public void drawFrameOnScreen(int textureId, BytedEffectConstants.TextureFormat } - /** - * The type Transition. + /** {zh} + * @brief 变换方式类 + */ + /** {en} + * @brief Transform mode class */ + public static class Transition { private float[] mMVPMatrix = new float[16]; private int mAngle = 0; - /** - * Instantiates a new Transition. - */ public Transition() { Matrix.setIdentityM(mMVPMatrix, 0); } - /** - * Instantiates a new Transition. - * - * @param transformMatrixArray the transform matrix array - */ public Transition(float[] transformMatrixArray) { for (int i = 0; i < transformMatrixArray.length; i++) { mMVPMatrix[i] = transformMatrixArray[i]; @@ -560,34 +622,31 @@ public Transition(float[] transformMatrixArray) { } - /** - * {zh} - * - * @param x the x - * @param y the y - * @return the transition + /** {zh} + * @brief 镜像 */ + /** {en} + * @brief Mirror image + */ + public Transition flip(boolean x, boolean y) { GlUtil.flip(mMVPMatrix, x, y); return this; } - /** - * Gets angle. - * - * @return the angle - */ public int getAngle() { - return mAngle % 360; + return mAngle%360; } - /** - * {zh} - * + /** {zh} * @param angle 旋转角度,仅支持 0/90/180/270 - * @return the transition + * @brief 旋转 */ + /** {en} + * @brief rotation + */ + public Transition rotate(float angle) { mAngle += angle; GlUtil.rotate(mMVPMatrix, angle); @@ -595,44 +654,34 @@ public Transition rotate(float angle) { } - /** - * Scale transition. - * - * @param sx the sx - * @param sy the sy - * @return the transition - */ - public Transition scale(float sx, float sy) { - GlUtil.scale(mMVPMatrix, sx, sy); + public Transition scale(float sx,float sy) { + GlUtil.scale(mMVPMatrix, sx , sy); return this; } - /** - * Crop transition. - * - * @param scaleType the scale type - * @param rotation the rotation - * @param textureWidth the texture width - * @param textureHeight the texture height - * @param surfaceWidth the surface width - * @param surfaceHeight the surface height - * @return the transition - */ - public Transition crop(ImageView.ScaleType scaleType, int rotation, int textureWidth, int textureHeight, int surfaceWidth, int surfaceHeight) { - if (rotation % 180 == 90) { - GlUtil.getShowMatrix(mMVPMatrix, scaleType, textureHeight, textureWidth, surfaceWidth, surfaceHeight); - } else { - GlUtil.getShowMatrix(mMVPMatrix, scaleType, textureWidth, textureHeight, surfaceWidth, surfaceHeight); + public Transition crop(ImageView.ScaleType scaleType, int rotation, int textureWidth, int textureHeight, int surfaceWidth, int surfaceHeight){ + if (rotation % 180 == 90){ + GlUtil.getShowMatrix(mMVPMatrix,scaleType, textureHeight, textureWidth, surfaceWidth, surfaceHeight); + }else { + GlUtil.getShowMatrix(mMVPMatrix,scaleType, textureWidth, textureHeight, surfaceWidth, surfaceHeight); } return this; } - /** - * {zh} - * + /** {zh} * @return 逆向后的 transition + * @brief 逆向生成新的 transition + * @details 变换操作有顺序之分,本方法可以将一系列操作逆序, + * 如将先镜像再旋转,逆序为先旋转再镜像 + */ + /** {en} + * @return Reverse transition + * @brief Reverse generation of new transition + * @details transformation operations can be divided into sequence. This method can reverse a series of operations, + * such as mirroring first and then rotating, and the reverse order is rotating first and then mirroring */ + public Transition reverse() { float[] invertedMatrix = new float[16]; @@ -644,23 +693,13 @@ public Transition reverse() { } - /** - * Get matrix float [ ]. - * - * @return the float [ ] - */ - public float[] getMatrix() { + public float[] getMatrix(){ return mMVPMatrix; } - /** - * To String. - * - * @return string - */ - public String toString() { - StringBuilder sb = new StringBuilder(); - for (float value : mMVPMatrix) { + public String toString(){ + StringBuilder sb =new StringBuilder(); + for (float value: mMVPMatrix){ sb.append(value).append(" "); } return sb.toString(); diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/LogUtils.kt b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/LogUtils.kt index 2ee86d9a5..1df151011 100644 --- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/LogUtils.kt +++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/LogUtils.kt @@ -24,118 +24,35 @@ package io.agora.beautyapi.bytedance.utils -import android.util.Log -import java.io.File -import java.io.FileOutputStream -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale -import java.util.concurrent.Executors +import io.agora.base.internal.Logging -/** - * Log utils - * - * @constructor Create empty Log utils - */ object LogUtils { private const val beautyType = "ByteDance" - private val timeFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.ROOT) - private val logFileName = "agora_beautyapi_${beautyType.toLowerCase(Locale.ROOT)}_android.log" - private val workerThread = Executors.newSingleThreadExecutor() - private var logOutputStream: FileOutputStream? = null - /** - * Set log file path - * - * @param path - */ - @JvmStatic - fun setLogFilePath(path: String){ - if(path.isEmpty()){ - e("LogUtils", "setLogFilePath >> path is empty!") - return - } - val direction = File(path) - if(!direction.exists()){ - direction.mkdirs() - } - val file = File(direction, logFileName) - if(!file.exists()){ - file.createNewFile() - } - val append = file.length() < 2 * 1024 * 1024 - logOutputStream = FileOutputStream(file, append) - } - /** - * I - * - * @param tag - * @param content - * @param args - */ @JvmStatic fun i(tag: String, content: String, vararg args: Any) { val consoleMessage = "[BeautyAPI][$beautyType] : ${String.format(content, args)}" - val fileMessage = "${timeFormat.format(Date())} : [BeautyAPI][$beautyType][$tag][INFO] : ${String.format(content, args)}" - Log.v(tag, consoleMessage) - saveToFile(fileMessage) + Logging.log(Logging.Severity.LS_INFO, tag, consoleMessage) } - /** - * D - * - * @param tag - * @param content - * @param args - */ @JvmStatic fun d(tag: String, content: String, vararg args: Any) { val consoleMessage = "[BeautyAPI][$beautyType] : ${String.format(content, args)}" - val fileMessage = "${timeFormat.format(Date())} : [BeautyAPI][$beautyType][$tag][DEBUG] : ${String.format(content, args)}" - Log.d(tag, consoleMessage) - saveToFile(fileMessage) + Logging.d(tag, consoleMessage) } - /** - * W - * - * @param tag - * @param content - * @param args - */ @JvmStatic fun w(tag: String, content: String, vararg args: Any){ val consoleMessage = "[BeautyAPI][$beautyType] : ${String.format(content, args)}" - val fileMessage = "${timeFormat.format(Date())} : [BeautyAPI][$beautyType][$tag][WARN] : ${String.format(content, args)}" - Log.w(tag, consoleMessage) - saveToFile(fileMessage) + Logging.w(tag, consoleMessage) } - /** - * E - * - * @param tag - * @param content - * @param args - */ @JvmStatic fun e(tag: String, content: String, vararg args: Any){ val consoleMessage = "[BeautyAPI][$beautyType] : ${String.format(content, args)}" - val fileMessage = "${timeFormat.format(Date())} : [BeautyAPI][$beautyType][$tag][ERROR] : ${String.format(content, args)}" - Log.e(tag, consoleMessage) - saveToFile(fileMessage) + Logging.e(tag, consoleMessage) } - - private fun saveToFile(message: String){ - val outputStream = logOutputStream ?: return - workerThread.execute { - outputStream.write(message.toByteArray()) - if(!message.endsWith("\n")){ - outputStream.write("\n".toByteArray()) - } - } - } } \ No newline at end of file diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/StatsHelper.kt b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/StatsHelper.kt index b4399ed7e..2f2abbe98 100644 --- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/StatsHelper.kt +++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/StatsHelper.kt @@ -30,13 +30,6 @@ import io.agora.beautyapi.bytedance.BeautyStats import kotlin.math.max import kotlin.math.min -/** - * Stats helper - * - * @property statsDuration - * @property onStatsChanged - * @constructor Create empty Stats helper - */ class StatsHelper( private val statsDuration: Long, private val onStatsChanged: (BeautyStats) -> Unit @@ -48,11 +41,6 @@ class StatsHelper( private var mCostMax = 0L private var mCostMin = Long.MAX_VALUE - /** - * Once - * - * @param cost - */ fun once(cost: Long) { val curr = System.currentTimeMillis() if (mStartTime == 0L) { @@ -80,10 +68,6 @@ class StatsHelper( mCostMin = min(mCostMin, cost) } - /** - * Reset - * - */ fun reset() { mMainHandler.removeCallbacksAndMessages(null) mStartTime = 0 diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/Drawable2d.java b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/Drawable2d.java index e807db10a..0e5e13c74 100644 --- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/Drawable2d.java +++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/Drawable2d.java @@ -32,33 +32,24 @@ */ public class Drawable2d { private static final int SIZEOF_FLOAT = 4; - /** - * The constant COORDS_PER_VERTEX. - */ public static final int COORDS_PER_VERTEX = 2; - /** - * The constant TEXTURE_COORD_STRIDE. - */ public static final int TEXTURE_COORD_STRIDE = COORDS_PER_VERTEX * SIZEOF_FLOAT; - /** - * The constant VERTEXTURE_STRIDE. - */ public static final int VERTEXTURE_STRIDE = COORDS_PER_VERTEX * SIZEOF_FLOAT; /** * Simple equilateral triangle (1.0 per side). Centered on (0,0). */ - private static final float[] TRIANGLE_COORDS = { - 0.0f, 0.577350269f, // 0 top - -0.5f, -0.288675135f, // 1 bottom left - 0.5f, -0.288675135f // 2 bottom right + private static final float TRIANGLE_COORDS[] = { + 0.0f, 0.577350269f, // 0 top + -0.5f, -0.288675135f, // 1 bottom left + 0.5f, -0.288675135f // 2 bottom right }; - private static final float[] TRIANGLE_TEX_COORDS = { - 0.5f, 0.0f, // 0 top center - 0.0f, 1.0f, // 1 bottom left - 1.0f, 1.0f, // 2 bottom right + private static final float TRIANGLE_TEX_COORDS[] = { + 0.5f, 0.0f, // 0 top center + 0.0f, 1.0f, // 1 bottom left + 1.0f, 1.0f, // 2 bottom right }; private static final FloatBuffer TRIANGLE_BUF = GlUtil.createFloatBuffer(TRIANGLE_COORDS); @@ -71,25 +62,28 @@ public class Drawable2d { *
* Triangles are 0-1-2 and 2-1-3 (counter-clockwise winding). */ - private static final float[] RECTANGLE_COORDS = { - -0.5f, -0.5f, // 0 bottom left - 0.5f, -0.5f, // 1 bottom right - -0.5f, 0.5f, // 2 top left - 0.5f, 0.5f, // 3 top right + private static final float RECTANGLE_COORDS[] = { + -0.5f, -0.5f, // 0 bottom left + 0.5f, -0.5f, // 1 bottom right + -0.5f, 0.5f, // 2 top left + 0.5f, 0.5f, // 3 top right }; - /** + /** {zh} + * FrameBuffer 与屏幕的坐标系是垂直镜像的,所以在将纹理绘制到一个 FrameBuffer 或屏幕上 + * 的时候,他们用的纹理顶点坐标是不同的,需要注意。 + */ + /** {en} * The coordinate system of the FrameBuffer and the screen is mirrored vertically, so when drawing the texture to a FrameBuffer or screen * , the vertex coordinates of the texture they use are different, which needs attention. - *
FrameBuffer 与屏幕的坐标系是垂直镜像的,所以在将纹理绘制到一个 FrameBuffer 或屏幕上 - * 的时候,他们用的纹理顶点坐标是不同的,需要注意。 */ - private static final float[] RECTANGLE_TEX_COORDS = { + + private static final float RECTANGLE_TEX_COORDS[] = { 0.0f, 1.0f, // 0 bottom left 1.0f, 1.0f, // 1 bottom right 0.0f, 0.0f, // 2 top left 1.0f, 0.0f // 3 top right }; - private static final float[] RECTANGLE_TEX_COORDS1 = { + private static final float RECTANGLE_TEX_COORDS1[] = { 0.0f, 0.0f, // 0 bottom left 1.0f, 0.0f, // 1 bottom right 0.0f, 1.0f, // 2 top left @@ -109,31 +103,33 @@ public class Drawable2d { * The texture coordinates are Y-inverted relative to RECTANGLE. (This seems to work out * right with external textures from SurfaceTexture.) */ - private static final float[] FULL_RECTANGLE_COORDS = { - -1.0f, -1.0f, // 0 bottom left - 1.0f, -1.0f, // 1 bottom right - -1.0f, 1.0f, // 2 top left - 1.0f, 1.0f, // 3 top right + private static final float FULL_RECTANGLE_COORDS[] = { + -1.0f, -1.0f, // 0 bottom left + 1.0f, -1.0f, // 1 bottom right + -1.0f, 1.0f, // 2 top left + 1.0f, 1.0f, // 3 top right }; - - /** + /** {zh} + * FrameBuffer 与屏幕的坐标系是垂直镜像的,所以在将纹理绘制到一个 FrameBuffer 或屏幕上 + * 的时候,他们用的纹理顶点坐标是不同的,需要注意。 + */ + /** {en} * The coordinate system of the FrameBuffer and the screen is mirrored vertically, so when drawing the texture to a FrameBuffer or screen * , the vertex coordinates of the texture they use are different, which needs attention. - *
FrameBuffer 与屏幕的坐标系是垂直镜像的,所以在将纹理绘制到一个 FrameBuffer 或屏幕上 - * 的时候,他们用的纹理顶点坐标是不同的,需要注意。 */ - private static final float[] FULL_RECTANGLE_TEX_COORDS = { - 0.0f, 1.0f, // 0 bottom left - 1.0f, 1.0f, // 1 bottom right - 0.0f, 0.0f, // 2 top left - 1.0f, 0.0f // 3 top right + + private static final float FULL_RECTANGLE_TEX_COORDS[] = { + 0.0f, 1.0f, // 0 bottom left + 1.0f, 1.0f, // 1 bottom right + 0.0f, 0.0f, // 2 top left + 1.0f, 0.0f // 3 top right }; - private static final float[] FULL_RECTANGLE_TEX_COORDS1 = { - 0.0f, 0.0f, // 0 bottom left - 1.0f, 0.0f, // 1 bottom right - 0.0f, 1.0f, // 2 top left - 1.0f, 1.0f // 3 top right + private static final float FULL_RECTANGLE_TEX_COORDS1[] = { + 0.0f, 0.0f, // 0 bottom left + 1.0f, 0.0f, // 1 bottom right + 0.0f, 1.0f, // 2 top left + 1.0f, 1.0f // 3 top right }; private static final FloatBuffer FULL_RECTANGLE_BUF = GlUtil.createFloatBuffer(FULL_RECTANGLE_COORDS); @@ -156,26 +152,13 @@ public class Drawable2d { * Enum values for constructor. */ public enum Prefab { - /** - * Triangle prefab. - */ - TRIANGLE, - /** - * Rectangle prefab. - */ - RECTANGLE, - /** - * Full rectangle prefab. - */ - FULL_RECTANGLE + TRIANGLE, RECTANGLE, FULL_RECTANGLE } /** * Prepares a drawable from a "pre-fabricated" shape definition. *
* Does no EGL/GL operations, so this can be done at any time. - * - * @param shape the shape */ public Drawable2d(Prefab shape) { switch (shape) { @@ -214,8 +197,6 @@ public Drawable2d(Prefab shape) { * Returns the array of vertices. *
* To avoid allocations, this returns internal state. The caller must not modify it. - * - * @return the vertex array */ public FloatBuffer getVertexArray() { return mVertexArray; @@ -225,27 +206,24 @@ public FloatBuffer getVertexArray() { * Returns the array of texture coordinates. *
* To avoid allocations, this returns internal state. The caller must not modify it. - * - * @return the tex coord array */ public FloatBuffer getTexCoordArray() { return mTexCoordArray; } - - /** - * Gets tex coor array fb. - * - * @return the tex coor array fb + /** {zh} + * @brief 返回 frameBuffer 绘制用 texture coordinates */ + /** {en} + * @brief Returns texture coordinates for drawing frameBuffer + */ + public FloatBuffer getTexCoorArrayFB() { return mTexCoordArrayFB; } /** * Returns the number of vertices stored in the vertex array. - * - * @return the vertex count */ public int getVertexCount() { return mVertexCount; @@ -253,8 +231,6 @@ public int getVertexCount() { /** * Returns the width, in bytes, of the data for each vertex. - * - * @return the vertex stride */ public int getVertexStride() { return mVertexStride; @@ -262,8 +238,6 @@ public int getVertexStride() { /** * Returns the width, in bytes, of the data for each texture coordinate. - * - * @return the tex coord stride */ public int getTexCoordStride() { return mTexCoordStride; @@ -271,37 +245,20 @@ public int getTexCoordStride() { /** * Returns the number of position coordinates per vertex. This will be 2 or 3. - * - * @return the coords per vertex */ public int getCoordsPerVertex() { return mCoordsPerVertex; } - /** - * Update vertex array. - * - * @param fullRectangleCoords the full rectangle coords - */ - public void updateVertexArray(float[] fullRectangleCoords) { - mVertexArray = GlUtil.createFloatBuffer(fullRectangleCoords); - mVertexCount = fullRectangleCoords.length / COORDS_PER_VERTEX; + public void updateVertexArray(float[] FULL_RECTANGLE_COORDS) { + mVertexArray = GlUtil.createFloatBuffer(FULL_RECTANGLE_COORDS); + mVertexCount = FULL_RECTANGLE_COORDS.length / COORDS_PER_VERTEX; } - /** - * Update tex coord array. - * - * @param fullRectangleTexCoords the full rectangle tex coords - */ - public void updateTexCoordArray(float[] fullRectangleTexCoords) { - mTexCoordArray = GlUtil.createFloatBuffer(fullRectangleTexCoords); + public void updateTexCoordArray(float[] FULL_RECTANGLE_TEX_COORDS) { + mTexCoordArray = GlUtil.createFloatBuffer(FULL_RECTANGLE_TEX_COORDS); } - /** - * Update tex coord array fb. - * - * @param coords the coords - */ public void updateTexCoordArrayFB(float[] coords) { mTexCoordArrayFB = GlUtil.createFloatBuffer(coords); } diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/Extensions.java b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/Extensions.java index 2d43b82b7..1b90c1b7c 100644 --- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/Extensions.java +++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/Extensions.java @@ -30,17 +30,8 @@ import java.io.IOException; import java.io.InputStream; -/** - * The type Extensions. - */ public abstract class Extensions { - /** - * Get bytes byte [ ]. - * - * @param inputStream the input stream - * @return the byte [ ] - */ public static byte[] getBytes(InputStream inputStream) { try { byte[] bytes = new byte[inputStream.available()]; @@ -54,13 +45,6 @@ public static byte[] getBytes(InputStream inputStream) { return new byte[0]; } - /** - * Get bytes byte [ ]. - * - * @param assetManager the asset manager - * @param fileName the file name - * @return the byte [ ] - */ public static byte[] getBytes(AssetManager assetManager, String fileName) { try { return getBytes(assetManager.open(fileName)); @@ -71,13 +55,6 @@ public static byte[] getBytes(AssetManager assetManager, String fileName) { return new byte[0]; } - /** - * Read text file from resource string. - * - * @param context the context - * @param resourceId the resource id - * @return the string - */ public static String readTextFileFromResource(Context context, int resourceId) { return new String(Extensions.getBytes(context.getResources().openRawResource(resourceId))); } diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/GlUtil.java b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/GlUtil.java index 3b0574d54..751e87e99 100644 --- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/GlUtil.java +++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/GlUtil.java @@ -48,14 +48,8 @@ * Some OpenGL utility functions. */ public abstract class GlUtil { - /** - * The constant TAG. - */ public static final String TAG = GlUtil.class.getSimpleName(); - /** - * The constant NO_TEXTURE. - */ public static final int NO_TEXTURE = -1; // public static final int TYPE_FITXY=0; // public static final int TYPE_CENTERCROP=1; @@ -63,14 +57,8 @@ public abstract class GlUtil { // public static final int TYPE_FITSTART=3; // public static final int TYPE_FITEND=4; - /** - * The constant x_scale. - */ - public static final float X_SCALE = 1.0f; - /** - * The constant y_scale. - */ - public static final float Y_SCALE = 1.0f; + public static float x_scale = 1.0f; + public static float y_scale = 1.0f; /** * Identity matrix for general use. Don't modify or life will get weird. @@ -91,8 +79,6 @@ private GlUtil() { /** * Creates a new program from the supplied vertex and fragment shaders. * - * @param vertexSource the vertex source - * @param fragmentSource the fragment source * @return A handle to the program, or 0 on failure. */ public static int createProgram(String vertexSource, String fragmentSource) { @@ -129,8 +115,6 @@ public static int createProgram(String vertexSource, String fragmentSource) { /** * Compiles the provided shader source. * - * @param shaderType the shader type - * @param source the source * @return A handle to the shader, or 0 on failure. */ public static int loadShader(int shaderType, String source) { @@ -151,8 +135,6 @@ public static int loadShader(int shaderType, String source) { /** * Checks to see if a GLES error has been raised. - * - * @param op the op */ public static void checkGlError(String op) { int error = GLES20.glGetError(); @@ -167,9 +149,6 @@ public static void checkGlError(String op) { * could not be found, but does not set the GL error. *
* Throws a RuntimeException if the location is invalid. - * - * @param location the location - * @param label the label */ public static void checkLocation(int location, String label) { if (location < 0) { @@ -178,6 +157,7 @@ public static void checkLocation(int location, String label) { } + /** * Creates a texture from raw data. * @@ -221,9 +201,7 @@ public static int createImageTexture(ByteBuffer data, int width, int height, int * @return Handle to texture. */ public static int createImageTexture(Bitmap bmp) { - if (null == bmp || bmp.isRecycled()) { - return NO_TEXTURE; - } + if (null == bmp || bmp.isRecycled())return NO_TEXTURE; int[] textureHandles = new int[1]; int textureHandle; GLES20.glGenTextures(1, textureHandles, 0); @@ -254,9 +232,6 @@ public static int createImageTexture(Bitmap bmp) { /** * Allocates a direct float buffer, and populates it with the float array data. - * - * @param coords the coords - * @return the float buffer */ public static FloatBuffer createFloatBuffer(float[] coords) { // Allocate a direct ByteBuffer, using 4 bytes per float, and copy coords into it. @@ -268,15 +243,6 @@ public static FloatBuffer createFloatBuffer(float[] coords) { return fb; } - /** - * Change mvp matrix crop float [ ]. - * - * @param viewWidth the view width - * @param viewHeight the view height - * @param textureWidth the texture width - * @param textureHeight the texture height - * @return the float [ ] - */ public static float[] changeMVPMatrixCrop(float viewWidth, float viewHeight, float textureWidth, float textureHeight) { float scale = viewWidth * textureHeight / viewHeight / textureWidth; float[] mvp = new float[16]; @@ -289,9 +255,6 @@ public static float[] changeMVPMatrixCrop(float viewWidth, float viewHeight, flo * Creates a texture object suitable for use with this program. *
* On exit, the texture will be bound.
- *
- * @param textureTarget the texture target
- * @return the int
*/
public static int createTextureObject(int textureTarget) {
int[] textures = new int[1];
@@ -311,37 +274,18 @@ public static int createTextureObject(int textureTarget) {
return texId;
}
- /**
- * Delete texture id.
- *
- * @param textureId the texture id
- */
public static void deleteTextureId(int[] textureId) {
if (textureId != null && textureId.length > 0) {
GLES20.glDeleteTextures(textureId.length, textureId, 0);
}
}
-
- /**
- * Delete texture id.
- *
- * @param textureId the texture id
- */
public static void deleteTextureId(int textureId) {
int[] textures = new int[1];
- textures[0] = textureId;
+ textures[0]= textureId;
GLES20.glDeleteTextures(textures.length, textures, 0);
}
- /**
- * Create fbo.
- *
- * @param fboTex the fbo tex
- * @param fboId the fbo id
- * @param width the width
- * @param height the height
- */
public static void createFBO(int[] fboTex, int[] fboId, int width, int height) {
//generate fbo id
GLES20.glGenFramebuffers(1, fboId, 0);
@@ -365,27 +309,12 @@ public static void createFBO(int[] fboTex, int[] fboId, int width, int height) {
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
}
- /**
- * Delete fbo.
- *
- * @param fboId the fbo id
- */
public static void deleteFBO(int[] fboId) {
if (fboId != null && fboId.length > 0) {
GLES20.glDeleteFramebuffers(fboId.length, fboId, 0);
}
}
- /**
- * Change mvp matrix crop float [ ].
- *
- * @param mvpMatrix the mvp matrix
- * @param viewWidth the view width
- * @param viewHeight the view height
- * @param textureWidth the texture width
- * @param textureHeight the texture height
- * @return the float [ ]
- */
public static float[] changeMVPMatrixCrop(float[] mvpMatrix, float viewWidth, float viewHeight, float textureWidth, float textureHeight) {
float scale = viewWidth * textureHeight / viewHeight / textureWidth;
if (scale == 1.0f) {
@@ -401,106 +330,74 @@ public static float[] changeMVPMatrixCrop(float[] mvpMatrix, float viewWidth, fl
}
- /**
- * Gets show matrix.
- *
- * @param matrix the matrix
- * @param imgWidth the img width
- * @param imgHeight the img height
- * @param viewWidth the view width
- * @param viewHeight the view height
- */
- public static void getShowMatrix(float[] matrix, int imgWidth, int imgHeight, int viewWidth, int viewHeight) {
- if (imgHeight > 0 && imgWidth > 0 && viewWidth > 0 && viewHeight > 0) {
- float sWhView = (float) viewWidth / viewHeight;
- float sWhImg = (float) imgWidth / imgHeight;
- float[] projection = new float[16];
- float[] camera = new float[16];
- if (sWhImg > sWhView) {
- Matrix.orthoM(projection, 0, -sWhView / sWhImg, sWhView / sWhImg, -1, 1, 1, 3);
- } else {
- Matrix.orthoM(projection, 0, -1, 1, -sWhImg / sWhView, sWhImg / sWhView, 1, 3);
+ public static void getShowMatrix(float[] matrix,int imgWidth,int imgHeight,int viewWidth,int viewHeight){
+ if(imgHeight>0&&imgWidth>0&&viewWidth>0&&viewHeight>0){
+ float sWhView=(float)viewWidth/viewHeight;
+ float sWhImg=(float)imgWidth/imgHeight;
+ float[] projection=new float[16];
+ float[] camera=new float[16];
+ if(sWhImg>sWhView){
+ Matrix.orthoM(projection,0,-sWhView/sWhImg,sWhView/sWhImg,-1,1,1,3);
+ }else{
+ Matrix.orthoM(projection,0,-1,1,-sWhImg/sWhView,sWhImg/sWhView,1,3);
}
- Matrix.setLookAtM(camera, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0);
- Matrix.multiplyMM(matrix, 0, projection, 0, camera, 0);
+ Matrix.setLookAtM(camera,0,0,0,1,0,0,0,0,1,0);
+ Matrix.multiplyMM(matrix,0,projection,0,camera,0);
}
}
- /**
- * Gets show matrix.
- *
- * @param matrix the matrix
- * @param type the type
- * @param imgWidth the img width
- * @param imgHeight the img height
- * @param viewWidth the view width
- * @param viewHeight the view height
- */
public static void getShowMatrix(float[] matrix, ImageView.ScaleType type, int imgWidth, int imgHeight, int viewWidth,
- int viewHeight) {
- if (imgHeight > 0 && imgWidth > 0 && viewWidth > 0 && viewHeight > 0) {
- float[] projection = new float[16];
- float[] camera = new float[16];
- if (type == FIT_XY) {
- Matrix.orthoM(projection, 0, -1, 1, -1, 1, 1, 3);
- Matrix.setLookAtM(camera, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0);
- Matrix.multiplyMM(matrix, 0, projection, 0, camera, 0);
+ int viewHeight){
+ if(imgHeight>0&&imgWidth>0&&viewWidth>0&&viewHeight>0){
+ float[] projection=new float[16];
+ float[] camera=new float[16];
+ if(type== FIT_XY){
+ Matrix.orthoM(projection,0,-1,1,-1,1,1,3);
+ Matrix.setLookAtM(camera,0,0,0,1,0,0,0,0,1,0);
+ Matrix.multiplyMM(matrix,0,projection,0,camera,0);
}
- float sWhView = (float) viewWidth / viewHeight;
- float sWhImg = (float) imgWidth / imgHeight;
- if (sWhImg > sWhView) {
- switch (type) {
+ float sWhView=(float)viewWidth/viewHeight;
+ float sWhImg=(float)imgWidth/imgHeight;
+ if(sWhImg>sWhView){
+ switch (type){
case CENTER_CROP:
- Matrix.orthoM(projection, 0, -sWhView / sWhImg, sWhView / sWhImg, -1, 1, 1, 3);
- Matrix.scaleM(projection, 0, X_SCALE, Y_SCALE, 1);
+ Matrix.orthoM(projection,0,-sWhView/sWhImg,sWhView/sWhImg,-1,1,1,3);
+ Matrix.scaleM(projection,0,x_scale,y_scale,1);
break;
case CENTER_INSIDE:
- Matrix.orthoM(projection, 0, -1, 1, -sWhImg / sWhView, sWhImg / sWhView, 1, 3);
+ Matrix.orthoM(projection,0,-1,1,-sWhImg/sWhView,sWhImg/sWhView,1,3);
break;
case FIT_START:
- Matrix.orthoM(projection, 0, -1, 1, 1 - 2 * sWhImg / sWhView, 1, 1, 3);
+ Matrix.orthoM(projection,0,-1,1,1-2*sWhImg/sWhView,1,1,3);
break;
case FIT_END:
- Matrix.orthoM(projection, 0, -1, 1, -1, 2 * sWhImg / sWhView - 1, 1, 3);
+ Matrix.orthoM(projection,0,-1,1,-1,2*sWhImg/sWhView-1,1,3);
break;
- default:
- // do nothing
}
- } else {
- switch (type) {
+ }else{
+ switch (type){
case CENTER_CROP:
- Matrix.orthoM(projection, 0, -1, 1, -sWhImg / sWhView, sWhImg / sWhView, 1, 3);
- Matrix.scaleM(projection, 0, X_SCALE, Y_SCALE, 1);
+ Matrix.orthoM(projection,0,-1,1,-sWhImg/sWhView,sWhImg/sWhView,1,3);
+ Matrix.scaleM(projection,0,x_scale,y_scale,1);
break;
case CENTER_INSIDE:
- Matrix.orthoM(projection, 0, -sWhView / sWhImg, sWhView / sWhImg, -1, 1, 1, 3);
+ Matrix.orthoM(projection,0,-sWhView/sWhImg,sWhView/sWhImg,-1,1,1,3);
break;
case FIT_START:
- Matrix.orthoM(projection, 0, -1, 2 * sWhView / sWhImg - 1, -1, 1, 1, 3);
+ Matrix.orthoM(projection,0,-1,2*sWhView/sWhImg-1,-1,1,1,3);
break;
case FIT_END:
- Matrix.orthoM(projection, 0, 1 - 2 * sWhView / sWhImg, 1, -1, 1, 1, 3);
+ Matrix.orthoM(projection,0,1-2*sWhView/sWhImg,1,-1,1,1,3);
break;
- default:
- // do nothing
}
}
- Matrix.setLookAtM(camera, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0);
- Matrix.multiplyMM(matrix, 0, projection, 0, camera, 0);
+ Matrix.setLookAtM(camera,0,0,0,1,0,0,0,0,1,0);
+ Matrix.multiplyMM(matrix,0,projection,0,camera,0);
}
}
- /**
- * Change mvp matrix inside float [ ].
- *
- * @param viewWidth the view width
- * @param viewHeight the view height
- * @param textureWidth the texture width
- * @param textureHeight the texture height
- * @return the float [ ]
- */
public static float[] changeMVPMatrixInside(float viewWidth, float viewHeight, float textureWidth, float textureHeight) {
float scale = viewWidth * textureHeight / viewHeight / textureWidth;
float[] mvp = new float[16];
@@ -512,8 +409,8 @@ public static float[] changeMVPMatrixInside(float viewWidth, float viewHeight, f
/**
* Prefer OpenGL ES 3.0, otherwise 2.0
*
- * @param context the context
- * @return support gl version
+ * @param context
+ * @return
*/
public static int getSupportGLVersion(Context context) {
final ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
@@ -526,55 +423,24 @@ public static int getSupportGLVersion(Context context) {
}
- /**
- * Rotate float [ ].
- *
- * @param m the m
- * @param angle the angle
- * @return the float [ ]
- */
- public static float[] rotate(float[] m, float angle) {
- Matrix.rotateM(m, 0, angle, 0, 0, 1);
+ public static float[] rotate(float[] m,float angle){
+ Matrix.rotateM(m,0,angle,0,0,1);
return m;
}
- /**
- * Flip float [ ].
- *
- * @param m the m
- * @param x the x
- * @param y the y
- * @return the float [ ]
- */
- public static float[] flip(float[] m, boolean x, boolean y) {
- if (x || y) {
- Matrix.scaleM(m, 0, x ? -1 : 1, y ? -1 : 1, 1);
+ public static float[] flip(float[] m,boolean x,boolean y){
+ if(x||y){
+ Matrix.scaleM(m,0,x?-1:1,y?-1:1,1);
}
return m;
}
- /**
- * Scale float [ ].
- *
- * @param m the m
- * @param x the x
- * @param y the y
- * @return the float [ ]
- */
- public static float[] scale(float[] m, float x, float y) {
- Matrix.scaleM(m, 0, x, y, 1);
+ public static float[] scale(float[] m,float x,float y){
+ Matrix.scaleM(m,0,x,y,1);
return m;
}
- /**
- * Read pixles buffer byte buffer.
- *
- * @param textureId the texture id
- * @param width the width
- * @param height the height
- * @return the byte buffer
- */
public static ByteBuffer readPixlesBuffer(int textureId, int width, int height) {
if (textureId == GlUtil.NO_TEXTURE) {
@@ -612,12 +478,7 @@ public static ByteBuffer readPixlesBuffer(int textureId, int width, int height)
return mCaptureBuffer;
}
- /**
- * Gets external oes texture id.
- *
- * @return the external oes texture id
- */
- public static int getExternalOESTextureID() {
+ public static int getExternalOESTextureID(){
int[] texture = new int[1];
GLES20.glGenTextures(1, texture, 0);
diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/Program.java b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/Program.java
index 3152c5606..71571a0c5 100644
--- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/Program.java
+++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/Program.java
@@ -31,96 +31,44 @@
import java.nio.ByteBuffer;
-/**
- * The type Program.
- */
public abstract class Program {
private static final String TAG = GlUtil.TAG;
- /**
- * The M program handle.
- */
-// Handles to the GL program and various components of it.
+ // Handles to the GL program and various components of it.
protected int mProgramHandle;
- /**
- * The M drawable 2 d.
- */
protected Drawable2d mDrawable2d;
- /**
- * The M frame buffers.
- */
protected int[] mFrameBuffers;
- /**
- * The M frame buffer textures.
- */
protected int[] mFrameBufferTextures;
- /**
- * The Frame buffer num.
- */
- protected int frameBufferNum = 1;
- /**
- * The M frame buffer shape.
- */
+ protected int FRAME_BUFFER_NUM = 1;
protected Point mFrameBufferShape;
-
/**
* Prepares the program in the current EGL context.
- *
- * @param vertexShader the vertex shader
- * @param fragmentShader2D the fragment shader 2 d
*/
- public Program(String vertexShader, String fragmentShader2D) {
- mProgramHandle = GlUtil.createProgram(vertexShader, fragmentShader2D);
+ public Program(String VERTEX_SHADER, String FRAGMENT_SHADER_2D) {
+ mProgramHandle = GlUtil.createProgram(VERTEX_SHADER, FRAGMENT_SHADER_2D);
mDrawable2d = getDrawable2d();
getLocations();
}
- /**
- * Instantiates a new Program.
- *
- * @param context the context
- * @param vertexShaderResourceId the vertex shader resource id
- * @param fragmentShaderResourceId the fragment shader resource id
- */
public Program(Context context, int vertexShaderResourceId, int fragmentShaderResourceId) {
this(Extensions.readTextFileFromResource(context, vertexShaderResourceId), Extensions.readTextFileFromResource(context, fragmentShaderResourceId));
}
- /**
- * Update vertex array.
- *
- * @param fullRectangleCoords the full rectangle coords
- */
- public void updateVertexArray(float[] fullRectangleCoords) {
- mDrawable2d.updateVertexArray(fullRectangleCoords);
+ public void updateVertexArray(float[] FULL_RECTANGLE_COORDS) {
+ mDrawable2d.updateVertexArray(FULL_RECTANGLE_COORDS);
}
- /**
- * Update tex coord array.
- *
- * @param fullRectangleTexCoords the full rectangle tex coords
- */
- public void updateTexCoordArray(float[] fullRectangleTexCoords) {
- mDrawable2d.updateTexCoordArray(fullRectangleTexCoords);
+ public void updateTexCoordArray(float[] FULL_RECTANGLE_TEX_COORDS) {
+ mDrawable2d.updateTexCoordArray(FULL_RECTANGLE_TEX_COORDS);
}
- /**
- * Update tex coord array fb.
- *
- * @param coords the coords
- */
public void updateTexCoordArrayFB(float[] coords) {
mDrawable2d.updateTexCoordArrayFB(coords);
}
- /**
- * Gets drawable 2 d.
- *
- * @return the drawable 2 d
- */
protected abstract Drawable2d getDrawable2d();
/**
@@ -130,42 +78,15 @@ public void updateTexCoordArrayFB(float[] coords) {
/**
* Issues the draw call. Does the full setup on every call.
- *
- * @param textureId the texture id
- * @param width the width
- * @param height the height
- * @param mvpMatrix the mvp matrix
*/
public abstract void drawFrameOnScreen(int textureId, int width, int height, float[] mvpMatrix);
- /**
- * Draw frame off screen int.
- *
- * @param textureId the texture id
- * @param width the width
- * @param height the height
- * @param mvpMatrix the mvp matrix
- * @return the int
- */
- public abstract int drawFrameOffScreen(int textureId, int width, int height, float[] mvpMatrix);
- /**
- * Read buffer byte buffer.
- *
- * @param textureId the texture id
- * @param width the width
- * @param height the height
- * @return the byte buffer
- */
+ public abstract int drawFrameOffScreen(int textureId,int width, int height, float[] mvpMatrix);
+
public abstract ByteBuffer readBuffer(int textureId, int width, int height);
- /**
- * Init frame buffer if need.
- *
- * @param width the width
- * @param height the height
- */
protected void initFrameBufferIfNeed(int width, int height) {
boolean need = false;
if (null == mFrameBufferShape || mFrameBufferShape.x != width || mFrameBufferShape.y != height) {
@@ -175,11 +96,11 @@ protected void initFrameBufferIfNeed(int width, int height) {
need = true;
}
if (need) {
- mFrameBuffers = new int[frameBufferNum];
- mFrameBufferTextures = new int[frameBufferNum];
- GLES20.glGenFramebuffers(frameBufferNum, mFrameBuffers, 0);
- GLES20.glGenTextures(frameBufferNum, mFrameBufferTextures, 0);
- for (int i = 0; i < frameBufferNum; i++) {
+ mFrameBuffers = new int[FRAME_BUFFER_NUM];
+ mFrameBufferTextures = new int[FRAME_BUFFER_NUM];
+ GLES20.glGenFramebuffers(FRAME_BUFFER_NUM, mFrameBuffers, 0);
+ GLES20.glGenTextures(FRAME_BUFFER_NUM, mFrameBufferTextures, 0);
+ for (int i = 0; i < FRAME_BUFFER_NUM; i++) {
bindFrameBuffer(mFrameBufferTextures[i], mFrameBuffers[i], width, height);
}
mFrameBufferShape = new Point(width, height);
@@ -190,15 +111,26 @@ protected void initFrameBufferIfNeed(int width, int height) {
private void destroyFrameBuffers() {
if (mFrameBufferTextures != null) {
- GLES20.glDeleteTextures(frameBufferNum, mFrameBufferTextures, 0);
+ GLES20.glDeleteTextures(FRAME_BUFFER_NUM, mFrameBufferTextures, 0);
mFrameBufferTextures = null;
}
if (mFrameBuffers != null) {
- GLES20.glDeleteFramebuffers(frameBufferNum, mFrameBuffers, 0);
+ GLES20.glDeleteFramebuffers(FRAME_BUFFER_NUM, mFrameBuffers, 0);
mFrameBuffers = null;
}
}
+ /** {zh}
+ * 纹理参数设置+buffer绑定
+ * set texture params
+ * and bind buffer
+ */
+ /** {en}
+ * Texture parameter setting + buffer binding
+ * set texture params
+ * and binding buffer
+ */
+
private void bindFrameBuffer(int textureId, int frameBuffer, int width, int height) {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0,
diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramManager.java b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramManager.java
index d227e6da6..d536a6f5f 100644
--- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramManager.java
+++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramManager.java
@@ -25,27 +25,21 @@
package io.agora.beautyapi.bytedance.utils.opengl;
-import com.bytedance.labcv.effectsdk.BytedEffectConstants;
+import com.effectsar.labcv.effectsdk.EffectsSDKEffectConstants;
-/**
- * The type Program manager.
- */
public class ProgramManager {
+ public ProgramManager() {
+ }
+
private ProgramTexture2d mProgramTexture2D;
private ProgramTextureOES mProgramTextureOES;
- /**
- * Gets program.
- *
- * @param srcTetxureFormat the src tetxure format
- * @return the program
- */
- public Program getProgram(BytedEffectConstants.TextureFormat srcTetxureFormat) {
- switch (srcTetxureFormat) {
+ public Program getProgram(EffectsSDKEffectConstants.TextureFormat srcTetxureFormat){
+ switch (srcTetxureFormat){
case Texure2D:
- if (null == mProgramTexture2D) {
+ if (null == mProgramTexture2D){
mProgramTexture2D = new ProgramTexture2d();
}
return mProgramTexture2D;
@@ -54,21 +48,18 @@ public Program getProgram(BytedEffectConstants.TextureFormat srcTetxureFormat) {
mProgramTextureOES = new ProgramTextureOES();
}
return mProgramTextureOES;
- default:
- return null;
}
+ return null;
+
}
- /**
- * Release.
- */
- public void release() {
- if (null != mProgramTexture2D) {
+ public void release(){
+ if (null != mProgramTexture2D){
mProgramTexture2D.release();
mProgramTexture2D = null;
}
- if (null != mProgramTextureOES) {
+ if (null != mProgramTextureOES){
mProgramTextureOES.release();
mProgramTextureOES = null;
diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramTexture2d.java b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramTexture2d.java
index 3aab4a67e..b81a0525f 100644
--- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramTexture2d.java
+++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramTexture2d.java
@@ -32,38 +32,32 @@
import java.nio.ByteBuffer;
-/**
- * The type Program texture 2 d.
- */
public class ProgramTexture2d extends Program {
// Simple vertex shader, used for all programs.
private static final String VERTEX_SHADER =
- "uniform mat4 uMVPMatrix;\n"
- + "attribute vec4 aPosition;\n"
- + "attribute vec2 aTextureCoord;\n"
- + "varying vec2 vTextureCoord;\n"
- + "void main() {\n"
- + " gl_Position = uMVPMatrix * aPosition;\n"
- + " vTextureCoord = aTextureCoord;\n"
- + "}\n";
+ "uniform mat4 uMVPMatrix;\n" +
+ "attribute vec4 aPosition;\n" +
+ "attribute vec2 aTextureCoord;\n" +
+ "varying vec2 vTextureCoord;\n" +
+ "void main() {\n" +
+ " gl_Position = uMVPMatrix * aPosition;\n" +
+ " vTextureCoord = aTextureCoord;\n" +
+ "}\n";
// Simple fragment shader for use with "normal" 2D textures.
private static final String FRAGMENT_SHADER_2D =
- "precision mediump float;\n"
- + "varying vec2 vTextureCoord;\n"
- + "uniform sampler2D sTexture;\n"
- + "void main() {\n"
- + " gl_FragColor = texture2D(sTexture, vTextureCoord);\n"
- + "}\n";
+ "precision mediump float;\n" +
+ "varying vec2 vTextureCoord;\n" +
+ "uniform sampler2D sTexture;\n" +
+ "void main() {\n" +
+ " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
+ "}\n";
private int muMVPMatrixLoc;
private int maPositionLoc;
private int maTextureCoordLoc;
- /**
- * Instantiates a new Program texture 2 d.
- */
public ProgramTexture2d() {
super(VERTEX_SHADER, FRAGMENT_SHADER_2D);
}
@@ -122,6 +116,7 @@ public void drawFrameOnScreen(int textureId, int width, int height, float[] mvpM
GLES20.glViewport(0, 0, width, height);
+
// Draw the rect.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, mDrawable2d.getVertexCount());
GlUtil.checkGlError("glDrawArrays");
@@ -192,17 +187,29 @@ public int drawFrameOffScreen(int textureId, int width, int height, float[] mvpM
return mFrameBufferTextures[0];
}
+ /** {zh}
+ * 读取渲染结果的buffer
+ * @param width 目标宽度
+ * @param height 目标高度
+ * @return 渲染结果的像素Buffer 格式RGBA
+ */
+ /** {en}
+ * Read the buffer
+ * @param width target width
+ * @param height target height
+ * @return pixel Buffer format of the rendered result RGBA
+ */
+
private int mWidth = 0;
private int mHeight = 0;
private ByteBuffer mCaptureBuffer = null;
-
@Override
public ByteBuffer readBuffer(int textureId, int width, int height) {
- if (textureId == GlUtil.NO_TEXTURE) {
+ if ( textureId == GlUtil.NO_TEXTURE) {
return null;
}
- if (width * height == 0) {
- return null;
+ if (width* height == 0){
+ return null;
}
if (mCaptureBuffer == null || mWidth * mHeight != width * height) {
@@ -212,7 +219,7 @@ public ByteBuffer readBuffer(int textureId, int width, int height) {
}
mCaptureBuffer.position(0);
int[] frameBuffer = new int[1];
- GLES20.glGenFramebuffers(1, frameBuffer, 0);
+ GLES20.glGenFramebuffers(1,frameBuffer,0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramTextureOES.java b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramTextureOES.java
index 56fd0f840..c2667f4e7 100644
--- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramTextureOES.java
+++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramTextureOES.java
@@ -32,32 +32,29 @@
import java.nio.ByteBuffer;
-/**
- * The type Program texture oes.
- */
public class ProgramTextureOES extends Program {
// Simple vertex shader, used for all programs.
private static final String VERTEX_SHADER =
- "uniform mat4 uMVPMatrix;\n"
- + "attribute vec4 aPosition;\n"
- + "attribute vec2 aTextureCoord;\n"
- + "varying vec2 vTextureCoord;\n"
- + "void main() {\n"
- + " gl_Position = uMVPMatrix * aPosition;\n"
- + " vTextureCoord = aTextureCoord;\n"
- + "}\n";
+ "uniform mat4 uMVPMatrix;\n" +
+ "attribute vec4 aPosition;\n" +
+ "attribute vec2 aTextureCoord;\n" +
+ "varying vec2 vTextureCoord;\n" +
+ "void main() {\n" +
+ " gl_Position = uMVPMatrix * aPosition;\n" +
+ " vTextureCoord = aTextureCoord;\n" +
+ "}\n";
// Simple fragment shader for use with external 2D textures (e.g. what we get from
// SurfaceTexture).
private static final String FRAGMENT_SHADER_EXT =
- "#extension GL_OES_EGL_image_external : require\n"
- + "precision mediump float;\n"
- + "varying vec2 vTextureCoord;\n"
- + "uniform samplerExternalOES sTexture;\n"
- + "void main() {\n"
- + " gl_FragColor = texture2D(sTexture, vTextureCoord);\n"
- + "}\n";
+ "#extension GL_OES_EGL_image_external : require\n" +
+ "precision mediump float;\n" +
+ "varying vec2 vTextureCoord;\n" +
+ "uniform samplerExternalOES sTexture;\n" +
+ "void main() {\n" +
+ " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
+ "}\n";
private int muMVPMatrixLoc;
private int maPositionLoc;
@@ -86,7 +83,7 @@ protected void getLocations() {
}
@Override
- public void drawFrameOnScreen(int textureId, int width, int height, float[] mvpMatrix) {
+ public void drawFrameOnScreen(int textureId,int width, int height, float[] mvpMatrix) {
GlUtil.checkGlError("draw start");
// Select the program.
@@ -159,6 +156,7 @@ public int drawFrameOffScreen(int textureId, int width, int height, float[] mvpM
GlUtil.checkGlError("glUniformMatrix4fv");
+
// Enable the "aPosition" vertex attribute.
GLES20.glEnableVertexAttribArray(maPositionLoc);
GlUtil.checkGlError("glEnableVertexAttribArray");
@@ -194,28 +192,33 @@ public int drawFrameOffScreen(int textureId, int width, int height, float[] mvpM
}
- /**
- * {en}
+ /** {zh}
+ * 读取渲染结果的buffer
+ * @param width 目标宽度
+ * @param height 目标高度
+ * @return 渲染结果的像素Buffer 格式RGBA
+ */
+ /** {en}
* Read the buffer
- *
- * @param width target width
+ * @param width target width
* @param height target height
* @return pixel Buffer format of the rendered result RGBA
*/
+
@Override
public ByteBuffer readBuffer(int textureId, int width, int height) {
- if (textureId == GlUtil.NO_TEXTURE) {
+ if ( textureId == GlUtil.NO_TEXTURE) {
return null;
}
- if (width * height == 0) {
- return null;
+ if (width* height == 0){
+ return null;
}
- ByteBuffer mCaptureBuffer = ByteBuffer.allocateDirect(width * height * 4);
+ ByteBuffer mCaptureBuffer = ByteBuffer.allocateDirect(width* height*4);
mCaptureBuffer.position(0);
int[] frameBuffer = new int[1];
- GLES20.glGenFramebuffers(1, frameBuffer, 0);
+ GLES20.glGenFramebuffers(1,frameBuffer,0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramTextureYUV.java b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramTextureYUV.java
index 8b68d35ef..14a992368 100644
--- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramTextureYUV.java
+++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/bytedance/utils/opengl/ProgramTextureYUV.java
@@ -41,9 +41,6 @@ public class ProgramTextureYUV extends Program {
private int mVTextureLoc;
private int mVUTextureLoc;
- /**
- * Instantiates a new Program texture yuv.
- */
public ProgramTextureYUV() {
super(VERTEX, FRAGMENT);
}
@@ -72,17 +69,6 @@ protected void getLocations() {
GlUtil.checkLocation(muMVPMatrixLoc, "vuTexture");
}
- /**
- * Draw frame off screen int.
- *
- * @param yTexture the y texture
- * @param uTexture the u texture
- * @param vTexture the v texture
- * @param width the width
- * @param height the height
- * @param mvpMatrix the mvp matrix
- * @return the int
- */
public int drawFrameOffScreen(int yTexture, int uTexture, int vTexture, int width, int height, float[] mvpMatrix) {
GlUtil.checkGlError("draw start");
@@ -138,16 +124,6 @@ public int drawFrameOffScreen(int yTexture, int uTexture, int vTexture, int widt
return mFrameBufferTextures[0];
}
- /**
- * Draw frame off screen int.
- *
- * @param yTexture the y texture
- * @param vuTexture the vu texture
- * @param width the width
- * @param height the height
- * @param mvpMatrix the mvp matrix
- * @return the int
- */
public int drawFrameOffScreen(int yTexture, int vuTexture, int width, int height, float[] mvpMatrix) {
GlUtil.checkGlError("draw start");
@@ -212,39 +188,33 @@ public ByteBuffer readBuffer(int textureId, int width, int height) {
return null;
}
- /**
- * The constant VERTEX.
- */
- public static final String VERTEX = "uniform mat4 uMVPMatrix;\n"
- + "attribute vec4 aPosition;\n"
- + "attribute vec2 aTextureCoord;\n"
- + "varying vec2 vTextureCoord;\n"
- + "void main() {\n"
- + " gl_Position = uMVPMatrix * aPosition;\n"
- + " vTextureCoord = aTextureCoord;\n"
- + "}\n";
- /**
- * The constant FRAGMENT.
- */
- public static final String FRAGMENT = "varying highp vec2 vTextureCoord;\n"
- + " uniform sampler2D yTexture;\n"
- + " uniform sampler2D vuTexture;\n"
- + " uniform sampler2D uTexture;\n"
- + " uniform sampler2D vTexture;\n"
- + " void main()\n"
- + " {\n"
- + " mediump vec3 yuv;\n"
- + " lowp vec3 rgb;\n"
- + " yuv.x = texture2D(yTexture, vTextureCoord).a - 0.065;\n"
- + " yuv.y = texture2D(vuTexture, vTextureCoord).a - 0.5;\n"
- + " yuv.z = texture2D(vuTexture, vTextureCoord).r - 0.5;\n"
-// + " rgb = mat3( 1, 1, 1,\n"
-// + " 0, -.21482, 2.12798,\n"
-// + " 1.28033, -.38059, 0) * yuv;\n"
- + " rgb.x = yuv.x + 1.4075 * yuv.z;\n"
- + " rgb.y = yuv.x - 0.3455 * yuv.y - 0.7169 * yuv.z;\n"
- + " rgb.z = yuv.x + 1.779 * yuv.y;\n"
-// + " gl_FragColor = vec4(rgb.x, rgb.y, rgb.z, 1);\n"
- + " gl_FragColor = vec4(rgb.x, rgb.y, rgb.z, 1);\n"
- + " }";
+ public static final String VERTEX = "uniform mat4 uMVPMatrix;\n" +
+ "attribute vec4 aPosition;\n" +
+ "attribute vec2 aTextureCoord;\n" +
+ "varying vec2 vTextureCoord;\n" +
+ "void main() {\n" +
+ " gl_Position = uMVPMatrix * aPosition;\n" +
+ " vTextureCoord = aTextureCoord;\n" +
+ "}\n";
+ public static final String FRAGMENT = "varying highp vec2 vTextureCoord;\n" +
+ " uniform sampler2D yTexture;\n" +
+ " uniform sampler2D vuTexture;\n" +
+ " uniform sampler2D uTexture;\n" +
+ " uniform sampler2D vTexture;\n" +
+ " void main()\n" +
+ " {\n" +
+ " mediump vec3 yuv;\n" +
+ " lowp vec3 rgb;\n" +
+ " yuv.x = texture2D(yTexture, vTextureCoord).a - 0.065;\n" +
+ " yuv.y = texture2D(vuTexture, vTextureCoord).a - 0.5;\n" +
+ " yuv.z = texture2D(vuTexture, vTextureCoord).r - 0.5;\n" +
+// " rgb = mat3( 1, 1, 1,\n" +
+// " 0, -.21482, 2.12798,\n" +
+// " 1.28033, -.38059, 0) * yuv;\n" +
+ " rgb.x = yuv.x + 1.4075 * yuv.z;\n" +
+ " rgb.y = yuv.x - 0.3455 * yuv.y - 0.7169 * yuv.z;\n" +
+ " rgb.z = yuv.x + 1.779 * yuv.y;\n" +
+// " gl_FragColor = vec4(rgb.x, rgb.y, rgb.z, 1);\n" +
+ " gl_FragColor = vec4(rgb.x, rgb.y, rgb.z, 1);\n" +
+ " }";
}
diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/FaceUnityBeautyAPI.kt b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/FaceUnityBeautyAPI.kt
index f7a07a85e..1058ea229 100644
--- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/FaceUnityBeautyAPI.kt
+++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/FaceUnityBeautyAPI.kt
@@ -31,37 +31,13 @@ import io.agora.base.VideoFrame
import io.agora.rtc2.Constants
import io.agora.rtc2.RtcEngine
-/**
- * Version
- */
-const val VERSION = "1.0.3"
+const val VERSION = "1.0.6"
-/**
- * Capture mode
- *
- * @constructor Create empty Capture mode
- */
enum class CaptureMode{
- /**
- * Agora
- *
- * @constructor Create empty Agora
- */
Agora, // 使用声网内部的祼数据接口进行处理
-
- /**
- * Custom
- *
- * @constructor Create empty Custom
- */
Custom // 自定义模式,需要自己调用onFrame接口将原始视频帧传给BeautyAPI做处理
}
-/**
- * I event callback
- *
- * @constructor Create empty I event callback
- */
interface IEventCallback{
/**
@@ -72,83 +48,27 @@ interface IEventCallback{
fun onBeautyStats(stats: BeautyStats)
}
-/**
- * Beauty stats
- *
- * @property minCostMs
- * @property maxCostMs
- * @property averageCostMs
- * @constructor Create empty Beauty stats
- */
data class BeautyStats(
val minCostMs:Long, // 统计区间内的最小值
val maxCostMs: Long, // 统计区间内的最大值
val averageCostMs: Long // 统计区间内的平均值
)
-/**
- * Mirror mode
- *
- * @constructor Create empty Mirror mode
- */
enum class MirrorMode {
// 没有镜像正常画面的定义:前置拍到画面和手机看到画面是左右不一致的,后置拍到画面和手机看到画面是左右一致的
- /**
- * Mirror Local Remote
- *
- * @constructor Create empty Mirror Local Remote
- */
MIRROR_LOCAL_REMOTE, //本地远端都镜像,前置默认,本地和远端贴纸都正常
-
- /**
- * Mirror Local Only
- *
- * @constructor Create empty Mirror Local Only
- */
MIRROR_LOCAL_ONLY, // 仅本地镜像,远端不镜像,,远端贴纸正常,本地贴纸镜像。用于打电话场景,电商直播场景(保证电商直播后面的告示牌文字是正的);这种模式因为本地远端是反的,所以肯定有一边的文字贴纸方向会是反的
-
- /**
- * Mirror Remote Only
- *
- * @constructor Create empty Mirror Remote Only
- */
MIRROR_REMOTE_ONLY, // 仅远端镜像,本地不镜像,远端贴纸正常,本地贴纸镜像
-
- /**
- * Mirror None
- *
- * @constructor Create empty Mirror None
- */
MIRROR_NONE // 本地远端都不镜像,后置默认,本地和远端贴纸都正常
}
-/**
- * Camera config
- *
- * @property frontMirror
- * @property backMirror
- * @constructor Create empty Camera config
- */
data class CameraConfig(
val frontMirror: MirrorMode = MirrorMode.MIRROR_LOCAL_REMOTE, // 前置默认镜像:本地远端都镜像
val backMirror: MirrorMode = MirrorMode.MIRROR_NONE // 后置默认镜像:本地远端都不镜像
)
-/**
- * Config
- *
- * @property context
- * @property rtcEngine
- * @property fuRenderKit
- * @property eventCallback
- * @property captureMode
- * @property statsDuration
- * @property statsEnable
- * @property cameraConfig
- * @constructor Create empty Config
- */
data class Config(
val context: Context, // Android Context 上下文
val rtcEngine: RtcEngine, // 声网Rtc引擎
@@ -160,103 +80,23 @@ data class Config(
val cameraConfig: CameraConfig = CameraConfig() // 摄像头镜像配置
)
-/**
- * Error code
- *
- * @property value
- * @constructor Create empty Error code
- */
enum class ErrorCode(val value: Int) {
- /**
- * Error Ok
- *
- * @constructor Create empty Error Ok
- */
ERROR_OK(0), // 一切正常
-
- /**
- * Error Has Not Initialized
- *
- * @constructor Create empty Error Has Not Initialized
- */
ERROR_HAS_NOT_INITIALIZED(101), // 没有调用Initialize或调用失败情况下调用了其他API
-
- /**
- * Error Has Initialized
- *
- * @constructor Create empty Error Has Initialized
- */
ERROR_HAS_INITIALIZED(102), // 已经Initialize成功后再次调用报错
-
- /**
- * Error Has Released
- *
- * @constructor Create empty Error Has Released
- */
ERROR_HAS_RELEASED(103), // 已经调用release销毁后还调用其他API
-
- /**
- * Error Process Not Custom
- *
- * @constructor Create empty Error Process Not Custom
- */
ERROR_PROCESS_NOT_CUSTOM(104), // 非Custom处理模式下调用onFrame接口从外部传入视频帧
-
- /**
- * Error Process Disable
- *
- * @constructor Create empty Error Process Disable
- */
- ERROR_PROCESS_DISABLE(105), // 当调用enable(false)禁用美颜后调用onFrame接口返回
-
- /**
- * Error View Type Error
- *
- * @constructor Create empty Error View Type Error
- */
- ERROR_VIEW_TYPE_ERROR(106), // 当调用setupLocalVideo时view类型错误时返回
-
- /**
- * Error Frame Skipped
- *
- * @constructor Create empty Error Frame Skipped
- */
- ERROR_FRAME_SKIPPED(107), // 当处理帧忽略时在onFrame返回
+ ERROR_VIEW_TYPE_ERROR(105), // 当调用setupLocalVideo时view类型错误时返回
+ ERROR_FRAME_SKIPPED(106), // 当处理帧忽略时在onFrame返回
}
-/**
- * Beauty preset
- *
- * @constructor Create empty Beauty preset
- */
enum class BeautyPreset {
- /**
- * Custom
- *
- * @constructor Create empty Custom
- */
CUSTOM, // 不使用推荐的美颜参数
-
- /**
- * Default
- *
- * @constructor Create empty Default
- */
DEFAULT // 默认的
}
-/**
- * Create face unity beauty a p i
- *
- * @return
- */
fun createFaceUnityBeautyAPI(): FaceUnityBeautyAPI = FaceUnityBeautyAPIImpl()
-/**
- * Face unity beauty a p i
- *
- * @constructor Create empty Face unity beauty a p i
- */
interface FaceUnityBeautyAPI {
/**
@@ -311,12 +151,19 @@ interface FaceUnityBeautyAPI {
fun isFrontCamera(): Boolean
/**
- * Get mirror applied
+ * 获取镜像状态
*
- * @return
+ * @return 镜像状态,true: 镜像,false:非镜像
*/
fun getMirrorApplied(): Boolean
+ /**
+ * 在处理线程里执行操作
+ *
+ * @param run 操作run
+ */
+ fun runOnProcessThread(run: ()->Unit)
+
/**
* 私参配置,用于不对外api的调用,多用于测试
*/
diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/FaceUnityBeautyAPIImpl.kt b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/FaceUnityBeautyAPIImpl.kt
index 84fb33481..dd51417aa 100644
--- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/FaceUnityBeautyAPIImpl.kt
+++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/FaceUnityBeautyAPIImpl.kt
@@ -45,10 +45,12 @@ import io.agora.base.VideoFrame
import io.agora.base.VideoFrame.I420Buffer
import io.agora.base.VideoFrame.SourceType
import io.agora.base.VideoFrame.TextureBuffer
+import io.agora.base.internal.video.EglBase
import io.agora.base.internal.video.YuvHelper
import io.agora.beautyapi.faceunity.utils.FuDeviceUtils
import io.agora.beautyapi.faceunity.utils.LogUtils
import io.agora.beautyapi.faceunity.utils.StatsHelper
+import io.agora.beautyapi.faceunity.utils.egl.GLFrameBuffer
import io.agora.beautyapi.faceunity.utils.egl.TextureProcessHelper
import io.agora.rtc2.Constants
import io.agora.rtc2.gl.EglBaseProvider
@@ -56,18 +58,15 @@ import io.agora.rtc2.video.IVideoFrameObserver
import io.agora.rtc2.video.VideoCanvas
import java.io.File
import java.nio.ByteBuffer
+import java.util.Collections
import java.util.concurrent.Callable
-/**
- * Face unity beauty a p i impl
- *
- * @constructor Create empty Face unity beauty a p i impl
- */
class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
private val TAG = "FaceUnityBeautyAPIImpl"
private val reportId = "scenarioAPI"
private val reportCategory = "beauty_android_$VERSION"
- private var beautyMode = 0 // 0: 自动根据buffer类型切换,1:固定使用OES纹理,2:固定使用i420,3: 单纹理异步模式(自创)
+ private var beautyMode = 0 // 0: 自动根据buffer类型切换,1:固定使用OES纹理,2:固定使用i420,3: 单纹理模式
+ private var enableTextureAsync = true // 是否开启纹理+异步缓存处理。对于GPU性能好的手机可以减小美颜处理耗时,对于中端机开启后效果也不明显。
private var textureBufferHelper: TextureBufferHelper? = null
private var wrapTextureBufferHelper: TextureBufferHelper? = null
@@ -84,32 +83,11 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
private var statsHelper: StatsHelper? = null
private var skipFrame = 0
private enum class ProcessSourceType{
- /**
- * Unknown
- *
- * @constructor Create empty Unknown
- */
UNKNOWN,
-
- /**
- * Texture Oes Async
- *
- * @constructor Create empty Texture Oes Async
- */
TEXTURE_OES_ASYNC,
-
- /**
- * Texture 2d Async
- *
- * @constructor Create empty Texture 2d Async
- */
TEXTURE_2D_ASYNC,
-
- /**
- * I420
- *
- * @constructor Create empty I420
- */
+ TEXTURE_OES,
+ TEXTURE_2D,
I420
}
private var currProcessSourceType = ProcessSourceType.UNKNOWN
@@ -117,26 +95,22 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
private var isFrontCamera = true
private var cameraConfig = CameraConfig()
private var localVideoRenderMode = Constants.RENDER_MODE_HIDDEN
+ private val pendingProcessRunList = Collections.synchronizedList(mutableListOf<()->Unit>())
+ private val transformGLFrameBuffer = GLFrameBuffer()
- /**
- * Initialize
- *
- * @param config
- * @return
- */
override fun initialize(config: Config): Int {
if (this.config != null) {
LogUtils.e(TAG, "initialize >> The beauty api has been initialized!")
return ErrorCode.ERROR_HAS_INITIALIZED.value
}
this.config = config
+ this.cameraConfig = config.cameraConfig
if (config.captureMode == CaptureMode.Agora) {
config.rtcEngine.registerVideoFrameObserver(this)
}
statsHelper = StatsHelper(config.statsDuration){
this.config?.eventCallback?.onBeautyStats(it)
}
- LogUtils.setLogFilePath(config.context.getExternalFilesDir("")?.absolutePath ?: "")
LogUtils.i(TAG, "initialize >> config = $config")
LogUtils.i(TAG, "initialize >> beauty api version=$VERSION, beauty sdk version=${FURenderKit.getInstance().getVersion()}")
@@ -153,12 +127,6 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
return ErrorCode.ERROR_OK.value
}
- /**
- * Enable
- *
- * @param enable
- * @return
- */
override fun enable(enable: Boolean): Int {
LogUtils.i(TAG, "enable >> enable = $enable")
if (config == null) {
@@ -183,13 +151,6 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
return ErrorCode.ERROR_OK.value
}
- /**
- * Setup local video
- *
- * @param view
- * @param renderMode
- * @return
- */
override fun setupLocalVideo(view: View, renderMode: Int): Int {
val rtcEngine = config?.rtcEngine
if(rtcEngine == null){
@@ -208,12 +169,6 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
return ErrorCode.ERROR_VIEW_TYPE_ERROR.value
}
- /**
- * On frame
- *
- * @param videoFrame
- * @return
- */
override fun onFrame(videoFrame: VideoFrame): Int {
val conf = config
if(conf == null){
@@ -228,9 +183,6 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
LogUtils.e(TAG, "onFrame >> The capture mode is not Custom!")
return ErrorCode.ERROR_PROCESS_NOT_CUSTOM.value
}
- if (!enable) {
- return ErrorCode.ERROR_PROCESS_DISABLE.value
- }
if (processBeauty(videoFrame)) {
return ErrorCode.ERROR_OK.value
}
@@ -238,12 +190,6 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
return ErrorCode.ERROR_FRAME_SKIPPED.value
}
- /**
- * Update camera config
- *
- * @param config
- * @return
- */
override fun updateCameraConfig(config: CameraConfig): Int {
LogUtils.i(TAG, "updateCameraConfig >> oldCameraConfig=$cameraConfig, newCameraConfig=$config")
cameraConfig = CameraConfig(config.frontMirror, config.backMirror)
@@ -252,30 +198,33 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
return ErrorCode.ERROR_OK.value
}
- /**
- * Is front camera
- *
- */
+ override fun runOnProcessThread(run: () -> Unit) {
+ if (config == null) {
+ LogUtils.e(TAG, "runOnProcessThread >> The beauty api has not been initialized!")
+ return
+ }
+ if (isReleased) {
+ LogUtils.e(TAG, "runOnProcessThread >> The beauty api has been released!")
+ return
+ }
+ if (textureBufferHelper?.handler?.looper?.thread == Thread.currentThread()) {
+ run.invoke()
+ } else if (textureBufferHelper != null) {
+ textureBufferHelper?.handler?.post(run)
+ } else {
+ pendingProcessRunList.add(run)
+ }
+ }
+
override fun isFrontCamera() = isFrontCamera
- /**
- * Set parameters
- *
- * @param key
- * @param value
- */
override fun setParameters(key: String, value: String) {
when(key){
"beauty_mode" -> beautyMode = value.toInt()
+ "enableTextureAsync" -> enableTextureAsync = value.toBoolean()
}
}
- /**
- * Set beauty preset
- *
- * @param preset
- * @return
- */
override fun setBeautyPreset(preset: BeautyPreset): Int {
val conf = config
if(conf == null){
@@ -290,8 +239,7 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
LogUtils.i(TAG, "setBeautyPreset >> preset = $preset")
config?.rtcEngine?.sendCustomReportMessage(reportId, reportCategory, "enable", "preset=$preset", 0)
- val recommendFaceBeauty =
- FaceBeauty(FUBundleData("graphics" + File.separator + "face_beautification.bundle"))
+ val recommendFaceBeauty = FaceBeauty(FUBundleData("graphics" + File.separator + "face_beautification.bundle"))
if (preset == BeautyPreset.DEFAULT) {
recommendFaceBeauty.filterName = FaceBeautyFilterEnum.FENNEN_1
recommendFaceBeauty.filterIntensity = 0.7
@@ -341,13 +289,9 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
return ErrorCode.ERROR_OK.value
}
- /**
- * Release
- *
- * @return
- */
override fun release(): Int {
- val fuRenderer = config?.fuRenderKit
+ val conf = config
+ val fuRenderer = conf?.fuRenderKit
if(fuRenderer == null){
LogUtils.e(TAG, "release >> The beauty api has not been initialized!")
return ErrorCode.ERROR_HAS_NOT_INITIALIZED.value
@@ -357,15 +301,20 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
return ErrorCode.ERROR_HAS_RELEASED.value
}
LogUtils.i(TAG, "release")
- config?.rtcEngine?.sendCustomReportMessage(reportId, reportCategory, "release", "", 0)
+ if (conf.captureMode == CaptureMode.Agora) {
+ conf.rtcEngine.registerVideoFrameObserver(null)
+ }
+ conf.rtcEngine.sendCustomReportMessage(reportId, reportCategory, "release", "", 0)
isReleased = true
textureBufferHelper?.let {
textureBufferHelper = null
+ it.handler.removeCallbacksAndMessages(null)
it.invoke {
fuRenderer.release()
mTextureProcessHelper?.release()
mTextureProcessHelper = null
+ transformGLFrameBuffer.release()
null
}
// it.handler.looper.quit()
@@ -377,6 +326,7 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
}
statsHelper?.reset()
statsHelper = null
+ pendingProcessRunList.clear()
return ErrorCode.ERROR_OK.value
}
@@ -459,6 +409,15 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
"FURender",
EglBaseProvider.instance().rootEglBase.eglBaseContext
)
+ textureBufferHelper?.invoke {
+ synchronized(pendingProcessRunList){
+ val iterator = pendingProcessRunList.iterator()
+ while (iterator.hasNext()){
+ iterator.next().invoke()
+ iterator.remove()
+ }
+ }
+ }
LogUtils.i(TAG, "processBeauty >> create texture buffer, beautyMode=$beautyMode")
}
if (wrapTextureBufferHelper == null) {
@@ -471,7 +430,13 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
val startTime = System.currentTimeMillis()
val processTexId = when (beautyMode) {
2 -> processBeautySingleBuffer(videoFrame)
- 3 -> processBeautySingleTextureAsync(videoFrame)
+ 3 -> {
+ if (enableTextureAsync) {
+ processBeautySingleTextureAsync(videoFrame)
+ } else {
+ processBeautySingleTexture(videoFrame)
+ }
+ }
else -> processBeautyAuto(videoFrame)
}
@@ -505,7 +470,11 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
private fun processBeautyAuto(videoFrame: VideoFrame): Int {
val buffer = videoFrame.buffer
return if (buffer is TextureBuffer) {
- processBeautySingleTextureAsync(videoFrame)
+ if (enableTextureAsync) {
+ processBeautySingleTextureAsync(videoFrame)
+ } else {
+ processBeautySingleTexture(videoFrame)
+ }
} else {
processBeautySingleBuffer(videoFrame)
}
@@ -555,22 +524,25 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
it.cameraFacing = CameraFacingEnum.CAMERA_FRONT
it.inputBufferMatrix = FUTransformMatrixEnum.CCROT0
it.inputTextureMatrix = FUTransformMatrixEnum.CCROT0
- it.outputMatrix = FUTransformMatrixEnum.CCROT0
+ it.outputMatrix = FUTransformMatrixEnum.CCROT0_FLIPVERTICAL
it.deviceOrientation = 270
} else {
it.cameraFacing = CameraFacingEnum.CAMERA_BACK
it.inputBufferMatrix = FUTransformMatrixEnum.CCROT0
it.inputTextureMatrix = FUTransformMatrixEnum.CCROT0
- it.outputMatrix = FUTransformMatrixEnum.CCROT0
+ it.outputMatrix = FUTransformMatrixEnum.CCROT0_FLIPVERTICAL
it.deviceOrientation = 270
}
}
if (isReleased) {
return@setFilter -1
}
- return@setFilter textureBufferHelper?.invoke {
- return@invoke fuRenderKit.renderWithInput(input).texture?.texId ?: -1
- } ?: -1
+ val ret = textureBufferHelper?.invoke {
+ synchronized(EglBase.lock){
+ return@invoke fuRenderKit.renderWithInput(input).texture?.texId ?: -1
+ }
+ }
+ return@setFilter ret ?: -1
}
}
@@ -595,6 +567,87 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
}
}
+ private fun processBeautySingleTexture(videoFrame: VideoFrame): Int {
+ val texBufferHelper = textureBufferHelper ?: return -1
+ val textureBuffer = videoFrame.buffer as? TextureBuffer ?: return -1
+
+ when(textureBuffer.type){
+ TextureBuffer.Type.OES -> {
+ if(currProcessSourceType != ProcessSourceType.TEXTURE_OES){
+ LogUtils.i(TAG, "processBeauty >> process source type change old=$currProcessSourceType, new=${ProcessSourceType.TEXTURE_OES}")
+ if (currProcessSourceType != ProcessSourceType.UNKNOWN) {
+ skipFrame = 3
+ }
+ currProcessSourceType = ProcessSourceType.TEXTURE_OES
+ return -1
+ }
+ }
+ else -> {
+ if(currProcessSourceType != ProcessSourceType.TEXTURE_2D){
+ LogUtils.i(TAG, "processBeauty >> process source type change old=$currProcessSourceType, new=${ProcessSourceType.TEXTURE_2D}")
+ if (currProcessSourceType != ProcessSourceType.UNKNOWN) {
+ skipFrame = 3
+ }
+ currProcessSourceType = ProcessSourceType.TEXTURE_2D
+ skipFrame = 6
+ return -1
+ }
+ }
+ }
+
+ val width = videoFrame.rotatedWidth
+ val height = videoFrame.rotatedHeight
+ val isFront = videoFrame.sourceType == SourceType.kFrontCamera
+ val rotation = videoFrame.rotation
+
+ return texBufferHelper.invoke {
+ val fuRenderKit = config?.fuRenderKit ?: return@invoke -1
+
+ transformGLFrameBuffer.setSize(width, height)
+ transformGLFrameBuffer.resetTransform()
+ transformGLFrameBuffer.setTexMatrix(textureBuffer.transformMatrixArray)
+ transformGLFrameBuffer.setRotation(rotation)
+ var flipH = isFront
+ if((isFrontCamera && !captureMirror) || (!isFrontCamera && captureMirror)){
+ flipH = !flipH
+ }
+ transformGLFrameBuffer.setFlipH(flipH)
+ val transformTexId = transformGLFrameBuffer.process(
+ textureBuffer.textureId, when (textureBuffer.type) {
+ TextureBuffer.Type.OES -> GLES11Ext.GL_TEXTURE_EXTERNAL_OES
+ else -> GLES20.GL_TEXTURE_2D
+ }
+ )
+
+ val input = FURenderInputData(width, height)
+ input.texture = FURenderInputData.FUTexture(
+ FUInputTextureEnum.FU_ADM_FLAG_COMMON_TEXTURE,
+ transformTexId
+ )
+ input.renderConfig.let {
+ if (isFront) {
+ it.cameraFacing = CameraFacingEnum.CAMERA_FRONT
+ it.inputBufferMatrix = FUTransformMatrixEnum.CCROT0
+ it.inputTextureMatrix = FUTransformMatrixEnum.CCROT0
+ it.outputMatrix = FUTransformMatrixEnum.CCROT0_FLIPVERTICAL
+ it.deviceOrientation = 270
+ } else {
+ it.cameraFacing = CameraFacingEnum.CAMERA_BACK
+ it.inputBufferMatrix = FUTransformMatrixEnum.CCROT0
+ it.inputTextureMatrix = FUTransformMatrixEnum.CCROT0
+ it.outputMatrix = FUTransformMatrixEnum.CCROT0_FLIPVERTICAL
+ it.deviceOrientation = 270
+ }
+ }
+ if (isReleased) {
+ return@invoke -1
+ }
+ synchronized(EglBase.lock){
+ return@invoke fuRenderKit.renderWithInput(input).texture?.texId ?: -1
+ }
+ }
+ }
+
private fun processBeautySingleBuffer(videoFrame: VideoFrame): Int {
val texBufferHelper = textureBufferHelper ?: return -1
if(currProcessSourceType != ProcessSourceType.I420){
@@ -611,6 +664,7 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
val height = buffer.height
val isFront = videoFrame.sourceType == SourceType.kFrontCamera
val mirror = (isFrontCamera && !captureMirror) || (!isFrontCamera && captureMirror)
+ val rotation = videoFrame.rotation
return texBufferHelper.invoke(Callable {
if(isReleased){
@@ -625,13 +679,71 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
input.renderConfig.let {
if (isFront) {
it.cameraFacing = CameraFacingEnum.CAMERA_FRONT
- it.inputBufferMatrix = if(mirror) FUTransformMatrixEnum.CCROT90 else FUTransformMatrixEnum.CCROT90_FLIPHORIZONTAL
- it.inputTextureMatrix = if(mirror) FUTransformMatrixEnum.CCROT90 else FUTransformMatrixEnum.CCROT90_FLIPHORIZONTAL
+ it.inputBufferMatrix = if(mirror) {
+ when (rotation) {
+ 0 -> FUTransformMatrixEnum.CCROT0
+ 180 -> FUTransformMatrixEnum.CCROT180
+ else -> FUTransformMatrixEnum.CCROT90
+ }
+ } else {
+ when (rotation) {
+ 0 -> FUTransformMatrixEnum.CCROT0_FLIPHORIZONTAL
+ 180 -> FUTransformMatrixEnum.CCROT0_FLIPVERTICAL
+ else -> FUTransformMatrixEnum.CCROT90_FLIPHORIZONTAL
+ }
+ }
+ it.inputTextureMatrix = if(mirror) {
+ when (rotation) {
+ 0 -> FUTransformMatrixEnum.CCROT0
+ 180 -> FUTransformMatrixEnum.CCROT180
+ else -> FUTransformMatrixEnum.CCROT90
+ }
+ } else {
+ when (rotation) {
+ 0 -> FUTransformMatrixEnum.CCROT0_FLIPHORIZONTAL
+ 180 -> FUTransformMatrixEnum.CCROT0_FLIPVERTICAL
+ else -> FUTransformMatrixEnum.CCROT90_FLIPHORIZONTAL
+ }
+ }
+ it.deviceOrientation = when(rotation){
+ 0 -> 270
+ 180 -> 90
+ else -> 0
+ }
it.outputMatrix = FUTransformMatrixEnum.CCROT0
} else {
it.cameraFacing = CameraFacingEnum.CAMERA_BACK
- it.inputBufferMatrix = if(mirror) FUTransformMatrixEnum.CCROT90_FLIPVERTICAL else FUTransformMatrixEnum.CCROT270
- it.inputTextureMatrix = if(mirror) FUTransformMatrixEnum.CCROT90_FLIPVERTICAL else FUTransformMatrixEnum.CCROT270
+ it.inputBufferMatrix = if(mirror) {
+ when (rotation) {
+ 0 -> FUTransformMatrixEnum.CCROT0_FLIPHORIZONTAL
+ 180 -> FUTransformMatrixEnum.CCROT0_FLIPVERTICAL
+ else -> FUTransformMatrixEnum.CCROT90_FLIPVERTICAL
+ }
+ } else {
+ when (rotation) {
+ 0 -> FUTransformMatrixEnum.CCROT0
+ 180 -> FUTransformMatrixEnum.CCROT180
+ else -> FUTransformMatrixEnum.CCROT270
+ }
+ }
+ it.inputTextureMatrix = if(mirror) {
+ when (rotation) {
+ 0 -> FUTransformMatrixEnum.CCROT0_FLIPHORIZONTAL
+ 180 -> FUTransformMatrixEnum.CCROT0_FLIPVERTICAL
+ else -> FUTransformMatrixEnum.CCROT90_FLIPVERTICAL
+ }
+ } else {
+ when (rotation) {
+ 0 -> FUTransformMatrixEnum.CCROT0
+ 180 -> FUTransformMatrixEnum.CCROT180
+ else -> FUTransformMatrixEnum.CCROT270
+ }
+ }
+ it.deviceOrientation = when(rotation){
+ 0 -> 270
+ 180 -> 90
+ else -> 0
+ }
it.outputMatrix = FUTransformMatrixEnum.CCROT0
}
}
@@ -642,7 +754,9 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
return@Callable -1
}
}
- return@Callable fuRenderKit.renderWithInput(input).texture?.texId ?: -1
+ synchronized(EglBase.lock){
+ return@Callable fuRenderKit.renderWithInput(input).texture?.texId ?: -1
+ }
})
}
@@ -676,75 +790,29 @@ class FaceUnityBeautyAPIImpl : FaceUnityBeautyAPI, IVideoFrameObserver {
// IVideoFrameObserver implements
- /**
- * On capture video frame
- *
- * @param sourceType
- * @param videoFrame
- * @return
- */
override fun onCaptureVideoFrame(sourceType: Int, videoFrame: VideoFrame?): Boolean {
videoFrame ?: return false
return processBeauty(videoFrame)
}
- /**
- * On pre encode video frame
- *
- * @param sourceType
- * @param videoFrame
- */
override fun onPreEncodeVideoFrame(sourceType: Int, videoFrame: VideoFrame?) = false
- /**
- * On media player video frame
- *
- * @param videoFrame
- * @param mediaPlayerId
- */
override fun onMediaPlayerVideoFrame(videoFrame: VideoFrame?, mediaPlayerId: Int) = false
- /**
- * On render video frame
- *
- * @param channelId
- * @param uid
- * @param videoFrame
- */
override fun onRenderVideoFrame(
channelId: String?,
uid: Int,
videoFrame: VideoFrame?
) = false
- /**
- * Get video frame process mode
- *
- */
override fun getVideoFrameProcessMode() = IVideoFrameObserver.PROCESS_MODE_READ_WRITE
- /**
- * Get video format preference
- *
- */
override fun getVideoFormatPreference() = IVideoFrameObserver.VIDEO_PIXEL_DEFAULT
- /**
- * Get rotation applied
- *
- */
override fun getRotationApplied() = false
- /**
- * Get mirror applied
- *
- */
override fun getMirrorApplied() = captureMirror && !enable
- /**
- * Get observed frame position
- *
- */
override fun getObservedFramePosition() = IVideoFrameObserver.POSITION_POST_CAPTURER
}
\ No newline at end of file
diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/FuDeviceUtils.java b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/FuDeviceUtils.java
index 8e7397963..5e03a313c 100644
--- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/FuDeviceUtils.java
+++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/FuDeviceUtils.java
@@ -40,31 +40,12 @@
import java.io.InputStream;
import java.io.InputStreamReader;
-/**
- * The type Fu device utils.
- */
-public final class FuDeviceUtils {
-
- private FuDeviceUtils() {
-
- }
+public class FuDeviceUtils {
- /**
- * The constant TAG.
- */
public static final String TAG = "FuDeviceUtils";
- /**
- * The constant DEVICE_LEVEL_HIGH.
- */
public static final int DEVICE_LEVEL_HIGH = 2;
- /**
- * The constant DEVICE_LEVEL_MID.
- */
public static final int DEVICE_LEVEL_MID = 1;
- /**
- * The constant DEVICE_LEVEL_LOW.
- */
public static final int DEVICE_LEVEL_LOW = 0;
/**
@@ -167,9 +148,7 @@ public static int getCPUMaxFreqKHz() {
try {
int freqBound = parseFileForValue("cpu MHz", stream);
freqBound *= 1024; //MHz -> kHz
- if (freqBound > maxFreq) {
- maxFreq = freqBound;
- }
+ if (freqBound > maxFreq) maxFreq = freqBound;
} finally {
stream.close();
}
@@ -266,9 +245,7 @@ private static int parseFileForValue(String textToMatch, FileInputStream stream)
int length = stream.read(buffer);
for (int i = 0; i < length; i++) {
if (buffer[i] == '\n' || i == 0) {
- if (buffer[i] == '\n') {
- i++;
- }
+ if (buffer[i] == '\n') i++;
for (int j = i; j < length; j++) {
int textIndex = j - i;
//Text doesn't match query at some point.
@@ -293,7 +270,6 @@ private static int parseFileForValue(String textToMatch, FileInputStream stream)
* Helper method used by {@link #parseFileForValue(String, FileInputStream) parseFileForValue}. Parses
* the next available number after the match in the file being read and returns it as an integer.
*
- * @param buffer Buffer.
* @param index - The index in the buffer array to begin looking.
* @return The next number on that line in the buffer, returned as an int. Returns
* DEVICEINFO_UNKNOWN = -1 in the event that no more numbers exist on the same line.
@@ -317,8 +293,8 @@ private static int extractValue(byte[] buffer, int index) {
/**
* 获取当前剩余内存(ram)
*
- * @param context the context
- * @return avail memory
+ * @param context
+ * @return
*/
public static long getAvailMemory(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
@@ -330,7 +306,7 @@ public static long getAvailMemory(Context context) {
/**
* 获取厂商信息
*
- * @return brand
+ * @return
*/
public static String getBrand() {
return Build.BRAND;
@@ -339,7 +315,7 @@ public static String getBrand() {
/**
* 获取手机机型
*
- * @return model
+ * @return
*/
public static String getModel() {
return Build.MODEL;
@@ -348,7 +324,7 @@ public static String getModel() {
/**
* 获取硬件信息(cpu型号)
*
- * @return hard ware
+ * @return
*/
public static String getHardWare() {
try {
@@ -377,15 +353,13 @@ public static String getHardWare() {
* Level judgement based on current memory and CPU.
*
* @param context - Context object.
- * @return int
+ * @return
*/
public static int judgeDeviceLevel(Context context) {
int level;
//有一些设备不符合下述的判断规则,则走一个机型判断模式
int specialDevice = judgeDeviceLevelInDeviceName();
- if (specialDevice >= 0) {
- return specialDevice;
- }
+ if (specialDevice >= 0) return specialDevice;
int ramLevel = judgeMemory(context);
int cpuLevel = judgeCPU();
@@ -398,30 +372,29 @@ public static int judgeDeviceLevel(Context context) {
level = DEVICE_LEVEL_MID;
}
}
- LogUtils.d(TAG, "DeviceLevel: " + level);
+ LogUtils.d(TAG,"DeviceLevel: " + level);
return level;
}
/**
* -1 不是特定的高低端机型
- *
- * @return level.
+ * @return
*/
private static int judgeDeviceLevelInDeviceName() {
String currentDeviceName = getDeviceName();
- for (String deviceName : UPSCALE_DEVICE) {
+ for (String deviceName:upscaleDevice) {
if (deviceName.equals(currentDeviceName)) {
return DEVICE_LEVEL_HIGH;
}
}
- for (String deviceName : MIDDLE_DEVICES) {
+ for (String deviceName:middleDevice) {
if (deviceName.equals(currentDeviceName)) {
return DEVICE_LEVEL_MID;
}
}
- for (String deviceName : LOW_DEVICES) {
+ for (String deviceName:lowDevice) {
if (deviceName.equals(currentDeviceName)) {
return DEVICE_LEVEL_LOW;
}
@@ -429,24 +402,14 @@ private static int judgeDeviceLevelInDeviceName() {
return -1;
}
- /**
- * The constant upscaleDevice.
- */
- public static final String[] UPSCALE_DEVICE = {"vivo X6S A", "MHA-AL00", "VKY-AL00", "V1838A"};
- /**
- * The constant lowDevice.
- */
- public static final String[] LOW_DEVICES = {};
- /**
- * The constant middleDevice.
- */
- public static final String[] MIDDLE_DEVICES = {"OPPO R11s", "PAR-AL00", "MI 8 Lite", "ONEPLUS A6000", "PRO 6", "PRO 7 Plus"};
+ public static final String[] upscaleDevice = {"vivo X6S A","MHA-AL00","VKY-AL00","V1838A"};
+ public static final String[] lowDevice = {};
+ public static final String[] middleDevice = {"OPPO R11s","PAR-AL00","MI 8 Lite","ONEPLUS A6000","PRO 6","PRO 7 Plus"};
/**
* 评定内存的等级.
*
- * @param context Context.
- * @return level.
+ * @return
*/
private static int judgeMemory(Context context) {
long ramMB = getTotalMemory(context) / (1024 * 1024);
@@ -468,7 +431,7 @@ private static int judgeMemory(Context context) {
/**
* 评定CPU等级.(按频率和厂商型号综合判断)
*
- * @return level.
+ * @return
*/
private static int judgeCPU() {
int level = 0;
@@ -482,8 +445,7 @@ private static int judgeCPU() {
return judgeQualcommCPU(cpuName, freqMHz);
} else if (cpuName.contains("hi") || cpuName.contains("kirin")) { //海思麒麟
return judgeSkinCPU(cpuName, freqMHz);
- } else if (cpuName.contains("MT")) {
- //联发科
+ } else if (cpuName.contains("MT")) {//联发科
return judgeMTCPU(cpuName, freqMHz);
}
}
@@ -504,9 +466,7 @@ private static int judgeCPU() {
/**
* 联发科芯片等级判定
*
- * @param cpuName CPU Name.
- * @param freqMHz CPU Freq MHz.
- * @return level
+ * @return
*/
private static int judgeMTCPU(String cpuName, int freqMHz) {
//P60之前的全是低端机 MT6771V/C
@@ -548,8 +508,8 @@ private static int judgeMTCPU(String cpuName, int freqMHz) {
/**
* 通过联发科CPU型号定义 -> 获取cpu version
*
- * @param cpuName CPU Name.
- * @return CPU Version.
+ * @param cpuName
+ * @return
*/
private static int getMTCPUVersion(String cpuName) {
//截取MT后面的四位数字
@@ -569,9 +529,7 @@ private static int getMTCPUVersion(String cpuName) {
/**
* 高通骁龙芯片等级判定
*
- * @param cpuName CPU Name.
- * @param freqMHz CPU Freq MHz.
- * @return level
+ * @return
*/
private static int judgeQualcommCPU(String cpuName, int freqMHz) {
int level = 0;
@@ -603,9 +561,8 @@ private static int judgeQualcommCPU(String cpuName, int freqMHz) {
/**
* 麒麟芯片等级判定
*
- * @param cpuName CPU Name.
- * @param freqMHz CPU Freq MHz.
- * @return level
+ * @param freqMHz
+ * @return
*/
private static int judgeSkinCPU(String cpuName, int freqMHz) {
//型号 -> kirin710之后 & 最高核心频率
@@ -633,22 +590,17 @@ private static int judgeSkinCPU(String cpuName, int freqMHz) {
return level;
}
- /**
- * The constant NEXUS_6P.
- */
- public static final String NEXUS_6P = "Nexus 6P";
+ public static final String Nexus_6P = "Nexus 6P";
/**
- * 获取设备名。
+ * 获取设备名
*
- * @return the device name
+ * @return
*/
public static String getDeviceName() {
String deviceName = "";
- if (Build.MODEL != null) {
- deviceName = Build.MODEL;
- }
- LogUtils.e(TAG, "deviceName: " + deviceName);
+ if (Build.MODEL != null) deviceName = Build.MODEL;
+ LogUtils.e(TAG,"deviceName: " + deviceName);
return deviceName;
}
}
diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/LogUtils.kt b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/LogUtils.kt
index 4722d73a7..4c1a5252d 100644
--- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/LogUtils.kt
+++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/LogUtils.kt
@@ -24,118 +24,34 @@
package io.agora.beautyapi.faceunity.utils
-import android.util.Log
-import java.io.File
-import java.io.FileOutputStream
-import java.text.SimpleDateFormat
-import java.util.Date
-import java.util.Locale
-import java.util.concurrent.Executors
+import io.agora.base.internal.Logging
-/**
- * Log utils
- *
- * @constructor Create empty Log utils
- */
object LogUtils {
private const val beautyType = "FaceUnity"
- private val timeFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.ROOT)
- private val logFileName = "agora_beautyapi_${beautyType.toLowerCase(Locale.US)}_android.log"
- private val workerThread = Executors.newSingleThreadExecutor()
- private var logOutputStream: FileOutputStream? = null
- /**
- * Set log file path
- *
- * @param path
- */
- @JvmStatic
- fun setLogFilePath(path: String){
- if(path.isEmpty()){
- e("LogUtils", "setLogFilePath >> path is empty!")
- return
- }
- val direction = File(path)
- if(!direction.exists()){
- direction.mkdirs()
- }
- val file = File(direction, logFileName)
- if(!file.exists()){
- file.createNewFile()
- }
- val append = file.length() < 2 * 1024 * 1024
- logOutputStream = FileOutputStream(file, append)
- }
-
- /**
- * I
- *
- * @param tag
- * @param content
- * @param args
- */
@JvmStatic
fun i(tag: String, content: String, vararg args: Any) {
val consoleMessage = "[BeautyAPI][$beautyType] : ${String.format(content, args)}"
- val fileMessage = "${timeFormat.format(Date())} : [BeautyAPI][$beautyType][$tag][INFO] : ${String.format(content, args)}"
- Log.v(tag, consoleMessage)
- saveToFile(fileMessage)
+ Logging.log(Logging.Severity.LS_INFO, tag, consoleMessage)
}
- /**
- * D
- *
- * @param tag
- * @param content
- * @param args
- */
@JvmStatic
fun d(tag: String, content: String, vararg args: Any) {
val consoleMessage = "[BeautyAPI][$beautyType] : ${String.format(content, args)}"
- val fileMessage = "${timeFormat.format(Date())} : [BeautyAPI][$beautyType][$tag][DEBUG] : ${String.format(content, args)}"
- Log.d(tag, consoleMessage)
- saveToFile(fileMessage)
+ Logging.d(tag, consoleMessage)
}
- /**
- * W
- *
- * @param tag
- * @param content
- * @param args
- */
@JvmStatic
fun w(tag: String, content: String, vararg args: Any){
val consoleMessage = "[BeautyAPI][$beautyType] : ${String.format(content, args)}"
- val fileMessage = "${timeFormat.format(Date())} : [BeautyAPI][$beautyType][$tag][WARN] : ${String.format(content, args)}"
- Log.w(tag, consoleMessage)
- saveToFile(fileMessage)
+ Logging.w(tag, consoleMessage)
}
- /**
- * E
- *
- * @param tag
- * @param content
- * @param args
- */
@JvmStatic
fun e(tag: String, content: String, vararg args: Any){
val consoleMessage = "[BeautyAPI][$beautyType] : ${String.format(content, args)}"
- val fileMessage = "${timeFormat.format(Date())} : [BeautyAPI][$beautyType][$tag][ERROR] : ${String.format(content, args)}"
- Log.e(tag, consoleMessage)
- saveToFile(fileMessage)
+ Logging.e(tag, consoleMessage)
}
-
- private fun saveToFile(message: String){
- val outputStream = logOutputStream ?: return
- workerThread.execute {
- outputStream.write(message.toByteArray())
- if(!message.endsWith("\n")){
- outputStream.write("\n".toByteArray())
- }
- }
- }
}
\ No newline at end of file
diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/StatsHelper.kt b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/StatsHelper.kt
index 6f2dacf46..cb4cf1292 100644
--- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/StatsHelper.kt
+++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/StatsHelper.kt
@@ -30,13 +30,6 @@ import io.agora.beautyapi.faceunity.BeautyStats
import kotlin.math.max
import kotlin.math.min
-/**
- * Stats helper
- *
- * @property statsDuration
- * @property onStatsChanged
- * @constructor Create empty Stats helper
- */
class StatsHelper(
private val statsDuration: Long,
private val onStatsChanged: (BeautyStats) -> Unit
@@ -48,11 +41,6 @@ class StatsHelper(
private var mCostMax = 0L
private var mCostMin = Long.MAX_VALUE
- /**
- * Once
- *
- * @param cost
- */
fun once(cost: Long) {
val curr = System.currentTimeMillis()
if (mStartTime == 0L) {
@@ -80,10 +68,6 @@ class StatsHelper(
mCostMin = min(mCostMin, cost)
}
- /**
- * Reset
- *
- */
fun reset() {
mMainHandler.removeCallbacksAndMessages(null)
mStartTime = 0
diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/EGLContextHelper.java b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/EGLContextHelper.java
index b3717d609..97b3c7a53 100644
--- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/EGLContextHelper.java
+++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/EGLContextHelper.java
@@ -36,9 +36,6 @@
import io.agora.beautyapi.faceunity.utils.LogUtils;
-/**
- * The type Egl context helper.
- */
public class EGLContextHelper {
private static final String DEBUG_TAG = "EGLContextManager";
private final int mRedSize = 8;
@@ -48,23 +45,12 @@ public class EGLContextHelper {
private final int mDepthSize = 16;
private final int mStencilSize = 0;
private final int mRenderType = 4;
+ public EGLContextHelper(){}
- /**
- * Instantiates a new Egl context helper.
- */
- public EGLContextHelper() {
- }
-
- /**
- * Init egl.
- *
- * @param shareContext the share context
- * @throws Exception the exception
- */
public void initEGL(EGLContext shareContext) throws Exception {
mEGL = (EGL10) GLDebugHelper.wrap(EGLContext.getEGL(),
GLDebugHelper.CONFIG_CHECK_GL_ERROR
- | GLDebugHelper.CONFIG_CHECK_THREAD, null);
+ | GLDebugHelper.CONFIG_CHECK_THREAD, null);
if (mEGL == null) {
throw new Exception("Couldn't get EGL");
@@ -83,8 +69,8 @@ public void initEGL(EGLContext shareContext) throws Exception {
+ curGLVersion[1]);
int[] num_config = new int[1];
- if (!mEGL.eglChooseConfig(mGLDisplay, mConfigSpec, null, 1,
- num_config)) {
+ if(!mEGL.eglChooseConfig(mGLDisplay, mConfigSpec, null, 1,
+ num_config)){
throw new IllegalArgumentException("eglChooseConfig failed");
}
int numConfigs = num_config[0];
@@ -129,75 +115,32 @@ public void initEGL(EGLContext shareContext) throws Exception {
}
- /**
- * Gets egl context.
- *
- * @return the egl context
- */
public EGLContext getEGLContext() {
return mGLContext;
}
- /**
- * Gets gl display.
- *
- * @return the gl display
- */
public EGLDisplay getGLDisplay() {
return mGLDisplay;
}
- /**
- * Gets gl config.
- *
- * @return the gl config
- */
public EGLConfig getGLConfig() {
return mGLConfig;
}
- /**
- * Gets gl surface.
- *
- * @return the gl surface
- */
public EGLSurface getGLSurface() {
return mGLSurface;
}
- /**
- * Gets egl.
- *
- * @return the egl
- */
public EGL10 getEGL() {
return mEGL;
}
- /**
- * The M egl.
- */
EGL10 mEGL;
- /**
- * The M gl display.
- */
EGLDisplay mGLDisplay;
- /**
- * The M gl config.
- */
EGLConfig mGLConfig;
- /**
- * The M gl surface.
- */
EGLSurface mGLSurface;
- /**
- * The M gl context.
- */
EGLContext mGLContext;
- /**
- * The M config spec.
- */
int[] mConfigSpec = new int[]{
EGL10.EGL_RED_SIZE, mRedSize,
EGL10.EGL_GREEN_SIZE, mGreenSize,
@@ -205,12 +148,9 @@ public EGL10 getEGL() {
EGL10.EGL_ALPHA_SIZE, mAlphaSize,
EGL10.EGL_DEPTH_SIZE, mDepthSize,
EGL10.EGL_STENCIL_SIZE, mStencilSize,
- EGL10.EGL_RENDERABLE_TYPE, mRenderType, //egl版本 2.0
+ EGL10.EGL_RENDERABLE_TYPE, mRenderType,//egl版本 2.0
EGL10.EGL_NONE};
- /**
- * Release.
- */
public void release() {
mEGL.eglMakeCurrent(mGLDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
@@ -221,25 +161,15 @@ public void release() {
LogUtils.i(DEBUG_TAG, "GL Cleaned up");
}
- /**
- * Egl make current boolean.
- *
- * @return the boolean
- */
- public boolean eglMakeCurrent() {
- if (mGLContext == EGL10.EGL_NO_CONTEXT) {
+ public boolean eglMakeCurrent(){
+ if(mGLContext == EGL10.EGL_NO_CONTEXT){
return false;
- } else {
+ }else{
return mEGL.eglMakeCurrent(mGLDisplay, mGLSurface, mGLSurface, mGLContext);
}
}
- /**
- * Egl make no current boolean.
- *
- * @return the boolean
- */
- public boolean eglMakeNoCurrent() {
+ public boolean eglMakeNoCurrent(){
return mEGL.eglMakeCurrent(mGLDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
}
@@ -251,7 +181,7 @@ private EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
EGL10.EGL_DEPTH_SIZE, 0);
int s = findConfigAttrib(egl, display, config,
EGL10.EGL_STENCIL_SIZE, 0);
- if (d >= mDepthSize && s >= mStencilSize) {
+ if ((d >= mDepthSize) && (s >= mStencilSize)) {
int r = findConfigAttrib(egl, display, config,
EGL10.EGL_RED_SIZE, 0);
int g = findConfigAttrib(egl, display, config,
@@ -260,8 +190,8 @@ private EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
EGL10.EGL_BLUE_SIZE, 0);
int a = findConfigAttrib(egl, display, config,
EGL10.EGL_ALPHA_SIZE, 0);
- if (r == mRedSize && g == mGreenSize
- && b == mBlueSize && a == mAlphaSize) {
+ if ((r == mRedSize) && (g == mGreenSize)
+ && (b == mBlueSize) && (a == mAlphaSize)) {
return config;
}
}
diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/GLCopyHelper.java b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/GLCopyHelper.java
index 6f92d1474..b475f39d9 100644
--- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/GLCopyHelper.java
+++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/GLCopyHelper.java
@@ -28,51 +28,31 @@
import android.opengl.GLES20;
import android.opengl.GLES30;
-/**
- * The type Gl copy helper.
- */
public class GLCopyHelper {
private final int bufferCount;
- /**
- * Instantiates a new Gl copy helper.
- */
- public GLCopyHelper() {
+ public GLCopyHelper(){
this(1);
}
- /**
- * Instantiates a new Gl copy helper.
- *
- * @param bufferCount the buffer count
- */
- public GLCopyHelper(int bufferCount) {
+ public GLCopyHelper(int bufferCount){
this.bufferCount = bufferCount;
}
private int[] mDstFrameBuffer;
private int[] mSrcFrameBuffer;
- /**
- * Copy 2 d texture to oes texture.
- *
- * @param srcTexture the src texture
- * @param dstTexture the dst texture
- * @param width the width
- * @param height the height
- * @param index the index
- */
public void copy2DTextureToOesTexture(
int srcTexture,
int dstTexture,
int width, int height,
- int index) {
- if (mDstFrameBuffer == null) {
+ int index){
+ if(mDstFrameBuffer == null){
mDstFrameBuffer = new int[bufferCount];
GLES20.glGenFramebuffers(bufferCount, mDstFrameBuffer, 0);
}
- if (mSrcFrameBuffer == null) {
+ if(mSrcFrameBuffer == null){
mSrcFrameBuffer = new int[bufferCount];
GLES20.glGenFramebuffers(bufferCount, mSrcFrameBuffer, 0);
}
@@ -90,16 +70,13 @@ public void copy2DTextureToOesTexture(
GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
}
- /**
- * Release.
- */
- public void release() {
- if (mDstFrameBuffer != null) {
+ public void release(){
+ if(mDstFrameBuffer != null){
GLES20.glDeleteFramebuffers(mDstFrameBuffer.length, mDstFrameBuffer, 0);
mDstFrameBuffer = null;
}
- if (mSrcFrameBuffer != null) {
+ if(mSrcFrameBuffer != null){
GLES20.glDeleteFramebuffers(mSrcFrameBuffer.length, mSrcFrameBuffer, 0);
mSrcFrameBuffer = null;
}
diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/GLFrameBuffer.java b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/GLFrameBuffer.java
index 4372c0700..e30f17ac3 100644
--- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/GLFrameBuffer.java
+++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/GLFrameBuffer.java
@@ -4,12 +4,10 @@
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
+import io.agora.base.internal.video.EglBase;
import io.agora.base.internal.video.GlRectDrawer;
import io.agora.base.internal.video.RendererCommon;
-/**
- * The type Gl frame buffer.
- */
public class GLFrameBuffer {
private int mFramebufferId = -1;
@@ -21,20 +19,10 @@ public class GLFrameBuffer {
private float[] mTexMatrix = GLUtils.IDENTITY_MATRIX;
- /**
- * Instantiates a new Gl frame buffer.
- */
public GLFrameBuffer() {
}
- /**
- * Sets size.
- *
- * @param width the width
- * @param height the height
- * @return the size
- */
public boolean setSize(int width, int height) {
if (mWidth != width || mHeight != height) {
mWidth = width;
@@ -45,66 +33,36 @@ public boolean setSize(int width, int height) {
return false;
}
- /**
- * Sets rotation.
- *
- * @param rotation the rotation
- */
public void setRotation(int rotation) {
if (mRotation != rotation) {
mRotation = rotation;
}
}
- /**
- * Sets flip v.
- *
- * @param flipV the flip v
- */
public void setFlipV(boolean flipV) {
if (isFlipV != flipV) {
isFlipV = flipV;
}
}
- /**
- * Sets flip h.
- *
- * @param flipH the flip h
- */
public void setFlipH(boolean flipH) {
if (isFlipH != flipH) {
isFlipH = flipH;
}
}
- /**
- * Sets texture id.
- *
- * @param textureId the texture id
- */
- public void setTextureId(int textureId) {
- if (mTextureId != textureId) {
+ public void setTextureId(int textureId){
+ if(mTextureId != textureId){
deleteTexture();
mTextureId = textureId;
isTextureChanged = true;
}
}
- /**
- * Gets texture id.
- *
- * @return the texture id
- */
- public int getTextureId() {
+ public int getTextureId(){
return mTextureId;
}
- /**
- * Sets tex matrix.
- *
- * @param matrix the matrix
- */
public void setTexMatrix(float[] matrix) {
if (matrix != null) {
mTexMatrix = matrix;
@@ -113,43 +71,32 @@ public void setTexMatrix(float[] matrix) {
}
}
- /**
- * Reset transform.
- */
- public void resetTransform() {
+ public void resetTransform(){
mTexMatrix = GLUtils.IDENTITY_MATRIX;
- isFlipH = false;
- isFlipV = false;
+ isFlipH = isFlipV = false;
mRotation = 0;
}
- /**
- * Process int.
- *
- * @param textureId the texture id
- * @param textureType the texture type
- * @return the int
- */
public int process(int textureId, int textureType) {
if (mWidth <= 0 && mHeight <= 0) {
throw new RuntimeException("setSize firstly!");
}
- if (mTextureId == -1) {
+ if(mTextureId == -1){
mTextureId = createTexture(mWidth, mHeight);
bindFramebuffer(mTextureId);
isTextureInner = true;
- } else if (isTextureInner && isSizeChanged) {
+ }else if(isTextureInner && isSizeChanged){
GLES20.glDeleteTextures(1, new int[]{mTextureId}, 0);
mTextureId = createTexture(mWidth, mHeight);
bindFramebuffer(mTextureId);
- } else if (isTextureChanged) {
+ }else if(isTextureChanged){
bindFramebuffer(mTextureId);
}
isTextureChanged = false;
isSizeChanged = false;
- if (drawer == null) {
+ if(drawer == null){
drawer = new GlRectDrawer();
}
@@ -160,31 +107,31 @@ public int process(int textureId, int textureType) {
transform.preTranslate(0.5f, 0.5f);
transform.preRotate(mRotation, 0.f, 0.f);
transform.preScale(
- isFlipH ? -1.f : 1.f,
- isFlipV ? -1.f : 1.f
+ isFlipH ? -1.f: 1.f,
+ isFlipV ? -1.f: 1.f
);
transform.preTranslate(-0.5f, -0.5f);
float[] matrix = RendererCommon.convertMatrixFromAndroidGraphicsMatrix(transform);
- if (textureType == GLES11Ext.GL_TEXTURE_EXTERNAL_OES) {
- drawer.drawOes(textureId, matrix, mWidth, mHeight, 0, 0, mWidth, mHeight);
- } else {
- drawer.drawRgb(textureId, matrix, mWidth, mHeight, 0, 0, mWidth, mHeight);
+ synchronized (EglBase.lock){
+ if(textureType == GLES11Ext.GL_TEXTURE_EXTERNAL_OES){
+ drawer.drawOes(textureId, 0, matrix, mWidth, mHeight, 0, 0, mWidth, mHeight);
+ }else{
+ drawer.drawRgb(textureId, 0, matrix, mWidth, mHeight, 0, 0, mWidth, mHeight);
+ }
}
- GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
+
+ GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_NONE);
GLES20.glFinish();
return mTextureId;
}
- /**
- * Release.
- */
- public void release() {
+ public void release(){
deleteTexture();
deleteFramebuffer();
- if (drawer != null) {
+ if(drawer != null){
drawer.release();
drawer = null;
}
@@ -198,14 +145,7 @@ private void deleteFramebuffer() {
}
}
- /**
- * Create texture int.
- *
- * @param width the width
- * @param height the height
- * @return the int
- */
- public int createTexture(int width, int height) {
+ public int createTexture(int width, int height){
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
GLUtils.checkGlError("glGenTextures");
@@ -229,13 +169,6 @@ public int createTexture(int width, int height) {
return textureId;
}
- /**
- * Resize texture.
- *
- * @param textureId the texture id
- * @param width the width
- * @param height the height
- */
public void resizeTexture(int textureId, int width, int height) {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0,
@@ -252,7 +185,7 @@ private void deleteTexture() {
}
private void bindFramebuffer(int textureId) {
- if (mFramebufferId == -1) {
+ if(mFramebufferId == -1){
int[] framebuffers = new int[1];
GLES20.glGenFramebuffers(1, framebuffers, 0);
GLUtils.checkGlError("glGenFramebuffers");
diff --git a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/GLTextureBufferQueue.kt b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/GLTextureBufferQueue.kt
index 2b9ca20b1..c8d193f8f 100644
--- a/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/GLTextureBufferQueue.kt
+++ b/Android/APIExample/app/src/main/java/io/agora/beautyapi/faceunity/utils/egl/GLTextureBufferQueue.kt
@@ -29,14 +29,6 @@ import android.util.Log
import android.util.Size
import java.util.concurrent.ConcurrentLinkedQueue
-/**
- * G l texture buffer queue
- *
- * @property glFrameBuffer
- * @property cacheCount
- * @property loggable
- * @constructor Create empty G l texture buffer queue
- */
class GLTextureBufferQueue(
private val glFrameBuffer: GLFrameBuffer = GLFrameBuffer(),
private val cacheCount: Int = 6,
@@ -49,12 +41,6 @@ class GLTextureBufferQueue(
private val textureIdQueue = ConcurrentLinkedQueue