Java 如何在android中录制视频时绘制视频,并保存视频和图形?

Java 如何在android中录制视频时绘制视频,并保存视频和图形?,java,android,drawing,opengl-es-2.0,camera2,Java,Android,Drawing,Opengl Es 2.0,Camera2,我正在尝试开发一个应用程序,允许我在录制视频时绘制视频,然后将录制的视频和视频保存在一个mp4文件中供以后使用。另外,我想使用camera2库,特别是我需要我的应用程序在高于API 21的设备上运行,我总是避免使用不推荐的库 我尝试了很多方法,包括FFmpeg,在其中我放置了TextureView.getBitmap()的叠加(来自摄影机)和从画布上获取的位图。它工作正常,但由于它的功能很慢,视频无法捕捉到足够的帧(甚至不到25 fps),而且运行速度很快。我希望音频也包括在内 我考虑过Medi

我正在尝试开发一个应用程序,允许我在录制视频时绘制视频,然后将录制的视频和视频保存在一个mp4文件中供以后使用。另外,我想使用camera2库,特别是我需要我的应用程序在高于API 21的设备上运行,我总是避免使用不推荐的库

我尝试了很多方法,包括FFmpeg,在其中我放置了TextureView.getBitmap()的叠加(来自摄影机)和从画布上获取的位图。它工作正常,但由于它的功能很慢,视频无法捕捉到足够的帧(甚至不到25 fps),而且运行速度很快。我希望音频也包括在内

我考虑过MediaProjection库,但我不确定它是否能够捕获包含摄像头和图形的布局,因为应用程序用户可能会在视频中添加文本,我不希望键盘出现

请帮忙,这已经是一周的研究了,我没有发现任何对我有用的东西

附言:如果在用户按下“停止录制”按钮后包含一点处理时间,我没有问题

编辑:

现在在Eddy的回答之后,我正在使用shadercam应用程序在相机表面绘制,因为该应用程序会进行视频渲染,解决方法是将我的画布渲染为位图,然后再渲染为GL纹理,但是我无法成功地完成。我需要你们的帮助,伙计们,我需要完成应用程序:S

我正在使用shadercam库(),并用以下代码替换了“ExampleRenderer”文件:

public class WriteDrawRenderer extends CameraRenderer
{
    private float offsetR = 1f;
    private float offsetG = 1f;
    private float offsetB = 1f;

    private float touchX = 1000000000;
    private float touchY = 1000000000;

    private  Bitmap textBitmap;

    private int textureId;

    private boolean isFirstTime = true;

    //creates a new canvas that will draw into a bitmap instead of rendering into the screen
    private Canvas bitmapCanvas;

    /**
     * By not modifying anything, our default shaders will be used in the assets folder of shadercam.
     *
     * Base all shaders off those, since there are some default uniforms/textures that will
     * be passed every time for the camera coordinates and texture coordinates
     */
    public WriteDrawRenderer(Context context, SurfaceTexture previewSurface, int width, int height)
    {
        super(context, previewSurface, width, height, "touchcolor.frag.glsl", "touchcolor.vert.glsl");
        //other setup if need be done here


    }

    /**
     * we override {@link #setUniformsAndAttribs()} and make sure to call the super so we can add
     * our own uniforms to our shaders here. CameraRenderer handles the rest for us automatically
     */
    @Override
    protected void setUniformsAndAttribs()
    {
        super.setUniformsAndAttribs();

        int offsetRLoc = GLES20.glGetUniformLocation(mCameraShaderProgram, "offsetR");
        int offsetGLoc = GLES20.glGetUniformLocation(mCameraShaderProgram, "offsetG");
        int offsetBLoc = GLES20.glGetUniformLocation(mCameraShaderProgram, "offsetB");

        GLES20.glUniform1f(offsetRLoc, offsetR);
        GLES20.glUniform1f(offsetGLoc, offsetG);
        GLES20.glUniform1f(offsetBLoc, offsetB);

        if (touchX < 1000000000 && touchY < 1000000000)
        {
            //creates a Paint object
            Paint yellowPaint = new Paint();
            //makes it yellow
            yellowPaint.setColor(Color.YELLOW);
            //sets the anti-aliasing for texts
            yellowPaint.setAntiAlias(true);
            yellowPaint.setTextSize(70);

            if (isFirstTime)
            {
                textBitmap = Bitmap.createBitmap(mSurfaceWidth, mSurfaceHeight, Bitmap.Config.ARGB_8888);
                bitmapCanvas = new Canvas(textBitmap);
            }

            bitmapCanvas.drawText("Test Text", touchX, touchY, yellowPaint);

            if (isFirstTime)
            {
                textureId = addTexture(textBitmap, "textBitmap");
                isFirstTime = false;
            }
            else
            {
                updateTexture(textureId, textBitmap);
            }

            touchX = 1000000000;
            touchY = 1000000000;
        }
    }

    /**
     * take touch points on that textureview and turn them into multipliers for the color channels
     * of our shader, simple, yet effective way to illustrate how easy it is to integrate app
     * interaction into our glsl shaders
     * @param rawX raw x on screen
     * @param rawY raw y on screen
     */
    public void setTouchPoint(float rawX, float rawY)
    {
        this.touchX = rawX;
        this.touchY = rawY;
    }
}
公共类WriteDrawRenderer扩展了CameraRenderer
{
专用浮动补偿=1f;
私人浮动抵销=1f;
私人浮动抵销b=1f;
私有浮动触摸X=100000000;
私人浮动touchY=100000000;
私有位图文本位图;
私密信息交换;
私有布尔值isFirstTime=true;
//创建一个新画布,该画布将绘制到位图中,而不是渲染到屏幕中
私有画布位图画布;
/**
*通过不修改任何内容,默认着色器将在shadercam的资产文件夹中使用。
*
*基于所有着色器,因为有一些默认制服/纹理将
*对于摄影机坐标和纹理坐标,每次都要传递
*/
公共WriteDrawRenderer(上下文上下文、SurfaceTexture previewSurface、整型宽度、整型高度)
{
super(上下文、预览表面、宽度、高度,“touchcolor.frag.glsl”、“touchcolor.vert.glsl”);
//如果需要,可在此处进行其他设置
}
/**
*我们重写{@link#setuniformsanadtribs()},并确保调用super以便添加
*我们自己的制服交给我们的着色器。摄影师会自动为我们处理剩下的
*/
@凌驾
受保护的void setuniformsanadtribs()
{
super.setuniformsandtribs();
int offsetRLoc=GLES20.glGetUniformLocation(mCameraShaderProgram,“offsetR”);
int offsetGLoc=GLES20.glGetUniformLocation(mCameraShaderProgram,“offsetG”);
int offsetBLoc=GLES20.glGetUniformLocation(mCameraShaderProgram,“offsetB”);
GLES20.glUniform1f(offsetRLoc,offsetR);
GLES20.glUniform1f(offsetGLoc,offsetG);
GLES20.glUniform1f(offsetBLoc,offsetB);
如果(touchX<100000000&&touchY<100000000)
{
//创建绘制对象
油漆黄色油漆=新油漆();
//它是黄色的
黄色油漆。设置颜色(颜色。黄色);
//设置文本的抗锯齿
yellowPaint.setAntiAlias(真);
黄色涂料。setTextSize(70);
如果(是第一次)
{
textBitmap=Bitmap.createBitmap(mSurfaceWidth、mSurfaceHeight、Bitmap.Config.ARGB_8888);
bitmapCanvas=新画布(文本位图);
}
bitmapCanvas.drawText(“测试文本”、touchX、touchY、yellowPaint);
如果(是第一次)
{
textureId=addTexture(textBitmap,“textBitmap”);
isFirstTime=false;
}
其他的
{
updateTexture(textureId、textBitmap);
}
touchX=100000000;
touchY=100000000;
}
}
/**
*在该textureview上获取接触点,并将其转化为颜色通道的倍增器
*我们的着色器,简单,但有效的方式来说明它是多么容易集成应用程序
*与glsl着色器的交互
*@param rawX屏幕上的原始x
*@param rawY raw在屏幕上
*/
公共无效设置接触点(浮点rawX、浮点rawY)
{
this.touchX=rawX;
this.touchY=rawY;
}
}
请帮助大家,已经一个月了,我仍然坚持使用同一个应用程序,对opengl一无所知。两周后,我尝试将此项目用于我的应用程序,但视频中没有呈现任何内容


提前感谢!

这里有一个大概的提纲应该可以用,但这是一个相当大的工作量:

  • 设置android.media.MediaRecorder以录制视频和音频
  • 从MediaRecorder获取一个曲面并从中设置一个EGLImage(,android.opengl.EGLConfig,java.lang.Object,int[],int));您需要一个完整的OpenGL上下文和设置。然后,您需要将该EGLImage设置为渲染目标
  • 在该GL上下文中创建SurfaceTexture
  • 配置摄影机以将数据发送到该SurfaceTexture
  • 启动MediaRecorder
  • 在从摄影机接收的每个帧上,将用户绘制的图形转换为GL纹理,并合成摄影机纹理和用户图形
  • 最后,调用glSwapBuffers将合成帧发送到录像机

  • 为什么不在你的应用程序中设置两种模式呢。一个是记录在案的