写点什么

Android 技术分享| 超简单,给 Android WebRTC 增加美颜滤镜功能

发布于: 刚刚
  • 视频采集渲染流程分析


在增加滤镜功能之前,需要对 WebRTC 视频采集的流程有一定了解。


WebRTC 中定义了 VideoCapture 接口类,其中定义了相机的初始化,预览,停止预览销毁等操作。


实现类是 CameraCapture,并且封装了 Camera1Capture、Camera2Capture 两个子类,甚至还有屏幕共享。


WebRTC 中开始视频采集非常的简单:


val videoCapture = createVideoCapture()videoSource = videoCapture.isScreencast.let { factory.createVideoSource(it) }videoCapture.initialize(surfaceTextureHelper,applicationContext,videoSource?.capturerObserver)videoCapture.startCapture(480, 640, 30)
复制代码


这里主要看一下 VideoSource 类和 capturerObserver。


VideoSource 中有以下方法


@Override    public void onFrameCaptured(VideoFrame frame) {      final VideoProcessor.FrameAdaptationParameters parameters =          nativeAndroidVideoTrackSource.adaptFrame(frame);      synchronized (videoProcessorLock) {        if (videoProcessor != null) {          videoProcessor.onFrameCaptured(frame, parameters);          return;        }      }      VideoFrame adaptedFrame = VideoProcessor.applyFrameAdaptationParameters(frame, parameters);      if (adaptedFrame != null) {        nativeAndroidVideoTrackSource.onFrameCaptured(adaptedFrame);        adaptedFrame.release();      }    }
复制代码


采集到的视频帧数据会回调给 onFrameCaptured,在这里会做一下对视频的裁切缩放处理,并通过 nativeAndroidVideoTrackSource 传递给 Native 层。


重点是 VideoProcessor 对象,据查是在 2019 年 2 月新增的。VideoSource 里面有 setVideoProcessor 方法用于设置 VideoProcessor,在上面方法中可知,如果设置了 VideoProcessor,视频帧则走 VideoProcessor 的 onFrameCaptured,否则的话直接传入 Native。


用 VideoProcessor 来实现处理发送前的视频帧非常方便,我们先来看下 VideoProcessor 类。


public interface VideoProcessor extends CapturerObserver {  public static class FrameAdaptationParameters {   ...
public FrameAdaptationParameters(int cropX, int cropY, int cropWidth, int cropHeight, int scaleWidth, int scaleHeight, long timestampNs, boolean drop) { ... } }
default void onFrameCaptured(VideoFrame frame, FrameAdaptationParameters parameters) { VideoFrame adaptedFrame = applyFrameAdaptationParameters(frame, parameters); if (adaptedFrame != null) { onFrameCaptured(adaptedFrame); adaptedFrame.release(); } }.... }
复制代码


VideoSource 中调用的 onFrameCaptured(frame, parameters) 并非 CapturerObserver 的 onFrameCaptured,也就是暂时不会传入 Native 增,它在这个方法中也做了对 ViewFrame 的裁切缩放,之后再传入底层。


所以我们可以在这里实现对视频帧的美颜滤镜处理。


 class FilterProcessor : VideoProcessor{              private var videoSink:VideoSink               override fun onCapturerStarted(success: Boolean) {        }
override fun onCapturerStopped() { }
override fun onFrameCaptured(frame: VideoFrame?) { val newFrame = // TODO: 在这对VideoFrame进行视频滤镜美颜处理 sink.onFrame(newFrame) }
override fun setSink(sink: VideoSink?) { //设置视频接收器 用来渲染并将frame传入Native videoSink = sink } }
val videoCapture = createVideoCapture()videoSource = videoCapture.isScreencast.let { factory.createVideoSource(it) }videoSource.setVideoProcessor(FilterProcessor())//设置处理器videoCapture.initialize(surfaceTextureHelper,applicationContext,videoSource?.capturerObserver)videoCapture.startCapture(480, 640, 30)
复制代码


美颜的话可以用 GPUImage,也可以用商用 SDK。


以上是在应用层的实现,利用 WebRTC 自带的类就行。如果是 NDK 开发,道理也是一样的。


创建一个代理类 CapturerObserverProxy 实现 CapturerObserver,并将真正的 nativeCapturerObserver 传进来,Native 会回调视频帧数据给 CapturerObserverProxy 的 onFrameCaptured,然后在 onFrameCaptured 中对视频进行美颜滤镜处理,再将处理好的 VideoFrame 用 nativeCapturerObserver 传给底层编码传输。


public class CapturerObserverProxy implements CapturerObserver {    public static final String TAG = CapturerObserverProxy.class.getSimpleName();
private CapturerObserver originalObserver; private RTCVideoEffector videoEffector;
public CapturerObserverProxy(final SurfaceTextureHelper surfaceTextureHelper, CapturerObserver observer, RTCVideoEffector effector) {
this.originalObserver = observer; this.videoEffector = effector;
final Handler handler = surfaceTextureHelper.getHandler(); ThreadUtils.invokeAtFrontUninterruptibly(handler, () -> videoEffector.init(surfaceTextureHelper) ); }
@Override public void onCapturerStarted(boolean success) { this.originalObserver.onCapturerStarted(success); }
@Override public void onCapturerStopped() { this.originalObserver.onCapturerStopped(); }
@Override public void onFrameCaptured(VideoFrame frame) { if (this.videoEffector.needToProcessFrame()) { VideoFrame.I420Buffer originalI420Buffer = frame.getBuffer().toI420(); VideoFrame.I420Buffer effectedI420Buffer = this.videoEffector.processByteBufferFrame( originalI420Buffer, frame.getRotation(), frame.getTimestampNs());
VideoFrame effectedVideoFrame = new VideoFrame( effectedI420Buffer, frame.getRotation(), frame.getTimestampNs()); originalI420Buffer.release(); this.originalObserver.onFrameCaptured(effectedVideoFrame); } else { this.originalObserver.onFrameCaptured(frame); } }}
videoCapturer.initialize(videoCapturerSurfaceTextureHelper, context, observerProxy);
复制代码


以上就是给 WebRTC 增加美颜功能的实现~

发布于: 刚刚阅读数: 2
用户头像

实时交互,万物互联! 2020.08.10 加入

实时交互,万物互联,全球实时互动云服务商领跑者!

评论

发布
暂无评论
Android技术分享| 超简单,给 Android WebRTC增加美颜滤镜功能