【WebRTC研究(3)】WebRTC接入IPC——数据源是YUV格式

本文基于peerconnection_client改动,新增FakeCapture类,继承于VideoCaptureImpl, 通过海康SDK获取YUV数据,调用IncomingFrame接口,自动进入WebRTC的编码和发送模块。实现推送IPC实时视频的功能。

代码修改

新增fake_capture_ipc.h文件

在peerconnection_client工程新增fake_capture_ipc.h文件

namespace webrtc {
namespace videocapturemodule {
class FakeCapture : public VideoCaptureImpl
{
public:
  FakeCapture();
  virtual ~FakeCapture();

  virtual int32_t Init(const char* deviceUniqueIdUTF8);

  /*************************************************************************
   *
   *   Start/Stop
   *
   *************************************************************************/
  int32_t StartCapture(const VideoCaptureCapability& capability) override;
  int32_t StopCapture() override;

  /**************************************************************************
   *
   *   Properties of the set device
   *
   **************************************************************************/

  bool CaptureStarted() override;
  int32_t CaptureSettings(VideoCaptureCapability& settings) override;

}
} // namespace videocapturemodule
} // namespace webrtc

新增文件需要修改ninja文件才能编译通过

  • include_dirs 头文件目录,类似于VS附加包含目录
  • build 参考其他文件,依次添加即可

修改video_capture_factory_windows.cc文件

rtc::scoped_refptr<VideoCaptureModule> VideoCaptureImpl::Create(
    const char* device_id) {
  if (device_id == nullptr)
    return nullptr;

    //注释原有代码
  // TODO(tommi): Use Media Foundation implementation for Vista and up.
//   rtc::scoped_refptr capture(
//       new rtc::RefCountedObject());
//   if (capture->Init(device_id) != 0) {
//     return nullptr;
//   }

  // 新增
    rtc::scoped_refptr<FakeCapture> capture(
      new rtc::RefCountedObject<FakeCapture>());
    if (capture->Init(device_id) != 0) {
      return nullptr;
    }

    return capture;
}

修改vcm_capture.cc文件

bool VcmCapturer::Init(size_t width,
                       size_t height,
                       size_t target_fps,
                       size_t capture_device_index) {
  /*************************************************************************
   *   省略部分代码
   *************************************************************************/
  vcm_->RegisterCaptureDataCallback(this);

  // chb
//   device_info->GetCapability(vcm_->CurrentDeviceName(), 0, capability_);
//   capability_.width = static_cast(width);
//   capability_.height = static_cast(height);
//   capability_.maxFPS =  static_cast(target_fps);
//   capability_.videoType = VideoType::kI420;

    //这里暂时手动修改成IPC的视频信息,
    //正式使用需要自己实现DeviceInfo类,通过SDK自动获取视频信息
  capability_.width = 2560;//static_cast(width);
  capability_.height = 1920;//static_cast(height);
  capability_.maxFPS = 20;    // static_cast(target_fps);
  capability_.videoType = VideoType::kYV12;//VideoType::kI420;

  if (vcm_->StartCapture(capability_) != 0) {
    Destroy();
    return false;
  }

  RTC_CHECK(vcm_->CaptureStarted());

  return true;
}

WebRTC添加第三方lib库

参考webrtc添加第三方库

我使用文章里面的方法三,如下:

在相关的h或者cpp中#pragma comment(lib, "./*.lib")

里面的方法四失败了,不知道什么原因,没有继续研究。

验证

通过web页面进行测试,测试代码如下:

<html>
<head>
<title>PeerConnection server test pagetitle>
head>
<script>
    var request = null;
    var hangingGet = null;
    var localName;
    var server;
    var myId = -1;
    var otherPeers = {};
    var messageCounter = 0;
    var pc;    
    var pcConfig = {"iceServers": [{"url": "stun:stun.l.google.com:19302"}]};
    var pcOptions = {
        optional: [
            {DtlsSrtpKeyAgreement: true}
        ]
    }
    var mediaConstraints = {'mandatory': {
        'OfferToReceiveAudio': true,
        'OfferToReceiveVideo': true }};
    var remoteStream;
    
    RTCPeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
    RTCSessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription;
    RTCIceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;
    getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
    URL = window.webkitURL || window.URL;
    
    function createPeerConnection(peer_id) {
        try {
            pc = new RTCPeerConnection(pcConfig, pcOptions);
            pc.onicecandidate = function(event) {
                if (event.candidate) {
                    var candidate = {
                        sdpMLineIndex: event.candidate.sdpMLineIndex,
                        sdpMid: event.candidate.sdpMid,
                        candidate: event.candidate.candidate
                    };
                    sendToPeer(peer_id, JSON.stringify(candidate));
                } else {
                  console.log("End of candidates.");
                }
            };
            pc.onconnecting = onSessionConnecting;
            pc.onopen = onSessionOpened;
            pc.onaddstream = onRemoteStreamAdded;
            pc.onremovestream = onRemoteStreamRemoved;
            console.log("Created RTCPeerConnnection with config: " + JSON.stringify(pcConfig));
        } 
        catch (e) {
            console.log("Failed to create PeerConnection with " + connectionId + ", exception: " + e.message);
        }
    }
    

    function onRemoteStreamAdded(event) {
      console.log("Remote stream added:", URL.createObjectURL(event.stream));
      var remoteVideoElement = document.getElementById('remote-video');
      remoteVideoElement.src = URL.createObjectURL(event.stream);
      remoteVideoElement.play();
    }

    function sld_success_cb() {
    }

    function sld_failure_cb() {
      console.log("setLocalDescription failed");
    }

    function aic_success_cb() {
    }

    function aic_failure_cb() {
      console.log("addIceCandidate failed");
    }

    
    function handlePeerMessage(peer_id, data) {
        ++messageCounter;
        var str = "Message from '" + otherPeers[peer_id] + ":" + data;
        trace(str);
        
        var dataJson = JSON.parse(data);
        console.log("received ", dataJson);
        if (data.search("offer") != -1) {
            createPeerConnection(peer_id);
            pc.setRemoteDescription(new RTCSessionDescription(dataJson), onRemoteSdpSucces, onRemoteSdpError);              
            pc.createAnswer(function(sessionDescription) {
                console.log("Create answer:", sessionDescription);
                pc.setLocalDescription(sessionDescription,sld_success_cb,sld_failure_cb);
                var data = JSON.stringify(sessionDescription);
                sendToPeer(peer_id, data);
            }, function(error) { // error
                console.log("Create answer error:", error);
            }, mediaConstraints); // type error  ); //}, null          
        }
        else {
            console.log("Adding ICE candiate ", dataJson);
            var candidate = new RTCIceCandidate({sdpMLineIndex: dataJson.sdpMLineIndex, candidate: dataJson.candidate});
            pc.addIceCandidate(candidate, aic_success_cb, aic_failure_cb);
        }
    }    
    
    function trace(txt) {
        var elem = document.getElementById("debug");
        elem.innerHTML += txt + "
"
; } function handleServerNotification(data) { trace("Server notification: " + data); var parsed = data.split(','); if (parseInt(parsed[2]) != 0) otherPeers[parseInt(parsed[1])] = parsed[0]; } function parseIntHeader(r, name) { var val = r.getResponseHeader(name); return val != null && val.length ? parseInt(val) : -1; } function hangingGetCallback() { try { if (hangingGet.readyState != 4) return; if (hangingGet.status != 200) { trace("server error: " + hangingGet.statusText); disconnect(); } else { var peer_id = parseIntHeader(hangingGet, "Pragma"); console.log("Message from:", peer_id, ':', hangingGet.responseText); if (peer_id == myId) { handleServerNotification(hangingGet.responseText); } else { handlePeerMessage(peer_id, hangingGet.responseText); } } if (hangingGet) { hangingGet.abort(); hangingGet = null; } if (myId != -1) window.setTimeout(startHangingGet, 0); } catch (e) { trace("Hanging get error: " + e.description); } } function startHangingGet() { try { hangingGet = new XMLHttpRequest(); hangingGet.onreadystatechange = hangingGetCallback; hangingGet.ontimeout = onHangingGetTimeout; hangingGet.open("GET", server + "/wait?peer_id=" + myId, true); hangingGet.send(); } catch (e) { trace("error" + e.description); } } function onHangingGetTimeout() { trace("hanging get timeout. issuing again."); hangingGet.abort(); hangingGet = null; if (myId != -1) window.setTimeout(startHangingGet, 0); } function signInCallback() { try { if (request.readyState == 4) { if (request.status == 200) { var peers = request.responseText.split("\n"); myId = parseInt(peers[0].split(',')[1]); trace("My id: " + myId); for (var i = 1; i < peers.length; ++i) { if (peers[i].length > 0) { trace("Peer " + i + ": " + peers[i]); var parsed = peers[i].split(','); otherPeers[parseInt(parsed[1])] = parsed[0]; } } startHangingGet(); request = null; } } } catch (e) { trace("error: " + e.description); } } function signIn() { try { request = new XMLHttpRequest(); request.onreadystatechange = signInCallback; request.open("GET", server + "/sign_in?" + localName, true); request.send(); } catch (e) { trace("error: " + e.description); } } function dummy() { } function sendToPeer(peer_id, data) { try { console.log(peer_id," Send ", data); if (myId == -1) { alert("Not connected"); return; } if (peer_id == myId) { alert("Can't send a message to oneself :)"); return; } var r = new XMLHttpRequest(); r.onreadystatechange = dummy r.open("POST", server + "/message?peer_id=" + myId + "&to=" + peer_id, true); r.setRequestHeader("Content-Type", "text/plain"); r.send(data); } catch (e) { trace("send to peer error: " + e.description); } } function connect() { localName = document.getElementById("local").value.toLowerCase(); server = document.getElementById("server").value.toLowerCase(); if (localName.length == 0) { alert("I need a name please."); document.getElementById("local").focus(); } else { document.getElementById("connect").disabled = true; document.getElementById("disconnect").disabled = false; signIn(); } } function disconnect() { if (request) { request.abort(); request = null; } if (hangingGet) { hangingGet.abort(); hangingGet = null; } if (myId != -1) { request = new XMLHttpRequest(); request.open("GET", server + "/sign_out?peer_id=" + myId, false); request.send(); request = null; myId = -1; } document.getElementById("connect").disabled = false; document.getElementById("disconnect").disabled = true; } window.onbeforeunload = disconnect; function send() { var text = document.getElementById("message").value; var peer_id = parseInt(document.getElementById("peer_id").value); if (!text.length || peer_id == 0) { alert("No text supplied or invalid peer id"); } else { sendToPeer(peer_id, text); } } function toggleMe(obj) { var id = obj.id.replace("toggle", "msg"); var t = document.getElementById(id); if (obj.innerText == "+") { obj.innerText = "-"; t.style.display = "block"; } else { obj.innerText = "+"; t.style.display = "none"; } } function onSessionConnecting(message) { console.log("Session connecting."); } function onSessionOpened(message) { console.log("Session opened."); } function onRemoteStreamRemoved(event) { console.log("Remote stream removed."); } function onRemoteSdpError(event) { console.error('onRemoteSdpError', event.name, event.message); } function onRemoteSdpSucces() { console.log('onRemoteSdpSucces'); }
script> <body> <div id="container"> <div id="remote"> <video id="remote-video" width="50%" height="50%">video> div> div> Server: <input type="text" id="server" value="http://192.168.28.198:8888" /><br> Your name: <input type="text" id="local" value="myclient"/> <button id="connect" onclick="connect();">Connectbutton> <button disabled="true" id="disconnect" onclick="disconnect();">Disconnectbutton> <br> <button onclick="document.getElementById('debug').innerHTML='';">Clear logbutton> <pre id="debug">pre> <br> <hr> body> html>

你可能感兴趣的:(WebRTC)