前言

推荐一个零声学院免费教程,个人觉得老师讲得不错,
分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:

在音视频中,主要包含音视频的采集、编码、传输、解码和渲染。这些,在webrtc中都有涉及。下面借鉴webrtc中的桌面采集来进行学习。

准备

  • 需要下载webrtc源码
  • m98 版本webrtc代码 https://pan.baidu.com/s/11_4_sAX9GibQHdvuIOTtNQ 提取码: vyfk

webrtc采集

webrtc 采集主要参考《PeerConnectionClient Demo 视频源为window抓屏
webrtc实现采集接口很简单

下面通过api简单的说明下webrtc采集部分:

屏幕采集
  • webrtc::DesktopCapturer::CreateScreenCapturer 创建一个屏幕采集类
    此方法为静态方法,创建一个屏幕采集
// static
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateScreenCapturer(
    const DesktopCaptureOptions& options) {
#if defined(RTC_ENABLE_WIN_WGC)
  if (options.allow_wgc_capturer() && IsWgcSupported(CaptureType::kScreen)) {
    return WgcCapturerWin::CreateRawScreenCapturer(options);
  }
#endif  // defined(RTC_ENABLE_WIN_WGC)

  std::unique_ptr<DesktopCapturer> capturer = CreateRawScreenCapturer(options);
  if (capturer && options.detect_updated_region()) {
    capturer.reset(new DesktopCapturerDifferWrapper(std::move(capturer)));
  }

  return capturer;
}	
窗口采集
  • webrtc::DesktopCapturer::CreateWindowCapturer 创建一个窗口采集类
    和上面一样,此方法为静态方法,创建一个窗口采集
// static
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateWindowCapturer(
   const DesktopCaptureOptions& options) {
#if defined(RTC_ENABLE_WIN_WGC)
 if (options.allow_wgc_capturer() && IsWgcSupported(CaptureType::kWindow)) {
   return WgcCapturerWin::CreateRawWindowCapturer(options);
 }
#endif  // defined(RTC_ENABLE_WIN_WGC)

#if defined(WEBRTC_WIN)
 if (options.allow_cropping_window_capturer()) {
   return CroppingWindowCapturer::CreateCapturer(options);
 }
#endif  // defined(WEBRTC_WIN)

 std::unique_ptr<DesktopCapturer> capturer = CreateRawWindowCapturer(options);
 if (capturer && options.detect_updated_region()) {
   capturer.reset(new DesktopCapturerDifferWrapper(std::move(capturer)));
 }

 return capturer;
}

webrtc采集数据回调类
  • webrtc创建好对应的屏幕(窗口)采集类,只需要设置对应的回调类,即可将采集到的数据进行回调出来。
  // Interface that must be implemented by the DesktopCapturer consumers.
  class Callback {
   public:
    // Called after a frame has been captured. `frame` is not nullptr if and
    // only if `result` is SUCCESS.
    virtual void OnCaptureResult(Result result,
                                 std::unique_ptr<DesktopFrame> frame) = 0;

   protected:
    virtual ~Callback() {}
  };

  • Callback 回调类,通过webrtc::DesktopCapturer::CreateScreenCapturer 创建的对象的start方法,设置回调对象。
void DesktopCapturerDifferWrapper::Start(DesktopCapturer::Callback* callback) {
  callback_ = callback;
  base_capturer_->Start(this);
}
···
webrtc::WindowCapturerTest callback;
capturer_->Start(&callback);

webrtc采集代码

#include <stdio.h>

#include <memory>
#include <string>
#include <utility>
#include <Windows.h>

#include "modules/desktop_capture/desktop_capture_options.h"
#include "modules/desktop_capture/desktop_capturer.h"
#include "modules/desktop_capture/desktop_frame.h"
#include "modules/desktop_capture/desktop_geometry.h"
#include "rtc_base/checks.h"
#include <api/video/i420_buffer.h>
#include <third_party/libyuv/include/libyuv.h>
#include <api/video/video_frame.h>

namespace webrtc {

    rtc::scoped_refptr<webrtc::I420Buffer> i420_buffer_;

    class WindowCapturerTest: public DesktopCapturer::Callback {
    public:
        // DesktopCapturer::Callback interface
        void OnCaptureResult(DesktopCapturer::Result result,
            std::unique_ptr<DesktopFrame> frame) override {
            if (result != webrtc::DesktopCapturer::Result::SUCCESS)
                return;

            int width = frame->size().width();
            int height = frame->size().height();

            if (!i420_buffer_.get() ||
                i420_buffer_->width() * i420_buffer_->height() != width * height) {
                i420_buffer_ = webrtc::I420Buffer::Create(width, height);
            }
            libyuv::ConvertToI420(frame->data(), 0, i420_buffer_->MutableDataY(),
                i420_buffer_->StrideY(), i420_buffer_->MutableDataU(),
                i420_buffer_->StrideU(), i420_buffer_->MutableDataV(),
                i420_buffer_->StrideV(), 0, 0, width, height, width,
                height, libyuv::kRotate0, libyuv::FOURCC_ARGB);

			webrtc::VideoFrame video_frame(webrtc::VideoFrame(i420_buffer_, 0, 0, webrtc::kVideoRotation_0));
            if (NULL == m_pFile)
            {
                if (m_nCount == 0) {
					char szMsg[256];
					sprintf(szMsg, ".\\test_%dx%d.yuv", width, height);
					printf(szMsg);
					printf("\r\n");
					m_pFile = fopen(szMsg, "wb");
                }

            }

            rtc::scoped_refptr<webrtc::VideoFrameBuffer> vfb = video_frame.video_frame_buffer();
            if (++m_nCount < 100) {
				if (m_pFile != NULL) {
					fwrite(vfb.get()->GetI420()->DataY(), 1, height * width, m_pFile);
					fwrite(vfb.get()->GetI420()->DataU(), 1, height * width / 4, m_pFile);
					fwrite(vfb.get()->GetI420()->DataV(), 1, height * width / 4, m_pFile);
					//fflush(m_pFile);
				}
            } else {
				if (m_pFile != NULL) {
                    fflush(m_pFile);
					fclose(m_pFile);
					m_pFile = NULL;
				}
            }

            i420_buffer_.release();
            frame.reset();
            //OnFrame(webrtc::VideoFrame(i420_buffer_, 0, 0, webrtc::kVideoRotation_0));
        }
        ~WindowCapturerTest() {
            if (m_pFile != NULL) {
                fflush(m_pFile);
				fclose(m_pFile);
				m_pFile = NULL;
            }
        }
    protected:
        std::unique_ptr<DesktopCapturer> capturer_;
        std::unique_ptr<DesktopFrame> frame_;
        int m_nCount = 0;
        FILE* m_pFile = NULL;
    };



}// namespace webrtc


std::unique_ptr<webrtc::DesktopCapturer> capturer_;

void startCapturer() {
    auto options = webrtc::DesktopCaptureOptions::CreateDefault();
    options.set_allow_directx_capturer(true);
    capturer_ = webrtc::DesktopCapturer::CreateScreenCapturer(options);//屏幕
    //capturer_ = webrtc::DesktopCapturer::CreateWindowCapturer(options);
    //capturer_ = webrtc::DesktopCapturer::CreateWindowCapturer(webrtc::DesktopCaptureOptions::CreateDefault());//窗口
    if (!capturer_.get())
        return;

    webrtc::WindowCapturerTest callback;
    capturer_->Start(&callback);

    webrtc::DesktopCapturer::SourceList sources;
    capturer_->GetSourceList(&sources);
    for (auto it = sources.begin(); it != sources.end(); ++it) {
        char szMsg[256];
        sprintf(szMsg, "it->id = 0x%x it->title=%s\r\n", it->id, it->title.c_str());
        printf(szMsg);
    }

    capturer_->SelectSource(sources[0].id);
    while (1)
    {
        //开始循环抓图
        capturer_->CaptureFrame();
        Sleep(40);
    }
}

int main()
{
    startCapturer();
    getchar();
    return 0;
}

webrtc 代码

CMakeLists.txt

CMAKE_MINIMUM_REQUIRED(VERSION 3.8)

IF(WIN32)
	CMAKE_POLICY(SET CMP0020 NEW)
ENDIF(WIN32)

SET(PRJ_NAME libwebrtc)

PROJECT(${PRJ_NAME})

ADD_DEFINITIONS(-D_LIB)
ADD_DEFINITIONS(-DWIN32)
ADD_DEFINITIONS(-DNOMINMAX)
ADD_DEFINITIONS(-DWEBRTC_WIN)
ADD_DEFINITIONS(-DWEBRTC_USE_H264)
ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)

AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} SOURCE_FILES)


SET(INCLUDE_PATHS
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/third_party
${CMAKE_CURRENT_SOURCE_DIR}/third_party/libyuv/include
)


INCLUDE_DIRECTORIES(${3DRLIB_INCLUDE_DIR} ${INCLUDE_PATHS})
LINK_DIRECTORIES(${3DRLIB_INCLUDE_DIR})

#FILE(GLOB INCLUDE_FILES  "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
#FILE(GLOB SRC_FILES  ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)

SET(THIS_SOURCE_FILES ${INCLUDE_FILES} ${SOURCE_FILES} ${SRC_FILES})

SET(CMAKE_INCLUDE_CURRENT_DIR ON)

#FIND_PACKAGE(Qt5 COMPONENTS Core Gui Widgets Network REQUIRED)
#SET(MOC_FILES )

#QT5_WRAP_CPP(THIS_SOURCE_FILES ${MOC_FILES})


# 添加筛选器
SET(API_TASK_QUEUE
api/task_queue/task_queue_base.cc
api/task_queue/task_queue_base.h
)

SET(API_VIDEO
api/video/color_space.cc
api/video/color_space.h
api/video/i420_buffer.cc
api/video/i420_buffer.h
#api/video/i422_buffer.cc
#api/video/i444_buffer.cc
#api/video/nv12_buffer.cc
#api/video/nv12_buffer.h
api/video/video_frame.cc
api/video/video_frame.h
api/video/video_frame_buffer.cc
api/video/video_frame_buffer.h
api/video/video_source_interface.cc
api/video/video_source_interface.h
)

SET(MEDIA_BASE
media/base/adapted_video_track_source.cc
media/base/video_adapter.cc
media/base/video_broadcaster.cc
media/base/video_common.cc
media/base/video_source_base.cc
)

SET(MODULES_DESKTOP_CAPTURE
modules/desktop_capture/blank_detector_desktop_capturer_wrapper.cc
modules/desktop_capture/cropped_desktop_frame.cc
modules/desktop_capture/cropping_window_capturer.cc
modules/desktop_capture/cropping_window_capturer_win.cc
modules/desktop_capture/desktop_and_cursor_composer.cc
modules/desktop_capture/desktop_capture_metrics_helper.cc
modules/desktop_capture/desktop_capturer.cc
modules/desktop_capture/desktop_capturer_differ_wrapper.cc
modules/desktop_capture/desktop_capturer_wrapper.cc
modules/desktop_capture/desktop_capture_options.cc
modules/desktop_capture/desktop_frame.cc
modules/desktop_capture/desktop_frame_rotation.cc
modules/desktop_capture/desktop_frame_win.cc
modules/desktop_capture/desktop_geometry.cc
modules/desktop_capture/desktop_region.cc
modules/desktop_capture/differ_block.cc
modules/desktop_capture/differ_vector_sse2.cc
modules/desktop_capture/fallback_desktop_capturer_wrapper.cc
modules/desktop_capture/full_screen_application_handler.cc
modules/desktop_capture/full_screen_window_detector.cc
modules/desktop_capture/mouse_cursor.cc
modules/desktop_capture/mouse_cursor_monitor_win.cc
modules/desktop_capture/resolution_tracker.cc
modules/desktop_capture/rgba_color.cc
modules/desktop_capture/screen_capturer_win.cc
modules/desktop_capture/screen_drawer.cc
modules/desktop_capture/screen_drawer_win.cc
modules/desktop_capture/shared_desktop_frame.cc
modules/desktop_capture/shared_memory.cc
modules/desktop_capture/window_capturer_win.cc
modules/desktop_capture/window_finder.cc
modules/desktop_capture/window_finder_win.cc
)

SET(MODULES_DESKTOP_CAPTURE_WIN
modules/desktop_capture/win/cursor.cc
modules/desktop_capture/win/d3d_device.cc
modules/desktop_capture/win/desktop.cc
modules/desktop_capture/win/display_configuration_monitor.cc
modules/desktop_capture/win/dxgi_adapter_duplicator.cc
modules/desktop_capture/win/dxgi_context.cc
modules/desktop_capture/win/dxgi_duplicator_controller.cc
modules/desktop_capture/win/dxgi_frame.cc
modules/desktop_capture/win/dxgi_output_duplicator.cc
modules/desktop_capture/win/dxgi_texture.cc
modules/desktop_capture/win/dxgi_texture_mapping.cc
modules/desktop_capture/win/dxgi_texture_staging.cc
modules/desktop_capture/win/full_screen_win_application_handler.cc
modules/desktop_capture/win/scoped_thread_desktop.cc
modules/desktop_capture/win/screen_capturer_win_directx.cc
modules/desktop_capture/win/screen_capturer_win_gdi.cc
modules/desktop_capture/win/screen_capturer_win_magnifier.cc
modules/desktop_capture/win/screen_capture_utils.cc
modules/desktop_capture/win/selected_window_context.cc
modules/desktop_capture/win/window_capture_utils.cc
modules/desktop_capture/win/desktop_capture_utils.cc
modules/desktop_capture/win/window_capturer_win_gdi.cc
)

SET(RTC_BASE
rtc_base/async_resolver_interface.cc
rtc_base/async_socket.cc
rtc_base/checks.cc
rtc_base/critical_section.cc
rtc_base/event.cc
rtc_base/event_tracer.cc
rtc_base/ip_address.cc
rtc_base/location.cc
rtc_base/logging.cc
rtc_base/message_handler.cc
rtc_base/net_helpers.cc
rtc_base/null_socket_server.cc
rtc_base/physical_socket_server.cc
rtc_base/platform_thread.cc
rtc_base/platform_thread_types.cc
rtc_base/signal_thread.cc
rtc_base/socket_address.cc
rtc_base/string_encode.cc
rtc_base/string_to_number.cc
rtc_base/string_utils.cc
rtc_base/thread.cc
rtc_base/time_utils.cc
rtc_base/system_time.cc
rtc_base/win32.cc
rtc_base/win/windows_version.cc
)

SET(RTC_BASE_NUMERICS
rtc_base/numerics/histogram_percentile_counter.cc
)

SET(RTC_BASE_MEMORY
rtc_base/memory/aligned_malloc.cc
)

SET(RTC_BASE_STRINGS
rtc_base/strings/string_builder.cc
)

SET(RTC_BASE_SYNCHRONIZATION
rtc_base/synchronization/sequence_checker.cc 
rtc_base/synchronization/sequence_checker_internal.cc
rtc_base/synchronization/yield_policy.cc
)

SET(SYSTEM_WRAPPERS
system_wrappers/source/cpu_features.cc
system_wrappers/source/cpu_info.cc
system_wrappers/source/field_trial.cc
system_wrappers/source/metrics.cc
system_wrappers/source/sleep.cc
)

SET(THIRD_PARTY_ABSL
third_party/absl/base/internal/throw_delegate.cc
third_party/absl/strings/ascii.cc
third_party/absl/strings/internal/memutil.cc
third_party/absl/strings/string_view.cc
)

SET(THIRD_PARTY_LIBYUV
third_party/libyuv/source/compare.cc
third_party/libyuv/source/compare_common.cc
third_party/libyuv/source/compare_gcc.cc
third_party/libyuv/source/compare_neon.cc
third_party/libyuv/source/compare_neon64.cc
third_party/libyuv/source/compare_win.cc
third_party/libyuv/source/convert.cc
third_party/libyuv/source/convert_argb.cc
third_party/libyuv/source/convert_from.cc
third_party/libyuv/source/convert_from_argb.cc
third_party/libyuv/source/convert_jpeg.cc
third_party/libyuv/source/convert_to_argb.cc
third_party/libyuv/source/convert_to_i420.cc 
third_party/libyuv/source/cpu_id.cc
third_party/libyuv/source/mjpeg_decoder.cc
third_party/libyuv/source/mjpeg_validate.cc
third_party/libyuv/source/planar_functions.cc
third_party/libyuv/source/rotate.cc
third_party/libyuv/source/rotate_argb.cc
third_party/libyuv/source/rotate_mips.cc
third_party/libyuv/source/rotate_neon.cc
third_party/libyuv/source/rotate_neon64.cc
third_party/libyuv/source/row_any.cc
third_party/libyuv/source/row_common.cc
third_party/libyuv/source/row_gcc.cc
third_party/libyuv/source/row_mips.cc
third_party/libyuv/source/row_neon.cc
third_party/libyuv/source/row_neon64.cc
third_party/libyuv/source/row_win.cc
third_party/libyuv/source/scale.cc
third_party/libyuv/source/scale_any.cc
third_party/libyuv/source/scale_argb.cc
third_party/libyuv/source/scale_common.cc
third_party/libyuv/source/scale_gcc.cc
third_party/libyuv/source/scale_mips.cc
third_party/libyuv/source/scale_neon.cc
third_party/libyuv/source/scale_neon64.cc
third_party/libyuv/source/scale_win.cc
third_party/libyuv/source/video_common.cc
)


SOURCE_GROUP(api/task/queue FILES ${API_TASK_QUEUE})
SOURCE_GROUP(api/video FILES ${API_VIDEO})
SOURCE_GROUP(media/base FILES ${MEDIA_BASE})
SOURCE_GROUP(modules/desktop/capture FILES ${MODULES_DESKTOP_CAPTURE})
SOURCE_GROUP(modules/desktop/capture/win FILES ${MODULES_DESKTOP_CAPTURE_WIN})
SOURCE_GROUP(rtc_base FILES ${RTC_BASE})
SOURCE_GROUP(rtc_base/memory FILES ${RTC_BASE_MEMORY})
SOURCE_GROUP(rtc_base/strings ${RTC_BASE_STRINGS})
SOURCE_GROUP(rtc_base/synchronization FILES ${RTC_BASE_SYNCHRONIZATION})
SOURCE_GROUP(rtc_base/numerics FILES ${RTC_BASE_NUMERICS})
SOURCE_GROUP(system_wrappers FILES ${SYSTEM_WRAPPERS})
SOURCE_GROUP(third_party/absl FILES ${THIRD_PARTY_ABSL})
SOURCE_GROUP(third_party/libyuv FILES ${THIRD_PARTY_LIBYUV})


FILE(GLOB CPP_FILES
${API_TASK_QUEUE}
${API_VIDEO}
${MEDIA_BASE}
${MODULES_DESKTOP_CAPTURE}
${MODULES_DESKTOP_CAPTURE_WIN}
${RTC_BASE}
${RTC_BASE_MEMORY}
${RTC_BASE_NUMERICS}
${RTC_BASE_STRINGS}
${RTC_BASE_SYNCHRONIZATION}
${SYSTEM_WRAPPERS}
${THIRD_PARTY_ABSL}
${THIRD_PARTY_LIBYUV}
)

ADD_LIBRARY(${PRJ_NAME} STATIC ${CPP_FILES})

#TARGET_LINK_LIBRARIES(${PRJ_NAME} Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network)

IF(WIN32)
	SET_TARGET_PROPERTIES(${PRJ_NAME} PROPERTIES DEBUG_POSTFIX _d)
	SET_TARGET_PROPERTIES(${PRJ_NAME} PROPERTIES LINK_FLAGS "/OPT:NOREF /OPT:NOICF")
ENDIF(WIN32)

webrtc代码说明

上面是抽取webrtc中的代码,通过webrtc来采集屏幕(窗口),API使用比较简单。通过cmake管理,方便进行
跨平台。同时,前期把这些代码抽取出来,方便后面进行集成。应用到其他工程中。同时,学习之余记录下来。

参考链接

windows下提取webrtc的录制窗口demo程序
PeerConnectionClient Demo 视频源为window抓屏

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐