├── .github ├── actions │ ├── combine_library │ │ └── action.yml │ └── tar_headers │ │ └── action.yml └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── build_for_mac.sh ├── build_for_win.bat ├── doc ├── image │ ├── IceCandidate.jpg │ ├── MessageQueue.png │ ├── PhysicalSocketServer-Wait.png │ ├── WSAWaitForMultipleEvents.png │ ├── control-sdp.png │ ├── kurento.png │ ├── licode-ppt-1.png │ ├── licode-ppt-2.png │ ├── licode-ppt-3.png │ ├── licode-ppt-4.png │ ├── licode-ppt-5.png │ ├── licode-ppt-6.png │ ├── licode-ppt-7.png │ ├── licode-ppt-8.png │ ├── licode.png │ ├── mediasoup.png │ ├── pc1.jpg │ ├── peerconnection.jpg │ ├── peerinterface.png │ ├── plana-sdp.png │ ├── plana.png │ ├── planb-sdp.png │ ├── planb.png │ ├── rtc-thread.png │ ├── sdp.jpg │ ├── sfu-cascaded-person.png │ ├── sfu-cascaded-postion.png │ ├── sfu-cascaded.png │ ├── sfu-single-person.png │ ├── sfu-single-postion.png │ ├── sfu-single-postion2.png │ ├── sfu-single.png │ ├── transport.png │ ├── unifiedplan-sdp.png │ ├── webrtc-levels.png │ ├── webrtc-server-base.png │ ├── webrtc-server.png │ ├── webrtc-stack.png │ ├── webrtc-stack2.png │ ├── webrtc-stream-server-1.png │ ├── webrtc-stream-server-2.png │ ├── webrtc-stream-server-3.png │ ├── webrtc-stream-server-4.png │ ├── webrtc-stream-server-5.png │ ├── webrtc-stream-server-6.jpeg │ ├── webrtc-stun.png │ └── webrtc-turn.png ├── webrtc native学习:PeerConnection介绍.md ├── webrtc native学习:SDP与webrtc.md ├── webrtc native学习:index.md ├── webrtc native学习:peerconnection-server.md ├── webrtc native学习:webrtc.lib的编译.md ├── webrtc native学习:webrtc与sip.md ├── webrtc native学习:webrtc协议.md ├── webrtc native学习:webrtc服务器.md ├── webrtc native学习:webrtc目录结构说明.md ├── webrtc native学习:基于Licode的WebRTC全球分布式架构.md ├── webrtc native学习:基础概念.md ├── webrtc native学习:多线程一 Event.md ├── webrtc native学习:多线程三 MessageHandler.md ├── webrtc native学习:多线程二 Crticalsection.md ├── webrtc native学习:多线程五 PhysicalSocketServer.md ├── webrtc native学习:多线程六 Thread.md ├── webrtc native学习:多线程四 MessageQueue.md ├── webrtc native学习:流媒体服务器架构.md ├── 时序图 │ ├── pc1.vsdx │ └── peerconnection.vsdx └── 类图 │ └── thread.md ├── examples ├── DesktopCamera │ ├── DesktopCapturer.pro │ ├── Info.plist │ ├── main.cpp │ ├── readme.md │ ├── render │ │ ├── qyuvopenglwidget.cpp │ │ ├── qyuvopenglwidget.h │ │ └── render.pri │ ├── screenshot │ │ └── main.png │ ├── test │ │ ├── mac_capturer.h │ │ ├── mac_capturer.mm │ │ ├── platform_video_capturer.cc │ │ ├── platform_video_capturer.h │ │ ├── test.pri │ │ ├── test_video_capturer.cc │ │ ├── test_video_capturer.h │ │ ├── vcm_capturer.cc │ │ └── vcm_capturer.h │ ├── widget.cpp │ ├── widget.h │ └── widget.ui ├── DesktopCapturer │ ├── DesktopCapturer.pro │ ├── Info.plist │ ├── main.cpp │ ├── readme.md │ ├── render │ │ ├── qyuvopenglwidget.cpp │ │ ├── qyuvopenglwidget.h │ │ └── render.pri │ ├── screenshot │ │ └── main.png │ ├── widget.cpp │ ├── widget.h │ └── widget.ui ├── OpenCamera │ ├── Info.plist │ ├── OpenCamera.pro │ ├── main.cpp │ ├── render │ │ ├── qyuvopenglwidget.cpp │ │ ├── qyuvopenglwidget.h │ │ └── render.pri │ ├── test │ │ ├── mac_capturer.h │ │ ├── mac_capturer.mm │ │ ├── platform_video_capturer.cc │ │ ├── platform_video_capturer.h │ │ ├── test.pri │ │ ├── test_video_capturer.cc │ │ ├── test_video_capturer.h │ │ ├── vcm_capturer.cc │ │ └── vcm_capturer.h │ ├── widget.cpp │ ├── widget.h │ └── widget.ui ├── peerconnection │ ├── client │ │ ├── Info.plist │ │ ├── client.pro │ │ ├── conductor.cc │ │ ├── conductor.h │ │ ├── defaults.cc │ │ ├── defaults.h │ │ ├── main.cpp │ │ ├── main_wnd.cpp │ │ ├── main_wnd.h │ │ ├── mainwnd.ui │ │ ├── peer_connection_client.cc │ │ ├── peer_connection_client.h │ │ ├── render │ │ │ ├── qyuvopenglwidget.cpp │ │ │ ├── qyuvopenglwidget.h │ │ │ └── render.pri │ │ ├── test │ │ │ ├── mac_capturer.h │ │ │ ├── mac_capturer.mm │ │ │ ├── platform_video_capturer.cc │ │ │ ├── platform_video_capturer.h │ │ │ ├── test.pri │ │ │ ├── test_video_capturer.cc │ │ │ ├── test_video_capturer.h │ │ │ ├── vcm_capturer.cc │ │ │ └── vcm_capturer.h │ │ ├── videorenderer.cpp │ │ └── videorenderer.h │ ├── pc1 │ │ ├── Info.plist │ │ ├── main.cpp │ │ ├── pc1.pro │ │ ├── peerconnectiona.cpp │ │ ├── peerconnectiona.h │ │ ├── peerconnectionb.cpp │ │ ├── peerconnectionb.h │ │ ├── readme.md │ │ ├── render │ │ │ ├── qyuvopenglwidget.cpp │ │ │ ├── qyuvopenglwidget.h │ │ │ └── render.pri │ │ ├── screenshot │ │ │ └── main.jpg │ │ ├── simplepeerconnection.cpp │ │ ├── simplepeerconnection.h │ │ ├── test │ │ │ ├── mac_capturer.h │ │ │ ├── mac_capturer.mm │ │ │ ├── platform_video_capturer.cc │ │ │ ├── platform_video_capturer.h │ │ │ ├── test.pri │ │ │ ├── test_video_capturer.cc │ │ │ ├── test_video_capturer.h │ │ │ ├── vcm_capturer.cc │ │ │ └── vcm_capturer.h │ │ ├── videorenderer.cpp │ │ ├── videorenderer.h │ │ ├── widget.cpp │ │ ├── widget.h │ │ └── widget.ui │ └── remote │ │ ├── Info.plist │ │ ├── bufferutil.cpp │ │ ├── bufferutil.h │ │ ├── conductor.cc │ │ ├── conductor.h │ │ ├── controlmsg.cpp │ │ ├── controlmsg.h │ │ ├── defaults.cc │ │ ├── defaults.h │ │ ├── flag_defs.h │ │ ├── inputinject.cpp │ │ ├── inputinject.h │ │ ├── main.cpp │ │ ├── main_wnd.cpp │ │ ├── main_wnd.h │ │ ├── mainwnd.ui │ │ ├── peer_connection_client.cc │ │ ├── peer_connection_client.h │ │ ├── remote.pro │ │ ├── render │ │ ├── qyuvopenglwidget.cpp │ │ ├── qyuvopenglwidget.h │ │ └── render.pri │ │ ├── test │ │ ├── desktop_capturer.cc │ │ ├── desktop_capturer.h │ │ ├── mac_capturer.h │ │ ├── mac_capturer.mm │ │ ├── platform_video_capturer.cc │ │ ├── platform_video_capturer.h │ │ ├── test.pri │ │ ├── test_video_capturer.cc │ │ ├── test_video_capturer.h │ │ ├── vcm_capturer.cc │ │ └── vcm_capturer.h │ │ ├── videorenderer.cpp │ │ └── videorenderer.h └── webrtc_common │ └── webrtc_common.pri ├── gclient ├── script └── custom_webrtc.py ├── sync_for_mac.sh └── sync_for_win.bat /.github/actions/combine_library/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Combine libraries' 2 | description: 'Combine the WebRTC static libraries into one using platform specific tools.' 3 | inputs: 4 | platform: 5 | description: 'The platform we are building for (android, ios, linux, mac, win).' 6 | required: true 7 | builddir: 8 | description: 'The the ninja build path.' 9 | required: true 10 | allowlist: 11 | description: 'The libraries to copy objects from' 12 | required: true 13 | default: "webrtc boringssl protobuf_lite field_trial_default metrics_default" 14 | outputs: 15 | library: 16 | description: "Path to generated library." 17 | value: ${{ steps.combine.outputs.library }} 18 | runs: 19 | using: "composite" 20 | steps: 21 | - shell: bash 22 | working-directory: ${{ inputs.builddir }} 23 | id: combine 24 | run: | 25 | set -x 26 | 27 | # Detect library extension. 28 | platform=${{ inputs.platform }} 29 | libext="a" 30 | if [ "${platform}" = "win" ]; then 31 | libext="lib" 32 | fi 33 | libname=libwebrtc_full.${libext} 34 | 35 | # Library allowlist filter 36 | allowlist=$(echo ${{ inputs.allowlist }}\\.${libext} | sed "s/ /\\\\.${libext}|/g") 37 | 38 | LIBS=$(cat .ninja_log | tr '\t' '\n' | grep -E "^obj/" | grep -E $allowlist | sort -u) 39 | # Combine libraries based on platform-specific tools 40 | case $platform in 41 | win) 42 | echo $LIBS | tr ' ' '\n' >$libname.list 43 | # LIB.exe from Microsoft C++ Toolset 44 | lib.exe /OUT:$libname @$libname.list 45 | ;; 46 | mac|ios) 47 | # libtool from XCode Command line tools 48 | libtool -static -o $libname $LIBS 49 | ;; 50 | *) 51 | # GNU ar + runlib 52 | echo "CREATE $libname" >$libname.ar 53 | for lib in $LIBS 54 | do 55 | echo "ADDLIB $lib" >>$libname.ar 56 | done 57 | echo "SAVE" >>$libname.ar 58 | echo "END" >>$libname.ar 59 | ar -M < $libname.ar 60 | ranlib $libname 61 | ;; 62 | esac 63 | 64 | ls -l 65 | echo "::set-output name=library::${libname}" 66 | -------------------------------------------------------------------------------- /.github/actions/tar_headers/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Tar required WebRTC header files.' 2 | description: 'Tar required WebRTC header files to be used by your application.' 3 | inputs: 4 | srcdir: 5 | description: 'The source dir where the WebRTC library has been checked out.' 6 | required: true 7 | exclude: 8 | description: 'The paths to exclude from header copying' 9 | required: true 10 | default: out ios sdk examples test build buildtools third_party/blink third_party/llvm-build third_party/win_build_output third_party/android_ndk third_party/catapult third_party/googletest third_party/android_deps third_party/android_sdk third_party/crashpad third_party/perfetto third_party/hunspell third_party/icu third_party/khronos 11 | outputs: 12 | tarball: 13 | description: "Path to generated tarball." 14 | value: ${{ steps.tar-headers.outputs.tarball }} 15 | runs: 16 | using: "composite" 17 | steps: 18 | - shell: bash 19 | id: tar-headers 20 | working-directory: "${{ inputs.srcdir }}" 21 | run: | 22 | set -x 23 | 24 | for p in ${{ inputs.exclude }} 25 | do 26 | EXCLUDE="$EXCLUDE -path ./${p} -prune -o" 27 | done 28 | 29 | TAR_FILE=headers.tar 30 | find . $EXCLUDE -type f -a \( -name "*.h" -o -name LICENSE -o -name COPYING \) -print -exec tar -rf $TAR_FILE "{}" \; 31 | echo "::set-output name=tarball::${TAR_FILE}" 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | /webrtc 34 | /out 35 | /exampleout 36 | /depot_tools 37 | /.vs 38 | /.vscode 39 | *.user 40 | *.DS_Store 41 | .cipd/ 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [DesktopCapturer-image]: https://raw.githubusercontent.com/barry-ran/learn_webrtc/master/examples/DesktopCapturer/screenshot/main.png 2 | 3 | [pc1-image]: https://raw.githubusercontent.com/barry-ran/learn_webrtc/master/examples/peerconnection/pc1/screenshot/main.jpg 4 | 5 | # learn_webrtc 6 | 学习webrtc,基于webrtc native开发音视频工具 7 | 8 | # example展示 9 | ## 桌面捕获 10 | [![界面][DesktopCapturer-image]](https://github.com/barry-ran/learn_webrtc/tree/master/examples/DesktopCapturer) 11 | 12 | ## pc1 13 | [![界面][pc1-image]](https://github.com/barry-ran/learn_webrtc/tree/master/examples/peerconnection/pc1) 14 | 15 | # 环境要求 16 | - 可以科学上网(首要前提) 17 | - git 18 | 19 | ## mac 20 | xcode 21 | 22 | ## win 23 | - vs2019 C++开发环境(Windows 10 SDK(10.0.20348.0)) 24 | 25 | 也可以给安装包指定命令行参数来安装(vs.exe为vs安装包,在这里[下载](https://visualstudio.microsoft.com/zh-hans/downloads/)) 26 | ``` 27 | vs.exe --add Microsoft.VisualStudio.Workload.NativeDesktop --add Microsoft.VisualStudio.Component.VC.ATLMFC --add Microsoft.VisualStudio.Component.Windows10SDK.20348 --includeRecommended 28 | 29 | ``` 30 | 31 | 注意: 32 | - Windows 10 SDK建议最新版本 33 | - win10 sdk需要安装了Debugging Tools For Windows(必须的,编译要求),没有安装的话 34 | 35 | 进入 控制面板\程序\程序和功能,选择Windows Software Development Kit,右键更改,选择Change,勾选Debugging Tools For Windows,点击Change 36 | 37 | # 编译步骤 38 | ## win 39 | - 设置vs2019_install环境变量 40 | ``` 41 | set vs2019_install=D:\Program Files (x86)\Microsoft Visual Studio\2019\Community 42 | ``` 43 | - 执行syc_for_win.bat同步webrtc代码(开发过程只需同步一次即可) 44 | - 执行build_for_win.bat release编译 45 | 46 | # 参考文档 47 | - [webrtc官方编译说明](https://webrtc.github.io/webrtc-org/native-code/development/) 48 | - [chromium编译官方说明](https://chromium.googlesource.com/chromium/src/+/master/docs/windows_build_instructions.md) 49 | - [github actions编译webrtc](https://github.com/godotengine/webrtc-actions) 50 | - [释放github actions更多空间](https://github.com/easimon/maximize-build-space) 51 | - [ssh调试github actions](https://github.com/marketplace/actions/debugging-with-tmate) 52 | - [webrtc C++包装](https://github.com/webrtc-sdk/libwebrtc) 53 | 54 | 55 | -------------------------------------------------------------------------------- /build_for_mac.sh: -------------------------------------------------------------------------------- 1 | # 获取绝对路径,保证其他目录执行此脚本依然正确 2 | { 3 | cd $(dirname "$0") 4 | script_path=$(pwd) 5 | cd - 6 | } &> /dev/null # disable output 7 | 8 | # 设置当前目录,cd的目录影响接下来执行程序的工作目录 9 | old_cd=$(pwd) 10 | cd $(dirname "$0") 11 | 12 | # 启动参数声明 13 | debug_mode="false" 14 | 15 | echo 16 | echo 17 | echo --------------------------------------------------------------- 18 | echo 检查编译参数[debug/release] 19 | echo --------------------------------------------------------------- 20 | 21 | # 编译模式 22 | mode=$(echo $1 | tr '[:upper:]' '[:lower:]') 23 | if [[ $mode != "release" && $mode != "debug" ]]; then 24 | echo "waring: unkonow build mode -- $1, default debug" 25 | debug_mode="true" 26 | else 27 | # 编译模式赋值 28 | if [ $1 == "release" ]; then 29 | debug_mode="false" 30 | else 31 | debug_mode="true" 32 | fi 33 | fi 34 | 35 | # 提示 36 | if [ $debug_mode == "true" ]; then 37 | echo 当前编译版本为debug版本 38 | else 39 | echo 当前编译版本为release版本 40 | fi 41 | 42 | # 环境变量设置 43 | depot_tools_path=$script_path/depot_tools 44 | export PATH=$depot_tools_path:$PATH 45 | 46 | # 设置相关路径 47 | gn=gn 48 | ninja=autoninja 49 | dispatch_path=$script_path/out 50 | if [ $debug_mode == "true" ]; then 51 | dispatch_path=$script_path/out/debug 52 | else 53 | dispatch_path=$script_path/out/release 54 | fi 55 | 56 | # 进入webrtc目录 57 | cd webrtc/src 58 | 59 | echo 60 | echo 61 | echo --------------------------------------------------------------- 62 | echo gn生成ninja脚本 63 | echo --------------------------------------------------------------- 64 | 65 | # ninja file 66 | args=is_debug=$debug_mode 67 | args=$args" target_os=\"mac\"" 68 | args=$args" target_cpu=\"x64\"" 69 | 70 | # 开启H264编码支持 71 | args=$args" proprietary_codecs=true" 72 | args=$args" ffmpeg_branding=\"Chrome\"" 73 | 74 | # 必须要打开,否则报错SetSessionDescriptionObserver未定义 https://groups.google.com/forum/#!topic/discuss-webrtc/PniiO9BumHA 75 | args=$args" use_rtti=true" 76 | args=$args" treat_warnings_as_errors=false" 77 | args=$args" rtc_include_pulse_audio=false" 78 | args=$args" rtc_build_examples=true" 79 | args=$args" rtc_build_tools=false" 80 | args=$args" rtc_enable_protobuf=false" 81 | args=$args" rtc_include_tests=false" 82 | args=$args" enable_libaom=false" 83 | args=$args" enable_google_benchmarks=false" 84 | args=$args" libyuv_include_tests=false" 85 | args=$args" symbol_level=0" 86 | args=$args" strip_debug_info=true" 87 | 88 | args=$args" use_sysroot=false" 89 | args=$args" use_custom_libcxx=false" 90 | args=$args" use_custom_libcxx_for_host=false" 91 | 92 | $gn gen $dispatch_path --ide=xcode --args="$args" 93 | if [ $? != 0 ]; then 94 | echo "generate ninja failed" 95 | exit 1 96 | fi 97 | 98 | echo 99 | echo 100 | echo --------------------------------------------------------------- 101 | echo 开始ninja编译 102 | echo --------------------------------------------------------------- 103 | 104 | # build 105 | $ninja -C $dispatch_path 106 | if [ $? != 0 ]; then 107 | echo "ninja build failed" 108 | exit 1 109 | fi 110 | 111 | # 恢复当前目录 112 | cd $old_cd 113 | 114 | echo 115 | echo 116 | echo --------------------------------------------------------------- 117 | echo 完成! 118 | echo --------------------------------------------------------------- -------------------------------------------------------------------------------- /build_for_win.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/build_for_win.bat -------------------------------------------------------------------------------- /doc/image/IceCandidate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/IceCandidate.jpg -------------------------------------------------------------------------------- /doc/image/MessageQueue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/MessageQueue.png -------------------------------------------------------------------------------- /doc/image/PhysicalSocketServer-Wait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/PhysicalSocketServer-Wait.png -------------------------------------------------------------------------------- /doc/image/WSAWaitForMultipleEvents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/WSAWaitForMultipleEvents.png -------------------------------------------------------------------------------- /doc/image/control-sdp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/control-sdp.png -------------------------------------------------------------------------------- /doc/image/kurento.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/kurento.png -------------------------------------------------------------------------------- /doc/image/licode-ppt-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/licode-ppt-1.png -------------------------------------------------------------------------------- /doc/image/licode-ppt-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/licode-ppt-2.png -------------------------------------------------------------------------------- /doc/image/licode-ppt-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/licode-ppt-3.png -------------------------------------------------------------------------------- /doc/image/licode-ppt-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/licode-ppt-4.png -------------------------------------------------------------------------------- /doc/image/licode-ppt-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/licode-ppt-5.png -------------------------------------------------------------------------------- /doc/image/licode-ppt-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/licode-ppt-6.png -------------------------------------------------------------------------------- /doc/image/licode-ppt-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/licode-ppt-7.png -------------------------------------------------------------------------------- /doc/image/licode-ppt-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/licode-ppt-8.png -------------------------------------------------------------------------------- /doc/image/licode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/licode.png -------------------------------------------------------------------------------- /doc/image/mediasoup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/mediasoup.png -------------------------------------------------------------------------------- /doc/image/pc1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/pc1.jpg -------------------------------------------------------------------------------- /doc/image/peerconnection.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/peerconnection.jpg -------------------------------------------------------------------------------- /doc/image/peerinterface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/peerinterface.png -------------------------------------------------------------------------------- /doc/image/plana-sdp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/plana-sdp.png -------------------------------------------------------------------------------- /doc/image/plana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/plana.png -------------------------------------------------------------------------------- /doc/image/planb-sdp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/planb-sdp.png -------------------------------------------------------------------------------- /doc/image/planb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/planb.png -------------------------------------------------------------------------------- /doc/image/rtc-thread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/rtc-thread.png -------------------------------------------------------------------------------- /doc/image/sdp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/sdp.jpg -------------------------------------------------------------------------------- /doc/image/sfu-cascaded-person.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/sfu-cascaded-person.png -------------------------------------------------------------------------------- /doc/image/sfu-cascaded-postion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/sfu-cascaded-postion.png -------------------------------------------------------------------------------- /doc/image/sfu-cascaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/sfu-cascaded.png -------------------------------------------------------------------------------- /doc/image/sfu-single-person.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/sfu-single-person.png -------------------------------------------------------------------------------- /doc/image/sfu-single-postion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/sfu-single-postion.png -------------------------------------------------------------------------------- /doc/image/sfu-single-postion2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/sfu-single-postion2.png -------------------------------------------------------------------------------- /doc/image/sfu-single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/sfu-single.png -------------------------------------------------------------------------------- /doc/image/transport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/transport.png -------------------------------------------------------------------------------- /doc/image/unifiedplan-sdp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/unifiedplan-sdp.png -------------------------------------------------------------------------------- /doc/image/webrtc-levels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/webrtc-levels.png -------------------------------------------------------------------------------- /doc/image/webrtc-server-base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/webrtc-server-base.png -------------------------------------------------------------------------------- /doc/image/webrtc-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/webrtc-server.png -------------------------------------------------------------------------------- /doc/image/webrtc-stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/webrtc-stack.png -------------------------------------------------------------------------------- /doc/image/webrtc-stack2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/webrtc-stack2.png -------------------------------------------------------------------------------- /doc/image/webrtc-stream-server-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/webrtc-stream-server-1.png -------------------------------------------------------------------------------- /doc/image/webrtc-stream-server-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/webrtc-stream-server-2.png -------------------------------------------------------------------------------- /doc/image/webrtc-stream-server-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/webrtc-stream-server-3.png -------------------------------------------------------------------------------- /doc/image/webrtc-stream-server-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/webrtc-stream-server-4.png -------------------------------------------------------------------------------- /doc/image/webrtc-stream-server-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/webrtc-stream-server-5.png -------------------------------------------------------------------------------- /doc/image/webrtc-stream-server-6.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/webrtc-stream-server-6.jpeg -------------------------------------------------------------------------------- /doc/image/webrtc-stun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/webrtc-stun.png -------------------------------------------------------------------------------- /doc/image/webrtc-turn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/image/webrtc-turn.png -------------------------------------------------------------------------------- /doc/webrtc native学习:index.md: -------------------------------------------------------------------------------- 1 | [webrtc.lib的编译-link]: https://github.com/barry-ran/learn_webrtc/blob/master/doc/webrtc%20native%E5%AD%A6%E4%B9%A0%EF%BC%9Awebrtc.lib%E7%9A%84%E7%BC%96%E8%AF%91.md 2 | 3 | [webrtc目录结构说明-link]: https://github.com/barry-ran/learn_webrtc/blob/master/doc/webrtc%20native%E5%AD%A6%E4%B9%A0%EF%BC%9Awebrtc%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84%E8%AF%B4%E6%98%8E.md 4 | 5 | [基础概念-link]: https://github.com/barry-ran/learn_webrtc/blob/master/doc/webrtc%20native%E5%AD%A6%E4%B9%A0%EF%BC%9A%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5.md 6 | 7 | [PeerConnection介绍-link]: https://github.com/barry-ran/learn_webrtc/blob/master/doc/webrtc%20native%E5%AD%A6%E4%B9%A0%EF%BC%9APeerConnection%E4%BB%8B%E7%BB%8D.md 8 | 9 | [-link]: https://github.com/barry-ran/learn_webrtc/blob/master/doc/ 10 | 11 | # webrtc native学习系列文章 12 | 13 | - [webrtc native学习:webrtc.lib的编译][webrtc.lib的编译-link] 14 | - [webrtc native学习:webrtc目录结构说明.md][webrtc目录结构说明-link] 15 | - [webrtc native学习:基础概念.md][基础概念-link] 16 | - [webrtc native学习:PeerConnection介绍.md][PeerConnection介绍-link] 17 | -------------------------------------------------------------------------------- /doc/webrtc native学习:peerconnection-server.md: -------------------------------------------------------------------------------- 1 | # peerconnection server简介 2 | 这里介绍的是webrtc自带的example中peerconnection的server 3 | 4 | 简单来说,server就是一个基于http的转发服务器: 5 | 1. 通过http协议(长连接)与客户端交互 6 | 2. 保存所有客户端信息,在客户端之间转发消息 7 | 8 | # 关键类说明 9 | ## SocketBase 10 | 封装了socket操作,主要是创建/销毁socket 11 | 12 | ## DataSocket 13 | 继承SocketBase,封装了http相关操作: 14 | 1. 收发数据 15 | 2. 解析http字段 16 | 3. 获取/比较http各个字段(http header,method等) 17 | 18 | ## ListeningSocket 19 | 继承SocketBase,分装了监听socket的操作,主要是listen监听和accept接收连接 20 | 21 | ## ChannelMember 22 | 代表一个客户端,封装了客户端相关数据,包括连接状态,id,name,相关DataSocket等 23 | 24 | 还封装了转发DataSocket data数据到其他ChannelMember的操作 25 | 26 | ## PeerChannel 27 | 通过vector保存管理所有连接的ChannelMember客户端,主要操作有:添加ChannelMember,关闭所有ChannelMember,查找目标ChannelMember等 28 | 29 | # 主要流程 30 | 1. 创建一个ListeningSocket监听指定端口 31 | 2. 创建一个PeerChannel用于管理所有客户端 32 | 3. select监听所有socket的事件 33 | 4. 如果是ListeningSocket上的连接事件,则创建一个新的DataSocket,并监听其事件 34 | 5. 如果是DataSocket上的事件,则收取数据,判断连接状态 35 | 6. 如果是新连接的客户端则创建ChannelMember并添加到PeerChannel中 36 | 7. 如果是已登录的客户端,则根据其事件类型处理消息(例如退出登录,转发消息给目标ChannelMember等) 37 | -------------------------------------------------------------------------------- /doc/webrtc native学习:webrtc.lib的编译.md: -------------------------------------------------------------------------------- 1 | # 编译webrtc.lib 2 | 首先从webrtc源码编译出webrtc.lib供我们上层开发使用,需要注意几个地方: 3 | - 使用最新的release分支 4 | 5 | git checkout -b branch-heads/72 remotes/branch-heads/72 6 | 7 | 切换完分支记得gclient sync,会同步不同分支下的编译工具,否则可能会编译不过 8 | 9 | - 编译md格式 10 | 11 | webrtc在windows下默认构建为mt格式的静态库,但是现在主流是md,不得已要修改webrtc编译脚本 12 | 13 | 修改build\config\win\BUILD.gn中默认的configs = [ ":static_crt" ]改为configs = [ ":dynamic_crt" ] 14 | 15 | - 指定gn参数 16 | 17 | 编译参数|说明 18 | -|- 19 | is_debug=true|debug还是release 20 | target_cpu="x86"|编译32位 21 | is_clang=false|不使用clang编译器 22 | rtc_build_examples=true|编译examples,指定了这个才会编译peerconnection相关库 23 | rtc_build_tools=false|不用编译tools 24 | rtc_include_tests=false|不用编译tests 25 | enable_iterator_debugging=true|debug模式要打开这个选项,否则[_ITERATOR_DEBUG_LEVEL](https://docs.microsoft.com/en-us/cpp/standard-library/debug-iterator-support?view=vs-2019)不匹配 26 | 27 | 28 | # 使用webrtc.lib(以vs工程为例) 29 | 按照以上步骤编译出的webrtc.lib我们可以集成到自己的项目中使用了,不过需要注意几个问题: 30 | 31 | - windows下定义几个宏 32 | 33 | 宏|说明 34 | -|- 35 | WEBRTC_WIN|告诉webrtc当前是windows平台 36 | WIN32_LEAN_AND_MEAN|待补充 37 | USE_BUILTIN_SW_CODECS|待补充 38 | HAVE_WEBRTC_VIDEO|待补充 39 | NOMINMAX|windows下max宏和std max冲突 40 | INCL_EXTRA_HTON_FUNCTIONS|待补充 41 | 42 | - 找不到头文件 43 | 根据缺少的头文件来看,需要指定几个头文件包含路径 44 | 45 | ..\..\..\webrtc\src\third_party\libyuv\include; 46 | 47 | ..\..\..\webrtc\src\third_party\jsoncpp\source\include; 48 | 49 | ..\..\..\webrtc\src;..\..\..\webrtc\src\third_party\abseil-cpp 50 | 51 | - 出现很多未定义的符号 52 | 未定义的符号只有一个原因,就是相应lib库没有引入,主要分三部分: 53 | 54 | - webrtc在windows下用了很多特定库,例如directshow的库,要引入以下几个库: 55 | 56 | - wmcodecdspuuid.lib 57 | - dmoguids.lib 58 | - Msdmo.lib 59 | - Secur32.lib 60 | - Shell32.lib、 61 | - Gdi32.lib 62 | - Winmm.lib 63 | - Advapi32.lib 64 | - strmiids.lib 65 | 66 | - webrtc.lib并没有包含所有的实现,如果用到的符号在webrtc.lib中没有,需要自己引入需要的lib,例如编译example/peerconnection_client的话,你还要引入其他几个webrtc相关库 67 | 68 | - webrtc.lib 69 | - create_peerconnection_factory.lib 70 | - rtc_base.lib 71 | - json_vc71_libmdd.lib json实现没有暴露出来,需要自己编译一下third_party/jsconcpp 72 | 73 | - 有的符号webrtc.lib没有包含,其他导出的lib库都没有包含,例如原gn项目依赖了test中的项目,test没有导出来 74 | 需要我们自己把相关的实现文件复制出来添加到现有工程中 75 | 76 | 例如webrtc\src\rtc_base\strings\json.cc中GetStringFromJson相关实现 -------------------------------------------------------------------------------- /doc/webrtc native学习:webrtc与sip.md: -------------------------------------------------------------------------------- 1 | # WebRTC 2 | ## 简介 3 | WebRTC,名称源自网页实时通信(Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的技术,是谷歌2010年以6820万美元收购Global IP Solutions公司而获得的一项技术。 4 | 5 | 这是百度百科上的介绍,维基百科也差不多。对完全小白来讲,可能不是很理解这句话。 6 | 7 | ## 首先,什么是实时通信? 8 | 举个直白的例子,我们平时打电话就是实时通信。现在有很多实时通信的软件,比如 丁丁、有信……这是手机app。PC客户端像Xlite、Linphone等等。这些客户端接入网络,注册到相应的服务器上就可以进行音频通信了,支持视频的还能进行视频通信。拿Xlite来说,它的信令机制采用的是sip协议。SIP协议是IMS网络广泛使用的信令协议,已经很成熟。两个uesr 通过Xlite客户端注册到sip server(如 Asterisk)上,就可以互相拨打对方的号码音视频通信了,不过就Xlite来说,语音通话是免费的,但是视频的话,是要支付money软件才提供视频功能的…… 9 | 10 | ## 其次,为什么要提出WebRTC? 11 | 一直以来,用户如果想通过互联网进行实时通信,就需要安装软件,要么就得在浏览器中安装插件。WebRTC的宗旨是不需用户安装任何插件,直接使用浏览器就可以进行实时音视频通信。就是如果WebRTC实现了,我们打开浏览器,输入网址,登陆进去,拨打号码,就可以互相音视频了。不再需要安软件,也不需要安装额外的浏览器插件。Web版QQ大家都用过吧,现在还只能发发消息发发表情,如果引入WebRTC,那音视频传文件都不在话下,现在QQ客户端有的功能,通过网页访问都能体验,估计到时候都不愿意再装体积越来越大的QQ客户端了吧。 12 | 13 | ## 最后,需要知道的内容 14 | 15 | 1. WebRTC已经纳入HTML5标准 16 | 2. 目前支持webrtc的浏览器有 Chrome Firefox Opera,IE不支持~ 17 | 3. WebRTC没有指定具体的信令协议,具体的信令协议留给应用程序实现。 18 | 4. webRTC使用JSEP协议建立会话,什么是JSEP后面说 19 | 5. WebRTC采用ICE实现NAT穿越 20 | 6. WebRTC客户端之间可以进行点对点的媒体传输。 21 | 22 | # JSEP 23 | JSEP(JavaScript Session Establishment Protocol,JavaScript会话建立协议)是一个信令API,允许开发者构建更强大的应用程序以及增加在信令协议选择上的灵活性。 24 | 25 | 建立会话最关键的就是媒体的协商,WebRTC虽然没有指定具体的信令协议,但是媒体协商采用了SDP协议。JSEP是干什么的呢,一方面提供接口如createOffer()供web应用程序调用生成SDP,另一方面提供ICE功能接口。这些功能都由浏览器实现,浏览器 26 | WebRTC传输信令(offer/answer)采用Websocket。 27 | 需要说明的是,如果web应用程序不使用额外的信令协议,仅使用JSEP,两个WebRTC client (同一个WebRTC client程序,两处登陆) 之间也是可以建立链接的,即只要应用程序能解析用WS传递过来的Offer/Answer消息,提取出其中的SDP和ICE信息就可以了。 28 | 29 | github上codelabdemo 就是不用其他信令协议,直接使用JSEP生成offer/answer信令,然后采用ws协议传输实现的。 30 | 31 | JSEP并不是信令协议,可以在JSEP的基础上引入SIP等信令协议,使WebRTC应用功能更加完备。 32 | 33 | # WebRTC与SIP互通 34 | 要想让WebRTC与sip互通,要解决两个层面的问题:信令层和媒体层。 35 | 两个网络使用的信令机制不同,所以要进行信令的转换,才能完成媒体的协商,建立会话。媒体层要完成编码的转换,以及rtp/srtp转换等功能。这里主要说项信令层面的互通。 36 | 37 | ## 信令互通方案 38 | 目前sip和webrtc信令上互通有两种解决方案: 39 | 40 | - 用JavaScript实现sip协议栈,webrtc应用程序基于这个协议栈开发。这样webrtc client发出的信令就是sip信令,但一般采用websocket为信令传输协议。这样的webrtc client就可以直接注册到支持ws的sip server上了。 41 | jssip 、sipml5 都是这种解决方案。 42 | 43 | - 通过转换网关实现协议的转换,从而互通。一个开源的网关项目就是 webrtc2sip。 44 | webrtc2sip是一个功能很完善的网关,既实现了信令层,也实现了媒体层,编码转换功能很强大,也可以直接当做媒体网关,用于编解码,沟通两端的媒体。 -------------------------------------------------------------------------------- /doc/webrtc native学习:webrtc协议.md: -------------------------------------------------------------------------------- 1 | 介绍一下webrtc涉及到的网络协议,主要协议如下所示: 2 | ![](image/webrtc-stack.png) 3 | 4 | 来个带颜色的图: 5 | 6 | ![](image/webrtc-stack2.png) 7 | 8 | 下面来分别介绍 9 | 10 | # UDP 11 | UDP是传输层协议,我们并不陌生。webrtc中的音视频传输、DataChannel中的数据传输,都是基于UDP的。 12 | 13 | WebRTC实时通信传输音视频的场景,讲究的是实时,当下,处理音频和视频流的应用一定要补偿间歇性的丢包,所以实时性的需求是大于可靠性的需求的。 14 | 15 | 如果使用TCP当传输层协议的话,如果中间出现丢包的情况,那么后续的所有的包都会被缓冲起来,因为TCP讲究可靠、有序;而UDP则正好相反,它只负责有什么消息我就传过去,不负责安全,不负责有没有到达,不负责交付顺序,这里从底层来看是满足WebRTC的需求的,所以WebRTC是采用UDP来当它的传输层协议的。 16 | 17 | 当然这里UDP只是作为传输层的基础,想要真正的达到WebRTC的要求,我们就要来分析在传输层之上,WebRTC做了哪些操作,用了哪些协议,来达到WebRTC的要求了。 18 | 19 | # ICE 20 | 交互式连接建立[Interactive Connectivity Establishment (ICE)](http://en.wikipedia.org/wiki/Interactive_Connectivity_Establishment) 是一个允许你的浏览器和对端浏览器建立连接的协议框架。在实际的网络当中,有很多原因能导致简单的从A端到B端直连不能如愿完成。这需要绕过阻止建立连接的防火墙,给你的设备分配一个唯一可见的地址(通常情况下我们的大部分设备没有一个固定的公网地址),如果路由器不允许主机直连,还得通过一台服务器转发数据。ICE通过使用以下几种技术完成上述工作。 21 | 22 | # NAT 23 | 网络地址转换协议[Network Address Translation (NAT)](http://en.wikipedia.org/wiki/NAT) 用来给你的(私网)设备映射一个公网的IP地址的协议。一般情况下,路由器的WAN口有一个公网IP,所有连接这个路由器LAN口的设备会分配一个私有网段的IP地址(例如192.168.1.3)。私网设备的IP被映射成路由器的公网IP和唯一的端口,通过这种方式不需要为每一个私网设备分配不同的公网IP,但是依然能被外网设备发现。 24 | 25 | 一些路由器严格地限定了部分私网设备的对外连接。这种情况下,即使STUN服务器识别了该私网设备的公网IP和端口的映射,依然无法和这个私网设备建立连接。这种情况下就需要转向TURN协议。 26 | 27 | # STUN 28 | NAT的会话穿越功能[Session Traversal Utilities for NAT (STUN)](http://en.wikipedia.org/wiki/STUN)(缩略语的最后一个字母是NAT的首字母)是一个允许位于NAT后的客户端找出自己的公网地址,判断出路由器阻止直连的限制方法的协议。 29 | 30 | 客户端通过给公网的STUN服务器发送请求获得自己的公网地址信息,以及是否能够被(穿过路由器)访问。 31 | ![](image/webrtc-stun.png) 32 | 33 | [STUN详细描述-RFC3489 STUN](https://datatracker.ietf.org/doc/rfc3489/) 34 | [STUN详细描述-RFC5389 STUN](https://datatracker.ietf.org/doc/rfc5389/) 35 | 36 | # TURN 37 | 一些路由器使用一种“对称型NAT”的NAT模型。这意味着路由器只接受和对端先前建立的连接(就是下一次请求建立新的连接映射)。 38 | 39 | NAT的中继穿越方式[Traversal Using Relays around NAT (TURN)](http://en.wikipedia.org/wiki/TURN) 通过TURN服务器中继所有数据的方式来绕过“对称型NAT”。你需要在TURN服务器上创建一个连接,然后告诉所有对端设备发包到服务器上,TURN服务器再把包转发给你。很显然这种方式是开销很大的,所以只有在没得选择的情况下采用。 40 | ![](image/webrtc-turn.png) 41 | 42 | # SDP 43 | 会话描述协议[Session Description Protocol (SDP)](http://en.wikipedia.org/wiki/Session_Description_Protocol) 是一个描述多媒体连接内容的协议,例如分辨率,格式,编码,加密算法等。所以在数据传输时两端都能够理解彼此的数据。本质上,这些描述内容的元数据并不是媒体流本身。 44 | 45 | # TLS 46 | 传输层安全性协议([Transport Layer Security](https://baike.baidu.com/item/TLS/2979545?fr=aladdin)),用于加密,保证传输安全,TLS是建立在传输层TCP协议之上的协议,服务于应用层,它的前身是SSL(Secure Socket Layer,安全套接字层),它实现了将应用层的报文进行加密后再交由TCP进行传输的功能。 47 | 48 | # DTLS 49 | DTLS([Datagram Transport Layer Security](https://baike.baidu.com/item/DTLS/8654469?fr=aladdin))即数据包传输层安全性协议。TLS不能用来保证UDP上传输的数据的安全,因此Datagram TLS试图在现存的TLS协议架构上提出扩展,使之支持UDP,即成为TLS的一个支持数据包传输的版本。 50 | 51 | # SCTP 52 | SCTP 流传输控制协议[Stream Control Transmission Protocol](https://blog.csdn.net/wuxing26jiayou/article/details/79743683),用于保证数据完整性,传输协议,在TCP/IP协议栈中所处的位置和TCP、UDP类似,兼有TCP/UDP两者特征。 53 | 54 | # SRTP 55 | SRTP,即安全实时传输协议([Secure Real-time Transport Protocol](https://blog.csdn.net/thinkerleo1997/article/details/80233530)),其是在实时传输协议(Real-time Transport Protocol)基础上所定义的一个协议,旨在为单播和多播应用程序中的实时传输协议的数据提供加密、消息认证、完整性保证和重放保护。 56 | 57 | # 总结 58 | webrtc是基于p2p的,由于NAT的存在,两个peer想要建立连接需要基于ICE框架,ICE中建立两个peer的连接主要基于STUN、TURN等协议。 59 | 60 | webrtc建立连接后,音视频传输和DataChannel传输数据都是基于UDP协议,但是UDP是不安全的,不可靠的,所以加了一层DTLS来加密保证安全,DataChannel数据传输要求可靠性,所以使用SCTP来保证数据可靠;音视频数据不要求完全完整,但是需要使用安全实时传输协议SRTP对音视频进行加密。 61 | 62 | webrtc的信令协议一般是基于TCP的,为了保证安全,一般加一层TLS。实际应用场景中,一般使用更上层的协议,例如http/https/websocket等。 63 | 64 | ## 对于音视频数据,是有DTLS和SRTP两层加密吗?为什么不能仅仅是DTLS+RTP?它们是如何协作的? 65 | DTLS和SRTP不是单纯的两层加密,它们是配合在一起的,叫做DTLS-SRTP,实际是通过DTLS握手交换获得密钥,然后用SRTP使用该密钥进行加密解密。 66 | 67 | [参考文档一](https://www.jianshu.com/p/50605466c039) 68 | 69 | [参考文档二](https://www.cnblogs.com/lanyuliuyun/p/8289306.html) 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /doc/webrtc native学习:webrtc目录结构说明.md: -------------------------------------------------------------------------------- 1 | [TOC] 2 | 3 | # src 根目录 4 | 5 | ## base chrome基础组件库,webrtc中没用到 6 | 7 | ## build 通用编译脚本 8 | 9 | ## build_overrides webrtc特定编译脚本 10 | 11 | ## buildtools 编译工具 12 | 13 | ## rtc_base webrtc基础组件库 14 | 15 | ## api webrtc主要的对外接口 16 | 包括peerconnection、mediastream、音视频、网络传输、ice、datachannel等等 17 | 18 | ## examples 实例代码 19 | 20 | ## modules 相对独立的功能模块 21 | 22 | ### desktop_capture 桌面捕获模块 23 | 提供屏幕捕获和窗口捕获功能,回调rgba元数据 24 | 25 | ## test 实用的测试代码,很有参考性 26 | 例如example/peerconnection中摄像头捕获就引用了这里封装的代码,这里还包括跨平台视频捕获(platform_video_capturer)等。 27 | 28 | ## testing 简单测试代码 29 | 30 | ## third_party 第三方库 -------------------------------------------------------------------------------- /doc/webrtc native学习:基础概念.md: -------------------------------------------------------------------------------- 1 | [webrtc标准](http://w3c.github.io/webrtc-pc/) 2 | [优秀博客](https://blog.piasy.com/2018/05/24/WebRTC-Video-Native-Journey/index.html) 3 | 4 | # 协议相关 5 | 6 | # 编程相关 7 | 8 | ## Capturer 9 | 负责视频数据采集,只有视频才有这一层抽象,它有多种实现: 10 | - 摄像头采集(Android 还有 Camera1/Camera2 两种实现) 11 | - 屏幕采集 12 | - 视频文件采集 13 | 14 | ## Source 15 | 媒体数据源抽象,用于向Track提供媒体数据,一个Source可以被多个Track共享。 16 | 17 | 主要有三个类: 18 | - MediaSourceInterface 媒体源通用接口,主要判断媒体源的状态,是否是远程媒体 19 | - VideoSourceInterface 视频源接口,主要提供了添加/移除VideoSink的操作 20 | - AudioSourceInterface 音频源接口,继承自MediaSourceInterface,增加了设置音量、添加/移除AudioSink的操作 21 | 22 | ## Track 23 | 媒体数据轨道的抽象,媒体数据从轨道的一端(Source)流向另一端(Sink)。 24 | 25 | 本质上相当于Source的代理。Track使用Source构造,然后封装了Source的AddSink/RemoveSink接口 26 | 27 | 因为是代理的Source,所以Track分为两类:AudioTrack和VideoTrack 28 | 29 | ## Stream 30 | Track容器,可以容纳多个Track 31 | 32 | 从主要的几个接口就可以看出来:AddTrack、RemoveTrack、GetAudioTracks、GetVideoTracks等 33 | 34 | ## Sink 35 | 媒体数据的消费者,用于处理音视频数据。 36 | 37 | 对于Video,Sink(VideoSinkInterface)用于处理VideoSource的视频数据,发送端的本地视频渲染、接收端收到远程视频后的渲染,都由Sink负责; 38 | 39 | 对于Audio,Sink(AudioTrackSinkInterface)用于处理AudioSource的音频数据; 40 | 41 | Sink一般的使用流程如下(渲染视频数据为例): 42 | - 自定义VideoRenderer类继承rtc::VideoSinkInterface 43 | - 实现OnFrame接口来处理视频帧 44 | - 调用VideoSourceInterface(或者它的子类,例如VideoTrackInterface)的AddOrUpdateSink将VideoRenderer添加到对应VideoSource上,VideoSource有了视频帧数据就会传递到VideoRenderer::OnFrame 45 | - 停止渲染的时候调用VideoSourceInterface(或者它的子类,例如VideoTrackInterface)的RemoveSink将VideoRenderer从VideoSource上移除即可 46 | 47 | ## Sender 48 | 49 | ## Receiver 50 | 51 | ## Transceiver 52 | transceiver收发器在peerconnection中承接了控制数据收发的功能,内部关联了ChannelInterface与RtpSenderInternal和RtpReceiverInternal。其中channel相关模块负责维护数据收发的业务流程,以视频发送为例,其中Stream相关模块用于视频编码和实现rtp/rtcp相关功能,最终打包后的数据由BaseChannel内的tramsport模块实现视频发送 53 | 54 | ## RtpTransceiver 55 | RtpTransceiver实现RtpTransceiverInterface,用于实现PeerConnection中Unified Plan SDP所指定的通用功能。其主要用于PeerConnection中维护RtpSenders, RtpReceivers和BaseChannels,同时其设计兼容B SDP。这里Unified Plan SDP中 m= section 指定维护一个sender和一个receiver,Plan B SDP中会维护多个sender和receiver,用a=ssrc区分。这里BaseChannel的生命周期是由ChannelManager管理的,RtpTransceiver中只保持对其指针的使用。对于音频或者视频数据的收发,分别通过AudioRtpSenders, AudioRtpReceivers和VoiceChannel 与 VideoRtpSenders, VideoRtpReceivers,VideoChannel实现 56 | 57 | ## Channel 58 | 59 | ## PeerConnection 60 | 它表示一个P2P连接其中的一端(Peer)。 61 | 62 | 我们知道webrtc是P2P的,所以PeerConnection是webrtc的门面,我们直接使用的都是PeerConnection的接口,它包含了建立p2p连接所需要的所有功能,主要包括设置sdp、创建ice通道、传输媒体数据,传输普通数据等。 63 | -------------------------------------------------------------------------------- /doc/webrtc native学习:多线程一 Event.md: -------------------------------------------------------------------------------- 1 | 2 | Webrtc 多线程模块主要涉及 criticalsection、event、messagequeue、thread、messagehandler、physicalsocketserver 等文件. 3 | 4 | # Event 5 | 文件路径 webrtc/rtc_base/event.h webrtc/rtc_base/event.c. 6 | 7 | event.h/event.cc文件中在 namespace rtc 中, 只有class Event类。 8 | 该类主要实现了跨平台的Win32 Event功能。Event类的各个成员函数与Win32 Event所提供的API几乎一致。 9 | 10 | 在 Linux 系统中,WebRTC 使用了mutex和条件变量来实现Event的功能。首先,对Win 32 API和pthread API做一下类比: 11 | 12 | - CreateEvent 13 | 14 | pthread_mutex_init、pthread_cond_init这两个函数用来创建pthread的mute和条件变量。 15 | 16 | - CloseHandle 17 | 18 | pthread_mutex_destroy、pthread_cond_destroy这两个函数用来销毁pthread的mute和条件变量。 19 | 20 | - SetEvent 21 | 22 | pthread_mutex_lock、pthread_mutex_unlock这两个函数加锁和解锁mutex, 23 | 24 | pthread_cond_broadcast函数用来解除所有等待在该条件变量上的线程的阻塞状态。 25 | 26 | - ResetEvent 27 | 28 | pthrea_mutex_lock、pthread_mutex_unlock(已解释) 29 | 30 | - WaitForSingleObject 31 | 32 | pthrea_mutex_lock、pthread_mutex_unlock(已解释)。pthrea_cond_wait函数用来使线程阻塞在条件变量上。 33 | 34 | 下面将大致解释一下 Event 类的实现原理: 35 | 36 | Event的主要功能由条件变量实现,mutex只是辅助条件变量起到锁的作用。条件变量的 pthread_cond_wait 和pthread_cond_broadcast函数与Win32 Event的WaitForSingleObject和SetEvent基本类似。Event是否为signal状态由布尔类型的成员变量event_status_控制。是否为manual reset的Event由布尔类型的成员变量is_manual_reset_控制。与Win32 Event不同的状况主要体现在Event的manual reset控制上。 37 | 38 | linux 系统下所有调用 Event::Wait 函数的线程会阻塞在pthread_cond_wait 函数上。当 Event::Set 函数被调用时,pthread_cond_broadcast 函数会解除所有等待在 pthread_cond_wait 函数上的线程的阻塞状态。这对于 manual reset 的 Win32 Event 来说没什么问题,问题出在 auto reset 的 Win32 Event 上。Auto reset 的 Win32 Event 每次只能解除一条等待在Event上的线程的阻塞状态,其他线程依然为阻塞状态。这就需要mutex来配合实现了。 39 | 40 | 在这里要重点解释一下 pthread_cond_wait 函数的第二个参数 pthread_mutex_t *mutex。当线程进入pthread_cond_wait 函数时会解锁 mutex,而在离开 pthread_cond_wait 时会重新加锁 mutex。可以理解为: 41 | 42 | ``` 43 | intpthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex) 44 | { 45 | pthread_mutex_unlock(mutex); 46 | … 47 | … 48 | … 49 | pthread_mutex_lock(mutex); 50 | return0; 51 | } 52 | ``` 53 | 这是 Win32 没有的行为,需要特别注意。 54 | 55 | 有了以上的机制后,模拟 auto rest的 Win32 Event 就没问题了。当第一条线程获得 mutex 锁并离开pthread_cond_wait 函数时,其他线程会依然被阻塞在 pthread_mutex_lock(mutex) 函数上,无法离开 pthread_cond_wait 函数。那条成功离开线程会马上检测当前的 Event 是否为 manual reset 的,如果不是就马上将 event_status_ 成员变量设置为 false,并解锁 mutex。这时其他线程才能有机会离开pthread_cond_wait 函数。不过当他们离开 pthread_cond_wait 后立即检测 event_status_ 成员变量,如果为 false 就重新调用 pthread_cond_wait 函数。这就完美实现了 Win32 Event 的 auto reset 的语义。 56 | 57 | 条件变量和 mutex 的配合是 Event 类的难点。如果读者还是不能完全理解,请仔细阅读以上 3 段的内容(也可以上网查找 pthread_cond_wait 函数),并结合 event.cc 的源代码反复揣摩,应该可以很快理解的(毕竟代码不多,而且也不是WebRTC中真正困难的部分) 58 | 59 | 作者:落冬风 60 | 链接:https://www.jianshu.com/p/7945e324bab4 61 | 来源:简书 62 | 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 -------------------------------------------------------------------------------- /doc/webrtc native学习:多线程三 MessageHandler.md: -------------------------------------------------------------------------------- 1 | 2 | webrtc/base/messagehandler.h/messagehandler.cc 文件仅仅定义了 MessageHandler 类,和一个模板工具类 FunctorMessageHandler 类。 3 | 4 | # MessageHandler 5 | MessageHandler 类的主要功能是定义了消息处理器的基本数据结构,子类在继承了该类之后要重载 OnMessage 函数,并实现消息响应的逻辑。 6 | 7 | # FunctorMessageHandler 8 | FunctorMessageHandler 类的主要功能是将一个函数投递到目标线程执行。该类主要通过 functor 模板实现(熟悉 C++ 的读者应该不会对它陌生,不熟悉的可以上网查找),而且定义了一个针对返回值类型为 void 的函数的特化版本(模板的特化和偏特也应该是一个 C++ 程序员掌握的一个知识点,该语法有些难度)。用户不需要创建或者继承 FunctorMessageHandler 类,仅需调用 Thread::Invoke 函数就能使用它的功能。 9 | 10 | 作者:落冬风 11 | 链接:https://www.jianshu.com/p/e3b902f60c7c 12 | 来源:简书 13 | 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 -------------------------------------------------------------------------------- /doc/webrtc native学习:多线程二 Crticalsection.md: -------------------------------------------------------------------------------- 1 | 2 | webrtc/base/ criticalsection.h/criticalsection.cc 文件中包含了3个类 CriticalSection、CritScope 和 TryCritScope。这3个类对于有多线程编程经验的Windows开发人员来说都是非常容易理解的。基本上就是对 Win32 CriticalSection 的简单封装。 3 | 4 | # CriticalSection 5 | CriticalSection 主要实现了跨平台实现临界区的功能。在 Linux 平台上使用了 pthread 的 mutex 模拟 Win32 的 Critical Section。以下对比一下 API: 6 | 7 | - InitializeCriticalSection 8 | 9 | pthread 的 mutex 初始化略比 Win32 的 CriticalSection 复杂一些。pthread_mutexattr_init 函数用来初始化一个 mutex 属性变量。pthread_mutexattr_settype 函数用来设置 mutex 的各种属性。在 CriticalSection 中为 mutex 设置了 PTHREAD_MUTEX_RECURSIVE。通过网上查询该属性被描述为: 10 | 11 | “如果一个线程对这种类型的互斥锁重复上锁,不会引起死锁,一个线程对这类互斥锁的多次重复上锁必须由这个线程来重复相同数量的解锁,这样才能解开这个互斥锁,别的线程才能得到这个互斥锁。如果试图解锁一个由别的线程锁定的互斥锁将会返回一个错误代码。如果一个线程试图解锁已经被解锁的互斥锁也将会返回一个错误代码。这种类型的互斥锁只能是进程私有的(作用域属性PTHREAD_PROCESS_PRIVATE )。” 12 | 13 | 通过设置不同的属性 pthread mutex 可以实现很多不同的特性。如果读者有兴趣可以上网查询一下不同的属性的意义。不过需要注意到的是在 Event 类中没有 mutex 属性,直接使用默认值创建了mutex。接着使用 CriticalSection 使用 pthread_mutex_init 函数创建了mutex。最后请不要忘记调用pthread_mutexattr_destroy 将 mutex 属性变量销毁掉。 14 | 15 | - DeleteCriticalSection 16 | 17 | pthread_mutex_destroy 函数用以销毁 mutex。 18 | 19 | - EnterCriticalSection 20 | 21 | pthread_mutex_lock 函数用以对 mutex 加锁。 22 | 23 | - TryEnterCriticalSection 24 | 25 | pthread_mutex_trylock 函数用以尝试对 mutex 加锁,如果加锁成功就返回 true,失败就返回 false。 26 | 27 | - LeaveCriticalSection 28 | 29 | pthread_mutex_unlock 函数用以解锁 mutex. 30 | 31 | 在 CriticalSection 中有个调试宏 CS_TRACK_OWNER。如果使用了这个宏, CriticalSection 可以使用 CurrentThreadIsOwner 函数用来判断是否是在当前线程加锁。在的段落重点提到过 CriticalSection使用 PTHREAD_MUTEX_RECURSIVE 属性来创建 mutex,该属性导致在另一个线程线程(非加锁线程)解锁 mutex 会返回一个错误。 32 | 33 | # CritScope 34 | 利用构造函数加锁 CriticalSection;并利用析构函数在退出代码块的时候解锁 CriticalSection 。该手法对于所有C++开发人员并不陌生。 35 | 36 | # TryCritScope 37 | 类似于 CritScope,利用构造函数尝试加锁 CriticalSection;并利用析构函数在退出代码块的时候解锁CriticalSection。 38 | 39 | 对于大多数熟练的Win32开发人员来说前两个文件的内容是很好理解的,不过是2道开胃菜而已。接着我们要真正开始进入分析多路信号分离器的范围了。这也是多线程篇的重点部分。我会尽可能详细的分析整个多路信号分离器的工作原理。不过也会抛弃一些实现细节,比如所有的代码分析都是基于“永久”等待信号事件的流程,不会去分析如何计算下一次等待时间。这样可以让我们更加专注于多路信号分离器的原理,而不被一些细节困扰。 40 | 41 | 作者:落冬风 42 | 链接:https://www.jianshu.com/p/8adba3bfbfc5 43 | 来源:简书 44 | 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 -------------------------------------------------------------------------------- /doc/webrtc native学习:流媒体服务器架构.md: -------------------------------------------------------------------------------- 1 | # WebRTC基础结构介绍 2 | 自从Google于2011年发布WebRTC以来,WebRTC一直是一个能够将互联网浏览器转换为强大的多媒体引擎的颠覆性技术。 WebRTC汇集了先进的实时通信技术,包括:先进的音视频编解码器(Opus和VP8/9),强制加密协议(SRTP和DTLS)和网络地址转换器(ICE&STUN)。 3 | 4 | 根据最初的定义,WebRTC被指定为P2P(peer-to-peer)技术。自成立以来,WebRTC已经大大降低了Web开发人员通过简单的Java API构建实时通信应用程序的难度。但要清楚,WebRTC是一种技术,而不是一个完整的应用程序或服务。 5 | 6 | 虽然WebRTC最初被设想为纯粹的P2P技术,但许多日常业务应用程序需要集中式媒体功能,通过P2S(peer-to-server)架构提高可靠性、效率或扩展性。对于P2P和P2S架构之间的问题对于构建WebRTC应用程序很重要。 7 | 8 | # P2P到P2S 9 | WebRTC旨在通过其浏览器(也称为P2P)在客户端之间直接发送媒体流。在P2P架构中,客户端建立通信之前,首先需要建立到应用服务器(有时也成为信令服务器)的信令连接。而 WebRTC规范中没有规定信令方法或协议,它允许采用现有方法(SIP,WebSockets,XMPP等)或实现专有信令过程。应用服务器保存业务逻辑,并作为会话描述协议(SDP)交换的中介。一旦SDP交换完成,两个客户端之间的直接媒体通信即可开始。 10 | ![](image/webrtc-stream-server-1.png) 11 | 12 | 虽然WebRTC主要是浏览器到浏览器,但是随着服务器将媒体锚定在网络中以充当媒体P2S(如下图)。在P2S架构中,客户端再次建立到应用服务器的信令连接。在该体系结构中,应用服务器继续管理业务逻辑,而且还利用到服务器的媒体控制连接来进行客户端和媒体服务器之间的SDP交换。一旦SDP交换完成,客户端和服务器之间的媒体通信即可开始。 13 | ![](image/webrtc-stream-server-2.png) 14 | 15 | 使用服务器端处理可以引入高级功能,例如用于合规性的集中审查,音频/视频回放,用于视频流的媒体分析,从而实现人脸监测、人脸识别等。根据架构,服务器端处理可以优化带宽并最大限度地减少客户端计算,从而能够使移动客户延长电池使用时间,并为其提供灵活的用户界面。 16 | 17 | 对于支持多个参与者(会议,远程学习,联络中心)的更复杂的应用程序,主要有三个WebRTC的网络结构: 18 | - P2P Mesh 19 | - MCU(Multi-point Control Unit) 20 | - SFU(Selective Forwarding Unit) 21 | 22 | # webrtc P2P 23 | 在分享webrtc服务器模型之前,先看一下webrtc中1对1的通信模型,后面的webrtc服务器模型中每一条连线都做了1对1的通信模型中的这些事: 24 | ![](image/webrtc-stream-server-3.png) 25 | 26 | 首先webrtc提供了音视频设备检测,音视频采集等能力,我们可以轻松得到音视频流;signal信令需要我们和信令服务器通信,自己实现一些业务逻辑;在真正建立连接的时候,还需要通过STUN/TURN服务器来穿透NAT建立连接,这块连接建立和音视频传输的能力也是webrtc提供的,我们需要指定STUN/TURN服务器即可。 27 | 28 | # 三种WebRCT网络结构 29 | 30 | ## Mesh 31 | 音视频数据流只在终端用户之间相互传输,不经过任何服务器节点,而且每个人都要与其它所有人建立P2P连接。 32 | ![](image/webrtc-stream-server-4.png) 33 | 34 | 每一个P2P连接有独立的传输策略控制,通讯质量有一定的保障(但是国内P2P连通率发现并不是那么理想)。但是,这种架构对于客户端系统是一种浪费,一方面需要分配更多的端口,消耗更多的系统资源;另一方面,由于要向其它三个客户端发送本地音视频数据,增加了上行网络带宽的消耗,在同等带宽条件下,支持的多人通话路数就相对有限,视频质量(码率)也比较低。 35 | 36 | 在多人视频场景下,Mesh方案的瓶颈是客户端性能和带宽,随着视频人数的增加,客户端每次要多发送/接收两路流(音/视频),一般能达到10人视频就不错了。所以这个方案会提高客户端所支持的最低配置的下限。 37 | 38 | ## MCU 39 | MCU是传统视频会议系统中的核心控制单元,在WebRTC的系统实现中, 适合于多人音视频通话场景,MCU可以对接收到的多路流进行转码和混合,并向每个终端输出单路流。 40 | ![](image/webrtc-stream-server-5.png) 41 | 42 | MCU将接收到的多路流进行转码和混合,并向每个终端输出单路流的做法,节省了终端用户的下行带宽,并且还能够对不同网络条件的用户,订制不同码率的输出视频流,让多人场景有更好的用户体验。它的缺点也显而易见,随着视频人数的增加,服务器进行多路流的转码和混合将消耗很大的cpu和gpu,即使是使用gpu硬解来转码混合,一台服务器所支持的同时视频人数也不会太高;而且服务端进行混流的话,多人视频显示的布局就由服务器决定了,混合完是什么样,客户端播放就是什么样,没法自由调整每一路视频的显示布局和分辨率。 43 | 44 | 在多人视频场景下,MCU方案的瓶颈是服务器性能,目前还没有好的办法来解决。 45 | 46 | ## SFU 47 | SFU从发布客户端复制音视频流的信息,然后分发到多个订阅客户端。 48 | ![](image/webrtc-stream-server-6.jpeg) 49 | 50 | SFU是解决服务器性能问题的有吸引力的方法,因为它不涉及视频解码和编码的计算费用,它以最低的开销来转发各路媒体流。但是随着视频人数的增加,服务端的下行带宽会不断增加,但是现在有很好的解决方法,例如simulcast,svc等等。 51 | 52 | 虽然SFU也有缺点,但是已经有了成熟的解决方案,所以SFU是目前视频会议主流的解决方案,思科,zoom,lark都是采用的SFU的方式。 -------------------------------------------------------------------------------- /doc/时序图/pc1.vsdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/时序图/pc1.vsdx -------------------------------------------------------------------------------- /doc/时序图/peerconnection.vsdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/时序图/peerconnection.vsdx -------------------------------------------------------------------------------- /doc/类图/thread.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/doc/类图/thread.md -------------------------------------------------------------------------------- /examples/DesktopCamera/DesktopCapturer.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2019-07-21T19:40:56 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = DesktopCapturer 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which has been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | CONFIG += c++17 26 | 27 | SOURCES += \ 28 | main.cpp \ 29 | widget.cpp 30 | 31 | HEADERS += \ 32 | widget.h 33 | 34 | FORMS += \ 35 | widget.ui 36 | 37 | # Default rules for deployment. 38 | qnx: target.path = /tmp/$${TARGET}/bin 39 | else: unix:!android: target.path = /opt/$${TARGET}/bin 40 | !isEmpty(target.path): INSTALLS += target 41 | 42 | include($$PWD/../webrtc_common/webrtc_common.pri) 43 | include($$PWD/render/render.pri) 44 | include($$PWD/test/test.pri) 45 | 46 | INCLUDEPATH += \ 47 | $$PWD/test \ 48 | $$PWD/render 49 | 50 | macos { 51 | QMAKE_INFO_PLIST = $$PWD/Info.plist 52 | } 53 | -------------------------------------------------------------------------------- /examples/DesktopCamera/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 19A546d 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleDisplayName 10 | DesktopCapturer 11 | CFBundleExecutable 12 | DesktopCapturer 13 | CFBundleIdentifier 14 | com.barry.DesktopCapturer 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | DesktopCapturer 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleVersion 24 | 1.0 25 | DTCompiler 26 | com.apple.compilers.llvm.clang.1_0 27 | DTSDKBuild 28 | 10.14 29 | DTSDKName 30 | macosx10.14 31 | DTXcode 32 | 1021 33 | DTXcodeBuild 34 | 10E1001 35 | LSMinimumSystemVersion 36 | 10.10.0 37 | NSCameraUsageDescription 38 | Camera access needed for video calling 39 | NSMicrophoneUsageDescription 40 | Microphone access needed for video calling 41 | NSPrincipalClass 42 | NSApplication 43 | 44 | 45 | -------------------------------------------------------------------------------- /examples/DesktopCamera/main.cpp: -------------------------------------------------------------------------------- 1 | #include "widget.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 7 | QApplication a(argc, argv); 8 | Widget w; 9 | w.show(); 10 | 11 | return a.exec(); 12 | } 13 | -------------------------------------------------------------------------------- /examples/DesktopCamera/readme.md: -------------------------------------------------------------------------------- 1 | [DesktopCapturer-image]: https://raw.githubusercontent.com/barry-ran/learn_webrtc/master/examples/DesktopCapturer/screenshot/main.png 2 | 3 | ![界面][DesktopCapturer-image] 4 | 5 | # DesktopCapturer 6 | 在webrtc桌面捕获模块中主要包括两部分,屏幕捕获和窗口捕获: 7 | 8 | - 桌面捕获,使用了三种方案,可自行设置使用哪种方案: 9 | 1. gdi 10 | 2. directx 11 | 3. magnifier 12 | - 窗口捕获,只有一种方案,且有bug 13 | 1. GetWindowDc + PrintWindow 14 | 15 | 这种方法没法获取硬件加速窗口或者opengl等绘制的显存窗口(例如Electron开发的客户端,qtwebengine窗口等),获取到一片黑 16 | 17 | 可以使用magnifier方案,然后将目标窗口以外的所有窗口(包括桌面)都忽略掉,达到目标窗口捕获的效果 18 | 19 | # 使用方法 20 | 1. 创建DesktopCapturer 21 | 2. 设置回调处理函数 22 | 3. 定时CaptureFrame()捕获 23 | 4. 回调函数中处理回调数据(回调数据为rgba) 24 | 25 | # 参考链接 26 | [视频直播:Windows中各类画面源的截取和合成方法总结](https://www.jianshu.com/p/0bbb9c4be735) 27 | 28 | [若干种窗口画面的捕获方法](https://blog.csdn.net/felicityWSH/article/details/62218390) 29 | -------------------------------------------------------------------------------- /examples/DesktopCamera/render/qyuvopenglwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef QYUVOPENGLWIDGET_H 2 | #define QYUVOPENGLWIDGET_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class QYUVOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit QYUVOpenGLWidget(QWidget *parent = nullptr); 13 | virtual ~QYUVOpenGLWidget(); 14 | 15 | QSize minimumSizeHint() const override; 16 | QSize sizeHint() const override; 17 | 18 | void setFrameSize(const QSize& frameSize); 19 | void setFrameVideoSize(const QSize& frameSize); 20 | const QSize& frameSize(); 21 | void updateTextures(const quint8* dataY, const quint8* dataU, const quint8* dataV, quint32 linesizeY, quint32 linesizeU, quint32 linesizeV); 22 | void updateVideoTextures(const quint8* dataY, const quint8* dataU, const quint8* dataV, quint32 linesizeY, quint32 linesizeU, quint32 linesizeV); 23 | 24 | protected: 25 | void initializeGL(); 26 | void paintGL(); 27 | void resizeGL(int width, int height); 28 | 29 | private: 30 | void initShader(); 31 | void initTextures(); 32 | void deInitTextures(); 33 | void updateTexture(bool video, GLuint texture, quint32 textureType, const quint8* pixels, quint32 stride); 34 | 35 | private: 36 | // 视频帧尺寸 37 | QSize m_frameSize = {-1, -1}; 38 | QSize m_frameVideoSize = {-1, -1}; 39 | bool m_needUpdate = false; 40 | bool m_textureInited = false; 41 | 42 | // 顶点缓冲对象(Vertex Buffer Objects, VBO):默认即为VertexBuffer(GL_ARRAY_BUFFER)类型 43 | QOpenGLBuffer m_vbo; 44 | 45 | // 着色器程序:编译链接着色器 46 | QOpenGLShaderProgram m_shaderProgram; 47 | 48 | // YUV纹理,用于生成纹理贴图 49 | GLuint m_texture[3] = {0}; 50 | GLuint m_textureVideo[3] = {0}; 51 | }; 52 | 53 | #endif // QYUVOPENGLWIDGET_H 54 | -------------------------------------------------------------------------------- /examples/DesktopCamera/render/render.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/qyuvopenglwidget.h 3 | 4 | SOURCES += \ 5 | $$PWD/qyuvopenglwidget.cpp 6 | -------------------------------------------------------------------------------- /examples/DesktopCamera/screenshot/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/examples/DesktopCamera/screenshot/main.png -------------------------------------------------------------------------------- /examples/DesktopCamera/test/mac_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_MAC_CAPTURER_H_ 11 | #define TEST_MAC_CAPTURER_H_ 12 | 13 | #include 14 | #include 15 | 16 | #include "api/media_stream_interface.h" 17 | #include "api/scoped_refptr.h" 18 | #include "modules/video_capture/video_capture.h" 19 | #include "rtc_base/thread.h" 20 | #include "test/test_video_capturer.h" 21 | 22 | namespace webrtc { 23 | namespace test { 24 | 25 | class MacCapturer : public TestVideoCapturer, 26 | public rtc::VideoSinkInterface { 27 | public: 28 | static MacCapturer* Create(size_t width, 29 | size_t height, 30 | size_t target_fps, 31 | size_t capture_device_index); 32 | ~MacCapturer() override; 33 | 34 | void OnFrame(const VideoFrame& frame) override; 35 | 36 | private: 37 | MacCapturer(size_t width, 38 | size_t height, 39 | size_t target_fps, 40 | size_t capture_device_index); 41 | void Destroy(); 42 | 43 | void* capturer_; 44 | void* adapter_; 45 | }; 46 | 47 | } // namespace test 48 | } // namespace webrtc 49 | 50 | #endif // TEST_MAC_CAPTURER_H_ 51 | -------------------------------------------------------------------------------- /examples/DesktopCamera/test/platform_video_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #include "platform_video_capturer.h" 11 | 12 | #include "absl/memory/memory.h" 13 | #if defined(WEBRTC_MAC) 14 | #include "test/mac_capturer.h" 15 | #else 16 | #include "vcm_capturer.h" 17 | #endif 18 | 19 | namespace webrtc { 20 | namespace test { 21 | 22 | std::unique_ptr CreateVideoCapturer( 23 | size_t width, 24 | size_t height, 25 | size_t target_fps, 26 | size_t capture_device_index) { 27 | #if defined(WEBRTC_MAC) 28 | return absl::WrapUnique(test::MacCapturer::Create( 29 | width, height, target_fps, capture_device_index)); 30 | #else 31 | return absl::WrapUnique(test::VcmCapturer::Create( 32 | width, height, target_fps, capture_device_index)); 33 | #endif 34 | } 35 | 36 | } // namespace test 37 | } // namespace webrtc 38 | -------------------------------------------------------------------------------- /examples/DesktopCamera/test/platform_video_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_PLATFORM_VIDEO_CAPTURER_H_ 11 | #define TEST_PLATFORM_VIDEO_CAPTURER_H_ 12 | 13 | #include 14 | 15 | #include "test_video_capturer.h" 16 | 17 | namespace webrtc { 18 | namespace test { 19 | 20 | std::unique_ptr CreateVideoCapturer( 21 | size_t width, 22 | size_t height, 23 | size_t target_fps, 24 | size_t capture_device_index); 25 | 26 | } // namespace test 27 | } // namespace webrtc 28 | 29 | #endif // TEST_PLATFORM_VIDEO_CAPTURER_H_ 30 | -------------------------------------------------------------------------------- /examples/DesktopCamera/test/test.pri: -------------------------------------------------------------------------------- 1 | SOURCES += \ 2 | $$PWD/test_video_capturer.cc \ 3 | $$PWD/platform_video_capturer.cc \ 4 | 5 | HEADERS += \ 6 | $$PWD/test_video_capturer.h \ 7 | $$PWD/platform_video_capturer.h 8 | 9 | win32 { 10 | SOURCES += \ 11 | $$PWD/vcm_capturer.cc 12 | 13 | HEADERS += \ 14 | $$PWD/vcm_capturer.h 15 | } 16 | 17 | macos { 18 | SOURCES += \ 19 | $$PWD/mac_capturer.mm 20 | 21 | HEADERS += \ 22 | $$PWD/mac_capturer.h 23 | } 24 | -------------------------------------------------------------------------------- /examples/DesktopCamera/test/test_video_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "test_video_capturer.h" 12 | 13 | #include 14 | 15 | #include "api/scoped_refptr.h" 16 | #include "api/video/i420_buffer.h" 17 | #include "api/video/video_frame_buffer.h" 18 | #include "api/video/video_rotation.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | TestVideoCapturer::TestVideoCapturer() = default; 23 | TestVideoCapturer::~TestVideoCapturer() = default; 24 | 25 | void TestVideoCapturer::OnFrame(const VideoFrame& frame) { 26 | int cropped_width = 0; 27 | int cropped_height = 0; 28 | int out_width = 0; 29 | int out_height = 0; 30 | 31 | if (!video_adapter_.AdaptFrameResolution( 32 | frame.width(), frame.height(), frame.timestamp_us() * 1000, 33 | &cropped_width, &cropped_height, &out_width, &out_height)) { 34 | // Drop frame in order to respect frame rate constraint. 35 | return; 36 | } 37 | 38 | if (out_height != frame.height() || out_width != frame.width()) { 39 | // Video adapter has requested a down-scale. Allocate a new buffer and 40 | // return scaled version. 41 | rtc::scoped_refptr scaled_buffer = 42 | I420Buffer::Create(out_width, out_height); 43 | scaled_buffer->ScaleFrom(*frame.video_frame_buffer()->ToI420()); 44 | broadcaster_.OnFrame(VideoFrame::Builder() 45 | .set_video_frame_buffer(scaled_buffer) 46 | .set_rotation(kVideoRotation_0) 47 | .set_timestamp_us(frame.timestamp_us()) 48 | .set_id(frame.id()) 49 | .build()); 50 | } else { 51 | // No adaptations needed, just return the frame as is. 52 | broadcaster_.OnFrame(frame); 53 | } 54 | } 55 | 56 | rtc::VideoSinkWants TestVideoCapturer::GetSinkWants() { 57 | return broadcaster_.wants(); 58 | } 59 | 60 | void TestVideoCapturer::AddOrUpdateSink( 61 | rtc::VideoSinkInterface* sink, 62 | const rtc::VideoSinkWants& wants) { 63 | broadcaster_.AddOrUpdateSink(sink, wants); 64 | UpdateVideoAdapter(); 65 | } 66 | 67 | void TestVideoCapturer::RemoveSink(rtc::VideoSinkInterface* sink) { 68 | broadcaster_.RemoveSink(sink); 69 | UpdateVideoAdapter(); 70 | } 71 | 72 | void TestVideoCapturer::UpdateVideoAdapter() { 73 | video_adapter_.OnSinkWants(broadcaster_.wants()); 74 | } 75 | 76 | } // namespace test 77 | } // namespace webrtc 78 | -------------------------------------------------------------------------------- /examples/DesktopCamera/test/test_video_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_TEST_VIDEO_CAPTURER_H_ 11 | #define TEST_TEST_VIDEO_CAPTURER_H_ 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include "api/video/video_frame.h" 18 | #include "api/video/video_source_interface.h" 19 | #include "media/base/video_adapter.h" 20 | #include "media/base/video_broadcaster.h" 21 | 22 | namespace webrtc { 23 | namespace test { 24 | 25 | class TestVideoCapturer : public rtc::VideoSourceInterface { 26 | public: 27 | TestVideoCapturer(); 28 | virtual ~TestVideoCapturer(); 29 | 30 | void AddOrUpdateSink(rtc::VideoSinkInterface* sink, 31 | const rtc::VideoSinkWants& wants) override; 32 | void RemoveSink(rtc::VideoSinkInterface* sink) override; 33 | 34 | protected: 35 | void OnFrame(const VideoFrame& frame); 36 | rtc::VideoSinkWants GetSinkWants(); 37 | 38 | private: 39 | void UpdateVideoAdapter(); 40 | 41 | rtc::VideoBroadcaster broadcaster_; 42 | cricket::VideoAdapter video_adapter_; 43 | }; 44 | } // namespace test 45 | } // namespace webrtc 46 | 47 | #endif // TEST_TEST_VIDEO_CAPTURER_H_ 48 | -------------------------------------------------------------------------------- /examples/DesktopCamera/test/vcm_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "vcm_capturer.h" 12 | 13 | #include 14 | #include 15 | 16 | #include "modules/video_capture/video_capture_factory.h" 17 | #include "rtc_base/checks.h" 18 | #include "rtc_base/logging.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | 23 | VcmCapturer::VcmCapturer() : vcm_(nullptr) {} 24 | 25 | bool VcmCapturer::Init(size_t width, 26 | size_t height, 27 | size_t target_fps, 28 | size_t capture_device_index) { 29 | std::unique_ptr device_info( 30 | VideoCaptureFactory::CreateDeviceInfo()); 31 | 32 | char device_name[256]; 33 | char unique_name[256]; 34 | if (device_info->GetDeviceName(static_cast(capture_device_index), 35 | device_name, sizeof(device_name), unique_name, 36 | sizeof(unique_name)) != 0) { 37 | Destroy(); 38 | return false; 39 | } 40 | 41 | vcm_ = webrtc::VideoCaptureFactory::Create(unique_name); 42 | if (!vcm_) { 43 | return false; 44 | } 45 | vcm_->RegisterCaptureDataCallback(this); 46 | 47 | device_info->GetCapability(vcm_->CurrentDeviceName(), 0, capability_); 48 | 49 | capability_.width = static_cast(width); 50 | capability_.height = static_cast(height); 51 | capability_.maxFPS = static_cast(target_fps); 52 | capability_.videoType = VideoType::kI420; 53 | 54 | if (vcm_->StartCapture(capability_) != 0) { 55 | Destroy(); 56 | return false; 57 | } 58 | 59 | RTC_CHECK(vcm_->CaptureStarted()); 60 | 61 | return true; 62 | } 63 | 64 | VcmCapturer* VcmCapturer::Create(size_t width, 65 | size_t height, 66 | size_t target_fps, 67 | size_t capture_device_index) { 68 | std::unique_ptr vcm_capturer(new VcmCapturer()); 69 | if (!vcm_capturer->Init(width, height, target_fps, capture_device_index)) { 70 | RTC_LOG(LS_WARNING) << "Failed to create VcmCapturer(w = " << width 71 | << ", h = " << height << ", fps = " << target_fps 72 | << ")"; 73 | return nullptr; 74 | } 75 | return vcm_capturer.release(); 76 | } 77 | 78 | void VcmCapturer::Destroy() { 79 | if (!vcm_) 80 | return; 81 | 82 | vcm_->StopCapture(); 83 | vcm_->DeRegisterCaptureDataCallback(); 84 | // Release reference to VCM. 85 | vcm_ = nullptr; 86 | } 87 | 88 | VcmCapturer::~VcmCapturer() { 89 | Destroy(); 90 | } 91 | 92 | void VcmCapturer::OnFrame(const VideoFrame& frame) { 93 | TestVideoCapturer::OnFrame(frame); 94 | } 95 | 96 | } // namespace test 97 | } // namespace webrtc 98 | -------------------------------------------------------------------------------- /examples/DesktopCamera/test/vcm_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_VCM_CAPTURER_H_ 11 | #define TEST_VCM_CAPTURER_H_ 12 | 13 | #include 14 | #include 15 | 16 | #include "api/scoped_refptr.h" 17 | #include "modules/video_capture/video_capture.h" 18 | #include "test_video_capturer.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | 23 | class VcmCapturer : public TestVideoCapturer, 24 | public rtc::VideoSinkInterface { 25 | public: 26 | static VcmCapturer* Create(size_t width, 27 | size_t height, 28 | size_t target_fps, 29 | size_t capture_device_index); 30 | virtual ~VcmCapturer(); 31 | 32 | void OnFrame(const VideoFrame& frame) override; 33 | 34 | private: 35 | VcmCapturer(); 36 | bool Init(size_t width, 37 | size_t height, 38 | size_t target_fps, 39 | size_t capture_device_index); 40 | void Destroy(); 41 | 42 | rtc::scoped_refptr vcm_; 43 | VideoCaptureCapability capability_; 44 | }; 45 | 46 | } // namespace test 47 | } // namespace webrtc 48 | 49 | #endif // TEST_VCM_CAPTURER_H_ 50 | -------------------------------------------------------------------------------- /examples/DesktopCamera/widget.h: -------------------------------------------------------------------------------- 1 | #ifndef WIDGET_H 2 | #define WIDGET_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "modules/desktop_capture/desktop_capturer.h" 9 | #include 10 | #include "modules/video_capture/video_capture.h" 11 | #include "test_video_capturer.h" 12 | 13 | namespace Ui { 14 | class Widget; 15 | } 16 | 17 | class Widget : public QWidget 18 | , public webrtc::DesktopCapturer::Callback 19 | , public rtc::VideoSinkInterface 20 | { 21 | Q_OBJECT 22 | 23 | public: 24 | explicit Widget(QWidget *parent = nullptr); 25 | ~Widget(); 26 | 27 | // DesktopCapturer::Callback 28 | // Called after a frame has been captured. |frame| is not nullptr if and 29 | // only if |result| is SUCCESS. 30 | void OnCaptureResult(webrtc::DesktopCapturer::Result result, 31 | std::unique_ptr frame) override; 32 | 33 | // VideoSinkInterface 34 | void OnFrame(const webrtc::VideoFrame& frame) override; 35 | 36 | Q_SIGNALS: 37 | void recvFrame(); 38 | 39 | private Q_SLOTS: 40 | void on_getWindowsBtn_clicked(); 41 | 42 | void on_startCaptureBtn_clicked(); 43 | 44 | void on_stopCaptureBtn_clicked(); 45 | 46 | void on_sourceListComBox_currentIndexChanged(int index); 47 | 48 | void onRecvFrame(); 49 | 50 | Q_SIGNALS: 51 | void recvVideoFrame(); 52 | 53 | private Q_SLOTS: 54 | void onRecvVideoFrame(); 55 | 56 | 57 | void OpenVideoCaptureDevice(); 58 | void CloseVideoCaptureDevice(); 59 | 60 | private: 61 | Ui::Widget *ui; 62 | 63 | std::unique_ptr window_capturer_; 64 | std::unique_ptr screen_capturer_; 65 | webrtc::DesktopCapturer::SourceId source_ = -1; 66 | QTimer* timer_ = new QTimer(this); 67 | 68 | QMutex mutex_; 69 | rtc::scoped_refptr i420_buffer_; 70 | 71 | std::unique_ptr video_capturer_; 72 | 73 | QMutex mutex_v_; 74 | rtc::scoped_refptr i420_buffer_v_; 75 | }; 76 | 77 | #endif // WIDGET_H 78 | -------------------------------------------------------------------------------- /examples/DesktopCamera/widget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Widget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 700 10 | 500 11 | 12 | 13 | 14 | 15 | 700 16 | 500 17 | 18 | 19 | 20 | DesktopCapturer 21 | 22 | 23 | 24 | 25 | 26 | background-color: rgb(0, 0, 0); 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 0 35 | 50 36 | 37 | 38 | 39 | 40 | 16777215 41 | 50 42 | 43 | 44 | 45 | 46 | 47 | 48 | Qt::Horizontal 49 | 50 | 51 | 52 | 40 53 | 20 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 窗口捕获 62 | 63 | 64 | true 65 | 66 | 67 | 68 | 69 | 70 | 71 | 屏幕捕获 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 刷新 82 | 83 | 84 | 85 | 86 | 87 | 88 | 开始 89 | 90 | 91 | 92 | 93 | 94 | 95 | 停止 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | QYUVOpenGLWidget 108 | QWidget 109 |
qyuvopenglwidget.h
110 | 1 111 |
112 |
113 | 114 | 115 |
116 | -------------------------------------------------------------------------------- /examples/DesktopCapturer/DesktopCapturer.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2019-07-21T19:40:56 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = DesktopCapturer 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which has been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | CONFIG += c++17 26 | 27 | SOURCES += \ 28 | main.cpp \ 29 | widget.cpp 30 | 31 | HEADERS += \ 32 | widget.h 33 | 34 | FORMS += \ 35 | widget.ui 36 | 37 | # Default rules for deployment. 38 | qnx: target.path = /tmp/$${TARGET}/bin 39 | else: unix:!android: target.path = /opt/$${TARGET}/bin 40 | !isEmpty(target.path): INSTALLS += target 41 | 42 | include($$PWD/../webrtc_common/webrtc_common.pri) 43 | include($$PWD/render/render.pri) 44 | 45 | INCLUDEPATH += \ 46 | $$PWD/render 47 | 48 | macos { 49 | QMAKE_INFO_PLIST = $$PWD/Info.plist 50 | } 51 | -------------------------------------------------------------------------------- /examples/DesktopCapturer/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 19A546d 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleDisplayName 10 | DesktopCapturer 11 | CFBundleExecutable 12 | DesktopCapturer 13 | CFBundleIdentifier 14 | com.barry.DesktopCapturer 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | DesktopCapturer 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleVersion 24 | 1.0 25 | DTCompiler 26 | com.apple.compilers.llvm.clang.1_0 27 | DTSDKBuild 28 | 10.14 29 | DTSDKName 30 | macosx10.14 31 | DTXcode 32 | 1021 33 | DTXcodeBuild 34 | 10E1001 35 | LSMinimumSystemVersion 36 | 10.10.0 37 | NSPrincipalClass 38 | NSApplication 39 | 40 | 41 | -------------------------------------------------------------------------------- /examples/DesktopCapturer/main.cpp: -------------------------------------------------------------------------------- 1 | #include "widget.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 7 | QApplication a(argc, argv); 8 | Widget w; 9 | w.show(); 10 | 11 | return a.exec(); 12 | } 13 | -------------------------------------------------------------------------------- /examples/DesktopCapturer/readme.md: -------------------------------------------------------------------------------- 1 | [DesktopCapturer-image]: https://raw.githubusercontent.com/barry-ran/learn_webrtc/master/examples/DesktopCapturer/screenshot/main.png 2 | 3 | ![界面][DesktopCapturer-image] 4 | 5 | # DesktopCapturer 6 | 在webrtc桌面捕获模块中主要包括两部分,屏幕捕获和窗口捕获: 7 | 8 | - 桌面捕获,使用了三种方案,可自行设置使用哪种方案: 9 | 1. gdi 10 | 2. directx 11 | 3. magnifier 12 | - 窗口捕获,只有一种方案,且有bug 13 | 1. GetWindowDc + PrintWindow 14 | 15 | 这种方法没法获取硬件加速窗口或者opengl等绘制的显存窗口(例如Electron开发的客户端,qtwebengine窗口等),获取到一片黑 16 | 17 | 可以使用magnifier方案,然后将目标窗口以外的所有窗口(包括桌面)都忽略掉,达到目标窗口捕获的效果 18 | 19 | # 使用方法 20 | 1. 创建DesktopCapturer 21 | 2. 设置回调处理函数 22 | 3. 定时CaptureFrame()捕获 23 | 4. 回调函数中处理回调数据(回调数据为rgba) 24 | 25 | # 参考链接 26 | [视频直播:Windows中各类画面源的截取和合成方法总结](https://www.jianshu.com/p/0bbb9c4be735) 27 | 28 | [若干种窗口画面的捕获方法](https://blog.csdn.net/felicityWSH/article/details/62218390) 29 | -------------------------------------------------------------------------------- /examples/DesktopCapturer/render/qyuvopenglwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef QYUVOPENGLWIDGET_H 2 | #define QYUVOPENGLWIDGET_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class QYUVOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit QYUVOpenGLWidget(QWidget *parent = nullptr); 13 | virtual ~QYUVOpenGLWidget(); 14 | 15 | QSize minimumSizeHint() const override; 16 | QSize sizeHint() const override; 17 | 18 | void setFrameSize(const QSize& frameSize); 19 | const QSize& frameSize(); 20 | void updateTextures(const quint8* dataY, const quint8* dataU, const quint8* dataV, quint32 linesizeY, quint32 linesizeU, quint32 linesizeV); 21 | 22 | protected: 23 | void initializeGL(); 24 | void paintGL(); 25 | void resizeGL(int width, int height); 26 | 27 | private: 28 | void initShader(); 29 | void initTextures(); 30 | void deInitTextures(); 31 | void updateTexture(GLuint texture, quint32 textureType, const quint8* pixels, quint32 stride); 32 | 33 | private: 34 | // 视频帧尺寸 35 | QSize m_frameSize = {-1, -1}; 36 | bool m_needUpdate = false; 37 | bool m_textureInited = false; 38 | 39 | // 顶点缓冲对象(Vertex Buffer Objects, VBO):默认即为VertexBuffer(GL_ARRAY_BUFFER)类型 40 | QOpenGLBuffer m_vbo; 41 | 42 | // 着色器程序:编译链接着色器 43 | QOpenGLShaderProgram m_shaderProgram; 44 | 45 | // YUV纹理,用于生成纹理贴图 46 | GLuint m_texture[3] = {0}; 47 | }; 48 | 49 | #endif // QYUVOPENGLWIDGET_H 50 | -------------------------------------------------------------------------------- /examples/DesktopCapturer/render/render.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/qyuvopenglwidget.h 3 | 4 | SOURCES += \ 5 | $$PWD/qyuvopenglwidget.cpp 6 | -------------------------------------------------------------------------------- /examples/DesktopCapturer/screenshot/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/examples/DesktopCapturer/screenshot/main.png -------------------------------------------------------------------------------- /examples/DesktopCapturer/widget.h: -------------------------------------------------------------------------------- 1 | #ifndef WIDGET_H 2 | #define WIDGET_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "modules/desktop_capture/desktop_capturer.h" 9 | #include 10 | 11 | namespace Ui { 12 | class Widget; 13 | } 14 | 15 | class Widget : public QWidget, 16 | public webrtc::DesktopCapturer::Callback 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | explicit Widget(QWidget *parent = nullptr); 22 | ~Widget(); 23 | 24 | // DesktopCapturer::Callback 25 | // Called after a frame has been captured. |frame| is not nullptr if and 26 | // only if |result| is SUCCESS. 27 | void OnCaptureResult(webrtc::DesktopCapturer::Result result, 28 | std::unique_ptr frame) override; 29 | 30 | Q_SIGNALS: 31 | void recvFrame(); 32 | 33 | private Q_SLOTS: 34 | void on_getWindowsBtn_clicked(); 35 | 36 | void on_startCaptureBtn_clicked(); 37 | 38 | void on_stopCaptureBtn_clicked(); 39 | 40 | void on_sourceListComBox_currentIndexChanged(int index); 41 | 42 | void onRecvFrame(); 43 | 44 | 45 | private: 46 | Ui::Widget *ui; 47 | 48 | std::unique_ptr window_capturer_; 49 | std::unique_ptr screen_capturer_; 50 | webrtc::DesktopCapturer::SourceId source_ = -1; 51 | QTimer* timer_ = new QTimer(this); 52 | 53 | QMutex mutex_; 54 | rtc::scoped_refptr i420_buffer_; 55 | }; 56 | 57 | #endif // WIDGET_H 58 | -------------------------------------------------------------------------------- /examples/DesktopCapturer/widget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Widget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 700 10 | 500 11 | 12 | 13 | 14 | 15 | 700 16 | 500 17 | 18 | 19 | 20 | DesktopCapturer 21 | 22 | 23 | 24 | 25 | 26 | background-color: rgb(0, 0, 0); 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 0 35 | 50 36 | 37 | 38 | 39 | 40 | 16777215 41 | 50 42 | 43 | 44 | 45 | 46 | 47 | 48 | Qt::Horizontal 49 | 50 | 51 | 52 | 40 53 | 20 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 窗口捕获 62 | 63 | 64 | true 65 | 66 | 67 | 68 | 69 | 70 | 71 | 屏幕捕获 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 刷新 82 | 83 | 84 | 85 | 86 | 87 | 88 | 开始 89 | 90 | 91 | 92 | 93 | 94 | 95 | 停止 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | QYUVOpenGLWidget 108 | QWidget 109 |
qyuvopenglwidget.h
110 | 1 111 |
112 |
113 | 114 | 115 |
116 | -------------------------------------------------------------------------------- /examples/OpenCamera/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 19A546d 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleDisplayName 10 | OpenCamera 11 | CFBundleExecutable 12 | OpenCamera 13 | CFBundleIdentifier 14 | com.Google.OpenCamera 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | OpenCamera 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleVersion 24 | 1.0 25 | DTCompiler 26 | com.apple.compilers.llvm.clang.1_0 27 | DTSDKBuild 28 | 10.14 29 | DTSDKName 30 | macosx10.14 31 | DTXcode 32 | 1021 33 | DTXcodeBuild 34 | 10E1001 35 | LSMinimumSystemVersion 36 | 10.10.0 37 | NSCameraUsageDescription 38 | Camera access needed for video calling 39 | NSMicrophoneUsageDescription 40 | Microphone access needed for video calling 41 | NSPrincipalClass 42 | NSApplication 43 | 44 | 45 | -------------------------------------------------------------------------------- /examples/OpenCamera/OpenCamera.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2019-08-09T21:10:41 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = OpenCamera 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which has been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | CONFIG += c++17 26 | 27 | SOURCES += \ 28 | main.cpp \ 29 | widget.cpp 30 | 31 | HEADERS += \ 32 | widget.h 33 | 34 | FORMS += \ 35 | widget.ui 36 | 37 | # Default rules for deployment. 38 | qnx: target.path = /tmp/$${TARGET}/bin 39 | else: unix:!android: target.path = /opt/$${TARGET}/bin 40 | !isEmpty(target.path): INSTALLS += target 41 | 42 | include($$PWD/../webrtc_common/webrtc_common.pri) 43 | include($$PWD/test/test.pri) 44 | include($$PWD/render/render.pri) 45 | 46 | INCLUDEPATH += \ 47 | $$PWD/test \ 48 | $$PWD/render 49 | 50 | macos { 51 | QMAKE_INFO_PLIST = $$PWD/Info.plist 52 | } 53 | -------------------------------------------------------------------------------- /examples/OpenCamera/main.cpp: -------------------------------------------------------------------------------- 1 | #include "widget.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 7 | QApplication a(argc, argv); 8 | Widget w; 9 | w.show(); 10 | 11 | return a.exec(); 12 | } 13 | -------------------------------------------------------------------------------- /examples/OpenCamera/render/qyuvopenglwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef QYUVOPENGLWIDGET_H 2 | #define QYUVOPENGLWIDGET_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class QYUVOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit QYUVOpenGLWidget(QWidget *parent = nullptr); 13 | virtual ~QYUVOpenGLWidget(); 14 | 15 | QSize minimumSizeHint() const override; 16 | QSize sizeHint() const override; 17 | 18 | void setFrameSize(const QSize& frameSize); 19 | const QSize& frameSize(); 20 | void updateTextures(const quint8* dataY, const quint8* dataU, const quint8* dataV, quint32 linesizeY, quint32 linesizeU, quint32 linesizeV); 21 | 22 | protected: 23 | void initializeGL(); 24 | void paintGL(); 25 | void resizeGL(int width, int height); 26 | 27 | private: 28 | void initShader(); 29 | void initTextures(); 30 | void deInitTextures(); 31 | void updateTexture(GLuint texture, quint32 textureType, const quint8* pixels, quint32 stride); 32 | 33 | private: 34 | // 视频帧尺寸 35 | QSize m_frameSize = {-1, -1}; 36 | bool m_needUpdate = false; 37 | bool m_textureInited = false; 38 | 39 | // 顶点缓冲对象(Vertex Buffer Objects, VBO):默认即为VertexBuffer(GL_ARRAY_BUFFER)类型 40 | QOpenGLBuffer m_vbo; 41 | 42 | // 着色器程序:编译链接着色器 43 | QOpenGLShaderProgram m_shaderProgram; 44 | 45 | // YUV纹理,用于生成纹理贴图 46 | GLuint m_texture[3] = {0}; 47 | }; 48 | 49 | #endif // QYUVOPENGLWIDGET_H 50 | -------------------------------------------------------------------------------- /examples/OpenCamera/render/render.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/qyuvopenglwidget.h 3 | 4 | SOURCES += \ 5 | $$PWD/qyuvopenglwidget.cpp 6 | -------------------------------------------------------------------------------- /examples/OpenCamera/test/mac_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_MAC_CAPTURER_H_ 11 | #define TEST_MAC_CAPTURER_H_ 12 | 13 | #include 14 | #include 15 | 16 | #include "api/media_stream_interface.h" 17 | #include "api/scoped_refptr.h" 18 | #include "modules/video_capture/video_capture.h" 19 | #include "rtc_base/thread.h" 20 | #include "test/test_video_capturer.h" 21 | 22 | namespace webrtc { 23 | namespace test { 24 | 25 | class MacCapturer : public TestVideoCapturer, 26 | public rtc::VideoSinkInterface { 27 | public: 28 | static MacCapturer* Create(size_t width, 29 | size_t height, 30 | size_t target_fps, 31 | size_t capture_device_index); 32 | ~MacCapturer() override; 33 | 34 | void OnFrame(const VideoFrame& frame) override; 35 | 36 | private: 37 | MacCapturer(size_t width, 38 | size_t height, 39 | size_t target_fps, 40 | size_t capture_device_index); 41 | void Destroy(); 42 | 43 | void* capturer_; 44 | void* adapter_; 45 | }; 46 | 47 | } // namespace test 48 | } // namespace webrtc 49 | 50 | #endif // TEST_MAC_CAPTURER_H_ 51 | -------------------------------------------------------------------------------- /examples/OpenCamera/test/platform_video_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #include "platform_video_capturer.h" 11 | 12 | #include "absl/memory/memory.h" 13 | #if defined(WEBRTC_MAC) 14 | #include "test/mac_capturer.h" 15 | #else 16 | #include "vcm_capturer.h" 17 | #endif 18 | 19 | namespace webrtc { 20 | namespace test { 21 | 22 | std::unique_ptr CreateVideoCapturer( 23 | size_t width, 24 | size_t height, 25 | size_t target_fps, 26 | size_t capture_device_index) { 27 | #if defined(WEBRTC_MAC) 28 | return absl::WrapUnique(test::MacCapturer::Create( 29 | width, height, target_fps, capture_device_index)); 30 | #else 31 | return absl::WrapUnique(test::VcmCapturer::Create( 32 | width, height, target_fps, capture_device_index)); 33 | #endif 34 | } 35 | 36 | } // namespace test 37 | } // namespace webrtc 38 | -------------------------------------------------------------------------------- /examples/OpenCamera/test/platform_video_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_PLATFORM_VIDEO_CAPTURER_H_ 11 | #define TEST_PLATFORM_VIDEO_CAPTURER_H_ 12 | 13 | #include 14 | 15 | #include "test_video_capturer.h" 16 | 17 | namespace webrtc { 18 | namespace test { 19 | 20 | std::unique_ptr CreateVideoCapturer( 21 | size_t width, 22 | size_t height, 23 | size_t target_fps, 24 | size_t capture_device_index); 25 | 26 | } // namespace test 27 | } // namespace webrtc 28 | 29 | #endif // TEST_PLATFORM_VIDEO_CAPTURER_H_ 30 | -------------------------------------------------------------------------------- /examples/OpenCamera/test/test.pri: -------------------------------------------------------------------------------- 1 | SOURCES += \ 2 | $$PWD/test_video_capturer.cc \ 3 | $$PWD/platform_video_capturer.cc \ 4 | 5 | HEADERS += \ 6 | $$PWD/test_video_capturer.h \ 7 | $$PWD/platform_video_capturer.h 8 | 9 | win32 { 10 | SOURCES += \ 11 | $$PWD/vcm_capturer.cc 12 | 13 | HEADERS += \ 14 | $$PWD/vcm_capturer.h 15 | } 16 | 17 | macos { 18 | SOURCES += \ 19 | $$PWD/mac_capturer.mm 20 | 21 | HEADERS += \ 22 | $$PWD/mac_capturer.h 23 | } 24 | -------------------------------------------------------------------------------- /examples/OpenCamera/test/test_video_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "test_video_capturer.h" 12 | 13 | #include 14 | 15 | #include "api/scoped_refptr.h" 16 | #include "api/video/i420_buffer.h" 17 | #include "api/video/video_frame_buffer.h" 18 | #include "api/video/video_rotation.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | TestVideoCapturer::TestVideoCapturer() = default; 23 | TestVideoCapturer::~TestVideoCapturer() = default; 24 | 25 | void TestVideoCapturer::OnFrame(const VideoFrame& frame) { 26 | int cropped_width = 0; 27 | int cropped_height = 0; 28 | int out_width = 0; 29 | int out_height = 0; 30 | 31 | if (!video_adapter_.AdaptFrameResolution( 32 | frame.width(), frame.height(), frame.timestamp_us() * 1000, 33 | &cropped_width, &cropped_height, &out_width, &out_height)) { 34 | // Drop frame in order to respect frame rate constraint. 35 | return; 36 | } 37 | 38 | if (out_height != frame.height() || out_width != frame.width()) { 39 | // Video adapter has requested a down-scale. Allocate a new buffer and 40 | // return scaled version. 41 | rtc::scoped_refptr scaled_buffer = 42 | I420Buffer::Create(out_width, out_height); 43 | scaled_buffer->ScaleFrom(*frame.video_frame_buffer()->ToI420()); 44 | broadcaster_.OnFrame(VideoFrame::Builder() 45 | .set_video_frame_buffer(scaled_buffer) 46 | .set_rotation(kVideoRotation_0) 47 | .set_timestamp_us(frame.timestamp_us()) 48 | .set_id(frame.id()) 49 | .build()); 50 | } else { 51 | // No adaptations needed, just return the frame as is. 52 | broadcaster_.OnFrame(frame); 53 | } 54 | } 55 | 56 | rtc::VideoSinkWants TestVideoCapturer::GetSinkWants() { 57 | return broadcaster_.wants(); 58 | } 59 | 60 | void TestVideoCapturer::AddOrUpdateSink( 61 | rtc::VideoSinkInterface* sink, 62 | const rtc::VideoSinkWants& wants) { 63 | broadcaster_.AddOrUpdateSink(sink, wants); 64 | UpdateVideoAdapter(); 65 | } 66 | 67 | void TestVideoCapturer::RemoveSink(rtc::VideoSinkInterface* sink) { 68 | broadcaster_.RemoveSink(sink); 69 | UpdateVideoAdapter(); 70 | } 71 | 72 | void TestVideoCapturer::UpdateVideoAdapter() { 73 | rtc::VideoSinkWants wants = broadcaster_.wants(); 74 | video_adapter_.OnSinkWants(broadcaster_.wants()); 75 | } 76 | 77 | } // namespace test 78 | } // namespace webrtc 79 | -------------------------------------------------------------------------------- /examples/OpenCamera/test/test_video_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_TEST_VIDEO_CAPTURER_H_ 11 | #define TEST_TEST_VIDEO_CAPTURER_H_ 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include "api/video/video_frame.h" 18 | #include "api/video/video_source_interface.h" 19 | #include "media/base/video_adapter.h" 20 | #include "media/base/video_broadcaster.h" 21 | 22 | namespace webrtc { 23 | namespace test { 24 | 25 | class TestVideoCapturer : public rtc::VideoSourceInterface { 26 | public: 27 | TestVideoCapturer(); 28 | virtual ~TestVideoCapturer(); 29 | 30 | void AddOrUpdateSink(rtc::VideoSinkInterface* sink, 31 | const rtc::VideoSinkWants& wants) override; 32 | void RemoveSink(rtc::VideoSinkInterface* sink) override; 33 | 34 | protected: 35 | void OnFrame(const VideoFrame& frame); 36 | rtc::VideoSinkWants GetSinkWants(); 37 | 38 | private: 39 | void UpdateVideoAdapter(); 40 | 41 | rtc::VideoBroadcaster broadcaster_; 42 | cricket::VideoAdapter video_adapter_; 43 | }; 44 | } // namespace test 45 | } // namespace webrtc 46 | 47 | #endif // TEST_TEST_VIDEO_CAPTURER_H_ 48 | -------------------------------------------------------------------------------- /examples/OpenCamera/test/vcm_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "vcm_capturer.h" 12 | 13 | #include 14 | #include 15 | 16 | #include "modules/video_capture/video_capture_factory.h" 17 | #include "rtc_base/checks.h" 18 | #include "rtc_base/logging.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | 23 | VcmCapturer::VcmCapturer() : vcm_(nullptr) {} 24 | 25 | bool VcmCapturer::Init(size_t width, 26 | size_t height, 27 | size_t target_fps, 28 | size_t capture_device_index) { 29 | std::unique_ptr device_info( 30 | VideoCaptureFactory::CreateDeviceInfo()); 31 | 32 | char device_name[256]; 33 | char unique_name[256]; 34 | if (device_info->GetDeviceName(static_cast(capture_device_index), 35 | device_name, sizeof(device_name), unique_name, 36 | sizeof(unique_name)) != 0) { 37 | Destroy(); 38 | return false; 39 | } 40 | 41 | vcm_ = webrtc::VideoCaptureFactory::Create(unique_name); 42 | if (!vcm_) { 43 | return false; 44 | } 45 | vcm_->RegisterCaptureDataCallback(this); 46 | 47 | device_info->GetCapability(vcm_->CurrentDeviceName(), 0, capability_); 48 | 49 | capability_.width = static_cast(width); 50 | capability_.height = static_cast(height); 51 | capability_.maxFPS = static_cast(target_fps); 52 | capability_.videoType = VideoType::kI420; 53 | 54 | if (vcm_->StartCapture(capability_) != 0) { 55 | Destroy(); 56 | return false; 57 | } 58 | 59 | RTC_CHECK(vcm_->CaptureStarted()); 60 | 61 | return true; 62 | } 63 | 64 | VcmCapturer* VcmCapturer::Create(size_t width, 65 | size_t height, 66 | size_t target_fps, 67 | size_t capture_device_index) { 68 | std::unique_ptr vcm_capturer(new VcmCapturer()); 69 | if (!vcm_capturer->Init(width, height, target_fps, capture_device_index)) { 70 | RTC_LOG(LS_WARNING) << "Failed to create VcmCapturer(w = " << width 71 | << ", h = " << height << ", fps = " << target_fps 72 | << ")"; 73 | return nullptr; 74 | } 75 | return vcm_capturer.release(); 76 | } 77 | 78 | void VcmCapturer::Destroy() { 79 | if (!vcm_) 80 | return; 81 | 82 | vcm_->StopCapture(); 83 | vcm_->DeRegisterCaptureDataCallback(); 84 | // Release reference to VCM. 85 | vcm_ = nullptr; 86 | } 87 | 88 | VcmCapturer::~VcmCapturer() { 89 | Destroy(); 90 | } 91 | 92 | void VcmCapturer::OnFrame(const VideoFrame& frame) { 93 | TestVideoCapturer::OnFrame(frame); 94 | } 95 | 96 | } // namespace test 97 | } // namespace webrtc 98 | -------------------------------------------------------------------------------- /examples/OpenCamera/test/vcm_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_VCM_CAPTURER_H_ 11 | #define TEST_VCM_CAPTURER_H_ 12 | 13 | #include 14 | #include 15 | 16 | #include "api/scoped_refptr.h" 17 | #include "modules/video_capture/video_capture.h" 18 | #include "test_video_capturer.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | 23 | class VcmCapturer : public TestVideoCapturer, 24 | public rtc::VideoSinkInterface { 25 | public: 26 | static VcmCapturer* Create(size_t width, 27 | size_t height, 28 | size_t target_fps, 29 | size_t capture_device_index); 30 | virtual ~VcmCapturer(); 31 | 32 | void OnFrame(const VideoFrame& frame) override; 33 | 34 | private: 35 | VcmCapturer(); 36 | bool Init(size_t width, 37 | size_t height, 38 | size_t target_fps, 39 | size_t capture_device_index); 40 | void Destroy(); 41 | 42 | rtc::scoped_refptr vcm_; 43 | VideoCaptureCapability capability_; 44 | }; 45 | 46 | } // namespace test 47 | } // namespace webrtc 48 | 49 | #endif // TEST_VCM_CAPTURER_H_ 50 | -------------------------------------------------------------------------------- /examples/OpenCamera/widget.h: -------------------------------------------------------------------------------- 1 | #ifndef WIDGET_H 2 | #define WIDGET_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "modules/video_capture/video_capture.h" 9 | #include "test_video_capturer.h" 10 | 11 | namespace Ui { 12 | class Widget; 13 | } 14 | 15 | class Widget 16 | : public QWidget 17 | , public rtc::VideoSinkInterface 18 | { 19 | Q_OBJECT 20 | public: 21 | explicit Widget(QWidget *parent = nullptr); 22 | ~Widget(); 23 | 24 | // VideoSinkInterface 25 | void OnFrame(const webrtc::VideoFrame& frame) override; 26 | 27 | Q_SIGNALS: 28 | void recvFrame(); 29 | 30 | private Q_SLOTS: 31 | void on_startBtn_clicked(); 32 | 33 | void on_stopBtn_clicked(); 34 | 35 | void OpenVideoCaptureDevice(); 36 | void CloseVideoCaptureDevice(); 37 | 38 | void on_updateDeviceBtn_clicked(); 39 | 40 | void onRecvFrame(); 41 | 42 | private: 43 | Ui::Widget *ui; 44 | 45 | std::unique_ptr video_capturer_; 46 | 47 | QMutex mutex_; 48 | rtc::scoped_refptr i420_buffer_; 49 | }; 50 | 51 | #endif // WIDGET_H 52 | -------------------------------------------------------------------------------- /examples/OpenCamera/widget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Widget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 643 10 | 392 11 | 12 | 13 | 14 | Widget 15 | 16 | 17 | 18 | 19 | 20 | background-color: rgb(0, 0, 0); 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 16777215 29 | 50 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | update device 40 | 41 | 42 | 43 | 44 | 45 | 46 | start 47 | 48 | 49 | 50 | 51 | 52 | 53 | stop 54 | 55 | 56 | 57 | 58 | 59 | 60 | Qt::Horizontal 61 | 62 | 63 | 64 | 40 65 | 20 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | QYUVOpenGLWidget 79 | QWidget 80 |
qyuvopenglwidget.h
81 | 1 82 |
83 |
84 | 85 | 86 |
87 | -------------------------------------------------------------------------------- /examples/peerconnection/client/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 19A546d 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleDisplayName 10 | Client 11 | CFBundleExecutable 12 | Client 13 | CFBundleIdentifier 14 | com.Google.Client 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | Client 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleVersion 24 | 1.0 25 | DTCompiler 26 | com.apple.compilers.llvm.clang.1_0 27 | DTSDKBuild 28 | 10.14 29 | DTSDKName 30 | macosx10.14 31 | DTXcode 32 | 1021 33 | DTXcodeBuild 34 | 10E1001 35 | LSMinimumSystemVersion 36 | 10.10.0 37 | NSCameraUsageDescription 38 | Camera access needed for video calling 39 | NSMicrophoneUsageDescription 40 | Microphone access needed for video calling 41 | NSPrincipalClass 42 | NSApplication 43 | 44 | 45 | -------------------------------------------------------------------------------- /examples/peerconnection/client/client.pro: -------------------------------------------------------------------------------- 1 | QT += core gui 2 | 3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 | 5 | CONFIG += c++17 6 | 7 | # The following define makes your compiler emit warnings if you use 8 | # any Qt feature that has been marked deprecated (the exact warnings 9 | # depend on your compiler). Please consult the documentation of the 10 | # deprecated API in order to know how to port your code away from it. 11 | DEFINES += QT_DEPRECATED_WARNINGS 12 | 13 | # You can also make your code fail to compile if it uses deprecated APIs. 14 | # In order to do so, uncomment the following line. 15 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 16 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 17 | 18 | SOURCES += \ 19 | main.cpp \ 20 | main_wnd.cpp \ 21 | defaults.cc \ 22 | peer_connection_client.cc \ 23 | conductor.cc \ 24 | videorenderer.cpp 25 | 26 | HEADERS += \ 27 | main_wnd.h \ 28 | defaults.h \ 29 | peer_connection_client.h \ 30 | conductor.h \ 31 | videorenderer.h 32 | 33 | FORMS += \ 34 | mainwnd.ui 35 | 36 | # Default rules for deployment. 37 | qnx: target.path = /tmp/$${TARGET}/bin 38 | else: unix:!android: target.path = /opt/$${TARGET}/bin 39 | !isEmpty(target.path): INSTALLS += target 40 | 41 | include($$PWD/../../webrtc_common/webrtc_common.pri) 42 | include($$PWD/test/test.pri) 43 | include($$PWD/render/render.pri) 44 | 45 | INCLUDEPATH += \ 46 | $$PWD/test \ 47 | $$PWD/render 48 | 49 | macos { 50 | QMAKE_INFO_PLIST = $$PWD/Info.plist 51 | } 52 | -------------------------------------------------------------------------------- /examples/peerconnection/client/defaults.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "defaults.h" 12 | 13 | #include 14 | 15 | #ifdef WIN32 16 | #include 17 | #else 18 | #include 19 | #endif 20 | 21 | #include "rtc_base/arraysize.h" 22 | 23 | const char kAudioLabel[] = "audio_label"; 24 | const char kVideoLabel[] = "video_label"; 25 | const char kStreamId[] = "stream_id"; 26 | const uint16_t kDefaultServerPort = 8888; 27 | 28 | std::string GetEnvVarOrDefault(const char* env_var_name, 29 | const char* default_value) { 30 | std::string value; 31 | const char* env_var = getenv(env_var_name); 32 | if (env_var) 33 | value = env_var; 34 | 35 | if (value.empty()) 36 | value = default_value; 37 | 38 | return value; 39 | } 40 | 41 | std::string GetPeerConnectionString() { 42 | return GetEnvVarOrDefault("WEBRTC_CONNECT", "stun:stun.l.google.com:19302"); 43 | } 44 | 45 | std::string GetDefaultServerName() { 46 | return GetEnvVarOrDefault("WEBRTC_SERVER", "localhost"); 47 | } 48 | 49 | std::string GetPeerName() { 50 | char computer_name[256]; 51 | std::string ret(GetEnvVarOrDefault("USERNAME", "user")); 52 | ret += '@'; 53 | if (gethostname(computer_name, arraysize(computer_name)) == 0) { 54 | ret += computer_name; 55 | } else { 56 | ret += "host"; 57 | } 58 | return ret; 59 | } 60 | -------------------------------------------------------------------------------- /examples/peerconnection/client/defaults.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #ifndef EXAMPLES_PEERCONNECTION_CLIENT_DEFAULTS_H_ 12 | #define EXAMPLES_PEERCONNECTION_CLIENT_DEFAULTS_H_ 13 | 14 | #include 15 | 16 | #include 17 | 18 | extern const char kAudioLabel[]; 19 | extern const char kVideoLabel[]; 20 | extern const char kStreamId[]; 21 | extern const uint16_t kDefaultServerPort; 22 | 23 | std::string GetEnvVarOrDefault(const char* env_var_name, 24 | const char* default_value); 25 | std::string GetPeerConnectionString(); 26 | std::string GetDefaultServerName(); 27 | std::string GetPeerName(); 28 | 29 | #endif // EXAMPLES_PEERCONNECTION_CLIENT_DEFAULTS_H_ 30 | -------------------------------------------------------------------------------- /examples/peerconnection/client/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main_wnd.h" 2 | 3 | #include 4 | #ifdef Q_OS_MAC 5 | #include 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | #include "conductor.h" 12 | #include "main_wnd.h" 13 | #include "peer_connection_client.h" 14 | #include "rtc_base/checks.h" 15 | #include "rtc_base/constructor_magic.h" 16 | #include "rtc_base/ssl_adapter.h" 17 | #ifdef Q_OS_WIN 18 | #include "rtc_base/win32_socket_init.h" 19 | #include "rtc_base/win32_socket_server.h" 20 | #endif 21 | #include "system_wrappers/include/field_trial.h" 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 26 | #ifdef Q_OS_WIN 27 | rtc::WinsockInitializer winsock_init; 28 | // 内部创建message wnd,定时在主线程处理message queue消息 29 | rtc::Win32SocketServer w32_ss; 30 | rtc::Win32Thread w32_thread(&w32_ss); 31 | rtc::ThreadManager::Instance()->SetCurrentThread(&w32_thread); 32 | #endif 33 | QApplication a(argc, argv); 34 | 35 | MainWnd wnd("", 0); 36 | if (!wnd.Create()) { 37 | RTC_NOTREACHED(); 38 | return -1; 39 | } 40 | 41 | rtc::InitializeSSL(); 42 | PeerConnectionClient client; 43 | rtc::scoped_refptr conductor( 44 | new rtc::RefCountedObject(&client, &wnd)); 45 | 46 | #ifdef Q_OS_MAC 47 | // for rtc::Thread::Current()->socketserver()->CreateAsyncSocket; 48 | // 定时在主线程处理message queue消息(这里主要为了socket消息),后面采用更好的方式 49 | QTimer processSocket(&a); 50 | QObject::connect(&processSocket, &QTimer::timeout, [=]() { 51 | rtc::Thread* thread = rtc::Thread::Current(); 52 | thread->ProcessMessages(0); 53 | }); 54 | processSocket.start(50); 55 | #endif 56 | 57 | int ret = a.exec(); 58 | 59 | #ifdef Q_OS_MAC 60 | processSocket.stop(); 61 | #endif 62 | 63 | rtc::CleanupSSL(); 64 | return ret; 65 | } 66 | -------------------------------------------------------------------------------- /examples/peerconnection/client/render/qyuvopenglwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef QYUVOPENGLWIDGET_H 2 | #define QYUVOPENGLWIDGET_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class QYUVOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit QYUVOpenGLWidget(QWidget *parent = nullptr); 13 | virtual ~QYUVOpenGLWidget(); 14 | 15 | QSize minimumSizeHint() const override; 16 | QSize sizeHint() const override; 17 | 18 | void setFrameSize(const QSize& frameSize); 19 | const QSize& frameSize(); 20 | void updateTextures(const quint8* dataY, const quint8* dataU, const quint8* dataV, quint32 linesizeY, quint32 linesizeU, quint32 linesizeV); 21 | 22 | protected: 23 | void initializeGL(); 24 | void paintGL(); 25 | void resizeGL(int width, int height); 26 | 27 | private: 28 | void initShader(); 29 | void initTextures(); 30 | void deInitTextures(); 31 | void updateTexture(GLuint texture, quint32 textureType, const quint8* pixels, quint32 stride); 32 | 33 | private: 34 | // 视频帧尺寸 35 | QSize m_frameSize = {-1, -1}; 36 | bool m_needUpdate = false; 37 | bool m_textureInited = false; 38 | 39 | // 顶点缓冲对象(Vertex Buffer Objects, VBO):默认即为VertexBuffer(GL_ARRAY_BUFFER)类型 40 | QOpenGLBuffer m_vbo; 41 | 42 | // 着色器程序:编译链接着色器 43 | QOpenGLShaderProgram m_shaderProgram; 44 | 45 | // YUV纹理,用于生成纹理贴图 46 | GLuint m_texture[3] = {0}; 47 | }; 48 | 49 | #endif // QYUVOPENGLWIDGET_H 50 | -------------------------------------------------------------------------------- /examples/peerconnection/client/render/render.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/qyuvopenglwidget.h 3 | 4 | SOURCES += \ 5 | $$PWD/qyuvopenglwidget.cpp 6 | -------------------------------------------------------------------------------- /examples/peerconnection/client/test/mac_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_MAC_CAPTURER_H_ 11 | #define TEST_MAC_CAPTURER_H_ 12 | 13 | #include 14 | #include 15 | 16 | #include "api/media_stream_interface.h" 17 | #include "api/scoped_refptr.h" 18 | #include "modules/video_capture/video_capture.h" 19 | #include "rtc_base/thread.h" 20 | #include "test/test_video_capturer.h" 21 | 22 | namespace webrtc { 23 | namespace test { 24 | 25 | class MacCapturer : public TestVideoCapturer, 26 | public rtc::VideoSinkInterface { 27 | public: 28 | static MacCapturer* Create(size_t width, 29 | size_t height, 30 | size_t target_fps, 31 | size_t capture_device_index); 32 | ~MacCapturer() override; 33 | 34 | void OnFrame(const VideoFrame& frame) override; 35 | 36 | private: 37 | MacCapturer(size_t width, 38 | size_t height, 39 | size_t target_fps, 40 | size_t capture_device_index); 41 | void Destroy(); 42 | 43 | void* capturer_; 44 | void* adapter_; 45 | }; 46 | 47 | } // namespace test 48 | } // namespace webrtc 49 | 50 | #endif // TEST_MAC_CAPTURER_H_ 51 | -------------------------------------------------------------------------------- /examples/peerconnection/client/test/platform_video_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #include "platform_video_capturer.h" 11 | 12 | #include "absl/memory/memory.h" 13 | #if defined(WEBRTC_MAC) 14 | #include "test/mac_capturer.h" 15 | #else 16 | #include "vcm_capturer.h" 17 | #endif 18 | 19 | namespace webrtc { 20 | namespace test { 21 | 22 | std::unique_ptr CreateVideoCapturer( 23 | size_t width, 24 | size_t height, 25 | size_t target_fps, 26 | size_t capture_device_index) { 27 | #if defined(WEBRTC_MAC) 28 | return absl::WrapUnique(test::MacCapturer::Create( 29 | width, height, target_fps, capture_device_index)); 30 | #else 31 | return absl::WrapUnique(test::VcmCapturer::Create( 32 | width, height, target_fps, capture_device_index)); 33 | #endif 34 | } 35 | 36 | } // namespace test 37 | } // namespace webrtc 38 | -------------------------------------------------------------------------------- /examples/peerconnection/client/test/platform_video_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_PLATFORM_VIDEO_CAPTURER_H_ 11 | #define TEST_PLATFORM_VIDEO_CAPTURER_H_ 12 | 13 | #include 14 | 15 | #include "test_video_capturer.h" 16 | 17 | namespace webrtc { 18 | namespace test { 19 | 20 | std::unique_ptr CreateVideoCapturer( 21 | size_t width, 22 | size_t height, 23 | size_t target_fps, 24 | size_t capture_device_index); 25 | 26 | } // namespace test 27 | } // namespace webrtc 28 | 29 | #endif // TEST_PLATFORM_VIDEO_CAPTURER_H_ 30 | -------------------------------------------------------------------------------- /examples/peerconnection/client/test/test.pri: -------------------------------------------------------------------------------- 1 | SOURCES += \ 2 | $$PWD/test_video_capturer.cc \ 3 | $$PWD/platform_video_capturer.cc 4 | 5 | HEADERS += \ 6 | $$PWD/test_video_capturer.h \ 7 | $$PWD/platform_video_capturer.h 8 | 9 | win32 { 10 | SOURCES += \ 11 | $$PWD/vcm_capturer.cc 12 | 13 | HEADERS += \ 14 | $$PWD/vcm_capturer.h 15 | } 16 | 17 | macos { 18 | SOURCES += \ 19 | $$PWD/mac_capturer.mm 20 | 21 | HEADERS += \ 22 | $$PWD/mac_capturer.h 23 | } 24 | -------------------------------------------------------------------------------- /examples/peerconnection/client/test/test_video_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "test_video_capturer.h" 12 | 13 | #include 14 | 15 | #include "api/scoped_refptr.h" 16 | #include "api/video/i420_buffer.h" 17 | #include "api/video/video_frame_buffer.h" 18 | #include "api/video/video_rotation.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | TestVideoCapturer::TestVideoCapturer() = default; 23 | TestVideoCapturer::~TestVideoCapturer() = default; 24 | 25 | void TestVideoCapturer::OnFrame(const VideoFrame& frame) { 26 | int cropped_width = 0; 27 | int cropped_height = 0; 28 | int out_width = 0; 29 | int out_height = 0; 30 | 31 | if (!video_adapter_.AdaptFrameResolution( 32 | frame.width(), frame.height(), frame.timestamp_us() * 1000, 33 | &cropped_width, &cropped_height, &out_width, &out_height)) { 34 | // Drop frame in order to respect frame rate constraint. 35 | return; 36 | } 37 | 38 | if (out_height != frame.height() || out_width != frame.width()) { 39 | // Video adapter has requested a down-scale. Allocate a new buffer and 40 | // return scaled version. 41 | rtc::scoped_refptr scaled_buffer = 42 | I420Buffer::Create(out_width, out_height); 43 | scaled_buffer->ScaleFrom(*frame.video_frame_buffer()->ToI420()); 44 | broadcaster_.OnFrame(VideoFrame::Builder() 45 | .set_video_frame_buffer(scaled_buffer) 46 | .set_rotation(kVideoRotation_0) 47 | .set_timestamp_us(frame.timestamp_us()) 48 | .set_id(frame.id()) 49 | .build()); 50 | } else { 51 | // No adaptations needed, just return the frame as is. 52 | broadcaster_.OnFrame(frame); 53 | } 54 | } 55 | 56 | rtc::VideoSinkWants TestVideoCapturer::GetSinkWants() { 57 | return broadcaster_.wants(); 58 | } 59 | 60 | void TestVideoCapturer::AddOrUpdateSink( 61 | rtc::VideoSinkInterface* sink, 62 | const rtc::VideoSinkWants& wants) { 63 | broadcaster_.AddOrUpdateSink(sink, wants); 64 | UpdateVideoAdapter(); 65 | } 66 | 67 | void TestVideoCapturer::RemoveSink(rtc::VideoSinkInterface* sink) { 68 | broadcaster_.RemoveSink(sink); 69 | UpdateVideoAdapter(); 70 | } 71 | 72 | void TestVideoCapturer::UpdateVideoAdapter() { 73 | rtc::VideoSinkWants wants = broadcaster_.wants(); 74 | video_adapter_.OnSinkWants(broadcaster_.wants()); 75 | } 76 | 77 | } // namespace test 78 | } // namespace webrtc 79 | -------------------------------------------------------------------------------- /examples/peerconnection/client/test/test_video_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_TEST_VIDEO_CAPTURER_H_ 11 | #define TEST_TEST_VIDEO_CAPTURER_H_ 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include "api/video/video_frame.h" 18 | #include "api/video/video_source_interface.h" 19 | #include "media/base/video_adapter.h" 20 | #include "media/base/video_broadcaster.h" 21 | 22 | namespace webrtc { 23 | namespace test { 24 | 25 | class TestVideoCapturer : public rtc::VideoSourceInterface { 26 | public: 27 | TestVideoCapturer(); 28 | virtual ~TestVideoCapturer(); 29 | 30 | void AddOrUpdateSink(rtc::VideoSinkInterface* sink, 31 | const rtc::VideoSinkWants& wants) override; 32 | void RemoveSink(rtc::VideoSinkInterface* sink) override; 33 | 34 | protected: 35 | void OnFrame(const VideoFrame& frame); 36 | rtc::VideoSinkWants GetSinkWants(); 37 | 38 | private: 39 | void UpdateVideoAdapter(); 40 | 41 | rtc::VideoBroadcaster broadcaster_; 42 | cricket::VideoAdapter video_adapter_; 43 | }; 44 | } // namespace test 45 | } // namespace webrtc 46 | 47 | #endif // TEST_TEST_VIDEO_CAPTURER_H_ 48 | -------------------------------------------------------------------------------- /examples/peerconnection/client/test/vcm_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "vcm_capturer.h" 12 | 13 | #include 14 | #include 15 | 16 | #include "modules/video_capture/video_capture_factory.h" 17 | #include "rtc_base/checks.h" 18 | #include "rtc_base/logging.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | 23 | VcmCapturer::VcmCapturer() : vcm_(nullptr) {} 24 | 25 | bool VcmCapturer::Init(size_t width, 26 | size_t height, 27 | size_t target_fps, 28 | size_t capture_device_index) { 29 | std::unique_ptr device_info( 30 | VideoCaptureFactory::CreateDeviceInfo()); 31 | 32 | char device_name[256]; 33 | char unique_name[256]; 34 | if (device_info->GetDeviceName(static_cast(capture_device_index), 35 | device_name, sizeof(device_name), unique_name, 36 | sizeof(unique_name)) != 0) { 37 | Destroy(); 38 | return false; 39 | } 40 | 41 | vcm_ = webrtc::VideoCaptureFactory::Create(unique_name); 42 | if (!vcm_) { 43 | return false; 44 | } 45 | vcm_->RegisterCaptureDataCallback(this); 46 | 47 | device_info->GetCapability(vcm_->CurrentDeviceName(), 0, capability_); 48 | 49 | capability_.width = static_cast(width); 50 | capability_.height = static_cast(height); 51 | capability_.maxFPS = static_cast(target_fps); 52 | capability_.videoType = VideoType::kI420; 53 | 54 | if (vcm_->StartCapture(capability_) != 0) { 55 | Destroy(); 56 | return false; 57 | } 58 | 59 | RTC_CHECK(vcm_->CaptureStarted()); 60 | 61 | return true; 62 | } 63 | 64 | VcmCapturer* VcmCapturer::Create(size_t width, 65 | size_t height, 66 | size_t target_fps, 67 | size_t capture_device_index) { 68 | std::unique_ptr vcm_capturer(new VcmCapturer()); 69 | if (!vcm_capturer->Init(width, height, target_fps, capture_device_index)) { 70 | RTC_LOG(LS_WARNING) << "Failed to create VcmCapturer(w = " << width 71 | << ", h = " << height << ", fps = " << target_fps 72 | << ")"; 73 | return nullptr; 74 | } 75 | return vcm_capturer.release(); 76 | } 77 | 78 | void VcmCapturer::Destroy() { 79 | if (!vcm_) 80 | return; 81 | 82 | vcm_->StopCapture(); 83 | vcm_->DeRegisterCaptureDataCallback(); 84 | // Release reference to VCM. 85 | vcm_ = nullptr; 86 | } 87 | 88 | VcmCapturer::~VcmCapturer() { 89 | Destroy(); 90 | } 91 | 92 | void VcmCapturer::OnFrame(const VideoFrame& frame) { 93 | TestVideoCapturer::OnFrame(frame); 94 | } 95 | 96 | } // namespace test 97 | } // namespace webrtc 98 | -------------------------------------------------------------------------------- /examples/peerconnection/client/test/vcm_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_VCM_CAPTURER_H_ 11 | #define TEST_VCM_CAPTURER_H_ 12 | 13 | #include 14 | #include 15 | 16 | #include "api/scoped_refptr.h" 17 | #include "modules/video_capture/video_capture.h" 18 | #include "test_video_capturer.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | 23 | class VcmCapturer : public TestVideoCapturer, 24 | public rtc::VideoSinkInterface { 25 | public: 26 | static VcmCapturer* Create(size_t width, 27 | size_t height, 28 | size_t target_fps, 29 | size_t capture_device_index); 30 | virtual ~VcmCapturer(); 31 | 32 | void OnFrame(const VideoFrame& frame) override; 33 | 34 | private: 35 | VcmCapturer(); 36 | bool Init(size_t width, 37 | size_t height, 38 | size_t target_fps, 39 | size_t capture_device_index); 40 | void Destroy(); 41 | 42 | rtc::scoped_refptr vcm_; 43 | VideoCaptureCapability capability_; 44 | }; 45 | 46 | } // namespace test 47 | } // namespace webrtc 48 | 49 | #endif // TEST_VCM_CAPTURER_H_ 50 | -------------------------------------------------------------------------------- /examples/peerconnection/client/videorenderer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "videorenderer.h" 7 | #include "api/video/i420_buffer.h" 8 | #include "third_party/libyuv/include/libyuv/convert_argb.h" 9 | 10 | VideoRenderer::VideoRenderer(webrtc::VideoTrackInterface* track_to_render) 11 | : rendered_track_(track_to_render) 12 | { 13 | rendered_track_->AddOrUpdateSink(this, rtc::VideoSinkWants()); 14 | } 15 | 16 | VideoRenderer::~VideoRenderer() 17 | { 18 | rendered_track_->RemoveSink(this); 19 | } 20 | 21 | void VideoRenderer::lock() 22 | { 23 | mutex_.lock(); 24 | } 25 | 26 | void VideoRenderer::unlock() 27 | { 28 | mutex_.unlock(); 29 | } 30 | 31 | webrtc::I420BufferInterface *VideoRenderer::getBuffer() 32 | { 33 | return i420_buffer_; 34 | } 35 | 36 | void VideoRenderer::OnFrame(const webrtc::VideoFrame &frame) 37 | { 38 | //TimeConsum tc(Q_FUNC_INFO); 39 | AutoLock lock(this); 40 | i420_buffer_ = frame.video_frame_buffer()->ToI420(); 41 | 42 | //qDebug() << Q_FUNC_INFO << ">>>>>>>frame: " << frame.width() << frame.height() << frame.size(); 43 | if (frame.rotation() != webrtc::kVideoRotation_0) { 44 | i420_buffer_ = webrtc::I420Buffer::Rotate(*i420_buffer_, frame.rotation()); 45 | } 46 | 47 | Q_EMIT recvFrame(); 48 | } 49 | -------------------------------------------------------------------------------- /examples/peerconnection/client/videorenderer.h: -------------------------------------------------------------------------------- 1 | #ifndef VIDEORENDERER_H 2 | #define VIDEORENDERER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "api/media_stream_interface.h" 10 | #include 11 | 12 | class VideoRenderer : public QObject, public rtc::VideoSinkInterface 13 | { 14 | Q_OBJECT 15 | public: 16 | VideoRenderer(webrtc::VideoTrackInterface* track_to_render); 17 | virtual ~VideoRenderer(); 18 | 19 | class TimeConsum 20 | { 21 | public: 22 | TimeConsum(const QString &log) 23 | : log_(log) 24 | { 25 | time_.start(); 26 | 27 | } 28 | ~TimeConsum() { 29 | qDebug() << log_ << "consum time:" << time_.elapsed(); 30 | } 31 | 32 | private: 33 | QTime time_; 34 | QString log_; 35 | }; 36 | 37 | void lock(); 38 | void unlock(); 39 | webrtc::I420BufferInterface *getBuffer(); 40 | 41 | template 42 | class AutoLock { 43 | public: 44 | explicit AutoLock(T* obj) : obj_(obj) { obj_->lock(); } 45 | ~AutoLock() { obj_->unlock(); } 46 | 47 | protected: 48 | T* obj_; 49 | }; 50 | 51 | Q_SIGNALS: 52 | void recvFrame(); 53 | 54 | protected: 55 | virtual void OnFrame(const webrtc::VideoFrame& frame); 56 | 57 | private: 58 | rtc::scoped_refptr rendered_track_ = nullptr; 59 | QMutex mutex_; 60 | rtc::scoped_refptr i420_buffer_; 61 | }; 62 | 63 | #endif // VIDEORENDERER_H 64 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 19A546d 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleDisplayName 10 | PC1 11 | CFBundleExecutable 12 | PC1 13 | CFBundleIdentifier 14 | com.Google.PC1 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | PC1 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleVersion 24 | 1.0 25 | DTCompiler 26 | com.apple.compilers.llvm.clang.1_0 27 | DTSDKBuild 28 | 10.14 29 | DTSDKName 30 | macosx10.14 31 | DTXcode 32 | 1021 33 | DTXcodeBuild 34 | 10E1001 35 | LSMinimumSystemVersion 36 | 10.10.0 37 | NSCameraUsageDescription 38 | Camera access needed for video calling 39 | NSMicrophoneUsageDescription 40 | Microphone access needed for video calling 41 | NSPrincipalClass 42 | NSApplication 43 | 44 | 45 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/main.cpp: -------------------------------------------------------------------------------- 1 | #include "widget.h" 2 | #include 3 | 4 | #ifdef Q_OS_WIN 5 | #include "rtc_base/win32_socket_init.h" 6 | #include "rtc_base/win32_socket_server.h" 7 | #endif 8 | 9 | #include "simplepeerconnection.h" 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 14 | #ifdef Q_OS_WIN 15 | rtc::WinsockInitializer winsock_init; 16 | rtc::Win32SocketServer w32_ss; 17 | rtc::Win32Thread w32_thread(&w32_ss); 18 | rtc::ThreadManager::Instance()->SetCurrentThread(&w32_thread); 19 | #else 20 | rtc::ThreadManager::Instance()->SetCurrentThread(rtc::ThreadManager::Instance()->CurrentThread()); 21 | #endif 22 | 23 | SimplePeerConnection::InitPeerConnectionFactory(); 24 | int exit; 25 | 26 | { 27 | QApplication a(argc, argv); 28 | Widget w; 29 | w.show(); 30 | exit = a.exec(); 31 | } 32 | 33 | SimplePeerConnection::ClearPeerConnectionFactory(); 34 | return exit; 35 | } 36 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/pc1.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2019-07-19T11:35:15 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = pc1 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which has been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | CONFIG += c++17 26 | 27 | SOURCES += \ 28 | main.cpp \ 29 | peerconnectiona.cpp \ 30 | peerconnectionb.cpp \ 31 | simplepeerconnection.cpp \ 32 | videorenderer.cpp \ 33 | widget.cpp 34 | 35 | HEADERS += \ 36 | peerconnectiona.h \ 37 | peerconnectionb.h \ 38 | simplepeerconnection.h \ 39 | videorenderer.h \ 40 | widget.h 41 | 42 | FORMS += \ 43 | widget.ui 44 | 45 | # Default rules for deployment. 46 | qnx: target.path = /tmp/$${TARGET}/bin 47 | else: unix:!android: target.path = /opt/$${TARGET}/bin 48 | !isEmpty(target.path): INSTALLS += target 49 | 50 | include($$PWD/../../webrtc_common/webrtc_common.pri) 51 | include($$PWD/test/test.pri) 52 | include($$PWD/render/render.pri) 53 | 54 | INCLUDEPATH += \ 55 | $$PWD/test \ 56 | $$PWD/render 57 | 58 | macos { 59 | QMAKE_INFO_PLIST = $$PWD/Info.plist 60 | } 61 | 62 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/peerconnectiona.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "peerconnectiona.h" 5 | 6 | PeerConnectionA::PeerConnectionA(QObject *parent) 7 | : SimplePeerConnection(parent) 8 | { 9 | 10 | } 11 | 12 | PeerConnectionA::~PeerConnectionA() 13 | { 14 | 15 | } 16 | 17 | void PeerConnectionA::OnRecvAnswer(QString type, QString sdp) 18 | { 19 | RTC_DCHECK(peer_connection_); 20 | std::string type_str = type.toStdString(); 21 | std::string sdpStr = sdp.toStdString(); 22 | 23 | // create session description 24 | absl::optional type_maybe = 25 | webrtc::SdpTypeFromString(type_str); 26 | webrtc::SdpType sdpType = *type_maybe; 27 | 28 | webrtc::SdpParseError error; 29 | std::unique_ptr session_description = 30 | webrtc::CreateSessionDescription(sdpType, sdpStr, &error); 31 | 32 | // set remote session description 33 | peer_connection_->SetRemoteDescription(DummySetSessionDescriptionObserver::Create(), 34 | session_description.release()); 35 | } 36 | 37 | void PeerConnectionA::OnAddTrack(rtc::scoped_refptr receiver, const std::vector > &streams) 38 | { 39 | qDebug() << ">>>>>>>>>>>>>>" << Q_FUNC_INFO; 40 | } 41 | 42 | void PeerConnectionA::OnRemoveTrack(rtc::scoped_refptr receiver) 43 | { 44 | qDebug() << ">>>>>>>>>>>>>>" << Q_FUNC_INFO; 45 | } 46 | 47 | void PeerConnectionA::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) 48 | { 49 | qDebug() << ">>>>>>>>>>>>>>" << Q_FUNC_INFO; 50 | } 51 | 52 | void PeerConnectionA::OnIceCandidate(const webrtc::IceCandidateInterface *candidate) 53 | { 54 | // 模拟网络发送IceCandidated 55 | Q_EMIT OnIceCandidated(candidate); 56 | qDebug() << ">>>>>>>>>>>>>>" << Q_FUNC_INFO; 57 | } 58 | 59 | void PeerConnectionA::OnSuccess(webrtc::SessionDescriptionInterface *desc) 60 | { 61 | qDebug() << ">>>>>>>>>>>>>>" << Q_FUNC_INFO; 62 | peer_connection_->SetLocalDescription(DummySetSessionDescriptionObserver::Create(), desc); 63 | std::string sdp; 64 | desc->ToString(&sdp); 65 | 66 | // 模拟网络发送sdp 67 | Q_EMIT CreateOffered(webrtc::SdpTypeToString(desc->GetType()), sdp.c_str()); 68 | } 69 | 70 | void PeerConnectionA::OnFailure(webrtc::RTCError error) 71 | { 72 | qDebug() << ">>>>>>>>>>>>>>" << Q_FUNC_INFO; 73 | } 74 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/peerconnectiona.h: -------------------------------------------------------------------------------- 1 | #ifndef PEERCONNECTIONA_H 2 | #define PEERCONNECTIONA_H 3 | 4 | #include "simplepeerconnection.h" 5 | 6 | class PeerConnectionA : public SimplePeerConnection 7 | 8 | { 9 | Q_OBJECT 10 | public: 11 | PeerConnectionA(QObject *parent = nullptr); 12 | virtual ~PeerConnectionA() override; 13 | 14 | Q_SIGNALS: 15 | void CreateOffered(QString type, QString sdp); 16 | 17 | public Q_SLOTS: 18 | void OnRecvAnswer(QString type, QString sdp); 19 | 20 | protected: 21 | void OnAddTrack( 22 | rtc::scoped_refptr receiver, 23 | const std::vector>& 24 | streams) override; 25 | void OnRemoveTrack( 26 | rtc::scoped_refptr receiver) override; 27 | void OnIceConnectionChange( 28 | webrtc::PeerConnectionInterface::IceConnectionState new_state) override; 29 | // pc需要联网,才会收到这个回调 30 | void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override; 31 | 32 | void OnSuccess(webrtc::SessionDescriptionInterface* desc) override; 33 | void OnFailure(webrtc::RTCError error) override; 34 | }; 35 | 36 | #endif // PEERCONNECTIONA_H 37 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/peerconnectionb.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "peerconnectionb.h" 4 | 5 | PeerConnectionB::PeerConnectionB(QObject *parent) 6 | : SimplePeerConnection(parent) 7 | { 8 | 9 | } 10 | 11 | PeerConnectionB::~PeerConnectionB() 12 | { 13 | 14 | } 15 | 16 | void PeerConnectionB::OnRecvOffer(QString type, QString sdp) 17 | { 18 | RTC_DCHECK(peer_connection_); 19 | std::string type_str = type.toStdString(); 20 | std::string sdpStr = sdp.toStdString(); 21 | 22 | // create session description 23 | absl::optional type_maybe = 24 | webrtc::SdpTypeFromString(type_str); 25 | webrtc::SdpType sdpType = *type_maybe; 26 | 27 | webrtc::SdpParseError error; 28 | std::unique_ptr session_description = 29 | webrtc::CreateSessionDescription(sdpType, sdpStr, &error); 30 | 31 | // set remote session description 32 | peer_connection_->SetRemoteDescription(DummySetSessionDescriptionObserver::Create(), 33 | session_description.release()); 34 | 35 | // send answer 36 | if (sdpType == webrtc::SdpType::kOffer) { 37 | peer_connection_->CreateAnswer( 38 | this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); 39 | } 40 | } 41 | 42 | void PeerConnectionB::OnAddTrack(rtc::scoped_refptr receiver, const std::vector > &streams) 43 | { 44 | qDebug() << ">>>>>>>>>>>>>>" << Q_FUNC_INFO; 45 | auto* track = reinterpret_cast(receiver->track().release()); 46 | if (track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) { 47 | auto* video_track = static_cast(track); 48 | Q_EMIT AddTracked(video_track); 49 | } 50 | track->Release(); 51 | } 52 | 53 | void PeerConnectionB::OnRemoveTrack(rtc::scoped_refptr receiver) 54 | { 55 | qDebug() << ">>>>>>>>>>>>>>" << Q_FUNC_INFO; 56 | } 57 | 58 | void PeerConnectionB::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) 59 | { 60 | qDebug() << ">>>>>>>>>>>>>>" << Q_FUNC_INFO; 61 | } 62 | 63 | void PeerConnectionB::OnIceCandidate(const webrtc::IceCandidateInterface *candidate) 64 | { 65 | // 模拟网络发送IceCandidated 66 | Q_EMIT OnIceCandidated(candidate); 67 | qDebug() << ">>>>>>>>>>>>>>" << Q_FUNC_INFO; 68 | } 69 | 70 | void PeerConnectionB::OnSuccess(webrtc::SessionDescriptionInterface *desc) 71 | { 72 | qDebug() << ">>>>>>>>>>>>>>" << Q_FUNC_INFO; 73 | peer_connection_->SetLocalDescription(DummySetSessionDescriptionObserver::Create(), desc); 74 | std::string sdp; 75 | desc->ToString(&sdp); 76 | 77 | // 模拟网络发送sdp 78 | Q_EMIT CreateAnswered(webrtc::SdpTypeToString(desc->GetType()), sdp.c_str()); 79 | } 80 | 81 | void PeerConnectionB::OnFailure(webrtc::RTCError error) 82 | { 83 | qDebug() << ">>>>>>>>>>>>>>" << Q_FUNC_INFO; 84 | } 85 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/peerconnectionb.h: -------------------------------------------------------------------------------- 1 | #ifndef PEERCONNECTIONB_H 2 | #define PEERCONNECTIONB_H 3 | 4 | #include "simplepeerconnection.h" 5 | 6 | class PeerConnectionB : public SimplePeerConnection 7 | { 8 | Q_OBJECT 9 | public: 10 | PeerConnectionB(QObject *parent = nullptr); 11 | virtual ~PeerConnectionB() override; 12 | 13 | Q_SIGNALS: 14 | void CreateAnswered(QString type, QString sdp); 15 | void AddTracked(webrtc::VideoTrackInterface* vieo_brack); 16 | 17 | public Q_SLOTS: 18 | void OnRecvOffer(QString type, QString sdp); 19 | 20 | protected: 21 | void OnAddTrack( 22 | rtc::scoped_refptr receiver, 23 | const std::vector>& 24 | streams) override; 25 | void OnRemoveTrack( 26 | rtc::scoped_refptr receiver) override; 27 | void OnIceConnectionChange( 28 | webrtc::PeerConnectionInterface::IceConnectionState new_state) override; 29 | void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override; 30 | 31 | void OnSuccess(webrtc::SessionDescriptionInterface* desc) override; 32 | void OnFailure(webrtc::RTCError error) override; 33 | }; 34 | 35 | #endif // PEERCONNECTIONB_H 36 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/readme.md: -------------------------------------------------------------------------------- 1 | [PeerConnection-introduce]: https://github.com/barry-ran/learn_webrtc/blob/master/doc/webrtc%20native%E5%AD%A6%E4%B9%A0%EF%BC%9APeerConnection%E4%BB%8B%E7%BB%8D.md 2 | 3 | [pc1-image]: https://raw.githubusercontent.com/barry-ran/learn_webrtc/master/examples/peerconnection/pc1/screenshot/main.jpg 4 | 5 | [pc1-sequence-image]: https://raw.githubusercontent.com/barry-ran/learn_webrtc/master/doc/image/pc1.jpg 6 | 7 | ![界面][pc1-image] 8 | 9 | # pc1 10 | 不用服务器的情况下,建立两个PeerConnection的P2P连接 11 | 12 | 参考[webrtc js demo](https://webrtc.github.io/samples/src/content/peerconnection/pc1/) 13 | 14 | 通过[PeerConnection介绍][PeerConnection-introduce]我们知道,要想建立两个PeerConnection的P2P连接,需要交换两种信息: 15 | 1. SDP:媒体会话描述信息,包括分辨率和编码格式等,用来协调匹配两个Peer的媒体编解码等信息 16 | 2. IceCandidate:ICE相关信息,包括候选地址、网络连接情况等,用来实现NAT穿透 17 | 18 | 在本例中我们两个PeerConnection位于同一个应用中,没有使用STUN服务器和Signal服务器,没有STUN服务器的话,PeerConnection只可以获得局域网内的ice候选地址,这对于本例足够了;没有Signal服务器的话,我们需要手动传递上述两种信息;在例子中我们使用Qt的信号槽来传递SDP和IceCandidate信息。 19 | 20 | ![时序图][pc1-sequence-image] 21 | 22 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/render/qyuvopenglwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef QYUVOPENGLWIDGET_H 2 | #define QYUVOPENGLWIDGET_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class QYUVOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit QYUVOpenGLWidget(QWidget *parent = nullptr); 13 | virtual ~QYUVOpenGLWidget(); 14 | 15 | QSize minimumSizeHint() const override; 16 | QSize sizeHint() const override; 17 | 18 | void setFrameSize(const QSize& frameSize); 19 | const QSize& frameSize(); 20 | void updateTextures(const quint8* dataY, const quint8* dataU, const quint8* dataV, quint32 linesizeY, quint32 linesizeU, quint32 linesizeV); 21 | 22 | protected: 23 | void initializeGL(); 24 | void paintGL(); 25 | void resizeGL(int width, int height); 26 | 27 | private: 28 | void initShader(); 29 | void initTextures(); 30 | void deInitTextures(); 31 | void updateTexture(GLuint texture, quint32 textureType, const quint8* pixels, quint32 stride); 32 | 33 | private: 34 | // 视频帧尺寸 35 | QSize m_frameSize = {-1, -1}; 36 | bool m_needUpdate = false; 37 | bool m_textureInited = false; 38 | 39 | // 顶点缓冲对象(Vertex Buffer Objects, VBO):默认即为VertexBuffer(GL_ARRAY_BUFFER)类型 40 | QOpenGLBuffer m_vbo; 41 | 42 | // 着色器程序:编译链接着色器 43 | QOpenGLShaderProgram m_shaderProgram; 44 | 45 | // YUV纹理,用于生成纹理贴图 46 | GLuint m_texture[3] = {0}; 47 | }; 48 | 49 | #endif // QYUVOPENGLWIDGET_H 50 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/render/render.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/qyuvopenglwidget.h 3 | 4 | SOURCES += \ 5 | $$PWD/qyuvopenglwidget.cpp 6 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/screenshot/main.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/examples/peerconnection/pc1/screenshot/main.jpg -------------------------------------------------------------------------------- /examples/peerconnection/pc1/simplepeerconnection.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLEPEERCONNECTION_H 2 | #define SIMPLEPEERCONNECTION_H 3 | 4 | #include 5 | 6 | #include "api/create_peerconnection_factory.h" 7 | #include "api/media_stream_interface.h" 8 | 9 | class DummySetSessionDescriptionObserver 10 | : public webrtc::SetSessionDescriptionObserver { 11 | public: 12 | static DummySetSessionDescriptionObserver* Create() { 13 | return new rtc::RefCountedObject(); 14 | } 15 | virtual void OnSuccess() { RTC_LOG(INFO) << __FUNCTION__; } 16 | virtual void OnFailure(webrtc::RTCError error) { 17 | RTC_LOG(INFO) << __FUNCTION__ << " " << ToString(error.type()) << ": " 18 | << error.message(); 19 | } 20 | }; 21 | 22 | class SimplePeerConnection : public QObject 23 | , public webrtc::PeerConnectionObserver 24 | , public webrtc::CreateSessionDescriptionObserver 25 | { 26 | Q_OBJECT 27 | public: 28 | SimplePeerConnection(QObject* parent = nullptr); 29 | ~SimplePeerConnection() override; 30 | 31 | static bool InitPeerConnectionFactory(); 32 | static void ClearPeerConnectionFactory(); 33 | webrtc::VideoTrackInterface* GetVideoTrack(); 34 | webrtc::PeerConnectionInterface* GetPeerConnection(); 35 | 36 | bool CreatePeerConnection(); 37 | void DeletePeerConnection(); 38 | void CreateTracks(); 39 | void AddTracks(); 40 | void CreateOffer(); 41 | 42 | Q_SIGNALS: 43 | void OnIceCandidated(const webrtc::IceCandidateInterface *candidate); 44 | 45 | public Q_SLOTS: 46 | void SetIceCandidate(const webrtc::IceCandidateInterface *candidate); 47 | 48 | protected: 49 | 50 | protected: 51 | // 52 | // PeerConnectionObserver implementation. 53 | // 54 | void OnSignalingChange( 55 | webrtc::PeerConnectionInterface::SignalingState new_state) override {} 56 | void OnAddTrack( 57 | rtc::scoped_refptr receiver, 58 | const std::vector>& 59 | streams) override {} 60 | void OnRemoveTrack( 61 | rtc::scoped_refptr receiver) override {} 62 | void OnDataChannel( 63 | rtc::scoped_refptr channel) override {} 64 | void OnRenegotiationNeeded() override {} 65 | void OnIceConnectionChange( 66 | webrtc::PeerConnectionInterface::IceConnectionState new_state) override {} 67 | void OnIceGatheringChange( 68 | webrtc::PeerConnectionInterface::IceGatheringState new_state) override {} 69 | void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override {} 70 | void OnIceConnectionReceivingChange(bool receiving) override {} 71 | 72 | // CreateSessionDescriptionObserver implementation. 73 | void OnSuccess(webrtc::SessionDescriptionInterface* desc) override {} 74 | void OnFailure(webrtc::RTCError error) override {} 75 | 76 | protected: 77 | rtc::scoped_refptr audio_track_; 78 | rtc::scoped_refptr video_track_; 79 | rtc::scoped_refptr peer_connection_; 80 | 81 | static std::unique_ptr s_worker_thread; 82 | static std::unique_ptr s_network_thread; 83 | static std::unique_ptr s_signaling_thread; 84 | static rtc::scoped_refptr 85 | s_peer_connection_factory; 86 | }; 87 | 88 | #endif // SIMPLEPEERCONNECTION_H 89 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/test/mac_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_MAC_CAPTURER_H_ 11 | #define TEST_MAC_CAPTURER_H_ 12 | 13 | #include 14 | #include 15 | 16 | #include "api/media_stream_interface.h" 17 | #include "api/scoped_refptr.h" 18 | #include "modules/video_capture/video_capture.h" 19 | #include "rtc_base/thread.h" 20 | #include "test/test_video_capturer.h" 21 | 22 | namespace webrtc { 23 | namespace test { 24 | 25 | class MacCapturer : public TestVideoCapturer, 26 | public rtc::VideoSinkInterface { 27 | public: 28 | static MacCapturer* Create(size_t width, 29 | size_t height, 30 | size_t target_fps, 31 | size_t capture_device_index); 32 | ~MacCapturer() override; 33 | 34 | void OnFrame(const VideoFrame& frame) override; 35 | 36 | private: 37 | MacCapturer(size_t width, 38 | size_t height, 39 | size_t target_fps, 40 | size_t capture_device_index); 41 | void Destroy(); 42 | 43 | void* capturer_; 44 | void* adapter_; 45 | }; 46 | 47 | } // namespace test 48 | } // namespace webrtc 49 | 50 | #endif // TEST_MAC_CAPTURER_H_ 51 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/test/platform_video_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #include "platform_video_capturer.h" 11 | 12 | #include "absl/memory/memory.h" 13 | #if defined(WEBRTC_MAC) 14 | #include "test/mac_capturer.h" 15 | #else 16 | #include "vcm_capturer.h" 17 | #endif 18 | 19 | namespace webrtc { 20 | namespace test { 21 | 22 | std::unique_ptr CreateVideoCapturer( 23 | size_t width, 24 | size_t height, 25 | size_t target_fps, 26 | size_t capture_device_index) { 27 | #if defined(WEBRTC_MAC) 28 | return absl::WrapUnique(test::MacCapturer::Create( 29 | width, height, target_fps, capture_device_index)); 30 | #else 31 | return absl::WrapUnique(test::VcmCapturer::Create( 32 | width, height, target_fps, capture_device_index)); 33 | #endif 34 | } 35 | 36 | } // namespace test 37 | } // namespace webrtc 38 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/test/platform_video_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_PLATFORM_VIDEO_CAPTURER_H_ 11 | #define TEST_PLATFORM_VIDEO_CAPTURER_H_ 12 | 13 | #include 14 | 15 | #include "test_video_capturer.h" 16 | 17 | namespace webrtc { 18 | namespace test { 19 | 20 | std::unique_ptr CreateVideoCapturer( 21 | size_t width, 22 | size_t height, 23 | size_t target_fps, 24 | size_t capture_device_index); 25 | 26 | } // namespace test 27 | } // namespace webrtc 28 | 29 | #endif // TEST_PLATFORM_VIDEO_CAPTURER_H_ 30 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/test/test.pri: -------------------------------------------------------------------------------- 1 | SOURCES += \ 2 | $$PWD/test_video_capturer.cc \ 3 | $$PWD/platform_video_capturer.cc \ 4 | 5 | HEADERS += \ 6 | $$PWD/test_video_capturer.h \ 7 | $$PWD/platform_video_capturer.h 8 | 9 | win32 { 10 | SOURCES += \ 11 | $$PWD/vcm_capturer.cc 12 | 13 | HEADERS += \ 14 | $$PWD/vcm_capturer.h 15 | } 16 | 17 | macos { 18 | SOURCES += \ 19 | $$PWD/mac_capturer.mm 20 | 21 | HEADERS += \ 22 | $$PWD/mac_capturer.h 23 | } 24 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/test/test_video_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "test_video_capturer.h" 12 | 13 | #include 14 | 15 | #include "api/scoped_refptr.h" 16 | #include "api/video/i420_buffer.h" 17 | #include "api/video/video_frame_buffer.h" 18 | #include "api/video/video_rotation.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | TestVideoCapturer::TestVideoCapturer() = default; 23 | TestVideoCapturer::~TestVideoCapturer() = default; 24 | 25 | void TestVideoCapturer::OnFrame(const VideoFrame& frame) { 26 | int cropped_width = 0; 27 | int cropped_height = 0; 28 | int out_width = 0; 29 | int out_height = 0; 30 | 31 | if (!video_adapter_.AdaptFrameResolution( 32 | frame.width(), frame.height(), frame.timestamp_us() * 1000, 33 | &cropped_width, &cropped_height, &out_width, &out_height)) { 34 | // Drop frame in order to respect frame rate constraint. 35 | return; 36 | } 37 | 38 | if (out_height != frame.height() || out_width != frame.width()) { 39 | // Video adapter has requested a down-scale. Allocate a new buffer and 40 | // return scaled version. 41 | rtc::scoped_refptr scaled_buffer = 42 | I420Buffer::Create(out_width, out_height); 43 | scaled_buffer->ScaleFrom(*frame.video_frame_buffer()->ToI420()); 44 | broadcaster_.OnFrame(VideoFrame::Builder() 45 | .set_video_frame_buffer(scaled_buffer) 46 | .set_rotation(kVideoRotation_0) 47 | .set_timestamp_us(frame.timestamp_us()) 48 | .set_id(frame.id()) 49 | .build()); 50 | } else { 51 | // No adaptations needed, just return the frame as is. 52 | broadcaster_.OnFrame(frame); 53 | } 54 | } 55 | 56 | rtc::VideoSinkWants TestVideoCapturer::GetSinkWants() { 57 | return broadcaster_.wants(); 58 | } 59 | 60 | void TestVideoCapturer::AddOrUpdateSink( 61 | rtc::VideoSinkInterface* sink, 62 | const rtc::VideoSinkWants& wants) { 63 | broadcaster_.AddOrUpdateSink(sink, wants); 64 | UpdateVideoAdapter(); 65 | } 66 | 67 | void TestVideoCapturer::RemoveSink(rtc::VideoSinkInterface* sink) { 68 | broadcaster_.RemoveSink(sink); 69 | UpdateVideoAdapter(); 70 | } 71 | 72 | void TestVideoCapturer::UpdateVideoAdapter() { 73 | rtc::VideoSinkWants wants = broadcaster_.wants(); 74 | video_adapter_.OnSinkWants(broadcaster_.wants()); 75 | } 76 | 77 | } // namespace test 78 | } // namespace webrtc 79 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/test/test_video_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_TEST_VIDEO_CAPTURER_H_ 11 | #define TEST_TEST_VIDEO_CAPTURER_H_ 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include "api/video/video_frame.h" 18 | #include "api/video/video_source_interface.h" 19 | #include "media/base/video_adapter.h" 20 | #include "media/base/video_broadcaster.h" 21 | 22 | namespace webrtc { 23 | namespace test { 24 | 25 | class TestVideoCapturer : public rtc::VideoSourceInterface { 26 | public: 27 | TestVideoCapturer(); 28 | virtual ~TestVideoCapturer(); 29 | 30 | void AddOrUpdateSink(rtc::VideoSinkInterface* sink, 31 | const rtc::VideoSinkWants& wants) override; 32 | void RemoveSink(rtc::VideoSinkInterface* sink) override; 33 | 34 | protected: 35 | void OnFrame(const VideoFrame& frame); 36 | rtc::VideoSinkWants GetSinkWants(); 37 | 38 | private: 39 | void UpdateVideoAdapter(); 40 | 41 | rtc::VideoBroadcaster broadcaster_; 42 | cricket::VideoAdapter video_adapter_; 43 | }; 44 | } // namespace test 45 | } // namespace webrtc 46 | 47 | #endif // TEST_TEST_VIDEO_CAPTURER_H_ 48 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/test/vcm_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "vcm_capturer.h" 12 | 13 | #include 14 | #include 15 | 16 | #include "modules/video_capture/video_capture_factory.h" 17 | #include "rtc_base/checks.h" 18 | #include "rtc_base/logging.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | 23 | VcmCapturer::VcmCapturer() : vcm_(nullptr) {} 24 | 25 | bool VcmCapturer::Init(size_t width, 26 | size_t height, 27 | size_t target_fps, 28 | size_t capture_device_index) { 29 | std::unique_ptr device_info( 30 | VideoCaptureFactory::CreateDeviceInfo()); 31 | 32 | char device_name[256]; 33 | char unique_name[256]; 34 | if (device_info->GetDeviceName(static_cast(capture_device_index), 35 | device_name, sizeof(device_name), unique_name, 36 | sizeof(unique_name)) != 0) { 37 | Destroy(); 38 | return false; 39 | } 40 | 41 | vcm_ = webrtc::VideoCaptureFactory::Create(unique_name); 42 | if (!vcm_) { 43 | return false; 44 | } 45 | vcm_->RegisterCaptureDataCallback(this); 46 | 47 | device_info->GetCapability(vcm_->CurrentDeviceName(), 0, capability_); 48 | 49 | capability_.width = static_cast(width); 50 | capability_.height = static_cast(height); 51 | capability_.maxFPS = static_cast(target_fps); 52 | capability_.videoType = VideoType::kI420; 53 | 54 | if (vcm_->StartCapture(capability_) != 0) { 55 | Destroy(); 56 | return false; 57 | } 58 | 59 | RTC_CHECK(vcm_->CaptureStarted()); 60 | 61 | return true; 62 | } 63 | 64 | VcmCapturer* VcmCapturer::Create(size_t width, 65 | size_t height, 66 | size_t target_fps, 67 | size_t capture_device_index) { 68 | std::unique_ptr vcm_capturer(new VcmCapturer()); 69 | if (!vcm_capturer->Init(width, height, target_fps, capture_device_index)) { 70 | RTC_LOG(LS_WARNING) << "Failed to create VcmCapturer(w = " << width 71 | << ", h = " << height << ", fps = " << target_fps 72 | << ")"; 73 | return nullptr; 74 | } 75 | return vcm_capturer.release(); 76 | } 77 | 78 | void VcmCapturer::Destroy() { 79 | if (!vcm_) 80 | return; 81 | 82 | vcm_->StopCapture(); 83 | vcm_->DeRegisterCaptureDataCallback(); 84 | // Release reference to VCM. 85 | vcm_ = nullptr; 86 | } 87 | 88 | VcmCapturer::~VcmCapturer() { 89 | Destroy(); 90 | } 91 | 92 | void VcmCapturer::OnFrame(const VideoFrame& frame) { 93 | TestVideoCapturer::OnFrame(frame); 94 | } 95 | 96 | } // namespace test 97 | } // namespace webrtc 98 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/test/vcm_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_VCM_CAPTURER_H_ 11 | #define TEST_VCM_CAPTURER_H_ 12 | 13 | #include 14 | #include 15 | 16 | #include "api/scoped_refptr.h" 17 | #include "modules/video_capture/video_capture.h" 18 | #include "test_video_capturer.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | 23 | class VcmCapturer : public TestVideoCapturer, 24 | public rtc::VideoSinkInterface { 25 | public: 26 | static VcmCapturer* Create(size_t width, 27 | size_t height, 28 | size_t target_fps, 29 | size_t capture_device_index); 30 | virtual ~VcmCapturer(); 31 | 32 | void OnFrame(const VideoFrame& frame) override; 33 | 34 | private: 35 | VcmCapturer(); 36 | bool Init(size_t width, 37 | size_t height, 38 | size_t target_fps, 39 | size_t capture_device_index); 40 | void Destroy(); 41 | 42 | rtc::scoped_refptr vcm_; 43 | VideoCaptureCapability capability_; 44 | }; 45 | 46 | } // namespace test 47 | } // namespace webrtc 48 | 49 | #endif // TEST_VCM_CAPTURER_H_ 50 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/videorenderer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "videorenderer.h" 7 | #include "api/video/i420_buffer.h" 8 | #include "third_party/libyuv/include/libyuv/convert_argb.h" 9 | #include "widget.h" 10 | 11 | VideoRenderer::VideoRenderer(webrtc::VideoTrackInterface* track_to_render) 12 | : rendered_track_(track_to_render) 13 | { 14 | rendered_track_->AddOrUpdateSink(this, rtc::VideoSinkWants()); 15 | } 16 | 17 | VideoRenderer::~VideoRenderer() 18 | { 19 | rendered_track_->RemoveSink(this); 20 | } 21 | 22 | void VideoRenderer::lock() 23 | { 24 | mutex_.lock(); 25 | } 26 | 27 | void VideoRenderer::unlock() 28 | { 29 | mutex_.unlock(); 30 | } 31 | 32 | webrtc::I420BufferInterface *VideoRenderer::getBuffer() 33 | { 34 | return i420_buffer_; 35 | } 36 | 37 | void VideoRenderer::OnFrame(const webrtc::VideoFrame &frame) 38 | { 39 | //TimeConsum tc(Q_FUNC_INFO); 40 | AutoLock lock(this); 41 | i420_buffer_ = frame.video_frame_buffer()->ToI420(); 42 | 43 | //qDebug() << Q_FUNC_INFO << ">>>>>>>frame: " << frame.width() << frame.height() << frame.size(); 44 | if (frame.rotation() != webrtc::kVideoRotation_0) { 45 | i420_buffer_ = webrtc::I420Buffer::Rotate(*i420_buffer_, frame.rotation()); 46 | } 47 | 48 | Q_EMIT recvFrame(); 49 | } 50 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/videorenderer.h: -------------------------------------------------------------------------------- 1 | #ifndef VIDEORENDERER_H 2 | #define VIDEORENDERER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "api/media_stream_interface.h" 10 | #include 11 | 12 | class VideoRenderer : public QObject, public rtc::VideoSinkInterface 13 | { 14 | Q_OBJECT 15 | public: 16 | VideoRenderer(webrtc::VideoTrackInterface* track_to_render); 17 | virtual ~VideoRenderer(); 18 | 19 | class TimeConsum 20 | { 21 | public: 22 | TimeConsum(const QString &log) 23 | : log_(log) 24 | { 25 | time_.start(); 26 | 27 | } 28 | ~TimeConsum() { 29 | qDebug() << log_ << "consum time:" << time_.elapsed(); 30 | } 31 | 32 | private: 33 | QTime time_; 34 | QString log_; 35 | }; 36 | 37 | void lock(); 38 | void unlock(); 39 | webrtc::I420BufferInterface *getBuffer(); 40 | 41 | template 42 | class AutoLock { 43 | public: 44 | explicit AutoLock(T* obj) : obj_(obj) { obj_->lock(); } 45 | ~AutoLock() { obj_->unlock(); } 46 | 47 | protected: 48 | T* obj_; 49 | }; 50 | 51 | Q_SIGNALS: 52 | void recvFrame(); 53 | 54 | protected: 55 | virtual void OnFrame(const webrtc::VideoFrame& frame); 56 | 57 | private: 58 | rtc::scoped_refptr rendered_track_ = nullptr; 59 | QMutex mutex_; 60 | rtc::scoped_refptr i420_buffer_; 61 | }; 62 | 63 | #endif // VIDEORENDERER_H 64 | -------------------------------------------------------------------------------- /examples/peerconnection/pc1/widget.h: -------------------------------------------------------------------------------- 1 | #ifndef WIDGET_H 2 | #define WIDGET_H 3 | 4 | #include 5 | 6 | #include "api/scoped_refptr.h" 7 | #include "videorenderer.h" 8 | 9 | namespace Ui { 10 | class Widget; 11 | } 12 | 13 | class PeerConnectionA; 14 | class PeerConnectionB; 15 | class Widget : public QWidget 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | explicit Widget(QWidget *parent = nullptr); 21 | ~Widget(); 22 | 23 | protected: 24 | void StartLocalRenderer(webrtc::VideoTrackInterface* local_video); 25 | void StopLocalRenderer(); 26 | 27 | void StartRemoteRenderer(webrtc::VideoTrackInterface* remote_video); 28 | void StopRemoteRenderer(); 29 | 30 | private Q_SLOTS: 31 | void on_startBtn_clicked(); 32 | 33 | void on_callBtn_clicked(); 34 | 35 | void on_hangUpBtn_clicked(); 36 | void onRecvLocalFrame(); 37 | void onRecvRemoteFrame(); 38 | 39 | private: 40 | Ui::Widget *ui; 41 | 42 | rtc::scoped_refptr peer_connection_a_; 43 | rtc::scoped_refptr peer_connection_b_; 44 | std::unique_ptr local_renderer_; 45 | std::unique_ptr remote_renderer_; 46 | }; 47 | 48 | #endif // WIDGET_H 49 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 19A546d 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleDisplayName 10 | Remote 11 | CFBundleExecutable 12 | Remote 13 | CFBundleIdentifier 14 | com.Google.Remote 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | Remote 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleVersion 24 | 1.0 25 | DTCompiler 26 | com.apple.compilers.llvm.clang.1_0 27 | DTSDKBuild 28 | 10.14 29 | DTSDKName 30 | macosx10.14 31 | DTXcode 32 | 1021 33 | DTXcodeBuild 34 | 10E1001 35 | LSMinimumSystemVersion 36 | 10.10.0 37 | NSCameraUsageDescription 38 | Camera access needed for video calling 39 | NSMicrophoneUsageDescription 40 | Microphone access needed for video calling 41 | NSPrincipalClass 42 | NSApplication 43 | 44 | 45 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/bufferutil.cpp: -------------------------------------------------------------------------------- 1 | #include "bufferutil.h" 2 | 3 | void BufferUtil::write32(QBuffer &buffer, quint32 value) 4 | { 5 | buffer.putChar(value >> 24); 6 | buffer.putChar(value >> 16); 7 | buffer.putChar(value >> 8); 8 | buffer.putChar(value); 9 | } 10 | 11 | void BufferUtil::write16(QBuffer &buffer, quint32 value) 12 | { 13 | buffer.putChar(value >> 8); 14 | buffer.putChar(value); 15 | } 16 | 17 | void BufferUtil::writeFloat(QBuffer &buffer, float value) 18 | { 19 | buffer.write((char*)&value, 4); 20 | } 21 | 22 | quint16 BufferUtil::read16(QBuffer &buffer) 23 | { 24 | uchar c; 25 | quint16 ret = 0; 26 | buffer.getChar(reinterpret_cast(&c)); 27 | ret |= (c << 8); 28 | buffer.getChar(reinterpret_cast(&c)); 29 | ret |= c; 30 | 31 | return ret; 32 | } 33 | 34 | quint32 BufferUtil::read32(QBuffer &buffer) 35 | { 36 | uchar c; 37 | quint32 ret = 0; 38 | buffer.getChar(reinterpret_cast(&c)); 39 | ret |= (c << 24); 40 | buffer.getChar(reinterpret_cast(&c)); 41 | ret |= (c << 16); 42 | buffer.getChar(reinterpret_cast(&c)); 43 | ret |= (c << 8); 44 | buffer.getChar(reinterpret_cast(&c)); 45 | ret |= c; 46 | 47 | return ret; 48 | } 49 | 50 | quint64 BufferUtil::read64(QBuffer &buffer) 51 | { 52 | quint32 msb = read32(buffer); 53 | quint32 lsb = read32(buffer); 54 | 55 | return ((quint64) msb << 32) | lsb;; 56 | } 57 | 58 | float BufferUtil::readFloat(QBuffer &buffer) 59 | { 60 | float ret = 0; 61 | buffer.read((char*)&ret, 4); 62 | return ret; 63 | } 64 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/bufferutil.h: -------------------------------------------------------------------------------- 1 | #ifndef BUFFERUTIL_H 2 | #define BUFFERUTIL_H 3 | #include 4 | 5 | class BufferUtil 6 | { 7 | public: 8 | static void write32(QBuffer& buffer, quint32 value); 9 | static void write16(QBuffer& buffer, quint32 value); 10 | static void writeFloat(QBuffer& buffer, float value); 11 | static quint16 read16(QBuffer& buffer); 12 | static quint32 read32(QBuffer& buffer); 13 | static quint64 read64(QBuffer& buffer); 14 | static float readFloat(QBuffer& buffer); 15 | }; 16 | 17 | #endif // BUFFERUTIL_H 18 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/controlmsg.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "controlmsg.h" 4 | #include "bufferutil.h" 5 | 6 | ControlMsg::ControlMsg(ControlMsgType controlMsgType) : QObject(nullptr) 7 | { 8 | m_data.type = controlMsgType; 9 | } 10 | 11 | ControlMsg::ControlMsg(const ControlMsg &msg) 12 | { 13 | m_data = msg.m_data; 14 | } 15 | 16 | ControlMsg::~ControlMsg() 17 | { 18 | 19 | } 20 | 21 | void ControlMsg::setInjectMouseMsgData(QEvent::Type action, Qt::MouseButton button, QPointF pos) 22 | { 23 | m_data.injectMouse.action = action; 24 | m_data.injectMouse.button = button; 25 | m_data.injectMouse.pos = pos; 26 | } 27 | 28 | void ControlMsg::getInjectMouseMsgData(QEvent::Type &action, Qt::MouseButton &button, QPointF &pos) 29 | { 30 | action = m_data.injectMouse.action; 31 | button = m_data.injectMouse.button; 32 | pos = m_data.injectMouse.pos; 33 | } 34 | 35 | QByteArray ControlMsg::serializeData() 36 | { 37 | QByteArray byteArray; 38 | QBuffer buffer(&byteArray); 39 | buffer.open(QBuffer::WriteOnly); 40 | buffer.putChar(m_data.type); 41 | 42 | switch (m_data.type) { 43 | case CMT_INJECT_MOUSE: 44 | BufferUtil::write32(buffer, m_data.injectMouse.action); 45 | BufferUtil::write32(buffer, (quint32)m_data.injectMouse.button); 46 | BufferUtil::writeFloat(buffer, m_data.injectMouse.pos.x()); 47 | BufferUtil::writeFloat(buffer, m_data.injectMouse.pos.y()); 48 | break; 49 | default: 50 | break; 51 | } 52 | buffer.close(); 53 | return byteArray; 54 | } 55 | 56 | ControlMsg ControlMsg::unserializeData(QByteArray &data) 57 | { 58 | ControlMsg msg; 59 | qint64 len = data.size(); 60 | if (len < 1) { 61 | return msg; 62 | } 63 | QBuffer buf(&data); 64 | buf.open(QBuffer::ReadOnly); 65 | char c = 0; 66 | buf.peek(&c, 1); 67 | ControlMsgType type = (ControlMsgType)c; 68 | switch (type) { 69 | case CMT_INJECT_MOUSE: 70 | if (len < (1 + 16)) { 71 | break; 72 | } 73 | buf.getChar(&c); 74 | msg.m_data.type = type; 75 | msg.m_data.injectMouse.action = (QEvent::Type)BufferUtil::read32(buf); 76 | msg.m_data.injectMouse.button = (Qt::MouseButton)BufferUtil::read32(buf); 77 | msg.m_data.injectMouse.pos.setX(BufferUtil::readFloat(buf)); 78 | msg.m_data.injectMouse.pos.setY(BufferUtil::readFloat(buf)); 79 | buf.close(); 80 | data.remove(0, 1 + 16); 81 | break; 82 | default: 83 | break; 84 | } 85 | return msg; 86 | } 87 | 88 | ControlMsg::ControlMsgType ControlMsg::type() 89 | { 90 | return m_data.type; 91 | } 92 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/controlmsg.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTROLMSG_H 2 | #define CONTROLMSG_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class ControlMsg : public QObject 9 | { 10 | Q_OBJECT 11 | public: 12 | enum ControlMsgType { 13 | CMT_NULL = -1, 14 | CMT_INJECT_MOUSE = 0, 15 | }; 16 | 17 | explicit ControlMsg(ControlMsgType controlMsgType = ControlMsg::CMT_NULL); 18 | ControlMsg(const ControlMsg& msg); 19 | virtual ~ControlMsg(); 20 | 21 | void setInjectMouseMsgData(QEvent::Type action, Qt::MouseButton button, QPointF pos); 22 | void getInjectMouseMsgData(QEvent::Type& action, Qt::MouseButton& button, QPointF& pos); 23 | QByteArray serializeData(); 24 | static ControlMsg unserializeData(QByteArray& data); 25 | 26 | ControlMsg::ControlMsgType type(); 27 | Q_SIGNALS: 28 | 29 | public Q_SLOTS: 30 | 31 | private: 32 | struct ControlMsgData { 33 | ControlMsgType type = CMT_NULL; 34 | union { 35 | struct { 36 | QEvent::Type action; 37 | Qt::MouseButton button; 38 | QPointF pos; 39 | } injectMouse; 40 | }; 41 | 42 | ControlMsgData(){} 43 | ~ControlMsgData(){} 44 | }; 45 | 46 | ControlMsgData m_data; 47 | }; 48 | 49 | #endif // CONTROLMSG_H 50 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/defaults.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "defaults.h" 12 | 13 | #include 14 | 15 | #ifdef WIN32 16 | #include 17 | #else 18 | #include 19 | #endif 20 | 21 | #include "rtc_base/arraysize.h" 22 | 23 | const char kAudioLabel[] = "audio_label"; 24 | const char kVideoLabel[] = "video_label"; 25 | const char kStreamId[] = "stream_id"; 26 | const uint16_t kDefaultServerPort = 8888; 27 | 28 | std::string GetEnvVarOrDefault(const char* env_var_name, 29 | const char* default_value) { 30 | std::string value; 31 | const char* env_var = getenv(env_var_name); 32 | if (env_var) 33 | value = env_var; 34 | 35 | if (value.empty()) 36 | value = default_value; 37 | 38 | return value; 39 | } 40 | 41 | std::string GetPeerConnectionString() { 42 | return GetEnvVarOrDefault("WEBRTC_CONNECT", "stun:stun.l.google.com:19302"); 43 | } 44 | 45 | std::string GetDefaultServerName() { 46 | return GetEnvVarOrDefault("WEBRTC_SERVER", "localhost"); 47 | } 48 | 49 | std::string GetPeerName() { 50 | char computer_name[256]; 51 | std::string ret(GetEnvVarOrDefault("USERNAME", "user")); 52 | ret += '@'; 53 | if (gethostname(computer_name, arraysize(computer_name)) == 0) { 54 | ret += computer_name; 55 | } else { 56 | ret += "host"; 57 | } 58 | return ret; 59 | } 60 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/defaults.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #ifndef EXAMPLES_PEERCONNECTION_CLIENT_DEFAULTS_H_ 12 | #define EXAMPLES_PEERCONNECTION_CLIENT_DEFAULTS_H_ 13 | 14 | #include 15 | 16 | #include 17 | 18 | extern const char kAudioLabel[]; 19 | extern const char kVideoLabel[]; 20 | extern const char kStreamId[]; 21 | extern const uint16_t kDefaultServerPort; 22 | 23 | std::string GetEnvVarOrDefault(const char* env_var_name, 24 | const char* default_value); 25 | std::string GetPeerConnectionString(); 26 | std::string GetDefaultServerName(); 27 | std::string GetPeerName(); 28 | 29 | #endif // EXAMPLES_PEERCONNECTION_CLIENT_DEFAULTS_H_ 30 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/flag_defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 The WebRTC Project Authors. All rights reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #ifndef EXAMPLES_PEERCONNECTION_CLIENT_FLAG_DEFS_H_ 12 | #define EXAMPLES_PEERCONNECTION_CLIENT_FLAG_DEFS_H_ 13 | 14 | #include "rtc_base/flags.h" 15 | 16 | extern const uint16_t kDefaultServerPort; // From defaults.[h|cc] 17 | 18 | // Define flags for the peerconnect_client testing tool, in a separate 19 | // header file so that they can be shared across the different main.cc's 20 | // for each platform. 21 | 22 | WEBRTC_DEFINE_bool(help, false, "Prints this message"); 23 | WEBRTC_DEFINE_bool(autoconnect, 24 | false, 25 | "Connect to the server without user " 26 | "intervention."); 27 | WEBRTC_DEFINE_string(server, "localhost", "The server to connect to."); 28 | WEBRTC_DEFINE_int(port, 29 | kDefaultServerPort, 30 | "The port on which the server is listening."); 31 | WEBRTC_DEFINE_bool( 32 | autocall, 33 | false, 34 | "Call the first available other client on " 35 | "the server without user intervention. Note: this flag should only be set " 36 | "to true on one of the two clients."); 37 | 38 | WEBRTC_DEFINE_string( 39 | force_fieldtrials, 40 | "", 41 | "Field trials control experimental features. This flag specifies the field " 42 | "trials in effect. E.g. running with " 43 | "--force_fieldtrials=WebRTC-FooFeature/Enabled/ " 44 | "will assign the group Enabled to field trial WebRTC-FooFeature. Multiple " 45 | "trials are separated by \"/\""); 46 | 47 | #endif // EXAMPLES_PEERCONNECTION_CLIENT_FLAG_DEFS_H_ 48 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/inputinject.cpp: -------------------------------------------------------------------------------- 1 | #include "inputinject.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | InputInject::InputInject() 8 | { 9 | 10 | } 11 | 12 | void InputInject::injectMouseEvent(QEvent::Type action, Qt::MouseButton button, QPointF pos) 13 | { 14 | /* 15 | QRect screenRect(GetSystemMetrics(SM_XVIRTUALSCREEN), 16 | GetSystemMetrics(SM_YVIRTUALSCREEN), 17 | GetSystemMetrics(SM_CXVIRTUALSCREEN), 18 | GetSystemMetrics(SM_CYVIRTUALSCREEN)); 19 | 20 | int x = screenRect.width() * pos.x(); 21 | int y = screenRect.height() * pos.y(); 22 | */ 23 | //action = QEvent::MouseMove; 24 | //button = Qt::LeftButton; 25 | //pos = QPointF(0.5f, 0.5f); 26 | 27 | // Translate the coordinates of the cursor into the coordinates of the virtual screen. 28 | QPoint realPos(65535 * pos.x(), 65535 * pos.y()); 29 | 30 | DWORD flags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; 31 | 32 | INPUT input; 33 | memset(&input, 0, sizeof(input)); 34 | 35 | input.type = INPUT_MOUSE; 36 | input.mi.dx = realPos.x(); 37 | input.mi.dy = realPos.y(); 38 | input.mi.dwFlags = flags; 39 | input.mi.mouseData = 0; 40 | 41 | switch (action) { 42 | case QEvent::MouseButtonPress: 43 | if (Qt::MouseButton::LeftButton == button) { 44 | input.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN; 45 | } else { 46 | input.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN; 47 | } 48 | break; 49 | case QEvent::MouseButtonRelease: 50 | if (Qt::MouseButton::LeftButton == button) { 51 | input.mi.dwFlags |= MOUSEEVENTF_LEFTUP; 52 | } else { 53 | input.mi.dwFlags |= MOUSEEVENTF_RIGHTUP; 54 | } 55 | break; 56 | case QEvent::MouseButtonDblClick: 57 | input.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN; 58 | ::SendInput(1, &input, sizeof(input)); 59 | input.mi.dwFlags = flags | MOUSEEVENTF_LEFTUP; 60 | ::SendInput(1, &input, sizeof(input)); 61 | input.mi.dwFlags = flags | MOUSEEVENTF_LEFTUP; 62 | ::SendInput(1, &input, sizeof(input)); 63 | input.mi.dwFlags = flags | MOUSEEVENTF_LEFTUP; 64 | break; 65 | case QEvent::MouseMove: 66 | break; 67 | default: 68 | return; 69 | } 70 | uint uRet = ::SendInput(1, &input, sizeof(input)); 71 | if(uRet <= 0) 72 | { 73 | DWORD dwErr=::GetLastError(); 74 | qDebug() << "**************************"; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/inputinject.h: -------------------------------------------------------------------------------- 1 | #ifndef INPUTINJECT_H 2 | #define INPUTINJECT_H 3 | 4 | #include 5 | #include 6 | 7 | class InputInject 8 | { 9 | public: 10 | InputInject(); 11 | 12 | static void injectMouseEvent(QEvent::Type action, Qt::MouseButton button, QPointF pos); 13 | }; 14 | 15 | #endif // INPUTINJECT_H 16 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main_wnd.h" 2 | 3 | #include 4 | #ifdef Q_OS_MAC 5 | #include 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | #include "conductor.h" 12 | #include "main_wnd.h" 13 | #include "peer_connection_client.h" 14 | #include "rtc_base/checks.h" 15 | #include "rtc_base/constructor_magic.h" 16 | #include "rtc_base/ssl_adapter.h" 17 | #ifdef Q_OS_WIN 18 | #include "rtc_base/win32_socket_init.h" 19 | #include "rtc_base/win32_socket_server.h" 20 | #endif 21 | #include "system_wrappers/include/field_trial.h" 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 26 | #ifdef Q_OS_WIN 27 | rtc::WinsockInitializer winsock_init; 28 | // 内部创建message wnd,定时在主线程处理message queue消息 29 | rtc::Win32SocketServer w32_ss; 30 | rtc::Win32Thread w32_thread(&w32_ss); 31 | rtc::ThreadManager::Instance()->SetCurrentThread(&w32_thread); 32 | #endif 33 | QApplication a(argc, argv); 34 | 35 | MainWnd wnd("", 0); 36 | if (!wnd.Create()) { 37 | RTC_NOTREACHED(); 38 | return -1; 39 | } 40 | 41 | rtc::InitializeSSL(); 42 | PeerConnectionClient client; 43 | rtc::scoped_refptr conductor( 44 | new rtc::RefCountedObject(&client, &wnd)); 45 | 46 | #ifdef Q_OS_MAC 47 | // for rtc::Thread::Current()->socketserver()->CreateAsyncSocket; 48 | // 定时在主线程处理message queue消息(这里主要为了socket消息),后面采用更好的方式 49 | QTimer processSocket(&a); 50 | QObject::connect(&processSocket, &QTimer::timeout, [=]() { 51 | rtc::Thread* thread = rtc::Thread::Current(); 52 | thread->ProcessMessages(0); 53 | }); 54 | processSocket.start(50); 55 | #endif 56 | 57 | int ret = a.exec(); 58 | 59 | #ifdef Q_OS_MAC 60 | processSocket.stop(); 61 | #endif 62 | 63 | rtc::CleanupSSL(); 64 | return ret; 65 | } 66 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/remote.pro: -------------------------------------------------------------------------------- 1 | QT += core gui 2 | 3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 | 5 | CONFIG += c++17 6 | 7 | # The following define makes your compiler emit warnings if you use 8 | # any Qt feature that has been marked deprecated (the exact warnings 9 | # depend on your compiler). Please consult the documentation of the 10 | # deprecated API in order to know how to port your code away from it. 11 | DEFINES += QT_DEPRECATED_WARNINGS 12 | 13 | # You can also make your code fail to compile if it uses deprecated APIs. 14 | # In order to do so, uncomment the following line. 15 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 16 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 17 | 18 | SOURCES += \ 19 | bufferutil.cpp \ 20 | controlmsg.cpp \ 21 | main.cpp \ 22 | main_wnd.cpp \ 23 | defaults.cc \ 24 | peer_connection_client.cc \ 25 | conductor.cc \ 26 | videorenderer.cpp 27 | 28 | HEADERS += \ 29 | bufferutil.h \ 30 | controlmsg.h \ 31 | main_wnd.h \ 32 | defaults.h \ 33 | peer_connection_client.h \ 34 | conductor.h \ 35 | videorenderer.h 36 | 37 | FORMS += \ 38 | mainwnd.ui 39 | 40 | # Default rules for deployment. 41 | qnx: target.path = /tmp/$${TARGET}/bin 42 | else: unix:!android: target.path = /opt/$${TARGET}/bin 43 | !isEmpty(target.path): INSTALLS += target 44 | 45 | include($$PWD/../../webrtc_common/webrtc_common.pri) 46 | include($$PWD/test/test.pri) 47 | include($$PWD/render/render.pri) 48 | 49 | INCLUDEPATH += \ 50 | $$PWD/test \ 51 | $$PWD/render 52 | 53 | win32 { 54 | SOURCES += \ 55 | inputinject.cpp 56 | 57 | HEADERS += \ 58 | inputinject.h 59 | } 60 | 61 | macos { 62 | QMAKE_INFO_PLIST = $$PWD/Info.plist 63 | } 64 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/render/qyuvopenglwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef QYUVOPENGLWIDGET_H 2 | #define QYUVOPENGLWIDGET_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class QYUVOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit QYUVOpenGLWidget(QWidget *parent = nullptr); 13 | virtual ~QYUVOpenGLWidget(); 14 | 15 | QSize minimumSizeHint() const override; 16 | QSize sizeHint() const override; 17 | 18 | void setFrameSize(const QSize& frameSize); 19 | const QSize& frameSize(); 20 | void updateTextures(const quint8* dataY, const quint8* dataU, const quint8* dataV, quint32 linesizeY, quint32 linesizeU, quint32 linesizeV); 21 | 22 | protected: 23 | void initializeGL(); 24 | void paintGL(); 25 | void resizeGL(int width, int height); 26 | 27 | private: 28 | void initShader(); 29 | void initTextures(); 30 | void deInitTextures(); 31 | void updateTexture(GLuint texture, quint32 textureType, const quint8* pixels, quint32 stride); 32 | 33 | private: 34 | // 视频帧尺寸 35 | QSize m_frameSize = {-1, -1}; 36 | bool m_needUpdate = false; 37 | bool m_textureInited = false; 38 | 39 | // 顶点缓冲对象(Vertex Buffer Objects, VBO):默认即为VertexBuffer(GL_ARRAY_BUFFER)类型 40 | QOpenGLBuffer m_vbo; 41 | 42 | // 着色器程序:编译链接着色器 43 | QOpenGLShaderProgram m_shaderProgram; 44 | 45 | // YUV纹理,用于生成纹理贴图 46 | GLuint m_texture[3] = {0}; 47 | }; 48 | 49 | #endif // QYUVOPENGLWIDGET_H 50 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/render/render.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/qyuvopenglwidget.h 3 | 4 | SOURCES += \ 5 | $$PWD/qyuvopenglwidget.cpp 6 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/test/desktop_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef DESKTOP_CAPTURER_H_ 11 | #define DESKTOP_CAPTURER_H_ 12 | 13 | #include "api/scoped_refptr.h" 14 | #include "modules/desktop_capture/desktop_capturer.h" 15 | #include "test_video_capturer.h" 16 | #include "api/video/i420_buffer.h" 17 | #include "rtc_base/thread.h" 18 | #include "rtc_base/message_handler.h" 19 | 20 | 21 | // https://my.oschina.net/u/988511/blog/3010478 22 | namespace webrtc { 23 | namespace test { 24 | 25 | class DesktopCapturer : public TestVideoCapturer, 26 | public rtc::MessageHandler, 27 | public webrtc::DesktopCapturer::Callback { 28 | public: 29 | static DesktopCapturer* Create(size_t width, 30 | size_t height, 31 | size_t target_fps, 32 | size_t capture_device_index); 33 | virtual ~DesktopCapturer() override; 34 | 35 | // DesktopCapturer::Callback 36 | // Called after a frame has been captured. |frame| is not nullptr if and 37 | // only if |result| is SUCCESS. 38 | void OnCaptureResult(webrtc::DesktopCapturer::Result result, 39 | std::unique_ptr frame) override; 40 | 41 | virtual void OnMessage(rtc::Message* msg); 42 | 43 | private: 44 | DesktopCapturer(); 45 | bool Init(size_t width, 46 | size_t height, 47 | size_t target_fps, 48 | size_t capture_device_index); 49 | void Destroy(); 50 | 51 | void CaptureFrame(); 52 | 53 | private: 54 | rtc::scoped_refptr i420_buffer_; 55 | std::unique_ptr screen_capturer_; 56 | }; 57 | 58 | } // namespace test 59 | } // namespace webrtc 60 | 61 | #endif // DESKTOP_CAPTURER_H_ 62 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/test/mac_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_MAC_CAPTURER_H_ 11 | #define TEST_MAC_CAPTURER_H_ 12 | 13 | #include 14 | #include 15 | 16 | #include "api/media_stream_interface.h" 17 | #include "api/scoped_refptr.h" 18 | #include "modules/video_capture/video_capture.h" 19 | #include "rtc_base/thread.h" 20 | #include "test/test_video_capturer.h" 21 | 22 | namespace webrtc { 23 | namespace test { 24 | 25 | class MacCapturer : public TestVideoCapturer, 26 | public rtc::VideoSinkInterface { 27 | public: 28 | static MacCapturer* Create(size_t width, 29 | size_t height, 30 | size_t target_fps, 31 | size_t capture_device_index); 32 | ~MacCapturer() override; 33 | 34 | void OnFrame(const VideoFrame& frame) override; 35 | 36 | private: 37 | MacCapturer(size_t width, 38 | size_t height, 39 | size_t target_fps, 40 | size_t capture_device_index); 41 | void Destroy(); 42 | 43 | void* capturer_; 44 | void* adapter_; 45 | }; 46 | 47 | } // namespace test 48 | } // namespace webrtc 49 | 50 | #endif // TEST_MAC_CAPTURER_H_ 51 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/test/platform_video_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #include "platform_video_capturer.h" 11 | 12 | #include "absl/memory/memory.h" 13 | #if defined(WEBRTC_MAC) 14 | #include "test/mac_capturer.h" 15 | #else 16 | #include "vcm_capturer.h" 17 | #endif 18 | #include "desktop_capturer.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | 23 | std::unique_ptr CreateVideoCapturer( 24 | size_t width, 25 | size_t height, 26 | size_t target_fps, 27 | size_t capture_device_index, 28 | bool desktop) { 29 | 30 | if (desktop) { 31 | return absl::WrapUnique(test::DesktopCapturer::Create( 32 | width, height, target_fps, capture_device_index)); 33 | } 34 | 35 | #if defined(WEBRTC_MAC) 36 | return absl::WrapUnique(test::MacCapturer::Create( 37 | width, height, target_fps, capture_device_index)); 38 | #else 39 | return absl::WrapUnique(test::VcmCapturer::Create( 40 | width, height, target_fps, capture_device_index)); 41 | #endif 42 | } 43 | 44 | } // namespace test 45 | } // namespace webrtc 46 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/test/platform_video_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_PLATFORM_VIDEO_CAPTURER_H_ 11 | #define TEST_PLATFORM_VIDEO_CAPTURER_H_ 12 | 13 | #include 14 | 15 | #include "test_video_capturer.h" 16 | 17 | namespace webrtc { 18 | namespace test { 19 | 20 | std::unique_ptr CreateVideoCapturer( 21 | size_t width, 22 | size_t height, 23 | size_t target_fps, 24 | size_t capture_device_index, 25 | bool desktop = false); 26 | 27 | } // namespace test 28 | } // namespace webrtc 29 | 30 | #endif // TEST_PLATFORM_VIDEO_CAPTURER_H_ 31 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/test/test.pri: -------------------------------------------------------------------------------- 1 | SOURCES += \ 2 | $$PWD/test_video_capturer.cc \ 3 | $$PWD/platform_video_capturer.cc \ 4 | $$PWD/desktop_capturer.cc 5 | 6 | HEADERS += \ 7 | $$PWD/test_video_capturer.h \ 8 | $$PWD/platform_video_capturer.h \ 9 | $$PWD/desktop_capturer.h 10 | 11 | win32 { 12 | SOURCES += \ 13 | $$PWD/vcm_capturer.cc 14 | 15 | HEADERS += \ 16 | $$PWD/vcm_capturer.h 17 | } 18 | 19 | macos { 20 | SOURCES += \ 21 | $$PWD/mac_capturer.mm 22 | 23 | HEADERS += \ 24 | $$PWD/mac_capturer.h 25 | } 26 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/test/test_video_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "test_video_capturer.h" 12 | 13 | #include 14 | 15 | #include "api/scoped_refptr.h" 16 | #include "api/video/i420_buffer.h" 17 | #include "api/video/video_frame_buffer.h" 18 | #include "api/video/video_rotation.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | TestVideoCapturer::TestVideoCapturer() = default; 23 | TestVideoCapturer::~TestVideoCapturer() = default; 24 | 25 | void TestVideoCapturer::OnFrame(const VideoFrame& frame) { 26 | int cropped_width = 0; 27 | int cropped_height = 0; 28 | int out_width = 0; 29 | int out_height = 0; 30 | 31 | if (!video_adapter_.AdaptFrameResolution( 32 | frame.width(), frame.height(), frame.timestamp_us() * 1000, 33 | &cropped_width, &cropped_height, &out_width, &out_height)) { 34 | // Drop frame in order to respect frame rate constraint. 35 | return; 36 | } 37 | 38 | if (out_height != frame.height() || out_width != frame.width()) { 39 | // Video adapter has requested a down-scale. Allocate a new buffer and 40 | // return scaled version. 41 | rtc::scoped_refptr scaled_buffer = 42 | I420Buffer::Create(out_width, out_height); 43 | scaled_buffer->ScaleFrom(*frame.video_frame_buffer()->ToI420()); 44 | broadcaster_.OnFrame(VideoFrame::Builder() 45 | .set_video_frame_buffer(scaled_buffer) 46 | .set_rotation(kVideoRotation_0) 47 | .set_timestamp_us(frame.timestamp_us()) 48 | .set_id(frame.id()) 49 | .build()); 50 | } else { 51 | // No adaptations needed, just return the frame as is. 52 | broadcaster_.OnFrame(frame); 53 | } 54 | } 55 | 56 | rtc::VideoSinkWants TestVideoCapturer::GetSinkWants() { 57 | return broadcaster_.wants(); 58 | } 59 | 60 | void TestVideoCapturer::AddOrUpdateSink( 61 | rtc::VideoSinkInterface* sink, 62 | const rtc::VideoSinkWants& wants) { 63 | broadcaster_.AddOrUpdateSink(sink, wants); 64 | UpdateVideoAdapter(); 65 | } 66 | 67 | void TestVideoCapturer::RemoveSink(rtc::VideoSinkInterface* sink) { 68 | broadcaster_.RemoveSink(sink); 69 | UpdateVideoAdapter(); 70 | } 71 | 72 | void TestVideoCapturer::UpdateVideoAdapter() { 73 | rtc::VideoSinkWants wants = broadcaster_.wants(); 74 | video_adapter_.OnSinkWants(wants); 75 | } 76 | 77 | } // namespace test 78 | } // namespace webrtc 79 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/test/test_video_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_TEST_VIDEO_CAPTURER_H_ 11 | #define TEST_TEST_VIDEO_CAPTURER_H_ 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include "api/video/video_frame.h" 18 | #include "api/video/video_source_interface.h" 19 | #include "media/base/video_adapter.h" 20 | #include "media/base/video_broadcaster.h" 21 | 22 | namespace webrtc { 23 | namespace test { 24 | 25 | class TestVideoCapturer : public rtc::VideoSourceInterface { 26 | public: 27 | TestVideoCapturer(); 28 | virtual ~TestVideoCapturer(); 29 | 30 | void AddOrUpdateSink(rtc::VideoSinkInterface* sink, 31 | const rtc::VideoSinkWants& wants) override; 32 | void RemoveSink(rtc::VideoSinkInterface* sink) override; 33 | 34 | protected: 35 | void OnFrame(const VideoFrame& frame); 36 | rtc::VideoSinkWants GetSinkWants(); 37 | 38 | private: 39 | void UpdateVideoAdapter(); 40 | 41 | rtc::VideoBroadcaster broadcaster_; 42 | cricket::VideoAdapter video_adapter_; 43 | }; 44 | } // namespace test 45 | } // namespace webrtc 46 | 47 | #endif // TEST_TEST_VIDEO_CAPTURER_H_ 48 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/test/vcm_capturer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | 11 | #include "vcm_capturer.h" 12 | 13 | #include 14 | #include 15 | 16 | #include "modules/video_capture/video_capture_factory.h" 17 | #include "rtc_base/checks.h" 18 | #include "rtc_base/logging.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | 23 | VcmCapturer::VcmCapturer() : vcm_(nullptr) {} 24 | 25 | bool VcmCapturer::Init(size_t width, 26 | size_t height, 27 | size_t target_fps, 28 | size_t capture_device_index) { 29 | std::unique_ptr device_info( 30 | VideoCaptureFactory::CreateDeviceInfo()); 31 | 32 | char device_name[256]; 33 | char unique_name[256]; 34 | if (device_info->GetDeviceName(static_cast(capture_device_index), 35 | device_name, sizeof(device_name), unique_name, 36 | sizeof(unique_name)) != 0) { 37 | Destroy(); 38 | return false; 39 | } 40 | 41 | vcm_ = webrtc::VideoCaptureFactory::Create(unique_name); 42 | if (!vcm_) { 43 | return false; 44 | } 45 | vcm_->RegisterCaptureDataCallback(this); 46 | 47 | device_info->GetCapability(vcm_->CurrentDeviceName(), 0, capability_); 48 | 49 | capability_.width = static_cast(width); 50 | capability_.height = static_cast(height); 51 | capability_.maxFPS = static_cast(target_fps); 52 | capability_.videoType = VideoType::kI420; 53 | 54 | if (vcm_->StartCapture(capability_) != 0) { 55 | Destroy(); 56 | return false; 57 | } 58 | 59 | RTC_CHECK(vcm_->CaptureStarted()); 60 | 61 | return true; 62 | } 63 | 64 | VcmCapturer* VcmCapturer::Create(size_t width, 65 | size_t height, 66 | size_t target_fps, 67 | size_t capture_device_index) { 68 | std::unique_ptr vcm_capturer(new VcmCapturer()); 69 | if (!vcm_capturer->Init(width, height, target_fps, capture_device_index)) { 70 | RTC_LOG(LS_WARNING) << "Failed to create VcmCapturer(w = " << width 71 | << ", h = " << height << ", fps = " << target_fps 72 | << ")"; 73 | return nullptr; 74 | } 75 | return vcm_capturer.release(); 76 | } 77 | 78 | void VcmCapturer::Destroy() { 79 | if (!vcm_) 80 | return; 81 | 82 | vcm_->StopCapture(); 83 | vcm_->DeRegisterCaptureDataCallback(); 84 | // Release reference to VCM. 85 | vcm_ = nullptr; 86 | } 87 | 88 | VcmCapturer::~VcmCapturer() { 89 | Destroy(); 90 | } 91 | 92 | void VcmCapturer::OnFrame(const VideoFrame& frame) { 93 | TestVideoCapturer::OnFrame(frame); 94 | } 95 | 96 | } // namespace test 97 | } // namespace webrtc 98 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/test/vcm_capturer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by a BSD-style license 5 | * that can be found in the LICENSE file in the root of the source 6 | * tree. An additional intellectual property rights grant can be found 7 | * in the file PATENTS. All contributing project authors may 8 | * be found in the AUTHORS file in the root of the source tree. 9 | */ 10 | #ifndef TEST_VCM_CAPTURER_H_ 11 | #define TEST_VCM_CAPTURER_H_ 12 | 13 | #include 14 | #include 15 | 16 | #include "api/scoped_refptr.h" 17 | #include "modules/video_capture/video_capture.h" 18 | #include "test_video_capturer.h" 19 | 20 | namespace webrtc { 21 | namespace test { 22 | 23 | class VcmCapturer : public TestVideoCapturer, 24 | public rtc::VideoSinkInterface { 25 | public: 26 | static VcmCapturer* Create(size_t width, 27 | size_t height, 28 | size_t target_fps, 29 | size_t capture_device_index); 30 | virtual ~VcmCapturer(); 31 | 32 | void OnFrame(const VideoFrame& frame) override; 33 | 34 | private: 35 | VcmCapturer(); 36 | bool Init(size_t width, 37 | size_t height, 38 | size_t target_fps, 39 | size_t capture_device_index); 40 | void Destroy(); 41 | 42 | rtc::scoped_refptr vcm_; 43 | VideoCaptureCapability capability_; 44 | }; 45 | 46 | } // namespace test 47 | } // namespace webrtc 48 | 49 | #endif // TEST_VCM_CAPTURER_H_ 50 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/videorenderer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "videorenderer.h" 7 | #include "api/video/i420_buffer.h" 8 | #include "third_party/libyuv/include/libyuv/convert_argb.h" 9 | 10 | VideoRenderer::VideoRenderer(webrtc::VideoTrackInterface* track_to_render) 11 | : rendered_track_(track_to_render) 12 | { 13 | rendered_track_->AddOrUpdateSink(this, rtc::VideoSinkWants()); 14 | } 15 | 16 | VideoRenderer::~VideoRenderer() 17 | { 18 | rendered_track_->RemoveSink(this); 19 | } 20 | 21 | void VideoRenderer::lock() 22 | { 23 | mutex_.lock(); 24 | } 25 | 26 | void VideoRenderer::unlock() 27 | { 28 | mutex_.unlock(); 29 | } 30 | 31 | webrtc::I420BufferInterface *VideoRenderer::getBuffer() 32 | { 33 | return i420_buffer_; 34 | } 35 | 36 | void VideoRenderer::OnFrame(const webrtc::VideoFrame &frame) 37 | { 38 | //TimeConsum tc(Q_FUNC_INFO); 39 | AutoLock lock(this); 40 | i420_buffer_ = frame.video_frame_buffer()->ToI420(); 41 | 42 | //qDebug() << Q_FUNC_INFO << ">>>>>>>frame: " << frame.width() << frame.height() << frame.size(); 43 | if (frame.rotation() != webrtc::kVideoRotation_0) { 44 | i420_buffer_ = webrtc::I420Buffer::Rotate(*i420_buffer_, frame.rotation()); 45 | } 46 | 47 | Q_EMIT recvFrame(); 48 | } 49 | -------------------------------------------------------------------------------- /examples/peerconnection/remote/videorenderer.h: -------------------------------------------------------------------------------- 1 | #ifndef VIDEORENDERER_H 2 | #define VIDEORENDERER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "api/media_stream_interface.h" 10 | #include 11 | 12 | class VideoRenderer : public QObject, public rtc::VideoSinkInterface 13 | { 14 | Q_OBJECT 15 | public: 16 | VideoRenderer(webrtc::VideoTrackInterface* track_to_render); 17 | virtual ~VideoRenderer(); 18 | 19 | class TimeConsum 20 | { 21 | public: 22 | TimeConsum(const QString &log) 23 | : log_(log) 24 | { 25 | time_.start(); 26 | 27 | } 28 | ~TimeConsum() { 29 | qDebug() << log_ << "consum time:" << time_.elapsed(); 30 | } 31 | 32 | private: 33 | QTime time_; 34 | QString log_; 35 | }; 36 | 37 | void lock(); 38 | void unlock(); 39 | webrtc::I420BufferInterface *getBuffer(); 40 | 41 | template 42 | class AutoLock { 43 | public: 44 | explicit AutoLock(T* obj) : obj_(obj) { obj_->lock(); } 45 | ~AutoLock() { obj_->unlock(); } 46 | 47 | protected: 48 | T* obj_; 49 | }; 50 | 51 | Q_SIGNALS: 52 | void recvFrame(); 53 | 54 | protected: 55 | virtual void OnFrame(const webrtc::VideoFrame& frame); 56 | 57 | private: 58 | rtc::scoped_refptr rendered_track_ = nullptr; 59 | QMutex mutex_; 60 | rtc::scoped_refptr i420_buffer_; 61 | }; 62 | 63 | #endif // VIDEORENDERER_H 64 | -------------------------------------------------------------------------------- /examples/webrtc_common/webrtc_common.pri: -------------------------------------------------------------------------------- 1 | CONFIG += no_keywords 2 | 3 | INCLUDEPATH += \ 4 | $$PWD/../../webrtc/src/third_party/libyuv/include \ 5 | $$PWD/../../webrtc/src \ 6 | $$PWD/../../webrtc/src/third_party/abseil-cpp 7 | 8 | BUILD_MODE = debug 9 | CONFIG(debug, debug|release) { 10 | BUILD_MODE = debug 11 | } else { 12 | BUILD_MODE = release 13 | } 14 | 15 | LIBS += \ 16 | -L$$PWD/../../out/$$BUILD_MODE/obj -lwebrtc \ 17 | -L$$PWD/../../out/$$BUILD_MODE/obj/api -lcreate_peerconnection_factory \ 18 | -L$$PWD/../../out/$$BUILD_MODE/obj/rtc_base -lrtc_base 19 | 20 | message($$LIBS) 21 | 22 | # *********************************************************** 23 | # Win平台下配置 24 | # *********************************************************** 25 | win32 { 26 | DEFINES += WEBRTC_WIN \ 27 | WIN32_LEAN_AND_MEAN \ 28 | USE_BUILTIN_SW_CODECS \ 29 | HAVE_WEBRTC_VIDEO \ 30 | INCL_EXTRA_HTON_FUNCTIONS \ 31 | NOMINMAX 32 | 33 | LIBS += \ 34 | -lwmcodecdspuuid \ 35 | -ldmoguids \ 36 | -lMsdmo \ 37 | -lSecur32 \ 38 | -lShell32 \ 39 | -lGdi32 \ 40 | -lWinmm \ 41 | -lAdvapi32 \ 42 | -lstrmiids \ 43 | -lDXGI \ 44 | -lD3D11 \ 45 | -lWs2_32 \ 46 | -lOle32 \ 47 | -lOleAut32 \ 48 | -lUser32 49 | 50 | PLANTFORM_MODE = win32 51 | contains(QT_ARCH, x86_64) { 52 | PLANTFORM_MODE = win64 53 | } else { 54 | PLANTFORM_MODE = win32 55 | } 56 | 57 | DESTDIR = $$PWD/../../exampleout/$$PLANTFORM_MODE/$$BUILD_MODE/$$TARGET 58 | DESTDIR = $$PWD/../../exampleout/$$PLANTFORM_MODE/$$BUILD_MODE/$$TARGET 59 | } 60 | 61 | # *********************************************************** 62 | # Mac平台下配置 63 | # *********************************************************** 64 | macos { 65 | DEFINES += WEBRTC_MAC \ 66 | WEBRTC_POSIX \ 67 | USE_BUILTIN_SW_CODECS \ 68 | HAVE_WEBRTC_VIDEO \ 69 | INCL_EXTRA_HTON_FUNCTIONS 70 | 71 | # QMAKE_LFLAGS += -F /System/Library/Frameworks/CoreFoundation.framework/ 72 | LIBS += \ 73 | -framework CoreFoundation \ 74 | -framework CoreGraphics \ 75 | -framework IOSurface \ 76 | -framework Foundation \ 77 | -framework AppKit \ 78 | -framework CoreMedia \ 79 | -framework AVFoundation \ 80 | -framework CoreVideo \ 81 | -framework CoreAudio \ 82 | -framework AudioToolbox 83 | 84 | LIBS += \ 85 | -L$$PWD/../../out/$$BUILD_MODE/obj/sdk -lvideocapture_objc \ 86 | -L$$PWD/../../out/$$BUILD_MODE/obj/sdk -lvideoframebuffer_objc \ 87 | -L$$PWD/../../out/$$BUILD_MODE/obj/sdk -lbase_objc \ 88 | -L$$PWD/../../out/$$BUILD_MODE/obj/sdk -lnative_video 89 | 90 | INCLUDEPATH += \ 91 | $$PWD/../../webrtc/src/sdk/objc/base \ 92 | $$PWD/../../webrtc/src/sdk/objc 93 | 94 | DESTDIR = $$PWD/../../exampleout/mac64/$$BUILD_MODE/$$TARGET 95 | } 96 | -------------------------------------------------------------------------------- /gclient: -------------------------------------------------------------------------------- 1 | solutions = [ 2 | { 3 | "name": "src", 4 | "url": "https://webrtc.googlesource.com/src.git", 5 | "managed": False, 6 | "custom_deps": { 7 | #"src/testing": None, 8 | "src/third_party/gtest-parallel": None, 9 | "src/third_party/accessibility_test_framework": None, 10 | "src/third_party/android_support_test_runner": None, 11 | "src/tools/swarming_client": None, 12 | "src/tools/luci-go": None, 13 | }, 14 | "custom_hooks": [ 15 | {"name": "test_fonts"}, 16 | {"name": "Generate component metadata for tests"}, 17 | # The download hook... hopefully 18 | {"name": ""}, 19 | ], 20 | }, 21 | ] 22 | -------------------------------------------------------------------------------- /script/custom_webrtc.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | def dynamic_crt(): 4 | with open(r'build\config\win\BUILD.gn', 'r+') as f1: 5 | infos = f1.readlines() 6 | find = False 7 | count = 0 8 | for info in infos: 9 | count += 1 10 | if -1 == info.find('configs = [ ":static_crt" ]'): 11 | continue 12 | infos[count-1] = info.replace('configs = [ ":static_crt" ]', 'configs = [ ":dynamic_crt" ]') 13 | print('replace static_crt with dynamic_crt') 14 | find = True 15 | break 16 | 17 | if not find: 18 | print('not find configs = [ ":static_crt" ]') 19 | return False 20 | 21 | f1.seek(0, 0) 22 | f1.writelines(infos) 23 | return True 24 | 25 | return False 26 | 27 | def remove_capture_checker(): 28 | with open(r'modules\video_capture\windows\sink_filter_ds.cc', 'r+') as f1: 29 | infos = f1.readlines() 30 | if -1 == infos[722].find('RTC_DCHECK_RUN_ON(&capture_checker_);'): 31 | print('not find RTC_DCHECK_RUN_ON(&capture_checker_);') 32 | return False 33 | 34 | line = infos[722].replace('RTC_DCHECK_RUN_ON(&capture_checker_);', '//RTC_DCHECK_RUN_ON(&capture_checker_);') 35 | infos[722] = line 36 | 37 | f1.seek(0, 0) 38 | f1.writelines(infos) 39 | return True 40 | 41 | return False 42 | 43 | if __name__ == '__main__': 44 | if not dynamic_crt(): 45 | print('dynamic_crt failed') 46 | exit(1) 47 | 48 | # this bug https://groups.google.com/forum/#!searchin/discuss-webrtc/$26capture_checker_$20iscurrent|sort:date/discuss-webrtc/HBzGZXL-FvM/SG2TSnaoBAAJ 49 | # if not remove_capture_checker(): 50 | # print('remove_capture_checker failed') 51 | # exit(1) 52 | 53 | exit(0) -------------------------------------------------------------------------------- /sync_for_mac.sh: -------------------------------------------------------------------------------- 1 | # 获取绝对路径,保证其他目录执行此脚本依然正确 2 | { 3 | cd $(dirname "$0") 4 | script_path=$(pwd) 5 | cd - 6 | } &> /dev/null # disable output 7 | 8 | # 设置当前目录,cd的目录影响接下来执行程序的工作目录 9 | old_cd=$(pwd) 10 | cd $(dirname "$0") 11 | 12 | echo 13 | echo --------------------------------------------------------------- 14 | echo 检查depot_tools 15 | echo --------------------------------------------------------------- 16 | 17 | depot_tools_path=$script_path/depot_tools 18 | if [ -d $depot_tools_path ];then 19 | echo $depot_tools_path 已存在 20 | else 21 | echo $depot_tools_path 不存在,下载depot_tools 22 | git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git 23 | fi 24 | 25 | if [ $? -ne 0 ]; then 26 | echo depot_tools下载失败 27 | exit 1 28 | fi 29 | 30 | # 环境变量设置 31 | export PATH=$depot_tools_path:$PATH 32 | 33 | echo 34 | echo --------------------------------------------------------------- 35 | echo 初始化depot_tools 36 | echo --------------------------------------------------------------- 37 | 38 | gclient 39 | 40 | if [ $? -ne 0 ]; then 41 | echo 初始化depot_tools失败 42 | exit 1 43 | fi 44 | 45 | echo 46 | echo --------------------------------------------------------------- 47 | echo 同步webrtc代码 48 | echo --------------------------------------------------------------- 49 | 50 | webrtc_path=$script_path/webrtc 51 | webrtc_src_path=$webrtc_path/src 52 | if [ ! -d $webrtc_path ];then 53 | mkdir $webrtc_path 54 | fi 55 | 56 | cd $webrtc_path 57 | if [ ! -d $webrtc_src_path ];then 58 | # fetch --nohooks webrtc_ios 59 | fetch --nohooks webrtc 60 | fi 61 | 62 | gclient sync --force --with_branch_heads --with_tags -D 63 | cd $webrtc_src_path 64 | 65 | # webrtc最新release https://chromiumdash.appspot.com/branches 66 | git checkout refs/remotes/branch-heads/4472 67 | 68 | # 切换分支以后必须sync,来同步不同分支的build tools 69 | # 不能再加--nohooks,否则不会下载webrtc\src\buildtools\win\gn.exe等编译工具 70 | gclient sync --with_branch_heads --with_tags -D 71 | 72 | if [ $? -ne 0 ]; then 73 | echo webrtc同步失败 74 | exit 1 75 | fi 76 | 77 | # 恢复工作目录 78 | cd $old_cd 79 | 80 | echo all同步成功 -------------------------------------------------------------------------------- /sync_for_win.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barry-ran/learn-webrtc/eec1e41c78e20f3bdc4542953e41032e79080d09/sync_for_win.bat --------------------------------------------------------------------------------