使用renderscript进行处理,使用mediacodec进行编码

Phy*_*xle 6 android renderscript mediacodec

我正在尝试开发一个在录制视频之前进行一些视频处理的相机应用程序.我决定使用Rendrscript进行处理,因为它提供了我想要使用的许多操作.我想使用MediaCodec进行编码.我找到了一些样本(包括Grafika),展示了如何使用GLES进行处理,但我还没有找到一个示例,说明如何使用RenderScript.尝试用Renderscript替换GLES我有以下问题:

  1. 我从编码器输入表面创建RenderScript输出分配.在Grafika示例中,EGL swapbuffer()用于向编码器发送缓冲区.Allocation.ioSend()是否做同样的事情?
  2. 在EGL中,setPresentationTime()用于设置时间戳.如何在Renderscript的分配中设置时间戳?
  3. 我应该使用MediaCodec.queueInputBuffer()代替提交输入缓冲区和时间戳吗?在那种情况下,我应该在调用queueInputBuffer之前调用Allocation.ioSend()吗?

Pet*_*ran 1

我遇到了同样的问题,我使用的解决方案是通过 EGL 设置时间戳,类似于RecordFBOActivity#doFrame。为了做到这一点,使用中间分配来弥合 RenderScript 和 OpenGL/EGL 之间的差距。

让我们将数据流视为具有阶段的处理管道。

原始管道

[Camera]
   --> [ImageAllocation]
       --> [RenderScript]
           --> [MediaCodecSurfaceAllocationForEncoder]
               --> [MediaCodec]
Run Code Online (Sandbox Code Playgroud)

在原始管道中,所有缓冲区都是 RS 分配。

MediaCodecSurfaceAllocation基于从编码器返回的 Surface,即MediaCodec#getSurface().

新管道

[Camera]
    --> [ImageAllocation]
        --> [RenderScript]
            --> [IntermediateAllocation]
                --> [EglWindowSurfaceForEncoder]
                    --> [MediaCodec]
Run Code Online (Sandbox Code Playgroud)

新管道有两大变化IntermediateAllocationEglWindowSurfaceForEncoder

IntermediateAllocation是一个基于 SurfaceTexture 的 Allocation,类似于CameraCaptureActivity中使用的全屏纹理 blitter 。

EglWindowSurfaceForEncoder包裹编码器的输入表面,类似于RecordFBOActivity#startEncoder

这里的关键是设置你自己的OnFrameAvailableListener

设置代码

void setup() {
    mEglWindowSurfaceForEncoder= new WindowSurface(mEglCore, encoderCore.getInputSurface(), true);

    mFullScreen = new FullFrameRect(
            new Texture2dProgram(Texture2dProgram.ProgramType.TEXTURE_EXT));
    mTextureId = mFullScreen.createTextureObject();
    mSurfaceTexture = new SurfaceTexture(mTextureId);    

    Type renderType = new Type.Builder(renderScript, Element.RGBA_8888(renderScript))
        .setX(width)
        .setY(height)
        .create();

    mIntermediateAllocation = Allocation.createTyped(
        renderScript,
        renderType,
                                                               Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_OUTPUT);

    mIntermediateAllocation .setSurface(surface);

    mAllocationFromCamera = ...
}
Run Code Online (Sandbox Code Playgroud)

在新相机图像上

mIntermediateAllocation.copyFrom(mAllocationFromCamera);
Run Code Online (Sandbox Code Playgroud)

OnFrame可用监听器

mSurfaceTexture.setOnFrameAvailableListener(
    new SurfaceTexture.OnFrameAvailableListener() {
        public void onFrameAvailableListener(SurfaceTexture) {

             //latch the image data from camera
             mSurfaceTexture.updateTexImage();

             // Draw the frame.
             mSurfaceTexture.getTransformMatrix(mSTMatrix);
             mFullScreen.drawFrame(mTextureId, mSTMatrix);

             // latch frame to encoder input
             mEglWindowSurfaceForEncoder.setPresentationTimes(timestampNanos);
             mEglWindowSurfaceForEncoder.swapBuffers();

        }        
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码必须在EGL上下文中运行(即在OpenGL渲染线程上)。