我的目标是接收M4V视频文件,将视频片段解码为PNG帧,修改这些帧,然后重新编码修剪后的视频(也适用于M4V)。
工作流程如下:[Input Video] -> Export Frames -> Modify Frames -> Encode Frames -> [Output Video]
。
对于解码过程,我一直在引用bigflake示例。使用ExtractMpegFramesTest示例代码,我能够从Bitmap
文件生成.m4v
帧,并将帧导出为PNG文件。
现在我正在尝试重新编码过程,使用EncodeAndMuxTest示例尝试创建另一组编码类。
我遇到的问题是,示例代码似乎在OpenGL中生成原始帧。我有一系列Bitmaps
我要编码/渲染到CodecInputSurface
对象。几乎与解码过程相反。
大多数示例代码都很好,我似乎只需要修改generateSurfaceFrame()
以使用OpenGL将Bitmap
呈现给Surface
。
这是我到目前为止的代码:
// Member variables (see EncodeAndMuxTest example)
private MediaCodec encoder;
private CodeInputSurface inputSurface;
private MediaMuxer muxer;
private int trackIndex;
private boolean hasMuxerStarted;
private MediaCodec.BufferInfo bufferInfo;
// This is called for each frame to be rendered into the video file
private void encodeFrame(Bitmap bitmap)
{
int textureId = 0;
try
{
textureId = loadTexture(bitmap);
// render the texture here?
}
finally
{
unloadTexture(textureId);
}
}
// Loads a texture into OpenGL
private int loadTexture(Bitmap bitmap)
{
final int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
int textureWidth = bitmap.getWidth();
int textureHeight = bitmap.getHeight();
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE);
return textures[0];
}
// Unloads a texture from OpenGL
private void unloadTexture(int textureId)
{
final int[] textures = new int[1];
textures[0] = textureId;
GLES20.glDeleteTextures(1, textures, 0);
}
我觉得我应该可以使用 ExtractMpegFramesTest 示例中的STextureRender
来实现类似功能,但它不会为我点击。
另一件事是性能,我真的想要获得有效的编码。我将编码90-450帧视频(3-15秒@ 30fps),所以这应该只需要几秒钟。
答案 0 :(得分:1)
您可以尝试使用英特尔INDE媒体包,它可以修改帧,剪切片段,连接文件等等。有几种用于帧修改的示例效果:颜色修改,文本覆盖等等,您可以轻松修改或添加新效果。它有一个很好的示例集和教程如何构建和运行app:https://software.intel.com/en-us/articles/intel-inde-media-pack-for-android-tutorials-running-samples
帧修改是基于gl着色器的,例如对于Sepia:
@Override
protected String getFragmentShader() {
return "#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;\n" +
"varying vec2 vTextureCoord;\n" +
"uniform mat3 uWeightsMatrix;\n" +
"uniform samplerExternalOES sTexture;\n" +
"void main() {\n" +
" vec4 color = texture2D(sTexture, vTextureCoord);\n" +
" vec3 color_new = min(uWeightsMatrix * color.rgb, 1.0);\n" +
" gl_FragColor = vec4(color_new.rgb, color.a);\n" +
"}\n";
}
其中uWeightsMatrix通过getAttributeLocation和glUniformMatrix3fv设置为着色器
protected float[] getWeights() {
return new float[]{
805.0f / 2048.0f, 715.0f / 2048.0f, 557.0f / 2048.0f,
1575.0f / 2048.0f, 1405.0f / 2048.0f, 1097.0f / 2048.0f,
387.0f / 2048.0f, 344.0f / 2048.0f, 268.0f / 2048.0f
};
}
答案 1 :(得分:1)
我能够将位图帧渲染到曲面以进行编码。 我使用MediaCodec + MediaMuxer使用InputSurface对位图帧进行编码,并使用OpenGL渲染位图。
看起来你所缺少的是用于渲染纹理的open gl命令
为了解决这个问题,我还添加了一些额外的open gl命令来使用顶点着色器渲染纹理。
渲染纹理的更多详细信息,请参阅此项目和util类在代码段中的GLUtils.texImage2D(..)之后,使用纹理句柄和适当的宽度和高度调用renderTexture(..)将修复所有位图渲染问题。
答案 2 :(得分:0)
请注意,原始STextureRender从SurfaceTexture渲染外部纹理。如果您希望它渲染纹理(从位图创建),您必须进行以下更改:
将目标参数GLES11Ext.GL_TEXTURE_EXTERNAL_OES
更改为GLES20.GL_TEXTURE_2D
将着色器定义"uniform samplerExternalOES sTexture;\n"
中的此行更改为“uniform sampler2D sTexture;\n”
从st.getTransformMatrix(mSTMatrix);
drawFrame
醇>
这个解决方案对我有用。