将位图帧渲染到Surface以进行编码

时间:2014-06-28 19:21:23

标签: android opengl-es mediacodec

我的目标是接收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),所以这应该只需要几秒钟。

3 个答案:

答案 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命令来使用顶点着色器渲染纹理。

有关使用open gl https://github.com/rsri/Pic2Fro/blob/b4fe69b44343dab2515c3fd6e769f3370bf31312/app/src/main/java/com/pic2fro/pic2fro/util/Util.java

渲染纹理的更多详细信息,请参阅此项目和util类

在代码段中的GLUtils.texImage2D(..)之后,使用纹理句柄和适当的宽度和高度调用renderTexture(..)将修复所有位图渲染问题。

另见我的相关答案 https://stackoverflow.com/a/49331295/7602598

答案 2 :(得分:0)

请注意,原始STextureRender从SurfaceTexture渲染外部纹理。如果您希望它渲染纹理(从位图创建),您必须进行以下更改:

  1. 将目标参数GLES11Ext.GL_TEXTURE_EXTERNAL_OES更改为GLES20.GL_TEXTURE_2D

  2. 将着色器定义"uniform samplerExternalOES sTexture;\n"中的此行更改为“uniform sampler2D sTexture;\n”

  3. st.getTransformMatrix(mSTMatrix);

  4. 中移除drawFrame

    这个解决方案对我有用。