在上一篇文章 WebRTC 开发(五)编译与运行 Mac 工程 中,我们编译了 WebRTC 的工程 AppRTCMobile,也看到了 App 启动后的初始界面。本文基于 WebRTC M76 ,将通过展示两人加入视频会议的 App 界面来分析视频画面的渲染流程。

不管是远端还是本地的用户的视频画面渲染,我们可以将网络或本地的一些预处理看成一个盒子或者模块,我们可以从盒子或模块中不断的取出视频帧,然后通过 cpu 或 gpu 的处理将视频帧,也就是一张图片呈现到显示器上。WebRTC 的视频帧处理逻辑以及渲染逻辑是怎样的呢?这需要通过阅读代码来理清楚流程。

在分析问题之前,我先展示下 WebRTC 的 AppRTCMobile 的视频会议演示效果,如下图所示:

视频会议中我使用的是两台 Macbook Pro,其中:(1)小窗口画面是本地用户,对应的是15寸 Mac;(2)大窗口画面是远端用户,对应的是13寸 Mac。对应的设备参数如下:

如果只有一台 Mac 机器,那该怎么测试两人加会效果呢?可以使用 WebRTC Web 版:https://appr.tc 加入会议。

摄像头采集

1

2RTCCameraVideoCapturer.h RTCCameraVideoCapturer.m

RTCFileVideoCapturer.h RTCFileVideoCapturer.m

视频渲染

1

2

3

4

5

6

7

8

9# metal

RTCMTLVideoView.h RTCMTLVideoView.m

RTCMTLNSVideoView.h RTCMTLNSVideoView.m

RTCMTLRenderer.h RTCMTLRenderer.mm

RTCMTLRenderer+Private.h

RTCMTLRGBRenderer.h RTCMTLRGBRenderer.mm

RTCMTLNV12Renderer.h RTCMTLNV12Renderer.mm

RTCMTLI420Renderer.h RTCMTLI420Renderer.mm

1

2

3

4

5

6

7

8

9

10# opengl

RTCNSGLVideoView.h RTCNSGLVideoView.m

RTCEAGLVideoView.h RTCEAGLVideoView.m

RTCOpenGLDefines.h RTCVideoViewShading.h

RTCDefaultShader.h RTCDefaultShader.mm

RTCShader.h RTCShader.mm

RTCNV12TextureCache.h RTCNV12TextureCache.m

RTCI420TextureCache.h RTCI420TextureCache.mm

RTCDisplayLinkTimer.h RTCDisplayLinkTimer.m

视频渲染方式有两种,分别为 Metal,OpenGL。

工程 AppRTCMobile 首选的渲染方式为 Metal,当硬件设备不支持 Metal 时,就使用 OpenGL。

采集渲染流程

摄像头采集和渲染逻辑的函数调用如下图:

从图中可以看出,视频的渲染方式为 Metal。

使用 OpenGL 渲染视频

当硬件设备支持 Metal 时,工程 AppRTCMobile 启用的是 Metal,但是我们想使用 OpenGL 来渲染视频,该怎么设置呢?

1

2

3APPRTCAppDelegate.h APPRTCAppDelegate.m

APPRTCViewController.h APPRTCViewController.m

Info.plist main.m

查看文件 APPRTCViewController.m 中的方法 - (void)setupViews

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59- (void)setupViews {

NSParameterAssert([[self subviews] count] == 0);

_logView = [[NSTextView alloc] initWithFrame:NSZeroRect];

[_logView setMinSize:NSMakeSize(0, kBottomViewHeight)];

[_logView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];

[_logView setVerticallyResizable:YES];

[_logView setAutoresizingMask:NSViewWidthSizable];

NSTextContainer* textContainer = [_logView textContainer];

NSSize containerSize = NSMakeSize(kContentWidth, FLT_MAX);

[textContainer setContainerSize:containerSize];

[textContainer setWidthTracksTextView:YES];

[_logView setEditable:NO];

[self setupActionItemsView];

_scrollView = [[NSScrollView alloc] initWithFrame:NSZeroRect];

[_scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];

[_scrollView setHasVerticalScroller:YES];

[_scrollView setDocumentView:_logView];

[self addSubview:_scrollView];

// NOTE (daniela): Ignoring Clang diagonstic here.

// We're performing run time check to make sure class is available on runtime.

// If not we're providing sensible default.

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Wpartial-availability"

if ([RTCMTLNSVideoView class] && [RTCMTLNSVideoView isMetalAvailable]) {

_remoteVideoView = [[RTCMTLNSVideoView alloc] initWithFrame:NSZeroRect];

_localVideoView = [[RTCMTLNSVideoView alloc] initWithFrame:NSZeroRect];

}

#pragma clang diagnostic pop

if (_remoteVideoView == nil) {

NSOpenGLPixelFormatAttribute attributes[] = {

NSOpenGLPFADoubleBuffer,

NSOpenGLPFADepthSize, 24,

NSOpenGLPFAOpenGLProfile,

NSOpenGLProfileVersion3_2Core,

0

};

NSOpenGLPixelFormat* pixelFormat =

[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];

RTCNSGLVideoView* remote =

[[RTCNSGLVideoView alloc] initWithFrame:NSZeroRect pixelFormat:pixelFormat];

remote.delegate = self;

_remoteVideoView = remote;

RTCNSGLVideoView* local =

[[RTCNSGLVideoView alloc] initWithFrame:NSZeroRect pixelFormat:pixelFormat];

local.delegate = self;

_localVideoView = local;

}

[_remoteVideoView setTranslatesAutoresizingMaskIntoConstraints:NO];

[self addSubview:_remoteVideoView];

[_localVideoView setTranslatesAutoresizingMaskIntoConstraints:NO];

[self addSubview:_localVideoView];

}

将其中的代码段注释掉,就可以启用 OpenGL 来渲染视频了

1

2

3

4

5

6

7

8

9

10

11if ([RTCMTLNSVideoView class] && [RTCMTLNSVideoView isMetalAvailable]) {

_remoteVideoView = [[RTCMTLNSVideoView alloc] initWithFrame:NSZeroRect];

_localVideoView = [[RTCMTLNSVideoView alloc] initWithFrame:NSZeroRect];

}

改为

// if ([RTCMTLNSVideoView class] && [RTCMTLNSVideoView isMetalAvailable]) {

// _remoteVideoView = [[RTCMTLNSVideoView alloc] initWithFrame:NSZeroRect];

// _localVideoView = [[RTCMTLNSVideoView alloc] initWithFrame:NSZeroRect];

// }

摄像头采集和 OpenGL 渲染视频的流程如下图:

webrtc 渲染_WebRTC 开发(六)摄像头采集与视频渲染分析相关推荐

  1. Linux SD卡驱动开发(六) —— SD卡启动过程总体分析

    一.工作流程 mmc驱动主要文件包括 drivers/mmc/card/block.c drivers/mmc/card/queue.c drivers/mmc/core/core.c drivers ...

  2. 基于FFMPEG采集摄像头图像编码MP4视频+时间水印

    1.硬件平台 操作系统:Ubuntu18.04 ffmpeg版本:ffmpeg4.2.5 摄像头:电脑自带或USB免驱摄像头 水印处理:avfilter 图像渲染:SDL库   摄像头图像采集+MP4 ...

  3. 百家号基于AE的视频渲染技术探索

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nm0WWHSi-1657593629762)(https://p3-juejin.byteimg.com/tos-cn- ...

  4. ADI Blackfin DSP处理器-BF533的开发详解52:图像处理专题-CMOS摄像头采集图像(含源码)

    硬件准备 ADSP-EDU-BF533:BF533开发板 AD-HP530ICE:ADI DSP仿真器 软件准备 Visual DSP++软件 硬件链接 功能介绍 板卡上设计了一个摄像头接口,可以连接 ...

  5. iOS音视频开发十三:视频渲染,用 Metal 渲染

    本系列文章通过拆解采集 → 编码 → 封装 → 解封装 → 解码 → 渲染流程并实现 Demo 来向大家介绍如何在 iOS/Android 平台上手音视频开发. 这里是第十三篇:iOS 视频渲染 De ...

  6. FFmpeg入门详解之122:Qt5 FFmpeg本地摄像头采集预览实战

    6.Qt5+FFmpeg本地摄像头采集预览实战 源码工程:S26_Test2 FFmpeg命令行处理摄像头 ffmpeg -list_devices true -f dshow -i dummy 命令 ...

  7. OCulus Rift 游戏开发六原则

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/46685477 作者:car ...

  8. Metal之实现视频采集与实时渲染

    一.视频渲染实现思路 ① 思路说明 通过AVFoundation进行视频数据的采集,并将采集到的原始数据存储到CMSampleBufferRef中,即视频帧数据(视频帧其实本质也是一张图片). 通过C ...

  9. ffmpeg实现摄像头拉流_利用ffmpeg一步一步编程实现摄像头采集编码推流直播系统...

    了解过ffmpeg的人都知道,利用ffmpeg命令即可实现将电脑中摄像头的画面发布出去,例如发布为UDP,RTP,RTMP等,甚至可以发布为HLS,将m3u8文件和视频ts片段保存至Web服务器,普通 ...

最新文章

  1. C++ string字符串的比较是否相等
  2. mysql-5.7.20实用下载、安装和配置方法,以及简单操作
  3. redis入门demo
  4. Android Studio的Gradle插件文档
  5. 如何找出SAP Fiori launchpad URL start_up请求发起的具体位置
  6. ATM + 购物商城程序
  7. 单片机蜂鸣器编程音乐_基于单片机的智能鱼缸温控系统设计
  8. 使用SQLDMO中“接口SQLDMO.Namelist 的 QueryInterface 失败”异常的解决方法
  9. verilog 中if....else语句以及case语句详细理解
  10. JavaScript学习指南(非常详细)
  11. 【行业专题报告】 汽车、二手车-专题资料
  12. cxonev4验证用户_欧姆龙编程组态软件Omron CX-ONE V4.50 简体中文版
  13. MES系统生产派工提高注塑行业生产效率
  14. 根据表一和表二写出查询结果如表三的sql语句
  15. python文件双击闪退_解决python文件双击运行秒退的问题
  16. 小米计算机弹歌曲,趣味冷知识!小米的T9拨号键盘可以弹乐曲,没想到吧!快来试试!...
  17. 深度学习基础 - 概率的三个公理
  18. Pohlig-Hellman算法解决DLP问题
  19. arr的push,pop,slice.....各种使用方法详细介绍
  20. 什么是绿色工厂?什么企业可以申报绿色工厂?

热门文章

  1. eclipse中要让一个 Java 源文件打开时编码格式为 UTF-8
  2. 剑指offer面试题58 - I. 翻转单词顺序(双指针)
  3. 英语语法基础篇-foundation
  4. OCR之Tesseract使用
  5. 避免unicode字符被截断的方法
  6. 怎样查找某个sp中哪条sql语句存在性能问题。
  7. atitit 提升数据库死锁处理总结
  8. Geek必备神器 - Google眼镜(Google glass)的十大特色
  9. VC 使用 MinGW编写的dll
  10. Bailian3860 Bailian3724 unix纪元【日期时间】