我们经常会遇到播放视频的需求,最近几年全面屏、刘海屏的出现使得屏幕的比例各种各样,下面是视频适配各种屏幕比例,类似于ImageView的scaleType=“centerCrop”。
public class ClipVideoView extends GLSurfaceView {
/**
* MediaPlayer
*/
private MediaPlayer mediaPlayer;
/**
* 视频路径
*/
private String videoPath;
/**
* OnPreparedListener
*/
private MediaPlayer.OnPreparedListener mOnPreparedListener;
/**
* 构造函数
*/
public ClipVideoView(Context context) {
this(context, null);
}
/**
* 构造函数
*/
public ClipVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
/**
* 初始化
*/
private void init() {
Logger.d("ClipVideoView init");
setEGLContextClientVersion(2);
setPreserveEGLContextOnPause(true);
setRenderer(new VideoRenderer(getContext()));
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
/**
* 设置视频播放监听器
*/
public void setPreparedListener(MediaPlayer.OnPreparedListener onPreparedListener) {
mOnPreparedListener = onPreparedListener;
}
/**
* 播放视频
*/
public void start(String path) {
if (mediaPlayer == null) {
Logger.d("start video mediaPlayer is null,path:" + path);
videoPath = path;
return;
}
try {
Logger.d("start video path:" + path);
mediaPlayer.reset();
mediaPlayer.setLooping(true);
mediaPlayer.setDataSource(path);
mediaPlayer.prepare();
mediaPlayer.start();
if (mOnPreparedListener != null) {
mOnPreparedListener.onPrepared(null);
}
} catch (Exception e) {
Logger.e("play video error:" + e + " video path:" + path);
}
}
@Override
public void onResume() {
super.onResume();
if (mediaPlayer != null && !"".equals(videoPath)) {
Logger.d("video restart");
mediaPlayer.start();
}
}
@Override
public void onPause() {
super.onPause();
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
Logger.d("video pause");
mediaPlayer.pause();
}
}
/**
* 销毁
*/
public void release() {
if (mediaPlayer != null) {
Logger.d("video release");
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
}
private class VideoRenderer implements Renderer {
/**
* TAG
*/
private static final String TAG = "VideoRenderer";
/**
* context
*/
private Context context;
/**
* 纹理id
*/
int textureId = -1;
/**
* 坐标点
*/
private final int COORDS_PER_VERTEX = 3;
/**
* 坐标点
*/
private final int TEXCOORDS_PER_VERTEX = 2;
/**
* float size
*/
private static final int FLOAT_SIZE = 4;
/**
* 定点坐标
*/
private final float[] QUAD_COORDS = {
-1.0f, 1.0f, 0.0f, // top left
-1.0f, -1.0f, 0.0f, // bottom left
1.0f, -1.0f, 0.0f, // bottom right
1.0f, 1.0f, 0.0f // top right
};
/**
* 纹理坐标
*/
private float[] quadTexCoords = {
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
0.0f, 0.0f
};
/**
* index
*/
private final short[] index = {0, 1, 2, 0, 2, 3};
/**
* 顶点
*/
private FloatBuffer quadVertices;
/**
* 纹理
*/
private FloatBuffer quadTexCoord;
/**
* 索引
*/
private ShortBuffer shortBuffer;
/**
* program
*/
private int quadProgram = -1;
/**
* 顶点参数索引
*/
private int quadPositionParam = -1;
/**
* 纹理参数索引
*/
private int quadTexCoordParam = -1;
/**
* oes
*/
private int uTextureSamplerLocation = -1;
/**
* 是否有新的一针视频
*/
private boolean updateSurface = false;
/**
* SurfaceTexture
*/
private SurfaceTexture surfaceTexture;
/**
* 锁
*/
private Object lock = new Object();
/**
* 构造函数
*/
public VideoRenderer(Context context) {
this.context = context;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Logger.d("onSurfaceCreated");
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
textureId = textures[0];
int textureTarget = GLES11Ext.GL_TEXTURE_EXTERNAL_OES;
GLES20.glBindTexture(textureTarget, textureId);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
int vertexShader =
ShaderUtil.loadGLShader(TAG, context, GLES20.GL_VERTEX_SHADER, R.raw.base_vertex);
int fragmentShader =
ShaderUtil.loadGLShader(
TAG, context, GLES20.GL_FRAGMENT_SHADER, R.raw.base_fragment_oes);
quadProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(quadProgram, vertexShader);
GLES20.glAttachShader(quadProgram, fragmentShader);
GLES20.glLinkProgram(quadProgram);
GLES20.glUseProgram(quadProgram);
ShaderUtil.checkGLError(TAG, "Program creation");
quadPositionParam = GLES20.glGetAttribLocation(quadProgram, "a_Position");
quadTexCoordParam = GLES20.glGetAttribLocation(quadProgram, "a_TexCoordinate");
uTextureSamplerLocation = GLES20.glGetUniformLocation(quadProgram, "u_Texture");
ShaderUtil.checkGLError(TAG, "Program parameters");
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setLooping(true);
surfaceTexture = new SurfaceTexture(textureId);
Surface surface = new Surface(surfaceTexture);
surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
synchronized (lock) {
updateSurface = true;
}
}
});
mediaPlayer.setSurface(surface);
if (!"".equals(videoPath) && !mediaPlayer.isPlaying()) {
start(videoPath);
}
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
Logger.d("onSurfaceChanged");
GLES20.glViewport(0, 0, width, height);
GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
quadVertices = ByteBuffer.allocateDirect(QUAD_COORDS.length * FLOAT_SIZE)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
quadVertices.put(QUAD_COORDS);
quadVertices.position(0);
float videoRatio = 16.0F / 9;
Log.d(TAG, "width:" + width + " height:" + height);
float viewRatio = ((float) width) / height;
Log.d(TAG, "videoRatio:" + videoRatio + " viewRatio:" + viewRatio);
if (viewRatio < videoRatio) {
float s = (1 - (9 / 16.F * viewRatio)) / 2.0F;
float[] texCoord = {
0.0f + s, 1.0f,
1.0f - s, 1.0f,
1.0f - s, 0.0f,
0.0f + s, 0.0f
};
Log.d(TAG, Arrays.toString(texCoord));
quadTexCoord = ByteBuffer.allocateDirect(texCoord.length * FLOAT_SIZE)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
quadTexCoord.put(texCoord);
quadTexCoord.position(0);
} else if (viewRatio > videoRatio) {
float s = (1 - (16 / (9 * viewRatio))) / 2.0F;
float[] texCoord = {
0.0f, 1.0f - s,
1.0f, 1.0f - s,
1.0f, 0.0f + s,
0.0f, 0.0f + s
};
Log.d(TAG, Arrays.toString(texCoord));
quadTexCoord = ByteBuffer.allocateDirect(texCoord.length * FLOAT_SIZE)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
quadTexCoord.put(texCoord);
quadTexCoord.position(0);
} else {
quadTexCoord = ByteBuffer.allocateDirect(quadTexCoords.length * FLOAT_SIZE)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
quadTexCoord.put(quadTexCoords);
quadTexCoord.position(0);
}
shortBuffer = ByteBuffer.allocateDirect(index.length * 2)
.order(ByteOrder.nativeOrder())
.asShortBuffer();
shortBuffer.put(index);
shortBuffer.position(0);
}
@Override
public void onDrawFrame(GL10 gl) {
synchronized (lock) {
if (updateSurface) {
surfaceTexture.updateTexImage();
updateSurface = false;
}
}
GLES20.glUseProgram(quadProgram);
// Set the vertex positions.
quadVertices.position(0);
GLES20.glEnableVertexAttribArray(quadPositionParam);
GLES20.glVertexAttribPointer(
quadPositionParam, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, quadVertices);
// Set the texture coordinates.
quadTexCoord.position(0);
GLES20.glEnableVertexAttribArray(quadTexCoordParam);
GLES20.glVertexAttribPointer(
quadTexCoordParam, TEXCOORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, quadTexCoord);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId);
GLES20.glUniform1i(uTextureSamplerLocation, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, index.length, GLES20.GL_UNSIGNED_SHORT, shortBuffer);
// Disable vertex arrays
GLES20.glDisableVertexAttribArray(quadPositionParam);
GLES20.glDisableVertexAttribArray(quadTexCoordParam);
}
}
}
同时在AndroidManifest.xml 文件中添加如下代码:
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
视频播放使用的是系统MediaPlayer,如果没有包体大小的限制建议使用ijkplayer。
转载:https://blog.csdn.net/mengks1987/article/details/102383410
查看评论