代码大量拷贝https://blog.csdn.net/king1425/article/details/72773331博客,有兴趣可以去看一下
,简单解释了一下流程和相关关联
TextureViewMediaActivity代码
public class TextureViewMediaActivity extends Activity {
private static final String TAG = "GLViewMediaActivity";
private GLSurfaceView glView;
public static final String videoPath = Environment.getExternalStorageDirectory().getPath() + "/Movies/早早早.mp4";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
glView = findViewById(R.id.surface_view);
glView.setEGLContextClientVersion(2);
GLVideoRenderer glVideoRenderer = new GLVideoRenderer(this, videoPath);//创建renderer
glView.setRenderer(glVideoRenderer);//设置renderer
}
}
GLVideoRenderer 类代码
package com.example.jarry.utils;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
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 com.example.jarry.playvideo_texuture.R;
import com.example.jarry.playvideo_texuture.TextureViewMediaActivity;
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 Administrator on 2018/8/16 0016.
*/
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 int screenWidth, screenHeight;
public GLVideoRenderer(Context context, String videoPath) {
this.context = context;
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);
initMediaPlayer();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
String vertexShader = ShaderUtils.readRawTextFile(context, R.raw.vetext_sharder);
String fragmentShader = ShaderUtils.readRawTextFile(context, R.raw.fragment_sharder);
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);
}
private void initMediaPlayer() {
mediaPlayer = new MediaPlayer();
try {
AssetFileDescriptor afd = context.getAssets().openFd("big_buck_bunny.mp4");
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
// String path = "http://192.168.1.254:8192";
// mediaPlayer.setDataSource(path);
// mediaPlayer.setDataSource(TextureViewMediaActivity.videoPath);
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setLooping(true);
mediaPlayer.setOnVideoSizeChangedListener(this);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
Log.d(TAG, "onSurfaceChanged: " + width + " " + height);
screenWidth = width;
screenHeight = height;
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
}
@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;
}
}
xml代码
fragment_sharder.glsl 片段着色器,滤镜效果就是下面Color那段作用
#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);
}
vetext_sharder 顶点着色器
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;
}
整个流程就是,创建一个GLSurfaceView用来装载视频,GLSurfaceView中设置renderer,自己自定义renderer
,主要绘制流程都在这个,里面,主要有三个方法onSurfaceCreated(),onSurfaceChanged(),onDrawFrame()
下面一段代码是初始化着色器代码,至于着色器里面的代码需要了解着色器语言
String vertexShader = ShaderUtils.readRawTextFile(context, R.raw.vetext_sharder);
String fragmentShader = ShaderUtils.readRawTextFile(context, R.raw.fragment_sharder);
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");
这一串代码是绑定纹理,设置mediaplayer每一帧作为纹理关联起来
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);
至于下面onDrawFrame()里面的代码,都是opengl绘制的api,了解相关api就可以了,有一本opengl书籍系统学习一下更好
代码已经贴完,有任何问题可以直接评论