其他
真香!阿里工程师的一段代码让我看饿了
一、前言
图片预先合成视频,中间不做处理,记录每张图片展示的时间戳位置,然后在相邻图片切换的时间段用OpenGL做画面处理。 图片合成视频的过程中,在画面帧写入时同时做特效处理。
1.方案
ffmpeg -r 1/5 -i img%03d.png -c:v libx264 -vf fps=25 -pix_fmt yuv420p out.mp4
前序退场起始点enterStartT,前序动画开始时间点。 前序退场结束点enterEndT,前序动画结束时间点。 后序入场起始点exitStartT,后序动画开始时间点。 后序入场结束点exitEndT,后序动画结束时间点。
//参数初始化
protected abstract void onPhaseInit();
//前序动画,enterRatio(0-1)
protected abstract void onPhaseEnter(float enterRatio);
//后序动画,exitRatio(0-1)
protected abstract void onPhaseExit(float exitRatio);
//动画结束
protected abstract void onPhaseFinish();
//一帧动画执行完毕,步进
protected abstract void onPhaseStep();
//前序图片的纹理
uniform sampler2D preTexture
//后序图片的纹理
uniform sampler2D nextTexture;
//过渡动画总体进度,0到1
uniform float progress;
//窗口的长宽比例
uniform float canvasRatio;
//透明度变化
uniform float canvasAlpha;
vec4 fromColor = texture2D(sTexture, fromUv);
vec4 nextColor = texture2D(nextTexture, nextUv);
vec4 mixColor = mix(fromColor, nextColor, mixIntensity);
gl_FragColor = vec4(mixColor.rgb, canvasAlpha);
ExifInterface exif = new ExifInterface(imageFile);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int rotation = parseRotation(orientation);
Matrix matrix = new Matrix(rotation);
mImageBitmap = Bitmap.createBitmap(mOriginBitmap, 0, 0, mOriginBitmap.getWidth(), mOriginBitmap.getHeight(), matrix, true);
//根据窗口尺寸生成一个空的bitmap
mCanvasBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas bitmapCanvas = new Canvas(mCanvasBitmap);
//翻转图片
bitmapCanvas.scale(1, -1, bitmapCanvas.getWidth() / 2f, bitmapCanvas.getHeight() / 2f);
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
int textureId = textures[0];
GLES20.glBindTexture(textureType, textureId);
GLES20.glTexParameterf(textureType, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameterf(textureType, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(textureType, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(textureType, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
//清除画布
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glUseProgram(mProgramHandle);
//绑定顶点坐标
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexBufferName);
GLES20.glVertexAttribPointer(getHandle(ATTRIBUTE_VEC4_POSITION), GLConstants.VERTICES_DATA_POS_SIZE, GLES20.GL_FLOAT,
false, GLConstants.VERTICES_DATA_STRIDE_BYTES, GLConstants.VERTICES_DATA_POS_OFFSET);
GLES20.glEnableVertexAttribArray(getHandle(ATTRIBUTE_VEC4_POSITION));
GLES20.glVertexAttribPointer(getHandle(ATTRIBUTE_VEC4_TEXTURE_COORD), GLConstants.VERTICES_DATA_UV_SIZE, GLES20.GL_FLOAT,
false, GLConstants.VERTICES_DATA_STRIDE_BYTES, GLConstants.VERTICES_DATA_UV_OFFSET);
GLES20.glEnableVertexAttribArray(getHandle(ATTRIBUTE_VEC4_TEXTURE_COORD));
//激活有效纹理
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
//绑定图片纹理坐标
GLES20.glBindTexture(targetTexture, texName);
GLES20.glUniform1i(getHandle(UNIFORM_SAMPLER2D_TEXTURE), 0);
//开启透明度混合
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
//绘制三角形条带
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
//重置环境参数绑定
GLES20.glDisableVertexAttribArray(getHandle(ATTRIBUTE_VEC4_POSITION));
GLES20.glDisableVertexAttribArray(getHandle(ATTRIBUTE_VEC4_TEXTURE_COORD));
GLES20.glBindTexture(targetTexture, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
2.平移覆盖转场
I.着色器实现
uniform int direction;
void main(void) {
float intensity;
if (direction == 0) {
intensity = step(0.0 + coord.x,progress);
} else if (direction == 1) {
intensity = step(1.0 - coord.x,progress);
} else if (direction == 2) {
intensity = step(1.0 - coord.y,progress);
} else if (direction == 3) {
intensity = step(0.0 + coord.y,progress);
}
vec4 mixColor = mix(fromColor, nextColor, intensity);
}
Declaration:
genType step(genType edge, genType x);
Parameters:
edge Specifies the location of the edge of the step function.
x Specify the value to be used to generate the step function.
I.着色器实现
uniform float squareSizeFactor;
uniform float imageWidthFactor;
uniform float imageHeightFactor;
void main(void) {
float revProgress = (1.0 - progress);
float distFromEdges = min(progress, revProgress);
float squareSize = (squareSizeFactor * distFromEdges) + 1.0;
float dx = squareSize * imageWidthFactor;
float dy = squareSize * imageHeightFactor;
vec2 coord = vec2(dx * floor(uv.x / dx), dy * floor(uv.y / dy));
vec4 fromColor = texture2D(preTexture, coord);
vec4 nextColor = texture2D(nextTexture, coord);
vec4 mixColor = mix(fromColor, nextColor, progress);
};
uniform float mixIntensity;
uniform float rippleTime;
uniform float rippleAmplitude;
uniform float rippleSpeed;
uniform float rippleOffset;
uniform vec2 rippleCenterShift;
void main(void) {
//纹理位置坐标归一化
vec2 curPosition = -1.0 + 2.0 * vTextureCoord;
//修正相对波纹中心点的位置偏移
curPosition -= rippleCenterShift;
//修正画面比例
curPosition.x *= canvasRatio;
//计算波纹里中心点的长度
float centerLength = length(curPosition);
//计算波纹出现的纹理位置
vec2 uv = vTextureCoord + (curPosition/centerLength)*cos(centerLength*rippleAmplitude-rippleTime*rippleSpeed)*rippleOffset;
vec4 fromColor = texture2D(preTexture, uv);
vec4 nextColor = texture2D(nextTexture, uv);
vec4 mixColor = mix(fromColor, nextColor, mixIntensity);
gl_FragColor = vec4(mixColor.rgb, canvasAlpha);
}
protected void onPhaseInit() {
mMixIntensity = MIX_INTENSITY_START;
mCanvasAlpha = CANVAS_ALPHA_DEFAULT;
mRippleAmplitude = 0;
mRippleSpeed = 0;
mRippleOffset = 0;
}
protected void onPhaseEnter(float enterRatio) {
mMixIntensity = enterRatio * 0.5f;
mCanvasAlpha = 1f - enterRatio;
mRippleAmplitude = enterRatio * RIPPLE_AMPLITUDE_DEFAULT;
mRippleSpeed = enterRatio * RIPPLE_SPEED_DEFAULT;
mRippleOffset = enterRatio * RIPPLE_OFFSET_DEFAULT;
}
protected void onPhaseExit(float exitRatio) {
mMixIntensity = exitRatio * 0.5f + 0.5f;
mCanvasAlpha = exitRatio;
mRippleAmplitude = (1f - exitRatio) * RIPPLE_AMPLITUDE_DEFAULT;
mRippleSpeed = (1f - exitRatio) * RIPPLE_SPEED_DEFAULT;
mRippleOffset = (1f - exitRatio) * RIPPLE_OFFSET_DEFAULT;
}
protected void onPhaseFinish() {
mMixIntensity = MIX_INTENSITY_END;
mCanvasAlpha = CANVAS_ALPHA_DEFAULT;
mRippleAmplitude = 0;
mRippleSpeed = 0;
mRippleOffset = 0;
}
protected void onPhaseStep() {
if (mCanvasAlpha < CANVAS_ALPHA_MINIMUN) {
mCanvasAlpha = CANVAS_ALPHA_MINIMUN;
}
}
long globalTimeMs = GLClock.get();
GLES20.glUniform1f(getHandle("rippleTime"), globalTimeMs / 1000f);
GLES20.glUniform1f(getHandle("rippleAmplitude"), mRippleAmplitude);
GLES20.glUniform1f(getHandle("rippleSpeed"), mRippleSpeed);
GLES20.glUniform1f(getHandle("rippleOffset"), mRippleOffset);
GLES20.glUniform2f(getHandle("rippleCenterShift"), mRippleCenterX, mRippleCenterY);
uniform vec2 squares;
uniform float smoothness;
float rand(vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
};
void main(void) {
vec2 uv = vTextureCoord.xy;
float randomSquare = rand(floor(squares * uv));
float intensity = smoothstep(0.0, -smoothness, randomSquare - (progress * (1.0 + smoothness)));
vec4 fromColor = texture2D(preTexture, uv);
vec4 nextColor = texture2D(nextTexture, uv);
vec4 mixColor = mix(fromColor, nextColor, intensity);
gl_FragColor = vec4(mixColor.rgb, canvasAlpha);
}
1000篇好文带你学懂区块链,更有认证问答官资格等你领!
识别下方二维码或点击“阅读原文”帮你破解区块链密码。