之前曾经写过用SurfaceView,TextureView+MediaPlayer 播放视频,和 ffmpeg avi解码后SurfaceView播放视频,今天再给大家来一篇openGL ES+MediaPlayer来播放视频。。。。当年也曾呆过camera开发组近一年时间,可惜那时候没写博客的意识,没能给自己给大家留下多少干货分享。。。

上个效果图吧:

这里写图片描述

用openGL着色器实现黑白(灰度图)效果。

即 0.299,0.587,0.114 CRT中转灰度的模型

这里写图片描述

下面看具体实现的逻辑:

如果你曾用openGL实现过贴图,那么就容易理解多了。和图片不同的是,视频需要不断地刷新,每当有新的一帧来时,我们都应该更新纹理,然后重新绘制。用openGL播放视频就是把视频贴到屏幕上。

对openGL不熟的同学先看这里:学openGL必知道的图形学知识

1.先写顶点着色器和片段着色器(我的习惯是这样,你也可以后边根据需要再写这个)

顶点着色器:

attribute vec4 aPosition;//顶点位置

attribute vec4 aTexCoord;//S T 纹理坐标

varying vec2 vTexCoord;

uniform mat4 uMatrix;

uniform mat4 uSTMatrix;

void main() {

vTexCoord = (uSTMatrix * aTexCoord).xy;

gl_Position = uMatrix*aPosition;

}

片段着色器:

#extension GL_OES_EGL_image_external : require

precision mediump float;

varying vec2 vTexCoord;

uniform samplerExternalOES sTexture;

void main() {

gl_FragColor=texture2D(sTexture, vTexCoord);

}

samplerExternalOES代替贴图片时的sampler2D,作用就是和surfaceTexture配合进行纹理更新和格式转换

2.MediaPlayer的输出

在GLVideoRenderer的构造函数中初始化MediaPlayer:

mediaPlayer=new MediaPlayer();

try{

mediaPlayer.setDataSource(context, Uri.parse(videoPath));

}catch (IOException e){

e.printStackTrace();

}

mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

mediaPlayer.setLooping(true);

mediaPlayer.setOnVideoSizeChangedListener(this);

onSurfaceCreated函数中使用SurfaceTexture来设置MediaPlayer的输出

我们要用SurfaceTexture 创建一个Surface,然后将这个Surface作为MediaPlayer的输出表面。

SurfaceTexture的主要作用就是,从视频流和相机数据流获取新一帧的数据,获取新数据调用的方法是updateTexImage。

需要注意的是MediaPlayer的输出往往不是RGB格式(一般是YUV),而GLSurfaceView需要RGB格式才能正常显示。

所以我们先在onSurfaceCreated中将生成纹理的代码改成这样:

textureId = textures[0];

GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);

ShaderUtils.checkGlError("ws-------glBindTexture mTextureID");

GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,

GLES20.GL_NEAREST);

GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,

GLES20.GL_LINEAR);

GLES11Ext.GL_TEXTURE_EXTERNAL_OES的用处是什么?

之前提到视频解码的输出格式是YUV的(YUV420sp,应该是),那么这个扩展纹理的作用就是实现YUV格式到RGB的自动转化,我们就不需要再为此写YUV转RGB的代码了

然后在onSurfaceCreated的最后加上如下代码:

surfaceTexture = new SurfaceTexture(textureId);

surfaceTexture.setOnFrameAvailableListener(this);//监听是否有新的一帧数据到来

Surface surface = new Surface(surfaceTexture);

mediaPlayer.setSurface(surface);

surface.release();

if (!playerPrepared){

try {

mediaPlayer.prepare();

playerPrepared=true;

} catch (IOException t) {

Log.e(TAG, "media player prepare failed");

}

mediaPlayer.start();

playerPrepared=true;

}

用SurfaceTexture 创建一个Surface,然后将这个Surface作为MediaPlayer的输出表面.

在onDrawFrame中

synchronized (this){

if (updateSurface){

surfaceTexture.updateTexImage();//获取新数据

surfaceTexture.getTransformMatrix(mSTMatrix);//让新的纹理和纹理坐标系能够正确的对应,mSTMatrix的定义是和projectionMatrix完全一样的。

updateSurface = false;

}

}

在有新数据时,用updateTexImage来更新纹理,这个getTransformMatrix的目的,是让新的纹理和纹理坐标系能够正确的对应,mSTMatrix的定义是和projectionMatrix完全一样的。

private final float[] vertexData = {

1f,-1f,0f,

-1f,-1f,0f,

1f,1f,0f,

-1f,1f,0f

};

private final float[] textureVertexData = {

1f,0f,

0f,0f,

1f,1f,

0f,1f

};

vertexData 代表要绘制的视口坐标。textureVertexData 代表视频纹理,与屏幕坐标对应

然后我们读取坐标,在此自己我们先与着色器映射。

在onSurfaceCreated映射

aPositionLocation= GLES20.glGetAttribLocation(programId,"aPosition");

uMatrixLocation=GLES20.glGetUniformLocation(programId,"uMatrix");

uSTMMatrixHandle = GLES20.glGetUniformLocation(programId, "uSTMatrix");

uTextureSamplerLocation=GLES20.glGetUniformLocation(programId,"sTexture");

aTextureCoordLocation=GLES20.glGetAttribLocation(programId,"aTexCoord");

onDrawFrame中读取:

GLES20.glUseProgram(programId);

GLES20.glUniformMatrix4fv(uMatrixLocation,1,false,projectionMatrix,0);

GLES20.glUniformMatrix4fv(uSTMMatrixHandle, 1, false, mSTMatrix, 0);

vertexBuffer.position(0);

GLES20.glEnableVertexAttribArray(aPositionLocation);

GLES20.glVertexAttribPointer(aPositionLocation, 3, GLES20.GL_FLOAT, false,

12, vertexBuffer);

textureVertexBuffer.position(0);

GLES20.glEnableVertexAttribArray(aTextureCoordLocation);

GLES20.glVertexAttribPointer(aTextureCoordLocation,2,GLES20.GL_FLOAT,false,8,textureVertexBuffer);

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);

GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,textureId);

GLES20.glUniform1i(uTextureSamplerLocation,0);

GLES20.glViewport(0,0,screenWidth,screenHeight);

GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

GLVideoRenderer 全部代码如下:

package com.ws.openglvideoplayer;

import android.content.Context;

import android.graphics.SurfaceTexture;

import android.media.AudioManager;

import android.media.MediaPlayer;

import android.net.Uri;

import android.opengl.GLES11Ext;

import android.opengl.GLES20;

import android.opengl.GLSurfaceView;

import android.opengl.Matrix;

import android.util.Log;

import android.view.Surface;

import java.io.IOException;

import java.nio.ByteBuffer;

import java.nio.ByteOrder;

import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;

import javax.microedition.khronos.opengles.GL10;

/**

* Created by Shuo.Wang on 2017/3/19.

*/

public class GLVideoRenderer implements GLSurfaceView.Renderer

, SurfaceTexture.OnFrameAvailableListener, MediaPlayer.OnVideoSizeChangedListener {

private static final String TAG = "GLRenderer";

private Context context;

private int aPositionLocation;

private int programId;

private FloatBuffer vertexBuffer;

private final float[] vertexData = {

1f,-1f,0f,

-1f,-1f,0f,

1f,1f,0f,

-1f,1f,0f

};

private final float[] projectionMatrix=new float[16];

private int uMatrixLocation;

private final float[] textureVertexData = {

1f,0f,

0f,0f,

1f,1f,

0f,1f

};

private FloatBuffer textureVertexBuffer;

private int uTextureSamplerLocation;

private int aTextureCoordLocation;

private int textureId;

private SurfaceTexture surfaceTexture;

private MediaPlayer mediaPlayer;

private float[] mSTMatrix = new float[16];

private int uSTMMatrixHandle;

private boolean updateSurface;

private boolean playerPrepared;

private int screenWidth,screenHeight;

public GLVideoRenderer(Context context,String videoPath) {

this.context = context;

playerPrepared=false;

synchronized(this) {

updateSurface = false;

}

vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)

.order(ByteOrder.nativeOrder())

.asFloatBuffer()

.put(vertexData);

vertexBuffer.position(0);

textureVertexBuffer = ByteBuffer.allocateDirect(textureVertexData.length * 4)

.order(ByteOrder.nativeOrder())

.asFloatBuffer()

.put(textureVertexData);

textureVertexBuffer.position(0);

mediaPlayer=new MediaPlayer();

try{

mediaPlayer.setDataSource(context, Uri.parse(videoPath));

}catch (IOException e){

e.printStackTrace();

}

mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

mediaPlayer.setLooping(true);

mediaPlayer.setOnVideoSizeChangedListener(this);

}

@Override

public void onSurfaceCreated(GL10 gl, EGLConfig config) {

String vertexShader = ShaderUtils.readRawTextFile(context, R.raw.simple_vertex_shader);

String fragmentShader= ShaderUtils.readRawTextFile(context, R.raw.simple_fragment_shader);

programId=ShaderUtils.createProgram(vertexShader,fragmentShader);

aPositionLocation= GLES20.glGetAttribLocation(programId,"aPosition");

uMatrixLocation=GLES20.glGetUniformLocation(programId,"uMatrix");

uSTMMatrixHandle = GLES20.glGetUniformLocation(programId, "uSTMatrix");

uTextureSamplerLocation=GLES20.glGetUniformLocation(programId,"sTexture");

aTextureCoordLocation=GLES20.glGetAttribLocation(programId,"aTexCoord");

int[] textures = new int[1];

GLES20.glGenTextures(1, textures, 0);

textureId = textures[0];

GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);

ShaderUtils.checkGlError("glBindTexture mTextureID");

/*GLES11Ext.GL_TEXTURE_EXTERNAL_OES的用处?

之前提到视频解码的输出格式是YUV的(YUV420p,应该是),那么这个扩展纹理的作用就是实现YUV格式到RGB的自动转化,

我们就不需要再为此写YUV转RGB的代码了*/

GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,

GLES20.GL_NEAREST);

GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,

GLES20.GL_LINEAR);

surfaceTexture = new SurfaceTexture(textureId);

surfaceTexture.setOnFrameAvailableListener(this);//监听是否有新的一帧数据到来

Surface surface = new Surface(surfaceTexture);

mediaPlayer.setSurface(surface);

surface.release();

if (!playerPrepared){

try {

mediaPlayer.prepare();

playerPrepared=true;

} catch (IOException t) {

Log.e(TAG, "media player prepare failed");

}

mediaPlayer.start();

playerPrepared=true;

}

}

@Override

public void onSurfaceChanged(GL10 gl, int width, int height) {

Log.d(TAG, "onSurfaceChanged: "+width+" "+height);

screenWidth=width; screenHeight=height;

}

@Override

public void onDrawFrame(GL10 gl) {

GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);

synchronized (this){

if (updateSurface){

surfaceTexture.updateTexImage();//获取新数据

surfaceTexture.getTransformMatrix(mSTMatrix);//让新的纹理和纹理坐标系能够正确的对应,mSTMatrix的定义是和projectionMatrix完全一样的。

updateSurface = false;

}

}

GLES20.glUseProgram(programId);

GLES20.glUniformMatrix4fv(uMatrixLocation,1,false,projectionMatrix,0);

GLES20.glUniformMatrix4fv(uSTMMatrixHandle, 1, false, mSTMatrix, 0);

vertexBuffer.position(0);

GLES20.glEnableVertexAttribArray(aPositionLocation);

GLES20.glVertexAttribPointer(aPositionLocation, 3, GLES20.GL_FLOAT, false,

12, vertexBuffer);

textureVertexBuffer.position(0);

GLES20.glEnableVertexAttribArray(aTextureCoordLocation);

GLES20.glVertexAttribPointer(aTextureCoordLocation,2,GLES20.GL_FLOAT,false,8,textureVertexBuffer);

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);

GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,textureId);

GLES20.glUniform1i(uTextureSamplerLocation,0);

GLES20.glViewport(0,0,screenWidth,screenHeight);

GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

}

@Override

synchronized public void onFrameAvailable(SurfaceTexture surface) {

updateSurface = true;

}

@Override

public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {

Log.d(TAG, "onVideoSizeChanged: "+width+" "+height);

updateProjection(width,height);

}

private void updateProjection(int videoWidth, int videoHeight){

float screenRatio=(float)screenWidth/screenHeight;

float videoRatio=(float)videoWidth/videoHeight;

if (videoRatio>screenRatio){

Matrix.orthoM(projectionMatrix,0,-1f,1f,-videoRatio/screenRatio,videoRatio/screenRatio,-1f,1f);

}else Matrix.orthoM(projectionMatrix,0,-screenRatio/videoRatio,screenRatio/videoRatio,-1f,1f,-1f,1f);

}

public MediaPlayer getMediaPlayer() {

return mediaPlayer;

}

}

要实现上图中的滤镜视频效果,只需用0.299,0.587,0.114 CRT中转灰度的模型算法。(自己可以网上搜寻更多效果,这里只是抛砖引玉)

更改片段着色器即可:

#extension GL_OES_EGL_image_external : require

precision mediump float;

varying vec2 vTexCoord;

uniform samplerExternalOES sTexture;

void main() {

//gl_FragColor=texture2D(sTexture, vTexCoord);

vec3 centralColor = texture2D(sTexture, vTexCoord).rgb;

gl_FragColor = vec4(0.299*centralColor.r+0.587*centralColor.g+0.114*centralColor.b);

}

这里写图片描述

到此结束,我们已经实现了openGL ES+MediaPlayer 渲染播放视频+滤镜效果。后期将讲述全景视频原理及实现过程,敬请关注~

android 视频播放滤镜,用openGL ES+MediaPlayer 渲染播放视频+滤镜效果相关推荐

  1. java opengl_java基于OpenGL ES实现渲染实例

    这篇文章主要介绍了java基于OpenGL ES实现渲染,实例分析了OpenGL渲染操作的相关技巧,需要的朋友可以参考下 本文实例讲述了java基于OpenGL ES实现渲染的方法.分享给大家供大家参 ...

  2. ANDROID 高性能图形处理 之 OPENGL ES

    原文:http://tangzm.com/blog/?p=20 在之前的介绍中我们说到在Android 4.2上使用RenderScript有诸多限制,我们于是尝试改用OpenGL ES 2.0来实现 ...

  3. android 播放器封装,Android视频播放最全总结:MediaPlayer+TextureView封装一个完美实现全屏、小窗视频播放器,附项目源码...

    原标题:Android视频播放最全总结:MediaPlayer+TextureView封装一个完美实现全屏.小窗视频播放器,附项目源码 作者:xiaoyanger 来源:http://www.jian ...

  4. cocos2d-x 2.X for Android中需要使用OpenGL ES 2.0

    cocos2d-x 2.X for Android中需要使用OpenGL ES 2.0 到了2.X版本中,cocos2d-x for Android已经不再支持(或者说放弃支持)opengl es 1 ...

  5. android 行车记录仪分析,基于Android架构行车记录仪的异常掉电可播放视频方法与流程...

    本发明涉及摄录像视频技术领域,特别涉及一种基于Android架构行车记录仪的异常掉电可播放视频方法. 背景技术: 随着车联网概念的兴起和技术的积累,越来越多的智能设备被接入到车辆上.行车记录仪作为非常 ...

  6. 谷歌play商店_如何在Android的Google Play商店中禁用自动播放视频

    谷歌play商店 Justin Duino 贾斯汀·杜伊诺(Justin Duino) Does anyone like autoplaying videos? I know I don't. Goo ...

  7. android OpenGL ES实现渲染到透明的纹理 render to transparent texture

    PC上OpenGL渲染到纹理,很容易得到透明背景,但是在android上OpenGL ES渲染出来是黑色背景,对于这个问题,想了两个解决办法. 1> 让android的OpenGL ES环境支持 ...

  8. android 特效相机实现,安卓特效相机(三) OpenGL ES 特效渲染

    系列文章: 特效的实现原理 接下来这篇文章我们讲下特效的具体实现原理. 由于预览画面的渲染是将Surface传给CameraDevice由它去绘制的,而且我没有找到什么可以接管或者添加渲染效果的接口, ...

  9. Android 3D开发,OpenGL ES 的使用(一)

    最近有人问OpenGL ES 的使用,我通过几行代码演示一下. 不需要讲 来源 历史或大篇前奏.. 通过短短的一段就能迅速理解OpenGL ES 初步使用方法,对OpenGL ES 有了大概的概念和感 ...

最新文章

  1. HDU1102(Prim算法)
  2. 《赤壁》:吴宇森恶搞三国的经过
  3. nyoj 寻找最大数
  4. HDU5528 - Count a * b
  5. “被枪指头,中国教授用功夫击退美国劫匪”,他的身份不简单
  6. K02-01通过简单exe介绍pro基本配置
  7. Unity V3 初步使用 —— 为我的.NET项目从简单三层架构转到IOC做准备
  8. 智能优化算法:跳蛛优化算法-附代码
  9. 用c#中的WebBrowser抢小米F码,抢小米手机以及自动测试实现原理
  10. matlab二维傅里叶变换ffshift,形象理解二维傅里叶变换
  11. R语言无法安装fUnitRoots包
  12. 异常:java.lang.IllegalArgumentException: Result Maps collection already contains
  13. linux 排查cpu负载过高原因
  14. 【图像分割】基于方向谷形检测实现静脉纹路分割附MATLAB代码
  15. 森林的先序和中序遍历
  16. IP、网关、端口、网段、子网掩码概念区别
  17. 玫瑰花的python程序代码_python玫瑰花代码讲解,怎样用程序编写编写玫瑰花的代码,c程序或gava或者python...
  18. 我6个月的学习编程经历:从”大齿怪“到“狂欢者”
  19. 扫描车牌是什么神经网络,卷积神经网络车牌识别
  20. eureka上被down掉的服务手动up

热门文章

  1. Linux压缩包和用户管理及开关机指令
  2. 移除添加的文件_文件压缩教程-文件批量压缩
  3. 微博3元一万粉软件_实测3款朋友圈很火的“日赚分红300元”游戏软件究竟靠不靠谱!!...
  4. C/C++之类的前置声明
  5. Oracle 原理: 物化视图,快照,实体化视图。
  6. android通过webservice连接SQL数据库(一)服务器端
  7. github上fork原项目,如何将本地仓库代码更新到最新版本?
  8. 前天看了sigmastar新品发布,双核,1.2GHZ,真香!更多你想要了解的SSD201/202技术问题,看过来!启明云端MM帮你整理了!拿走不谢
  9. 怎么计算python程序执行时间_【华为云技术分享】计算python程序执行时间
  10. JAVA定义一个多边形类_如何在每个数据类别中绘制多个多边形?