webrtc源码学习 - windows摄像头采集

windows 摄像头采集方案

现在市场上大多数的摄像头和采集卡在Windows系统上的驱动基于WDM架构,微软定义了采集卡设备与上层程序间的通信驱动接口,这已经成为一种标准,因此,控制摄像头和采集图像基本都通过Directshow框架来实现。

webrtc 摄像头采集

由上面的介绍,我们知道在windows 几乎都dshow,那webrtc 摄像头采集也是采用的dshow
摄像头采集的模块
在这里插入图片描述
类图 ,VideoCaptureDS 是采集的实现类,DS 也就是DirectShow 的简写。
在这里插入图片描述

接下来,我们看一下VideoCaptureDS 具体实现的几个函数,想看懂代码,需要先对dshow 有所了解。可以先看下我另一篇文章windows 摄像头采集
1、根据名称获得 caputre_filter
2、创建 graph
3、通过graph 获得 media control ,用来控制采集
4、添加 caputre_filter 都添加到 graph 中,_outputCapturePin 采集pin
5、创建 CaptureSinkFilter,添加到 graph 中
6、链接 输出 和 sink 的输入


int32_t VideoCaptureDS::Init(const char* deviceUniqueIdUTF8) {
  const int32_t nameLength = (int32_t)strlen((char*)deviceUniqueIdUTF8);
  if (nameLength > kVideoCaptureUniqueNameLength)
    return -1;

  // Store the device name
  _deviceUniqueId = new (std::nothrow) char[nameLength + 1];
  memcpy(_deviceUniqueId, deviceUniqueIdUTF8, nameLength + 1);

  if (_dsInfo.Init() != 0)
    return -1;

  _captureFilter = _dsInfo.GetDeviceFilter(deviceUniqueIdUTF8);
  if (!_captureFilter) {
    RTC_LOG(LS_INFO) << "Failed to create capture filter.";
    return -1;
  }

  // Get the interface for DirectShow's GraphBuilder
  HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
                                IID_IGraphBuilder, (void**)&_graphBuilder);
  if (FAILED(hr)) {
    RTC_LOG(LS_INFO) << "Failed to create graph builder.";
    return -1;
  }

  hr = _graphBuilder->QueryInterface(IID_IMediaControl, (void**)&_mediaControl);
  if (FAILED(hr)) {
    RTC_LOG(LS_INFO) << "Failed to create media control builder.";
    return -1;
  }
  hr = _graphBuilder->AddFilter(_captureFilter, CAPTURE_FILTER_NAME);
  if (FAILED(hr)) {
    RTC_LOG(LS_INFO) << "Failed to add the capture device to the graph.";
    return -1;
  }

  _outputCapturePin = GetOutputPin(_captureFilter, PIN_CATEGORY_CAPTURE);
  if (!_outputCapturePin) {
    RTC_LOG(LS_INFO) << "Failed to get output capture pin";
    return -1;
  }

  // Create the sink filte used for receiving Captured frames.
  sink_filter_ = new ComRefCount<CaptureSinkFilter>(this);

  hr = _graphBuilder->AddFilter(sink_filter_, SINK_FILTER_NAME);
  if (FAILED(hr)) {
    RTC_LOG(LS_INFO) << "Failed to add the send filter to the graph.";
    return -1;
  }

  _inputSendPin = GetInputPin(sink_filter_);
  if (!_inputSendPin) {
    RTC_LOG(LS_INFO) << "Failed to get input send pin";
    return -1;
  }

  // Temporary connect here.
  // This is done so that no one else can use the capture device.
  if (SetCameraOutput(_requestedCapability) != 0) {
    return -1;
  }
  hr = _mediaControl->Pause();
  if (FAILED(hr)) {
    RTC_LOG(LS_INFO)
        << "Failed to Pause the Capture device. Is it already occupied? " << hr;
    return -1;
  }
  RTC_LOG(LS_INFO) << "Capture device '" << deviceUniqueIdUTF8
                   << "' initialized.";
  return 0;
}

链接 cpature output pin 和 sink input pin

int32_t VideoCaptureDS::SetCameraOutput(
    const VideoCaptureCapability& requestedCapability) {
  // Get the best matching capability
  VideoCaptureCapability capability;
  int32_t capabilityIndex;

  // Store the new requested size
  _requestedCapability = requestedCapability;
  // Match the requested capability with the supported.
  if ((capabilityIndex = _dsInfo.GetBestMatchedCapability(
           _deviceUniqueId, _requestedCapability, capability)) < 0) {
    return -1;
  }
  // Reduce the frame rate if possible.
  if (capability.maxFPS > requestedCapability.maxFPS) {
    capability.maxFPS = requestedCapability.maxFPS;
  } else if (capability.maxFPS <= 0) {
    capability.maxFPS = 30;
  }

  // Convert it to the windows capability index since they are not nexessary
  // the same
  VideoCaptureCapabilityWindows windowsCapability;
  if (_dsInfo.GetWindowsCapability(capabilityIndex, windowsCapability) != 0) {
    return -1;
  }

  IAMStreamConfig* streamConfig = NULL;
  AM_MEDIA_TYPE* pmt = NULL;
  VIDEO_STREAM_CONFIG_CAPS caps;

  HRESULT hr = _outputCapturePin->QueryInterface(IID_IAMStreamConfig,
                                                 (void**)&streamConfig);
  if (hr) {
    RTC_LOG(LS_INFO) << "Can't get the Capture format settings.";
    return -1;
  }

  // Get the windows capability from the capture device
  bool isDVCamera = false;
  hr = streamConfig->GetStreamCaps(windowsCapability.directShowCapabilityIndex,
                                   &pmt, reinterpret_cast<BYTE*>(&caps));
  if (hr == S_OK) {
    if (pmt->formattype == FORMAT_VideoInfo2) {
      VIDEOINFOHEADER2* h = reinterpret_cast<VIDEOINFOHEADER2*>(pmt->pbFormat);
      if (capability.maxFPS > 0 && windowsCapability.supportFrameRateControl) {
        h->AvgTimePerFrame = REFERENCE_TIME(10000000.0 / capability.maxFPS);
      }
    } else {
      VIDEOINFOHEADER* h = reinterpret_cast<VIDEOINFOHEADER*>(pmt->pbFormat);
      if (capability.maxFPS > 0 && windowsCapability.supportFrameRateControl) {
        h->AvgTimePerFrame = REFERENCE_TIME(10000000.0 / capability.maxFPS);
      }
    }

    // Set the sink filter to request this capability
    sink_filter_->SetRequestedCapability(capability);
    // Order the capture device to use this capability
    hr += streamConfig->SetFormat(pmt);

    // Check if this is a DV camera and we need to add MS DV Filter
    if (pmt->subtype == MEDIASUBTYPE_dvsl ||
        pmt->subtype == MEDIASUBTYPE_dvsd || pmt->subtype == MEDIASUBTYPE_dvhd)
      isDVCamera = true;  // This is a DV camera. Use MS DV filter
  }
  RELEASE_AND_CLEAR(streamConfig);

  if (FAILED(hr)) {
    RTC_LOG(LS_INFO) << "Failed to set capture device output format";
    return -1;
  }

  if (isDVCamera) {
    hr = ConnectDVCamera();
  } else {
    hr = _graphBuilder->ConnectDirect(_outputCapturePin, _inputSendPin, NULL);
  }
  if (hr != S_OK) {
    RTC_LOG(LS_INFO) << "Failed to connect the Capture graph " << hr;
    return -1;
  }
  return 0;
}

启动采集

int32_t VideoCaptureDS::StartCapture(const VideoCaptureCapability& capability) {
  rtc::CritScope cs(&_apiCs);

  HRESULT hr = _mediaControl->Run();
  if (FAILED(hr)) {
    RTC_LOG(LS_INFO) << "Failed to start the Capture device.";
    return -1;
  }
  return 0;
}

数据流

获取数据的流程,是蓝色部分,代码不复杂,重点需要关注下VcmCapturer,他既是消费者,又是source。
在这里插入图片描述

webrtc 摄像头的使用

创建CapturerTrackSource 作为source 也就上图右下角的位置的,作为摄像头最上层的一个封装,是一个source , 然后封装为videotrack。添加Sink 进行消费。 如果想了解 track 和 source 的实现,可参考我另一篇文章。

rtc::scoped_refptr<CapturerTrackSource> video_device =
      CapturerTrackSource::Create();
  if (video_device) {
    rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track_(
        peer_connection_factory_->CreateVideoTrack(kVideoLabel, video_device));
    main_wnd_->StartLocalRenderer(video_track_);

    result_or_error = peer_connection_->AddTrack(video_track_, {kStreamId});
    if (!result_or_error.ok()) {
      RTC_LOG(LS_ERROR) << "Failed to add video track to PeerConnection: "
                        << result_or_error.error().message();
    }
  } else {
    RTC_LOG(LS_ERROR) << "OpenVideoCaptureDevice failed";
  }
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: webrtc-qt-example是一个基于Qt框架开发的WebRTC示例项目。 WebRTC是一种开源的实时通信技术,能够支持音频、视频和数据的实时传输。它通过浏览器之间的端对端连接,实现了高质量的实时通信。 webrtc-qt-example的目的是展示如何使用Qt进行WebRTC开发。Qt是一套跨平台的C++应用程序开发框架,它提供了丰富的工具和库,使开发者能够快速构建可靠的应用程序。 这个示例项目提供了一些基本的功能和界面,使开发者能够了解和学习如何将WebRTC集成到Qt应用程序中。它包含了常见的WebRTC功能,如媒体流捕获、媒体流传输、信令交换等。 通过webrtc-qt-example,开发者可以学习到如何使用Qt的多媒体模块来捕获音频、视频和媒体设备。同时,也可以学习到如何使用Qt的网络模块来进行实时信令交换和流传输。 这个示例项目还提供了一些简单的界面,方便开发者进行测试和调试。开发者可以通过该界面实现与其他WebRTC应用的通信,例如建立视频通话、音频通话等。 总之,webrtc-qt-example是一个非常实用的示例项目,可以帮助开发者快速上手并掌握WebRTC在Qt中的开发。 ### 回答2: webrtc-qt-example是一个基于Qt框架的WebRTC示例应用程序。WebRTC是一种开源项目,它提供了在浏览器之间进行实时通信的能力,包括视频和音频的传输。而webrtc-qt-example则是将这种技术集成到Qt应用程序中的一个示例。 在webrtc-qt-example中,它使用了Qt的多媒体框架和WebRTC提供的API来实现音视频的传输和显示。通过使用WebRTC的API,webrtc-qt-example可以建立点对点的连接,进行音频和视频的实时传输。 webrtc-qt-example中的代码结构清晰,易于理解和扩展。它提供了一些基本的功能,如建立连接、发送和接收音视频流、呼叫取消等。开发者可以根据自己的需求来对这些功能进行定制和扩展。 此外,webrtc-qt-example还支持一些高级特性,如媒体设备的选择、音视频的编码和解码等。开发者可以通过修改代码来选择不同的媒体设备,并且可以使用不同的编码和解码算法来满足自己的需求。 总之,webrtc-qt-example是一个很棒的WebRTC示例应用程序,它可以帮助开发者快速了解和使用WebRTC技术。无论是为了实现实时视频通话、视频会议还是其他需要音视频传输的应用场景,webrtc-qt-example都提供了一个良好的起点,帮助开发者快速上手并实现自己的需求。 ### 回答3: webrtc-qt-example是一个基于Qt框架和WebRTC技术的示例应用。WebRTC是一种用于在Web浏览器上实现实时通信的开源项目,它提供了一套丰富的API和协议,可以实现音视频通话、数据传输以及屏幕共享等功能。 webrtc-qt-example利用Qt框架提供的跨平台能力,结合WebRTC技术,展示了在Qt应用中如何实现实时通信功能。这个示例应用具有以下特点和功能: 1. 界面友好:webrtc-qt-example使用Qt的GUI绘制工具,具有美观、直观的用户界面,便于用户操作和使用。 2. 实时通信:webrtc-qt-example内置了WebRTC的音视频通信功能,可以实现实时的语音和视频通话,支持两个或多个用户之间的通信。 3. 数据传输:除了音视频通话,webrtc-qt-example还支持在通话中传输数据。可以通过编写代码,实现实时文本传输或共享文件等功能。 4. 屏幕共享:webrtc-qt-example还支持屏幕共享功能,可以将自己的屏幕内容分享给其他用户,实现远程协助或在线教育等应用场景。 通过webrtc-qt-example的学习和实践,开发者可以了解并深入理解WebRTC技术的使用方法,以及在Qt框架中的应用。同时,借助webrtc-qt-example提供的示例代码和API文档,开发者可以进一步开发出更加复杂和功能丰富的实时通信应用,满足不同领域的需求。 总之,webrtc-qt-example是一个基于Qt框架和WebRTC技术的示例应用,具备实时音视频通话、数据传输和屏幕共享等功能,适用于开发者学习、实践和开发基于WebRTC的实时通信应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值