Android视频裁剪适配,类似于ImageView的scaleType=centerCrop
生活随笔
收集整理的這篇文章主要介紹了
Android视频裁剪适配,类似于ImageView的scaleType=centerCrop
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
我們經(jīng)常會遇到播放視頻的需求,最近幾年全面屏、劉海屏的出現(xiàn)使得屏幕的比例各種各樣,下面是視頻適配各種屏幕比例,類似于ImageView的scaleType=“centerCrop”。
public class ClipVideoView extends GLSurfaceView {/*** MediaPlayer*/private MediaPlayer mediaPlayer;/*** 視頻路徑*/private String videoPath;/*** OnPreparedListener*/private MediaPlayer.OnPreparedListener mOnPreparedListener;/*** 構(gòu)造函數(shù)*/public ClipVideoView(Context context) {this(context, null);}/*** 構(gòu)造函數(shù)*/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);}/*** 設(shè)置視頻播放監(jiān)聽器*/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);}}@Overridepublic void onResume() {super.onResume();if (mediaPlayer != null && !"".equals(videoPath)) {Logger.d("video restart");mediaPlayer.start();}}@Overridepublic 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 left1.0f, -1.0f, 0.0f, // bottom right1.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;/*** 頂點參數(shù)索引*/private int quadPositionParam = -1;/*** 紋理參數(shù)索引*/private int quadTexCoordParam = -1;/*** oes*/private int uTextureSamplerLocation = -1;/*** 是否有新的一針視頻*/private boolean updateSurface = false;/*** SurfaceTexture*/private SurfaceTexture surfaceTexture;/*** 鎖*/private Object lock = new Object();/*** 構(gòu)造函數(shù)*/public VideoRenderer(Context context) {this.context = context;}@Overridepublic 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() {@Overridepublic void onFrameAvailable(SurfaceTexture surfaceTexture) {synchronized (lock) {updateSurface = true;}}});mediaPlayer.setSurface(surface);if (!"".equals(videoPath) && !mediaPlayer.isPlaying()) {start(videoPath);}}@Overridepublic 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);}@Overridepublic 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 arraysGLES20.glDisableVertexAttribArray(quadPositionParam);GLES20.glDisableVertexAttribArray(quadTexCoordParam);}} }base_vertex.glsl文件:
attribute vec4 a_Position; attribute vec2 a_TexCoordinate;varying vec2 v_TexCoord;void main() {v_TexCoord = a_TexCoordinate;gl_Position = a_Position; }base_fragment.glsl文件:
#extension GL_OES_EGL_image_external : require precision mediump float;uniform samplerExternalOES u_Texture; varying vec2 v_TexCoord;void main() {gl_FragColor = texture2D(u_Texture, v_TexCoord); }2個glsl文件放在:res/raw 目錄下:
ShareUtil:
/** Copyright 2017 Google Inc. All Rights Reserved.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/ package com.jd.lib.armart.arcore.arcore.rendering;import android.content.Context; import android.opengl.GLES20; import android.util.Log;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader;/*** des: shader 工具類* [@author]: mengqingdong* [@date]: 2019-08-14 09:52*/ public class ShaderUtil {/*** Converts a raw text file, saved as a resource, into an OpenGL ES shader.** @param type The type of shader we will be creating.* @param resId The resource ID of the raw text file about to be turned into a shader.* @return The shader object handler.*/public static int loadGLShader(String tag, Context context, int type, int resId) {String code = readRawTextFile(context, resId);int shader = GLES20.glCreateShader(type);GLES20.glShaderSource(shader, code);GLES20.glCompileShader(shader);// Get the compilation status.final int[] compileStatus = new int[1];GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);// If the compilation failed, delete the shader.if (compileStatus[0] == 0) {Log.e(tag, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shader));GLES20.glDeleteShader(shader);shader = 0;}if (shader == 0) {throw new RuntimeException("Error creating shader.");}return shader;}/*** Checks if we've had an error inside of OpenGL ES, and if so what that error is.** @param label Label to report in case of error.* @throws RuntimeException If an OpenGL error is detected.*/public static void checkGLError(String tag, String label) {int lastError = GLES20.GL_NO_ERROR;// Drain the queue of all errors.int error;while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {Log.e(tag, label + ": glError " + error);lastError = error;}if (lastError != GLES20.GL_NO_ERROR) {throw new RuntimeException(label + ": glError " + lastError);}}/*** Converts a raw text file into a string.** @param resId The resource ID of the raw text file about to be turned into a shader.* @return The context of the text file, or null in case of error.*/private static String readRawTextFile(Context context, int resId) {InputStream inputStream = context.getResources().openRawResource(resId);try {BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));StringBuilder sb = new StringBuilder();String line;while ((line = reader.readLine()) != null) {sb.append(line).append("\n");}reader.close();return sb.toString();} catch (IOException e) {e.printStackTrace();}return null;} }同時在AndroidManifest.xml 文件中添加如下代碼:
<uses-feature android:glEsVersion="0x00020000" android:required="true" />視頻播放使用的是系統(tǒng)MediaPlayer,如果沒有包體大小的限制建議使用ijkplayer。
總結(jié)
以上是生活随笔為你收集整理的Android视频裁剪适配,类似于ImageView的scaleType=centerCrop的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 代码设计的基础原则_设计原则:良好设计的
- 下一篇: 如何自动申请京东试用商品、签到获取京豆