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

Posted

技术标签:

【中文标题】在android中录制视频时如何在视频上绘图,并保存视频和绘图?【英文标题】:How can I draw on a video while recording it in android, and save the video and the drawing? 【发布时间】:2017-03-04 16:02:33 【问题描述】:

我正在尝试开发一款应用程序,该应用程序允许我在录制视频时对其进行绘图,然后将录制文件和视频保存在一个 mp4 文件中以供以后使用。此外,我想使用 camera2 库,特别是我需要我的应用程序在高于 API 21 的设备上运行,而且我总是避免使用已弃用的库。

我尝试了很多方法来做到这一点,包括 FFmpeg,我在其中放置了 TextureView.getBitmap()(来自相机)的叠加层和从画布上获取的位图。它有效,但由于它是一个慢速功能,视频无法捕捉到足够的帧(甚至 25 fps),而且运行速度非常快。我也希望包含音频。

我考虑了 MediaProjection 库,但我不确定它是否可以仅在其 VirtualDisplay 内捕获包含相机和绘图的布局,因为应用程序用户也可以在视频上添加文本,而我没有想要键盘出现。

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

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

已编辑:

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

我正在使用 shadercam 库 (https://github.com/googlecreativelab/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;
    

请帮助大家,已经一个月了,我仍然坚持使用同一个应用程序 :( 并且不知道 opengl。两周后,我正在尝试将这个项目用于我的应用程序,但没有呈现任何内容视频。

提前致谢!

【问题讨论】:

为什么不在您的应用程序中设置两种模式。一个只用于录制,第二个选项允许用户在之后添加绘图,基本上是一个带有时间线的视频编辑器,以及在特定时间段内添加文本、位图等选项,完成后,您可以通过 ffmpeg 生成输出视频...跨度> 上面的评论是关于效率的,你说 FFmpeg 太慢了,无法捕捉所有帧,同时还要处理图纸的覆盖等 两种模式的应用程序不是我想要的,无论如何谢谢 【参考方案1】:

这里有一个粗略的大纲,应该可行,但需要做很多工作:

    设置 android.media.MediaRecorder 用于录制视频和音频 从 MediaRecorder 获取一个 Surface 并从中设置一个 EGLImage (https://developer.android.com/reference/android/opengl/EGL14.html#eglCreateWindowSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.lang.Object, int[], int) );您将需要一个完整的 OpenGL 上下文并为此进行设置。然后,您需要将该 EGLImage 设置为您的渲染目标。 在该 GL 上下文中创建 SurfaceTexture。 将相机配置为向该 SurfaceTexture 发送数据 启动 MediaRecorder 在从相机接收到的每一帧上,将用户完成的绘图转换为 GL 纹理,并将相机纹理和用户绘图合成。 最后调用glSwapBuffers将合成帧发送到录像机

【讨论】:

感谢您的回答,但如果您能详细说明一下,我是相机 API 的新手,尤其是媒体记录器,我对 GL 完全一无所知,无法直接找到既不在这里也不在谷歌上转发它。我正在为相机使用纹理视图,因为这是谷歌推荐用于我的 API 版本的,这适用于 open GL 吗?我应该做什么以及如何做,以及如何设置 MediaRecorder 以从 OpenGL 获取帧。至少我需要一些外部链接来启发我的方式。非常感谢:D 对不起,但我不知道完整的示例,我写一个简单的示例代码太多了。 github.com/yulu/ShaderCam 涵盖将相机数据渲染到屏幕上; ***.com/questions/16274569/… 有从 GL 到视频录制的链接。在这两者之间,您需要将用户绘图合成到相机数据上。

以上是关于在android中录制视频时如何在视频上绘图,并保存视频和绘图?的主要内容,如果未能解决你的问题,请参考以下文章

在 Android 上录制视频时添加叠加层

在 android 的视频视图中播放视频时不录制语音

在 Android 上录制视频时拍照

如何在我的 Android 应用中录制视频?

如何从我的 Android 设备直接在 Helix 服务器上录制视频?

如何在android上使用ffmpeg录制视频?