本文基于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添加第三方库
我使用文章里面的方法三,如下:
在相关的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>