简单地解释一下安卓的SurfaceView和TextureView:

  • SurfaceView是一个可以在子线程中更新UI的View,它有自己的Surface,也就是一块绘图缓冲区,可以直接显示在屏幕上,不受视图层级的影响。SurfaceView适合用于高帧率的场景,如游戏或摄像头预览,但是它不支持动画或变形效果,也不能进行截图。
  • TextureView是一个可以像普通View一样进行平移、缩放、旋转等操作的View,它也有自己的SurfaceTexture,也就是一块可以转换为OpenGL ES外部纹理的图像流缓冲区。TextureView可以用于对图像流进行二次处理,如添加滤镜等,也可以进行截图,但是它需要开启硬件加速,而且相比SurfaceView有更高的内存和耗电消耗。
  • SurfaceView和TextureView都可以用于播放视频或渲染动画,具体选择哪个要根据需求和性能考虑。一般来说,如果需要高性能和低延迟,可以选择SurfaceView;如果需要更多的视图特性和图像处理能力,可以选择TextureView。

SurfaceView或TextureView渲染视频的基本流程

SurfaceView或TextureView播放视频和渲染动画的流程大致如下:

  • 首先,需要创建一个SurfaceView或TextureView的实例,并添加到布局中,设置好宽高和位置等属性。
  • 然后,需要获取SurfaceView或TextureView的SurfaceHolder或SurfaceTexture,这是一个用于管理绘图缓冲区的对象,可以通过getHolder()或getSurfaceTexture()方法获取。
  • 接着,需要创建一个MediaPlayer的实例,并设置好数据源,如视频文件的路径或网络地址。MediaPlayer是一个用于控制音视频播放的对象,可以通过setDataSource()方法设置数据源。
  • 接下来,需要将MediaPlayer和SurfaceHolder或SurfaceTexture关联起来,这样MediaPlayer就可以将视频帧绘制到SurfaceView或TextureView上。可以通过setDisplay()或setSurface()方法实现关联。
  • 最后,需要调用MediaPlayer的prepare()或prepareAsync()方法准备播放,并在准备完成后调用start()方法开始播放。可以通过setOnPreparedListener()方法设置一个监听器,在准备完成时回调。

渲染动画的流程和播放视频类似,只是不需要使用MediaPlayer,而是使用自己的绘制逻辑,在子线程中不断地更新SurfaceView或TextureView的内容。具体的绘制逻辑可以根据需求自定义,例如使用Canvas或OpenGL ES等。

自定义绘制逻辑

如果你想自定义绘制逻辑,可以使用OpenGL ES或者Canvas等技术来对视频帧进行处理,例如添加滤镜、水印、动画等效果。可以在SurfaceView或TextureView的绘制线程中实现你的绘制逻辑,或者使用自定义的渲染器类来封装绘制逻辑。

使用TextureView渲染视频并将视频从中间分开,左右两部分叠加在一起绘制的示例代码:

//创建一个TextureView
TextureView textureView = new TextureView(this);
//设置SurfaceTextureListener
textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        //创建一个MediaPlayer
        MediaPlayer mediaPlayer = new MediaPlayer();
        //设置数据源为视频文件的路径或网络地址
        mediaPlayer.setDataSource(videoPath);
        //设置SurfaceTexture
        mediaPlayer.setSurface(new Surface(surface));
        //准备播放
        mediaPlayer.prepareAsync();
        //设置OnPreparedListener
        mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                //开始播放
                mp.start();
            }
        });
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        //获取当前帧的Bitmap
        Bitmap bitmap = textureView.getBitmap();
        //将Bitmap从中间分开,左右两部分叠加在一起绘制
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint();
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
        canvas.drawBitmap(bitmap, 0, 0, paint);
        canvas.drawBitmap(bitmap, -bitmap.getWidth() / 2, 0, paint);
        //将处理后的Bitmap显示在TextureView上
        textureView.draw(canvas);
    }
});