目录

1、概述

2、模块原理

2.1、 播放器

2.2、 显示渲染

2.3、 颜色滤镜

3、总结

1、概述

本文介绍一个在Android上面实现的一个实时调整滤镜参数的播放器例子。市面上一些美颜,画质增强等播放器的大致原理都是如此。通过调整图1中的三个参数就可以实时看到画面颜色、明暗、艳丽程度的变化。

图1

2、模块原理

这个例子可以分为三个模块:解码播放、显示渲染、颜色参数调整转化。本文重点是颜色滤镜参数的调整。

2.1、 播放器

这里采用的是系统的媒体播放器MediapPayer播放一个放在工程raw资源路径下的MP4文件。播放代码如下:

 private void setupPlayer() {try {mMediaPlayer = MediaPlayer.create(this, R.raw.testfile);mMediaPlayer.setSurface(mSurface);mMediaPlayer.setLooping(true);} catch (Exception e) {e.printStackTrace();}mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mediaPlayer) {mMediaPlayer.start();}});}

这个播放器的输入是testfile.mp4,解码出来的画面会通过Surface传给渲染层。

2.2、 显示渲染

这里渲染采用的是OpenGl ES 2.0,由于跨平台,兼容性好被广泛应用。Android对OpenGL ES支持非常好,可以在JNI中开发也有对应的JAVA接口,本文采用的是JAVA。

下面是使用OpenGL ES的步骤:

1、在layout文件中配置一个GLSurfaceView

    <android.opengl.GLSurfaceViewandroid:id="@+id/video_view"android:layout_width="match_parent"android:layout_height="320dp" />

2、在Activity文件中设置GlSurfaceView。这里主要是设置Render回调,onSurfaveCreate是初始化一些值,onDrawFrame是画每一帧。

mVideoView = findViewById(R.id.video_view);
mVideoView.setEGLContextClientVersion(2);
mVideoView.setRenderer(new GLSurfaceView.Renderer() {@Overridepublic void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {mReactShape = new RectShape();int textureId = GLUtil.generateOESTexture();mSurfaceTexture = new SurfaceTexture(textureId);mSurfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {@Overridepublic void onFrameAvailable(SurfaceTexture surfaceTexture) {mFrameAvailable = true;}});mSurface = new Surface(mSurfaceTexture);mReactShape.setTextureId(textureId);setupPlayer();}@Overridepublic void onSurfaceChanged(GL10 gl10, int i, int i1) {}@Overridepublic void onDrawFrame(GL10 gl10) {if (mFrameAvailable) {mSurfaceTexture.updateTexImage();mFrameAvailable = false;}float[] colorFilter = mColorFilterMatrixUtil.getColorFilterArray16();mReactShape.setColorFilterArray(colorFilter);mReactShape.draw();}});

3、在第二步是配置渲染的线程(GLSurfaceView 有自己独立的线程),具体内容显示还需要一个载体。这里采用的是一个矩形的ReactShape来画每一帧。

package com.test.videocolorfilter;import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.Matrix;
import android.util.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;public class RectShape {private float width = 2;private float height = 2;private int mTextureId = 0;private int mProgram = -1;private int mPositionHandle;private int mTexCoordHandle;private int mMVPHandle;private int mColorFilterHandle;private FloatBuffer mVertices, mTexCoord;private float[] mModelProjection = new float[16];private float[] mColorFilterArray = new float[16];private final static String VERTEX_SHADER ="uniform mat4 uMVPMatrix;\n" +"attribute vec4 a_Position;\n" +"attribute vec2 aTexCoor;\n" +"varying vec2 vTextureCoord;\n" +"uniform float uAngle;\n" +"void main(){\n" +"    gl_Position = uMVPMatrix * a_Position;\n" +"    vTextureCoord = aTexCoor;\n" +"}\n";private final static String FRAGMENT_SHADER ="#extension GL_OES_EGL_image_external : require\n" +"precision highp float;\n" +"varying vec2 vTextureCoord;\n" +"uniform samplerExternalOES uTexture;\n" +"uniform mat4 uColorFilterMatrix;\n" +"void main() {\n" +"     vec4 val = texture2D(uTexture, vTextureCoord); \n" +"     gl_FragColor = val*uColorFilterMatrix; \n" +"}\n";public RectShape() {init();}protected void init() {Matrix.setIdentityM(mModelProjection, 0);Matrix.setIdentityM(mColorFilterArray, 0);float[] vertices = new float[]{-width / 2, -height / 2, 0,width / 2, height / 2, 0,-width / 2, height / 2, 0,width / 2, height / 2, 0,-width / 2, -height / 2, 0,width / 2, -height / 2, 0,};ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);vbb.order(ByteOrder.nativeOrder());mVertices = vbb.asFloatBuffer();mVertices.put(vertices);mVertices.position(0);// create programmProgram = GLUtil.createProgram(VERTEX_SHADER, FRAGMENT_SHADER);mPositionHandle = GLES20.glGetAttribLocation(mProgram, "a_Position");mTexCoordHandle = GLES20.glGetAttribLocation(mProgram, "aTexCoor");mMVPHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");mColorFilterHandle = GLES20.glGetUniformLocation(mProgram, "uColorFilterMatrix");//setup buffers for the texture 2D coordinatesfloat[] texCoord = new float[]{0.0f, 1.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f, 0.0f,0.0f, 1.0f,1.0f, 1.0f,};ByteBuffer cbb = ByteBuffer.allocateDirect(texCoord.length * 4);cbb.order(ByteOrder.nativeOrder()); //set the byte ordermTexCoord = cbb.asFloatBuffer(); //convert to byte buffermTexCoord.put(texCoord); //load data to byte buffermTexCoord.position(0); //set the start point}public void setTextureId(int textureId) {mTextureId = textureId;}public void draw() {draw(mTextureId);}public void draw(int textureId) {
//        Log.d("RectShape", "draw "+ textureId);GLES20.glUseProgram(mProgram);GLES20.glUniformMatrix4fv(mMVPHandle, 1, false, mModelProjection, 0);GLES20.glUniformMatrix4fv(mColorFilterHandle, 1, false, mColorFilterArray, 0);if (textureId > 0) {// render textureGLES20.glActiveTexture(GLES20.GL_TEXTURE0);GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);}// draw trianglesGLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, mVertices);GLES20.glEnableVertexAttribArray(mPositionHandle);GLES20.glVertexAttribPointer(mTexCoordHandle, 2, GLES20.GL_FLOAT, false, 0, mTexCoord);GLES20.glEnableVertexAttribArray(mTexCoordHandle);GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mVertices.capacity() / 3);}public void setColorFilterArray(float filter[]) {System.arraycopy(filter, 0, mColorFilterArray, 0, 16);}public void release() {if (mProgram >= 0) {GLES20.glDeleteProgram(mProgram);mProgram = -1;}}}

这个类最主要的是部分是两个shader和draw()函数。

shader采用的是GLSL语言,在openGL ES 2.0以后开始使用,分为顶点着色器和片元着色器;顶点着色器指定了顶点转化关系和几何姿态的调整以及投影关系;片元着色器指定的是像素色彩以及光照等变化,这部分通过编译最终执行在GPU中。

draw()函数是将纹理,几何坐标,纹理坐标、姿态矩阵、颜色矩阵等值传给shader。这些值可以每一帧都不一样。

2.3、 颜色滤镜

看道这篇文章的同学应该都比较喜欢或熟悉用RGB来描述图像,RGB三基色描述在图像数字化确实比较方便。但是对于眼睛或者设计师调整却并不方便。在滤镜调整过程中大家其实更偏向另外一种颜色模型HSL(hue,saturation,lightness)下图是HSL的原理模型:

图 2

Android对HSL调整有很好的支持,在SDK的android.graphic包中有一个ColorMatrix类。这个类时管理一个5x4的颜色矩阵,支持色相、饱和度、明度调整接口。ColorMatrix T表示如下:

颜色C表示如下:

新颜色C`

R' = a*R + b*G + c*B + d*A + e;
           G' = f*R + g*G + h*B + i*A + j;
           B' = k*R + l*G + m*B + n*A + o;
           A' = p*R + q*G + r*B + s*A + t;

从上图模型可以看出,hue(色相)是调整颜色属性,直观地说就是让颜色偏绿点还是偏红点,效果如下图:

图 3-色相调整效果

saturation(饱和度)指的是色彩纯度。是色彩的构成要素之一。纯度越高,表现越鲜明,纯度较低,表现则较黯淡。效果如下图;

图4-饱和度调整效果

lightness(明度)是调整颜色的能量程度,直白说就是黑还是白,调整效果如下图:

图5-明度调整效果

3、总结

  • 本文的滤镜只是采用的颜色调整,还没有实现锐化、模糊、马赛克等像素位置变化的效果。
  • 播放器采用的最简单的本地MediaPlayer对于一些直播可能需要替换支持跟多协议的播放器如ijkplayer。
  • 本文的配套的工程github地址https://github.com/liyang-hello/VideoColorFilter,如有兴趣可以下载。

Android实时滤镜实现相关推荐

  1. Android 实时滤镜 高斯模糊(带源码)

    最近在做一个这样一个需求,一个控件可以实时预览摄像头的内容,并且对此图像进行高斯模糊处理,现在来记录一下. 基本的实现思路 1,摄像头实时预览的数据会回调给onPreviewFrame(byte[] ...

  2. android camera 实时滤镜,【Camera】Android平台Camera实时滤镜实现方法

    Android+JNI+OpenGL开发自己的美图秀秀 2016-01-18 16:39 阅读(5116) 评论(19) Android平台Camera实时滤镜实现方法探讨(十一)--实时美颜滤镜 2 ...

  3. Android平台美颜相机/Camera实时滤镜/视频编解码/影像后期/人脸技术探索——1.1 工程思路与难点

    回到目录 本文主要探讨搭建一款Android平台下美颜相机可能需要填的坑,内容会不断更新.. 相机框架 相机框架相对比较简单,现有的开源代码很多,可以很容易的实现拍照和录像的功能. 预览尺寸选择 预览 ...

  4. android相机实时滤镜,android 包含美颜等40余种实时滤镜相机

    MagicCamera Idea from:android-gpuimage Real-time Filter Camera&VideoRecorder And ImageEditor Wit ...

  5. 自定义相机Camera,相机/视频实时滤镜 - android

    使用相机或自定义相机,借助Android SDK Camera类的,或Camera2的类.全新的设计的Camera2是从 SDK 5.0(API Level 21)开始才被引入的,取代原来Camera ...

  6. android 滤镜开源,Android Camera 实时滤镜(三)

    一.基于Android平台基本滤镜算法的实现 1.Android提供了改变图像数值的方法ColorMatrix,通过ColorMatrix方法可以实现基本滤镜,如黑白.灰色.泛黄等效果. 2.通过Co ...

  7. android照片美颜项目_MagicCamera: MagicCamera 是 Android 平台开源相机项目,具有包括实时美颜等40种实时滤镜,功能包括对图片进行磨皮/美白等后期处理...

    MagicCamera Idea from:android-gpuimage Real-time Filter Camera&VideoRecorder And ImageEditor Wit ...

  8. Android平台Camera实时滤镜实现方法

    Android+JNI+OpenGL开发自己的美图秀秀 Android平台Camera实时滤镜实现方法探讨(十一)--实时美颜滤镜 Android平台Camera实时滤镜实现方法探讨(十)--代码地址 ...

  9. Android Camera 实时滤镜(五)

    Android 静态滤镜的实现 一.回顾知识点 1.基本滤镜效果的实现(黑白滤镜) 用到的技术是ColorMatrix.通过改变RGBA的系数,从而改变图像的成像效果. Created with Ra ...

最新文章

  1. IM与工作信息流整合
  2. linux转mysql_转linux下mysql命令
  3. vectorvn1610报价_【8.5873.5444.G323】价格_厂家 - 中国供应商
  4. Kuangyeye and hamburgers
  5. Spring Cloud实战小贴士:随机端口
  6. 程序员谈谈我的职场观(一)
  7. 基于Linux命令行终端的ftp客户端程序
  8. 基于linux下的在线电子词典
  9. js新窗口打开页面固定尺寸大小
  10. 【GAN论文解读系列】NeurIPS 2016 InfoGAN 使用InfoGAN解耦出可解释的特征
  11. VS Winform如何设置光标样式
  12. 30个让你大呼惊艳的数据可视化作品!
  13. oracle虚拟机共享U盘,技巧分享:虚拟机也能使用U盘及USB设备
  14. idea重置插件的使用
  15. AIX磁盘管理基础知识
  16. 云存储相关技术及术语的探讨
  17. C语言-XLSX基础数据解析(需借助libxml2库)
  18. 南大计算机跨专业考研,GitHub - weizhang27/NJU-CS-Kaoyan: 南京大学计算机考研相关问题...
  19. 外网远程访问公司内网OA办公系统
  20. 常用计算机office操作知识,【公基小考点】​OFFICE操作常识

热门文章

  1. BCGControlBar Library for .NET 7.1.1 Crack
  2. 小程序接入查快递功能
  3. 中国粘胶纤维市场消费量调研及投资商机研究报告2022-2028年
  4. leadtools ocr java_LEADTOOLS OCR文字识别教程:开始文字识别
  5. wps如何设置一个全屏的背景
  6. 计算机教室窗子长宽高,窗户尺寸多大
  7. 2022年度“强国杯”技术技能大赛upload_lol
  8. 基于 Flink 构建大规模实时风控系统在阿里巴巴的落地
  9. python死机怎么办_Python线程死机
  10. android 字体荧光效果,Android实现锁屏荧光效果