Sample之MediaEffects
来源:互联网 发布:江苏悠迅网络是干嘛的 编辑:程序博客网 时间:2024/05/16 08:16
Sample源码阅读学习
Google地址:https://developer.android.com/samples/MediaEffects/project.html
我的注释代码:https://github.com/CL-window/Media-Effects-Framework.git
本项目是 展示OpenGL ES 2.0的纹理图像帧的各种滤镜效果,
主要是 Effect,GLSurfaceView,GLES20的使用,具体都在代码的注释里,贴上主要的代码
// https://code.tutsplus.com/tutorials/how-to-use-android-media-effects-with-opengl-es--cms-23650public class MediaEffectsFragment extends Fragment implements GLSurfaceView.Renderer { private static final String STATE_CURRENT_EFFECT = "current_effect"; private GLSurfaceView mEffectView; private int[] mTextures = new int[2]; // Media Effects Framework private EffectContext mEffectContext; // 用于 getFactory() EffectFactory private Effect mEffect; private TextureRenderer mTexRenderer = new TextureRenderer(); private int mImageWidth; private int mImageHeight; private boolean mInitialized = false; private int mCurrentEffect; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true);// 使用菜单 } @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_media_effects, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { mEffectView = (GLSurfaceView) view.findViewById(R.id.effectsview); mEffectView.setEGLContextClientVersion(2);// 用OpenGLES 2.0 mEffectView.setRenderer(this);// Renderer mEffectView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);// 只在绘制数据发生改变时才绘制view // 下面这段代码处理横竖屏时,会重新 onCreate,配合onSaveInstanceState if (null != savedInstanceState && savedInstanceState.containsKey(STATE_CURRENT_EFFECT)) { setCurrentEffect(savedInstanceState.getInt(STATE_CURRENT_EFFECT)); } else { setCurrentEffect(R.id.none); } } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.media_effects, menu);// 菜单view的初始化 } // 菜单的item点击事件 @Override public boolean onOptionsItemSelected(MenuItem item) { setCurrentEffect(item.getItemId()); mEffectView.requestRender();// 手动调用 onDrawFrame return true; } // fragment销毁前,保存需要保存的信息,当前选择的预览模式 @Override public void onSaveInstanceState(Bundle outState) { outState.putInt(STATE_CURRENT_EFFECT, mCurrentEffect); } // Renderer @Override public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) { // Nothing to do here 仅调用一次,用于设置view的OpenGLES环境 } // 如果view的几何形状发生变化了就调用,例如当竖屏变为横屏时 @Override public void onSurfaceChanged(GL10 gl, int width, int height) { if (mTexRenderer != null) { mTexRenderer.updateViewSize(width, height); } } // 每次View被重绘时被调用,重点 @Override public void onDrawFrame(GL10 gl) { if (!mInitialized) { //Only need to do this once 初始化 mEffectContext = EffectContext.createWithCurrentGlContext(); mTexRenderer.init(); loadTextures();// 加载图片文理 mInitialized = true; } if (mCurrentEffect != R.id.none) { //if an effect is chosen initialize it and apply it to the texture initEffect(); applyEffect(); } renderResult(); } private void setCurrentEffect(int effect) { mCurrentEffect = effect; } private void loadTextures() { // Generate textures GLES20.glGenTextures(2, mTextures, 0);// initialize the array // Load input bitmap Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.puppy); mImageWidth = bitmap.getWidth(); mImageHeight = bitmap.getHeight(); mTexRenderer.updateTextureSize(mImageWidth, mImageHeight); // Upload to texture GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]); // activate the texture at index 0 GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); // Set texture parameters GLToolbox.initTexParams(); } private void initEffect() { EffectFactory effectFactory = mEffectContext.getFactory(); if (mEffect != null) { mEffect.release(); } // Initialize the correct effect based on the selected menu/action item switch (mCurrentEffect) { case R.id.none: break; case R.id.autofix: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_AUTOFIX); mEffect.setParameter("scale", 0.5f); break; case R.id.bw: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_BLACKWHITE); mEffect.setParameter("black", .1f); mEffect.setParameter("white", .7f); break; case R.id.brightness: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_BRIGHTNESS); mEffect.setParameter("brightness", 2.0f); break; case R.id.contrast: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_CONTRAST); mEffect.setParameter("contrast", 1.4f); break; case R.id.crossprocess: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_CROSSPROCESS); break; case R.id.documentary: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_DOCUMENTARY); break; case R.id.duotone: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_DUOTONE); mEffect.setParameter("first_color", Color.YELLOW); mEffect.setParameter("second_color", Color.DKGRAY); break; case R.id.filllight: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_FILLLIGHT); mEffect.setParameter("strength", .8f); break; case R.id.fisheye: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_FISHEYE); mEffect.setParameter("scale", .5f); break; case R.id.flipvert: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_FLIP); mEffect.setParameter("vertical", true); break; case R.id.fliphor: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_FLIP); mEffect.setParameter("horizontal", true); break; case R.id.grain: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_GRAIN); mEffect.setParameter("strength", 1.0f); break; case R.id.grayscale: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_GRAYSCALE); break; case R.id.lomoish: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_LOMOISH); break; case R.id.negative: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_NEGATIVE); break; case R.id.posterize: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_POSTERIZE); break; case R.id.rotate: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_ROTATE); mEffect.setParameter("angle", 180); break; case R.id.saturate: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_SATURATE); mEffect.setParameter("scale", .5f); break; case R.id.sepia: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_SEPIA); break; case R.id.sharpen: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_SHARPEN); break; case R.id.temperature: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_TEMPERATURE); mEffect.setParameter("scale", .9f); break; case R.id.tint: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_TINT); mEffect.setParameter("tint", Color.MAGENTA); break; case R.id.vignette: mEffect = effectFactory.createEffect(EffectFactory.EFFECT_VIGNETTE); mEffect.setParameter("scale", .5f); break; default: break; } } private void applyEffect() { // apply(int inputTexId, int width, int height, int outputTexId) mEffect.apply(mTextures[0], mImageWidth, mImageHeight, mTextures[1]); } private void renderResult() { if (mCurrentEffect != R.id.none) { // if no effect is chosen, just render the original bitmap mTexRenderer.renderTexture(mTextures[1]); } else { // render the result of applyEffect() mTexRenderer.renderTexture(mTextures[0]); } }}
public class TextureRenderer { private int mProgram; private int mTexSamplerHandle; private int mTexCoordHandle; private int mPosCoordHandle; private FloatBuffer mTexVertices; private FloatBuffer mPosVertices; private int mViewWidth; private int mViewHeight; private int mTexWidth; private int mTexHeight; // The C code for the vertex shader private static final String VERTEX_SHADER = "attribute vec4 a_position;\n" + "attribute vec2 a_texcoord;\n" + "varying vec2 v_texcoord;\n" + "void main() {\n" + " gl_Position = a_position;\n" + " v_texcoord = a_texcoord;\n" + "}\n"; // C code for the fragment shader private static final String FRAGMENT_SHADER = "precision mediump float;\n" + "uniform sampler2D tex_sampler;\n" + "varying vec2 v_texcoord;\n" + "void main() {\n" + " gl_FragColor = texture2D(tex_sampler, v_texcoord);\n" + "}\n"; private static final float[] TEX_VERTICES = { 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f }; private static final float[] POS_VERTICES = { -1.0f, -1.0f,// bottom left 1.0f, -1.0f, // bottom right -1.0f, 1.0f, // top left 1.0f, 1.0f // top right };/** * TEX_VERTICES 和 POS_VERTICES 是处理坐标系的,2D的矩形,四个点 * OpenGL世界坐标系 \ Android UI坐标系 OpenGL文理坐标系 * (-1,1) \ (1,1) (0,0) (1,0) \ (0,1) (1,1) * \------\------\ \-------------\------> \------------\ * \ \(0,0) \ \ \ \ \ * -----\------\------\------> \ \ \ \ * \ \ \ \ \ \ \ * \------\------\ \-------------\ \------------\------> * (-1,-1) \ (1,-1) \(0,1) (1,1) (0,0) (1,0) * */ private static final int FLOAT_SIZE_BYTES = 4; // a float uses 4 bytes public void init() { // Create program mProgram = GLToolbox.createProgram(VERTEX_SHADER, FRAGMENT_SHADER); // Bind attributes and uniforms // get a handle to the constant uTexture mentioned in the fragment shader code. mTexSamplerHandle = GLES20.glGetUniformLocation(mProgram, "tex_sampler"); // get a handle to the variables a_position and a_texcoord mentioned in the vertex shader code. mTexCoordHandle = GLES20.glGetAttribLocation(mProgram, "a_texcoord"); mPosCoordHandle = GLES20.glGetAttribLocation(mProgram, "a_position"); // Setup coordinate buffers /* ByteBuffer.allocateDirect: create buffer * ByteBuffer.nativeOrder: determine the byte order * asFloatBuffer: convert the ByteBuffer instance into a FloatBuffer * put: load the array into the buffer * position: make sure that the buffer is read from the beginning * */ mTexVertices = ByteBuffer.allocateDirect( TEX_VERTICES.length * FLOAT_SIZE_BYTES) .order(ByteOrder.nativeOrder()).asFloatBuffer(); mTexVertices.put(TEX_VERTICES).position(0); mPosVertices = ByteBuffer.allocateDirect( POS_VERTICES.length * FLOAT_SIZE_BYTES) .order(ByteOrder.nativeOrder()).asFloatBuffer(); mPosVertices.put(POS_VERTICES).position(0); } public void tearDown() { GLES20.glDeleteProgram(mProgram); } public void updateTextureSize(int texWidth, int texHeight) { mTexWidth = texWidth; mTexHeight = texHeight; computeOutputVertices(); } public void updateViewSize(int viewWidth, int viewHeight) { mViewWidth = viewWidth; mViewHeight = viewHeight; computeOutputVertices(); } public void renderTexture(int texId) { // Bind default FBO ,create a named frame buffer object GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); // Use our shader program ,using the program we just linked. GLES20.glUseProgram(mProgram); GLToolbox.checkGlError("glUseProgram"); // Set viewport GLES20.glViewport(0, 0, mViewWidth, mViewHeight); GLToolbox.checkGlError("glViewport"); // Disable blending GLES20.glDisable(GLES20.GL_BLEND);// to disable the blending of colors while rendering // Set the vertex attributes /* * glVertexAttribPointer associate the aPosition handles with the textureBuffer * */ GLES20.glVertexAttribPointer(mTexCoordHandle, 2, GLES20.GL_FLOAT, false, 0, mTexVertices); GLES20.glEnableVertexAttribArray(mTexCoordHandle); GLES20.glVertexAttribPointer(mPosCoordHandle, 2, GLES20.GL_FLOAT, false, 0, mPosVertices); GLES20.glEnableVertexAttribArray(mPosCoordHandle); GLToolbox.checkGlError("vertex attribute setup"); // Set the input texture GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLToolbox.checkGlError("glActiveTexture"); // glBindTexture bind the texture (passed as an argument to the draw method) to the fragment shader. GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId); GLToolbox.checkGlError("glBindTexture"); GLES20.glUniform1i(mTexSamplerHandle, 0); // Draw GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // glClear : Clear the contents of the GLSurfaceView GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); // glDrawArrays : draw the two triangles (and thus the square). GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); } private void computeOutputVertices() { if (mPosVertices != null) { float imgAspectRatio = mTexWidth / (float)mTexHeight; float viewAspectRatio = mViewWidth / (float)mViewHeight; float relativeAspectRatio = viewAspectRatio / imgAspectRatio; float x0, y0, x1, y1; if (relativeAspectRatio > 1.0f) { x0 = -1.0f / relativeAspectRatio; y0 = -1.0f; x1 = 1.0f / relativeAspectRatio; y1 = 1.0f; } else { x0 = -1.0f; y0 = -relativeAspectRatio; x1 = 1.0f; y1 = relativeAspectRatio; } float[] coords = new float[] { x0, y0, x1, y0, x0, y1, x1, y1 }; mPosVertices.put(coords).position(0); } }}
GLSurfaceView 结合 OpenGLES使用步骤(个人总结,如果觉得不对,欢迎指正):
1.找到view,初始化
mEffectView = (GLSurfaceView) view.findViewById(R.id.effectsview);
mEffectView.setEGLContextClientVersion(2);// 用OpenGLES 2.0
mEffectView.setRenderer(this);// Renderer
mEffectView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);// 只在绘制数据发生改变时才绘制view
2. 实现 Renderer 的三个函数
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
// 仅调用一次,用于设置view的OpenGLES环境
}
// 如果view的几何形状发生变化了就调用,例如当竖屏变为横屏时
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
}
// 每次View被重绘时被调用,重点
@Override
public void onDrawFrame(GL10 gl) {
}
3. 用来显示图片的是 TextureRenderer onDrawFrame 里 初始化,只一次
这里 create a vertex shader create a fragment shader
int shader = GLES20.glCreateShader(shaderType);// create a shader object and return a reference
GLES20.glShaderSource(shader, source);// associate the shader code (source) with the shader.
GLES20.glCompileShader(shader);// compile the shader code
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
创建好后
GLES20.glAttachShader(program, vertexShader);// attach the shaders to the program.
GLES20.glAttachShader(program, pixelShader);
GLES20.glLinkProgram(program); // link the program
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
// Bind attributes and uniforms
// get a handle to the constant uTexture mentioned in the fragment shader code.
mTexSamplerHandle = GLES20.glGetUniformLocation(mProgram,"tex_sampler");
// get a handle to the variables a_position and a_texcoord mentioned in the vertex shader code.
mTexCoordHandle = GLES20.glGetAttribLocation(mProgram, "a_texcoord");
mPosCoordHandle = GLES20.glGetAttribLocation(mProgram, "a_position");
/* ByteBuffer.allocateDirect: create buffer
* ByteBuffer.nativeOrder: determine the byte order
* asFloatBuffer: convert the ByteBuffer instance into a FloatBuffer
* put: load the array into the buffer
* position: make sure that the buffer is read from the beginning
* */
mTexVertices = ByteBuffer.allocateDirect(
TEX_VERTICES.length * FLOAT_SIZE_BYTES)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mTexVertices.put(TEX_VERTICES).position(0);
mPosVertices = ByteBuffer.allocateDirect(
POS_VERTICES.length * FLOAT_SIZE_BYTES)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mPosVertices.put(POS_VERTICES).position(0);
到这里,GLES20与 TextureRenderer 就绑定好了
4.onDrawFrame 里 GLES20 初始化,只一次
// Generate textures
GLES20.glGenTextures(2, mTextures, 0);// initialize the array
// Upload bitmap to texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]); // activate the texture at index 0
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// set various properties that decide how the texture is rendered
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE);
至此,GLES20初始化完成,图片也设置进去了
5.需要显示出来
// Bind default FBO ,create a named frame buffer object
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
// Use our shader program ,using the program we just linked.
GLES20.glUseProgram(mProgram);
// Set viewport
GLES20.glViewport(0, 0, mViewWidth, mViewHeight);
// Disable blending
GLES20.glDisable(GLES20.GL_BLEND);// to disable the blending of colors while rendering
// Set the vertex attributes
/*
* glVertexAttribPointer associate the aPosition handles with the textureBuffer
* */
GLES20.glVertexAttribPointer(mTexCoordHandle, 2, GLES20.GL_FLOAT, false,
0, mTexVertices);
GLES20.glEnableVertexAttribArray(mTexCoordHandle);
GLES20.glVertexAttribPointer(mPosCoordHandle, 2, GLES20.GL_FLOAT, false,
0, mPosVertices);
GLES20.glEnableVertexAttribArray(mPosCoordHandle);
// Set the input texture
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
// glBindTexture bind the texture (passed as an argument to the draw method) to the fragment shader.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texId);
GLES20.glUniform1i(mTexSamplerHandle, 0);
// Draw
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// glClear : Clear the contents of the GLSurfaceView
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// glDrawArrays : draw the two triangles (and thus the square).
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
done.
6.当滤镜改变时,手动通知GLSurfaceView mEffectView.requestRender();// 手动调用 onDrawFrame
// apply(int inputTexId, int width, int height, int outputTexId)
mEffect.apply(mTextures[0], mImageWidth, mImageHeight, mTextures[1]);
- Sample之MediaEffects
- SliverLight 之Sample
- Android Sample 之 BasicNetworking
- Android Sample 之 BasicNetworking
- android sample 之 其他
- openstack 之 ceilometer: Sample
- Sample之Camera2BasicFragment
- Sample之ShaderCamera_Example
- Sample之Renderscript
- S60 sample project 之 Helloworldbasic
- S60 sample project 之 Myview
- 【jbpm3.2.3】之二 sample
- sample
- !!!sample
- sample
- 多线程之使用互斥信号量Sample~
- 多线程之使用事件对象Sample。。
- 多线程之使用临界区Sample。。
- [Leetcode] Convert a Number to Hexadecimal
- OpenGL纹理映射总结
- Java面试题大全(Java基础一)
- android studio打包失败,没遇见过,真的很坑!!!
- Ubuntu的root密码
- Sample之MediaEffects
- 【codevs】二叉苹果树 (二叉树的树形dp)
- C语言文件读写操作总结
- 安卓四大组件
- Android studio常见问题
- CSS实现元素水平/垂直居中的方法
- protobuf源码编译
- javascript实现继承
- SQLite.Net使用入门(二)【结合Asp.Net MVC】